diff --git a/.dockerignore b/.dockerignore index 203f3fdb1d..6bac5029e7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,11 +3,11 @@ **/dist **/node_modules plugins -!plugins/scalprum-backend +!plugins/auth-backend-module-oidc-provider !plugins/dynamic-plugins-info !plugins/dynamic-plugins-info-backend -!plugins/auth-backend-module-oidc-provider !plugins/licensed-users-info-backend +!plugins/scalprum-backend *.local.yaml coverage dist-types diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 65952aa112..54875242d9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,6 +3,9 @@ contact_links: - name: ❓ Red Hat Developer Hub JIRA url: https://issues.redhat.com/browse/RHIDP about: Please report any showcase/RHDH issues or feature requests in JIRA - https://issues.redhat.com/browse/RHIDP + - name: ❓ Janus-IDP Plugins + url: https://issues.redhat.com/browse/RHIDP + about: Please report any issues with https://github.com/janus-idp/backstage-plugins in JIRA - https://issues.redhat.com/browse/RHIDP - name: ❓ Backstage Community Plugins url: https://github.com/backstage/community-plugins/issues about: Please report any plugin issues or feature requests in https://github.com/backstage/community-plugins/issues diff --git a/.github/renovate.json b/.github/renovate.json index 2f2c29a549..c879685f71 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -5,144 +5,237 @@ ":rebaseStalePrs", "group:allNonMajor", "default:pinDigestsDisabled", - "default:automergeBranchPush" + ":automergeBranch" + ], + "labels": [ + "kind/dependency upgrade" ], - "python": { - "groupName": "python ", - "additionalBranchPrefix": "python ", - "dependencyDashboardApproval": true, - "description": "require dashboard approval for all python dependencies due to potential conflicts" - }, - "labels": ["kind/dependency upgrade"], "npm": { "minimumReleaseAge": "1 day" }, "pip_requirements": { - "fileMatch": ["requirements.*\\.in"] - }, - "docker": { - "digest": { - "enabled": false - } + "fileMatch": [ + "requirements.*\\.in" + ] }, "major": { "dependencyDashboardApproval": true }, + "recreateWhen": "never", "packageRules": [ { - "matchDatasources": ["docker"], - "groupName": ["Docker base images"] + "matchCategories": [ + "python" + ], + "groupName": "python ", + "additionalBranchPrefix": "python ", + "dependencyDashboardApproval": true, + "description": "require dashboard approval for all python dependencies due to potential conflicts" + }, + { + "matchCategories": [ + "docker" + ], + "digest": { + "enabled": false + } + }, + { + "matchDatasources": [ + "docker" + ], + "groupName": "Docker base images" }, { - "matchDepTypes": ["devDependencies"], - "matchUpdateTypes": ["patch", "minor"], + "matchDepTypes": [ + "devDependencies" + ], + "matchUpdateTypes": [ + "patch", + "minor" + ], "matchCurrentVersion": "!/^0/", - "groupName": ["DevDependencies (non-major)"], + "groupName": "DevDependencies (non-major)", "automerge": true }, { - "matchDepTypes": ["devDependencies"], - "matchUpdateTypes": ["major"], - "groupName": ["DevDependencies "] + "matchDepTypes": [ + "devDependencies" + ], + "matchUpdateTypes": [ + "major" + ], + "groupName": "DevDependencies " }, { - "matchDepTypes": ["dependencies", "peerDependencies"], + "matchDepTypes": [ + "dependencies", + "peerDependencies" + ], "groupName": "Dependencies (non-major)", - "matchUpdateTypes": ["minor", "patch"] + "matchUpdateTypes": [ + "minor", + "patch" + ] }, { - "matchDepTypes": ["dependencies", "peerDependencies"], + "matchDepTypes": [ + "dependencies", + "peerDependencies" + ], "groupName": "Dependencies", - "matchUpdateTypes": ["major"] + "matchUpdateTypes": [ + "major" + ] }, { - "extends": ["packages:test"], - "matchUpdateTypes": ["patch", "minor"], + "extends": [ + "packages:test" + ], + "matchUpdateTypes": [ + "patch", + "minor" + ], "matchCurrentVersion": "!/^0/", "groupName": "Test packages (non-major)", "automerge": true }, { - "extends": ["packages:test"], - "matchUpdateTypes": ["major"], + "extends": [ + "packages:test" + ], + "matchUpdateTypes": [ + "major" + ], "groupName": "Test packages " }, { - "extends": ["packages:linters"], - "matchUpdateTypes": ["patch", "minor"], + "extends": [ + "packages:linters" + ], + "matchUpdateTypes": [ + "patch", + "minor" + ], "matchCurrentVersion": "!/^0/", "groupName": "linters (non-major)", "automerge": true }, { - "extends": ["packages:linters"], - "matchUpdateTypes": ["major"], + "extends": [ + "packages:linters" + ], + "matchUpdateTypes": [ + "major" + ], "groupName": "linters" }, { - "extends": "monorepo:material-ui", - "matchUpdateTypes": ["patch", "minor"], + "extends": [ + "monorepo:material-ui" + ], + "matchUpdateTypes": [ + "patch", + "minor" + ], "groupName": "material-ui (non-major)", "automerge": true }, { - "extends": "monorepo:material-ui", - "matchUpdateTypes": ["major"], + "extends": [ + "monorepo:material-ui" + ], + "matchUpdateTypes": [ + "major" + ], "groupName": "material-ui" }, { - "extends": "monorepo:react", - "matchUpdateTypes": ["patch", "minor"], + "extends": [ + "monorepo:react" + ], + "matchUpdateTypes": [ + "patch", + "minor" + ], "groupName": "react (non-major)", "automerge": true }, { - "extends": "monorepo:react", - "matchUpdateTypes": ["major"], + "extends": [ + "monorepo:react" + ], + "matchUpdateTypes": [ + "major" + ], "groupName": "react" }, { - "extends": "monorepo:emotion", - "matchUpdateTypes": ["patch", "minor"], + "extends": [ + "monorepo:emotion" + ], + "matchUpdateTypes": [ + "patch", + "minor" + ], "groupName": "emotion (non-major)", "automerge": true }, { - "extends": "monorepo:emotion", - "matchUpdateTypes": ["major"], + "extends": [ + "monorepo:emotion" + ], + "matchUpdateTypes": [ + "major" + ], "groupName": "emotion" }, { - "matchPackagePrefixes": ["@types/"], - "matchUpdateTypes": ["patch", "minor"], - "groupName": "types (non-major)" + "matchUpdateTypes": [ + "patch", + "minor" + ], + "groupName": "types (non-major)", + "matchPackageNames": [ + "@types/{/,}**" + ] }, { - "matchPackagePrefixes": ["@types/"], - "matchUpdateTypes": ["major"], - "groupName": "types " + "matchUpdateTypes": [ + "major" + ], + "groupName": "types ", + "matchPackageNames": [ + "@types/{/,}**" + ] }, { - "matchPackagePatterns": [ - "^@backstage/", - "^@backstage-community/", - "^@janus-idp/", - "^@immobiliarelabs/", - "^@roadiehq/", - "^@pagerduty/", - "^@internal/" - ], "description": "ignore updates to all backstage updates and 3rd party plugins", - "groupName": ["Backstage packages"], + "groupName": "Backstage packages", "dependencyDashboardApproval": true, - "enabled": false + "enabled": false, + "matchPackageNames": [ + "/^@backstage//", + "/^@backstage-community//", + "/^@janus-idp//", + "/^@immobiliarelabs//", + "/^@roadiehq//", + "/^@pagerduty//", + "/^@internal//" + ] } ], - "ignorePaths": ["**/dist-dynamic/**"], - "ignoreDeps": ["@roadiehq/backstage-plugin-argo-cd"], + "ignorePaths": [ + "**/dist-dynamic/**" + ], + "ignoreDeps": [ + "@roadiehq/backstage-plugin-argo-cd" + ], "vulnerabilityAlerts": { "enabled": true, - "addLabels": ["kind/security"] + "addLabels": [ + "kind/security" + ] }, "osvVulnerabilityAlerts": true } diff --git a/.github/workflows/cache-cleanup.yaml b/.github/workflows/cache-cleanup.yaml index f6cde761c2..0e9c3a0d1c 100644 --- a/.github/workflows/cache-cleanup.yaml +++ b/.github/workflows/cache-cleanup.yaml @@ -1,6 +1,6 @@ # based on https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#managing-caches -name: cleanup caches by a branch +name: Cleanup caches by a branch on: pull_request: types: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 6772717103..0000000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2023-2024 The Janus IDP 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. - -name: CI - -on: - pull_request: - branches-ignore: - - 'changeset-release/**' - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.event.number || github.ref }} - cancel-in-progress: true - -jobs: - ci: - name: Main Job - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - - name: Setup local Turbo cache - uses: dtinth/setup-github-actions-caching-for-turbo@v1 - - - name: Use app-config.example.yaml - run: rm app-config.yaml && mv app-config.example.yaml app-config.yaml - - - name: Install Dependencies - run: | - yarn install - if [[ $(git diff --name-only . | grep yarn.lock || true) ]]; then - echo "After 'yarn install', workspace is dirty! The following files have changed:" - echo - git diff --name-only . || true - exit 42 - fi - - name: Prettier - run: | - yarn run prettier:check - - - name: CI - run: yarn run ci diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index e7c8d46197..0dcbe43802 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -14,10 +14,6 @@ on: pull_request: paths-ignore: - 'docs/**' - - 'showcase-docs/**' - - '.changeset/**' - branches-ignore: - - 'changeset-release/**' schedule: - cron: '17 0 * * 2' diff --git a/.github/workflows/link-checker.config.json b/.github/workflows/link-checker.config.json new file mode 100644 index 0000000000..d6579d4c0d --- /dev/null +++ b/.github/workflows/link-checker.config.json @@ -0,0 +1,7 @@ +{ + "ignorePatterns": [ + { "pattern": "^http://localhost:7007" }, + { "pattern": "^https://pkgs.devel.redhat.com" }, + { "pattern": "^https://gitlab.cee.redhat.com" } + ] +} diff --git a/.github/workflows/link-checker.yaml b/.github/workflows/link-checker.yaml new file mode 100644 index 0000000000..446ef4fa84 --- /dev/null +++ b/.github/workflows/link-checker.yaml @@ -0,0 +1,27 @@ +name: Check Markdown links + +on: + pull_request: + paths: + - '**.md' + - 'docs/**' + + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Check markdown links in docs + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + config-file: '.github/workflows/link-checker.config.json' + folder-path: 'docs/' + + - name: Check markdown files in root + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + config-file: '.github/workflows/link-checker.config.json' + # ignore subfolders we don't want to check everthing, there is a lot of files from plugins that we don't control + max-depth: 0 diff --git a/.github/workflows/next-docker-build.yaml b/.github/workflows/next-build-image.yaml similarity index 93% rename from .github/workflows/next-docker-build.yaml rename to .github/workflows/next-build-image.yaml index 98c5b9afea..723c64c663 100644 --- a/.github/workflows/next-docker-build.yaml +++ b/.github/workflows/next-build-image.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: Next Docker Build +name: Next on: push: @@ -27,8 +27,8 @@ env: REGISTRY: quay.io jobs: - next-docker-build: - name: Next Docker Build + build-image: + name: Build Image runs-on: ubuntu-latest permissions: contents: read @@ -42,7 +42,7 @@ jobs: - name: Get the last commit short SHA run: | - SHORT_SHA=$(git rev-parse --short HEAD) + SHORT_SHA=$(git rev-parse --short=8 HEAD) echo "SHORT_SHA=$SHORT_SHA" >> $GITHUB_ENV if [[ -f packages/app/src/build-metadata.json ]]; then repo="${{ github.repository }}" diff --git a/.github/workflows/on-new-issue.yaml b/.github/workflows/on-new-issue.yaml index 4cef3bd30e..c92f0b0a3b 100644 --- a/.github/workflows/on-new-issue.yaml +++ b/.github/workflows/on-new-issue.yaml @@ -1,3 +1,5 @@ +name: On New Issue + on: issues: types: diff --git a/.github/workflows/pr-docker-build.yaml b/.github/workflows/pr-build-image.yaml similarity index 85% rename from .github/workflows/pr-docker-build.yaml rename to .github/workflows/pr-build-image.yaml index f2a5933c67..788d2a47db 100644 --- a/.github/workflows/pr-docker-build.yaml +++ b/.github/workflows/pr-build-image.yaml @@ -12,16 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: PR Docker Build +name: PR Build Image on: pull_request_target: paths-ignore: - 'docs/**' - - 'showcase-docs/**' - - '.changeset/**' - branches-ignore: - - 'changeset-release/**' concurrency: group: ${{ github.workflow }}-${{ github.event.number || github.event.pull_request.head.ref }} @@ -31,8 +27,8 @@ env: REGISTRY: quay.io jobs: - pr-docker-build: - name: PR Docker Build + build-image: + name: Build Image runs-on: ubuntu-latest permissions: contents: read @@ -58,7 +54,7 @@ jobs: - name: Get the last commit short SHA of the PR run: | - SHORT_SHA=$(git rev-parse --short ${{ github.event.pull_request.head.sha }}) + SHORT_SHA=$(git rev-parse --short=8 ${{ github.event.pull_request.head.sha }}) echo "SHORT_SHA=$SHORT_SHA" >> $GITHUB_ENV if [[ -f packages/app/src/build-metadata.json ]]; then repoPR="${{ github.repository }}/pull/${{ github.event.number }}" @@ -89,5 +85,5 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: 'The image is available at: `quay.io/${{ github.repository }}:pr-${{ github.event.number }}`!' + body: 'The image is available at:\n* [`quay.io/${{ github.repository }}:pr-${{ github.event.number }}`](https://quay.io/${{ github.repository }}:pr-${{ github.event.number }}) or\n* [`quay.io/${{ github.repository }}:pr-${{ github.event.number }}-${{ env.SHORT_SHA }}`](https://quay.io/${{ github.repository }}:pr-${{ github.event.number }}-${{ env.SHORT_SHA }})' }) diff --git a/.github/workflows/pr-semantic.yaml b/.github/workflows/pr-semantic.yaml new file mode 100644 index 0000000000..801662905c --- /dev/null +++ b/.github/workflows/pr-semantic.yaml @@ -0,0 +1,73 @@ +name: PR Semantic + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + - labeled + - unlabeled + +jobs: + title: + name: Conventional Commits + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5 + id: lint_pr_title + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Since we use `conventionalcommits` preset for + # `@semantic-release/commit-analyzer`, this list has to match allowed types + # Ref: https://github.com/conventional-changelog/conventional-changelog-config-spec/blob/master/versions/2.2.0/README.md#types + types: | + feat + fix + chore + docs + style + refactor + perf + test + revert + requireScope: false + subjectPattern: ^(?![A-Z]).+$ + subjectPatternError: | + The subject "{subject}" found in the pull request title "{title}" + didn't match the configured pattern. Please ensure that the subject + doesn't start with an uppercase character. + ignoreLabels: | + ignore-semantic-pull-request + # For work-in-progress PRs you can typically use draft pull requests + # from GitHub. However, private repositories on the free plan don't have + # this option and therefore this action allows you to opt-in to using the + # special "[WIP]" prefix to indicate this state. This will avoid the + # validation of the PR title and the pull request checks remain pending. + # Note that a second check will be reported if this is enabled. + wip: true + + - uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 # v2 + # When the previous steps fails, the workflow would stop. By adding this + # condition you can continue the execution with the populated error message. + if: always() && (steps.lint_pr_title.outputs.error_message != null) + with: + header: pr-title-lint-error + message: | + Hey there and thank you for opening this pull request! 👋🏼 + + We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. + + Details: + + ``` + ${{ steps.lint_pr_title.outputs.error_message }} + ``` + + # Delete a previous comment when the issue has been resolved + - if: ${{ steps.lint_pr_title.outputs.error_message == null }} + uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 # v2 + with: + header: pr-title-lint-error + delete: true diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000000..68e47fac60 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,109 @@ +# Copyright 2023-2024 The Janus IDP 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. + +name: PR + +on: + pull_request: + +env: + TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha }} + TURBO_SCM_HEAD: ${{ github.sha }} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build with Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 + with: + node-version: ${{ matrix.node-version }} + registry-url: 'https://registry.npmjs.org' + + - name: Setup local Turbo cache + uses: dtinth/setup-github-actions-caching-for-turbo@cc723b4600e40a6b8815b65701d8614b91e2669e # v1 + + - name: Use app-config.example.yaml + run: rm app-config.yaml && mv app-config.example.yaml app-config.yaml + + - name: Install dependencies + uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} + + - name: Build packages + run: yarn run build --continue --affected + + test: + name: Test with Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 + with: + node-version: ${{ matrix.node-version }} + registry-url: 'https://registry.npmjs.org' + + - name: Setup local Turbo cache + uses: dtinth/setup-github-actions-caching-for-turbo@cc723b4600e40a6b8815b65701d8614b91e2669e # v1 + + - name: Use app-config.example.yaml + run: rm app-config.yaml && mv app-config.example.yaml app-config.yaml + + - name: Install dependencies + uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} + + - name: Run prettier + run: yarn prettier:check --continue --affected + + - name: Run lint + run: yarn run lint:check --continue --affected + + - name: Run monorepo tools + run: yarn run monorepo:check + + - name: Regenerate dockerfiles + run: | + yarn run build:dockerfile; if [[ $(git diff --name-only | grep Dockerfile || true) != "" ]]; then \ + echo "ERROR: Workspace is dirty! Must run 'yarn build:dockerfile' and commit changes!"; exit 1; \ + fi + + - name: Run tests + run: yarn run test --continue --affected + + - name: Verify wrappers + run: yarn workspace dynamic-plugins-utils run test:wrappers diff --git a/.github/workflows/techdocs.yaml b/.github/workflows/techdocs.yaml index 2d321c3343..2475cac993 100644 --- a/.github/workflows/techdocs.yaml +++ b/.github/workflows/techdocs.yaml @@ -43,27 +43,20 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Node - uses: actions/setup-node@v4 + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 with: node-version-file: '.nvmrc' - cache: 'yarn' + registry-url: 'https://registry.npmjs.org' - name: Setup local Turbo cache uses: dtinth/setup-github-actions-caching-for-turbo@v1 - - name: Install Dependencies - run: | - yarn install - if [[ $(git diff --name-only . | grep yarn.lock || true) ]]; then - echo "After 'yarn install', workspace is dirty! The following files have changed:" - echo - git diff --name-only . || true - exit 42 - fi + - name: Install dependencies + uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + with: + cache-prefix: ${{ runner.os }}-v20 - name: Lint run: | diff --git a/.github/workflows/update-backstage.yaml b/.github/workflows/update-backstage.yaml new file mode 100644 index 0000000000..46dfa7afce --- /dev/null +++ b/.github/workflows/update-backstage.yaml @@ -0,0 +1,100 @@ +# Copyright 2024 The Janus IDP 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. + +name: Update Backstage + +env: + TURBO_SCM_BASE: ${{ github.sha }} + +# enforce only one release action per release branch at a time +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +on: + workflow_dispatch: + inputs: + release: + description: 'Backstage release version (e.g., 1.2.3)' + required: false + pattern: + description: | + Specify a glob pattern to select packages for upgrade (e.g., `@{backstage,backstage-community}/*`). + To update all Backstage-related packages, use `@{backstage,backstage-community,janus-idp,roadiehq,immobiliarelabs,pagerduty,parfuemerie-douglas}/*`. + required: false + schedule: + - cron: "15 3 * * WED" # Every Wednesday at 3:15 AM + +jobs: + create-pr: + name: Create PR + runs-on: ubuntu-latest + + steps: + - name: Generate token + id: generate-token + uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + with: + app-id: ${{ vars.JANUS_IDP_GITHUB_APP_ID }} + private-key: ${{ secrets.JANUS_IDP_GITHUB_APP_PRIVATE_KEY }} + + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + token: ${{ steps.generate-token.outputs.token }} + + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 + with: + node-version-file: '.nvmrc' + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + with: + cache-prefix: ${{ runner.os }}-v20 + + - name: Run versons:bump script + run: | + yarn versions:bump \ + ${{ inputs.release && format('--release {0}', inputs.release) }} \ + ${{ inputs.pattern && format('--pattern {0}', inputs.pattern) }} + + - name: Determine PR details + id: pr-details + run: | + if [[ -n "${{ inputs.release }}" ]]; then + echo "commit_message=feat: update Backstage to ${{ inputs.release }}" >> $GITHUB_OUTPUT + echo "branch=dependencies/backstage-${{ inputs.release }}" >> $GITHUB_OUTPUT + elif [[ -n "${{ inputs.pattern }}" ]]; then + sanitized_branch=$(echo "${{ inputs.pattern }}" | tr -d '@{}*' | tr '/' '-' | tr ',' '.') + # Remove trailing hyphen if present + sanitized_branch=${sanitized_branch%-*} + echo "commit_message=feat: update Backstage plugins dependencies with pattern ${{ inputs.pattern }}" >> $GITHUB_OUTPUT + echo "branch=dependencies/${sanitized_branch}" >> $GITHUB_OUTPUT + else + echo "commit_message=feat: update Backstage to the latest version" >> $GITHUB_OUTPUT + echo "branch=dependencies/backstage-latest" >> $GITHUB_OUTPUT + fi + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ steps.generate-token.outputs.token }} + commit-message: ${{ steps.pr-details.outputs.commit_message }} + title: ${{ steps.pr-details.outputs.commit_message }} + branch: ${{ steps.pr-details.outputs.branch }} + base: main + signoff: true + sign-commits: true diff --git a/.github/workflows/versioned-docker-build.yaml b/.github/workflows/versioned-build-image.yaml similarity index 96% rename from .github/workflows/versioned-docker-build.yaml rename to .github/workflows/versioned-build-image.yaml index c459961d57..5045cd09db 100644 --- a/.github/workflows/versioned-docker-build.yaml +++ b/.github/workflows/versioned-build-image.yaml @@ -13,7 +13,7 @@ # limitations under the License. # on push of a tag, trigger a container build for that tag and push to http://quay.io/janus-idp/backstage-showcase -name: Versioned Docker Build +name: Versioned on: push: @@ -28,8 +28,8 @@ env: REGISTRY: quay.io jobs: - versioned-docker-build: - name: Versioned Docker Build + build-image: + name: Build Image runs-on: ubuntu-latest permissions: contents: read diff --git a/.gitignore b/.gitignore index 1d1c028f91..e079204493 100644 --- a/.gitignore +++ b/.gitignore @@ -16,13 +16,13 @@ coverage node_modules/ # Yarn 3 files -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions +**/.pnp.* +**/.yarn/* +!**/.yarn/patches +!**/.yarn/plugins +!**/.yarn/releases +!**/.yarn/sdks +!**/.yarn/versions # dotenv environment variables file .env @@ -32,6 +32,7 @@ node_modules/ dist dist-types dist-scalprum +dist-dynamic # Temporary change files created by Vim *.swp @@ -54,11 +55,11 @@ site # Dynamic plugins root content dynamic-plugins-root/* !dynamic-plugins-root/.gitkeep -dynamic-plugins/wrappers/*/dist-dynamic/src -dynamic-plugins/imports/*/ -dynamic-plugins/*/dist-dynamic/src #dev caches .webpack-cache .idea/ .idea/ + +# Private Keys +*.pem diff --git a/.ibm/OWNERS b/.ibm/OWNERS index 19298c889a..24a56a9cfe 100644 --- a/.ibm/OWNERS +++ b/.ibm/OWNERS @@ -1,6 +1,16 @@ reviewers: - josephca - - rnapoles-rh + - gustavolira + - subhashkhileri + - albarbaro + - nilgaar + - zdrapela + - psrna approvers: - josephca - - rnapoles-rh + - gustavolira + - subhashkhileri + - albarbaro + - nilgaar + - zdrapela + - psrna diff --git a/.ibm/images/Dockerfile b/.ibm/images/Dockerfile index deac140e70..a16a8fcc37 100644 --- a/.ibm/images/Dockerfile +++ b/.ibm/images/Dockerfile @@ -1,89 +1,60 @@ -FROM mcr.microsoft.com/playwright:v1.47.0-jammy +# Base image from Microsoft Playwright +FROM mcr.microsoft.com/playwright:v1.47.2-jammy +# Set environment variables for the container ENV CI=1 \ - QT_X11_NO_MITSHM=1 \ - _X11_NO_MITSHM=1 \ - _MITSHM=0 \ - NODE_PATH=/usr/local/lib/node_modules - -# Define Helm and OpenShift CLI (oc) versions -ENV HELM_VERSION="v3.12.3" -ENV OC_VERSION="4.14.3" - -ARG CI_XBUILD - -# should be root user + QT_X11_NO_MITSHM=1 \ + _X11_NO_MITSHM=1 \ + _MITSHM=0 \ + NODE_PATH=/usr/local/lib/node_modules \ + HELM_VERSION="v3.12.3" \ + OC_VERSION="4.14.3" \ + OCM_VERSION="0.1.76" \ + GO_VERSION="1.19" \ + GO_SHA256="464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6" \ + GOPATH="/go" \ + PATH="$GOPATH/bin:/usr/local/go/bin:$PATH" + +# Install essential dependencies and Node.js tools +RUN apt-get update && apt-get install -y --no-install-recommends \ + make gcc g++ python3 rsync sshpass \ + nodejs \ + openssl libssl-dev ca-certificates \ + curl wget jq colorized-logs && \ + npm install -g typescript yarn@latest && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ + echo "Node: $(node -v)\nNPM: $(npm -v)\nYarn: $(yarn -v)\nTypeScript: $(tsc -v)" + +# Ensure the current user is root and verify permissions RUN echo "whoami: $(whoami)" \ - # command "id" should print: - # uid=0(root) gid=0(root) groups=0(root) - # which means the current user is root - && id \ - && npm install -g typescript \ - # give every user read access to the "/root" folder where the binary is cached - # we really only need to worry about the top folder, fortunately - && ls -la /root \ - && chmod 755 /root \ - # always grab the latest Yarn - # otherwise the base image might have old versions - # NPM does not need to be installed as it is already included with Node. - && npm i -g yarn@latest \ - # Show where Node loads required modules from - && node -p 'module.paths' - # plus Electron and bundled Node versions - -RUN echo " node version: $(node -v) \n" \ - "npm version: $(npm -v) \n" \ - "yarn version: $(yarn -v) \n" \ - "typescript version: $(tsc -v) \n" \ - "debian version: $(cat /etc/debian_version) \n" \ - "user: $(whoami) \n" - -RUN curl -fsSL https://clis.cloud.ibm.com/install/linux | sh && \ - curl -sLO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \ - chmod +x kubectl && \ - mv kubectl /usr/local/bin/ && \ + # The "id" command should confirm the user is root + && id \ + # Make the "/root" folder readable for all users + && chmod 755 /root \ + # Check where Node.js loads required modules + && node -p 'module.paths' + +# Install Helm, OpenShift CLI, ocm-cli, and yq +RUN curl -fsSL -o /tmp/helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" && \ + tar -xzvf /tmp/helm.tar.gz -C /tmp && mv /tmp/linux-amd64/helm /usr/local/bin/helm && \ + curl -fsSL -o /tmp/openshift-client-linux.tar.gz "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/${OC_VERSION}/openshift-client-linux-${OC_VERSION}.tar.gz" && \ + tar -xzvf /tmp/openshift-client-linux.tar.gz -C /usr/local/bin oc kubectl && \ + curl -Lo /usr/local/bin/ocm "https://github.com/openshift-online/ocm-cli/releases/download/v${OCM_VERSION}/ocm-linux-amd64" && \ + chmod +x /usr/local/bin/ocm && \ + curl -fsSL "https://github.com/mikefarah/yq/releases/download/v4.43.1/yq_linux_amd64.tar.gz" | tar -xz && \ + mv yq_linux_amd64 /usr/local/bin/yq && \ + rm -rf /tmp/* /var/tmp/* + +# Install Azure CLI +RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Install Google Cloud CLI +RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \ + curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg && \ apt-get update -y && \ - apt-get install -y sshpass jq colorized-logs && \ - rm -rf /var/lib/apt/lists/* - -# Set Go version and the expected SHA256 hash for verification -ENV GO_VERSION 1.19 -ENV GO_SHA256 464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6 - -# Install Go and other tools used by the pipeline -RUN apt-get update && \ - apt-get install -y curl && \ - curl -LO "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" && \ - echo "${GO_SHA256} go${GO_VERSION}.linux-amd64.tar.gz" | sha256sum -c - && \ - tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz && \ - rm go${GO_VERSION}.linux-amd64.tar.gz && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install Helm -RUN curl -fsSL -o /tmp/helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" \ - && tar -xzvf /tmp/helm.tar.gz -C /tmp \ - && mv /tmp/linux-amd64/helm /usr/local/bin/helm \ - && rm -rf /tmp/* - -# Install OpenShift CLI (oc) -RUN curl -fsSL -o /tmp/openshift-client-linux.tar.gz "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/${OC_VERSION}/openshift-client-linux-${OC_VERSION}.tar.gz" \ - && tar -xzvf /tmp/openshift-client-linux.tar.gz -C /usr/local/bin oc kubectl \ - && rm -rf /tmp/* - -# Install rsync -RUN apt-get update -y && \ - apt-get install -y rsync - -# Install yq -RUN wget https://github.com/mikefarah/yq/releases/download/v4.43.1/yq_linux_amd64.tar.gz -O - | tar xz && mv yq_linux_amd64 /usr/bin/yq - -# Set environment variables to make Go work correctly -ENV GOPATH /go -ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH - -RUN go install github.com/kadel/pr-commenter@latest && \ - ibmcloud plugin install -f cloud-object-storage && \ - ibmcloud plugin install -f kubernetes-service + apt-get install google-cloud-cli google-cloud-sdk-gke-gcloud-auth-plugin -y && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +# Set working directory WORKDIR /tmp/ diff --git a/.ibm/pipelines/README.md b/.ibm/pipelines/README.md index ff4b00ea98..d3c261de3f 100644 --- a/.ibm/pipelines/README.md +++ b/.ibm/pipelines/README.md @@ -1,6 +1,6 @@ # Installation Instructions for Tests -For tests dependent on `janus-idp-backstage-plugin-ocm-backend-dynamic` and `janus-idp-backstage-plugin-ocm`, it's necessary to install **Advanced Cluster Management for Kubernetes "MultiClusterHub"**. +For tests dependent on `backstage-community-plugin-ocm-backend-dynamic` and `backstage-community-plugin-ocm`, it's necessary to install **Advanced Cluster Management for Kubernetes "MultiClusterHub"**. Please follow these steps for installation: diff --git a/.ibm/pipelines/auth/secrets-rhdh-secrets.yaml b/.ibm/pipelines/auth/secrets-rhdh-secrets.yaml index 4479fc1a66..51d9e76640 100644 --- a/.ibm/pipelines/auth/secrets-rhdh-secrets.yaml +++ b/.ibm/pipelines/auth/secrets-rhdh-secrets.yaml @@ -19,17 +19,17 @@ data: GITHUB_ORG_2: amFudXMtdGVzdA== GITLAB_TOKEN: dGVtcA== K8S_CLUSTER_NAME: bXktY2x1c3Rlcgo= - K8S_CLUSTER_API_SERVER_URL: aHR0cHM6Ly9jMTAwLWUudXMtZWFzdC5jb250YWluZXJzLmNsb3VkLmlibS5jb206MzIyMTIK + K8S_CLUSTER_API_SERVER_URL: dGVtcA== K8S_CLUSTER_TOKEN_ENCODED: dGVtcA== OCM_CLUSTER_URL: dGVtcA== OCM_CLUSTER_TOKEN: dGVtcA== - KEYCLOAK_BASE_URL: aHR0cHM6Ly9rZXljbG9hay1rZXljbG9hay5yaGRoLXByLW9zLWE5ODA1NjUwODMwYjIyYzNhZWUyNDNlNTFkNzk1NjVkLTAwMDAudXMtZWFzdC5jb250YWluZXJzLmFwcGRvbWFpbi5jbG91ZA== + KEYCLOAK_BASE_URL: dGVtcA== KEYCLOAK_LOGIN_REALM: bXlyZWFsbQ== KEYCLOAK_REALM: bXlyZWFsbQ== KEYCLOAK_CLIENT_ID: bXljbGllbnQ= KEYCLOAK_CLIENT_SECRET: dGVtcA== ACR_SECRET: dGVtcA== - DH_TARGET_URL: aHR0cDovL3Rlc3QtYmFja3N0YWdlLWN1c3RvbWl6YXRpb24tcHJvdmlkZXItc2hvd2Nhc2UtY2kucmhkaC1wci1vcy1hOTgwNTY1MDgzMGIyMmMzYWVlMjQzZTUxZDc5NTY1ZC0wMDAwLnVzLWVhc3QuY29udGFpbmVycy5hcHBkb21haW4uY2xvdWQ= + DH_TARGET_URL: dGVzdC1iYWNrc3RhZ2UtY3VzdG9taXphdGlvbi1wcm92aWRlci1zaG93Y2FzZS1jaS5yaGRoLXByLW9zLWE5ODA1NjUwODMwYjIyYzNhZWUyNDNlNTFkNzk1NjVkLTAwMDAudXMtZWFzdC5jb250YWluZXJzLmFwcGRvbWFpbi5jbG91ZA== GOOGLE_CLIENT_ID: dGVtcA== GOOGLE_CLIENT_SECRET: dGVtcA== type: Opaque diff --git a/.ibm/pipelines/cluster/aks/az.sh b/.ibm/pipelines/cluster/aks/az.sh new file mode 100644 index 0000000000..7959e111b3 --- /dev/null +++ b/.ibm/pipelines/cluster/aks/az.sh @@ -0,0 +1,40 @@ +az_login() { + az login --service-principal -u $ARM_CLIENT_ID -p $ARM_CLIENT_SECRET --tenant $ARM_TENANT_ID + az account set --subscription $ARM_SUBSCRIPTION_ID +} + +az_aks_start() { + local name=$1 + local resource_group=$2 + az aks start --name $name --resource-group $resource_group +} + +az_aks_stop() { + local name=$1 + local resource_group=$2 + az aks stop --name $name --resource-group $resource_group +} + +az_aks_approuting_enable() { + local name=$1 + local resource_group=$2 + set +xe + local output=$(az aks approuting enable --name $name --resource-group $resource_group 2>&1 | sed 's/^ERROR: //') + set -xe + exit_status=$? + + if [ $exit_status -ne 0 ]; then + if [[ "$output" == *"App Routing is already enabled"* ]]; then + echo "App Routing is already enabled. Continuing..." + else + echo "Error: $output" + exit 1 + fi + fi +} + +az_aks_get_credentials() { + local name=$1 + local resource_group=$2 + az aks get-credentials --name="${name}" --resource-group="${resource_group}" --overwrite-existing +} \ No newline at end of file diff --git a/.ibm/pipelines/cluster/aks/deployment.sh b/.ibm/pipelines/cluster/aks/deployment.sh new file mode 100644 index 0000000000..245ebe1106 --- /dev/null +++ b/.ibm/pipelines/cluster/aks/deployment.sh @@ -0,0 +1,39 @@ +initiate_aks_deployment() { + add_helm_repos + delete_namespace "${NAME_SPACE_RBAC_K8S}" + configure_namespace "${NAME_SPACE_K8S}" + # Renable when namespace termination issue is solved + # install_tekton_pipelines + uninstall_helmchart "${NAME_SPACE_K8S}" "${RELEASE_NAME}" + cd "${DIR}" + apply_yaml_files "${DIR}" "${NAME_SPACE_K8S}" + yq_merge_value_files "${DIR}/value_files/${HELM_CHART_VALUE_FILE_NAME}" "${DIR}/value_files/${HELM_CHART_AKS_DIFF_VALUE_FILE_NAME}" "/tmp/${HELM_CHART_K8S_MERGED_VALUE_FILE_NAME}" + mkdir -p "${ARTIFACT_DIR}/${NAME_SPACE_K8S}" + cp -a "/tmp/${HELM_CHART_K8S_MERGED_VALUE_FILE_NAME}" "${ARTIFACT_DIR}/${NAME_SPACE_K8S}/" # Save the final value-file into the artifacts directory. + echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE: ${NAME_SPACE_K8S}" + helm upgrade -i "${RELEASE_NAME}" -n "${NAME_SPACE_K8S}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" \ + -f "/tmp/${HELM_CHART_K8S_MERGED_VALUE_FILE_NAME}" \ + --set global.host="${K8S_CLUSTER_ROUTER_BASE}" \ + --set upstream.backstage.image.repository="${QUAY_REPO}" \ + --set upstream.backstage.image.tag="${TAG_NAME}" +} + +initiate_rbac_aks_deployment() { + add_helm_repos + delete_namespace "${NAME_SPACE_K8S}" + configure_namespace "${NAME_SPACE_RBAC_K8S}" + # Renable when namespace termination issue is solved + # install_tekton_pipelines + uninstall_helmchart "${NAME_SPACE_RBAC_K8S}" "${RELEASE_NAME_RBAC}" + cd "${DIR}" + apply_yaml_files "${DIR}" "${NAME_SPACE_RBAC_K8S}" + yq_merge_value_files "${DIR}/value_files/${HELM_CHART_RBAC_VALUE_FILE_NAME}" "${DIR}/value_files/${HELM_CHART_RBAC_AKS_DIFF_VALUE_FILE_NAME}" "/tmp/${HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME}" + mkdir -p "${ARTIFACT_DIR}/${NAME_SPACE_RBAC_K8S}" + cp -a "/tmp/${HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME}" "${ARTIFACT_DIR}/${NAME_SPACE_RBAC_K8S}/" # Save the final value-file into the artifacts directory. + echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE: ${NAME_SPACE_RBAC_K8S}" + helm upgrade -i "${RELEASE_NAME_RBAC}" -n "${NAME_SPACE_RBAC_K8S}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" \ + -f "/tmp/${HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME}" \ + --set global.host="${K8S_CLUSTER_ROUTER_BASE}" \ + --set upstream.backstage.image.repository="${QUAY_REPO}" \ + --set upstream.backstage.image.tag="${TAG_NAME}" +} diff --git a/.ibm/pipelines/cluster/gke/deployment.sh b/.ibm/pipelines/cluster/gke/deployment.sh new file mode 100644 index 0000000000..99c910fd81 --- /dev/null +++ b/.ibm/pipelines/cluster/gke/deployment.sh @@ -0,0 +1,44 @@ +initiate_gke_deployment() { + gcloud_ssl_cert_create $GKE_CERT_NAME $GKE_INSTANCE_DOMAIN_NAME $GOOGLE_CLOUD_PROJECT + add_helm_repos + delete_namespace "${NAME_SPACE_RBAC_K8S}" + configure_namespace "${NAME_SPACE_K8S}" + # Renable when namespace termination issue is solved + # install_tekton_pipelines + uninstall_helmchart "${NAME_SPACE_K8S}" "${RELEASE_NAME}" + cd "${DIR}" + apply_yaml_files "${DIR}" "${NAME_SPACE_K8S}" + oc apply -f "${DIR}/cluster/gke/frontend-config.yaml" --namespace="${project}" + yq_merge_value_files "${DIR}/value_files/${HELM_CHART_VALUE_FILE_NAME}" "${DIR}/value_files/${HELM_CHART_GKE_DIFF_VALUE_FILE_NAME}" "/tmp/${HELM_CHART_K8S_MERGED_VALUE_FILE_NAME}" + mkdir -p "${ARTIFACT_DIR}/${NAME_SPACE_K8S}" + cp -a "/tmp/${HELM_CHART_K8S_MERGED_VALUE_FILE_NAME}" "${ARTIFACT_DIR}/${NAME_SPACE_K8S}/" # Save the final value-file into the artifacts directory. + echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE: ${NAME_SPACE_K8S}" + helm upgrade -i "${RELEASE_NAME}" -n "${NAME_SPACE_K8S}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" \ + -f "/tmp/${HELM_CHART_K8S_MERGED_VALUE_FILE_NAME}" \ + --set global.host="${K8S_CLUSTER_ROUTER_BASE}" \ + --set upstream.backstage.image.repository="${QUAY_REPO}" \ + --set upstream.backstage.image.tag="${TAG_NAME}" \ + --set upstream.ingress.annotations."ingress\.gcp\.kubernetes\.io/pre-shared-cert"="${GKE_CERT_NAME}" +} + +initiate_rbac_gke_deployment() { + gcloud_ssl_cert_create $GKE_CERT_NAME $GKE_INSTANCE_DOMAIN_NAME $GOOGLE_CLOUD_PROJECT + add_helm_repos + delete_namespace "${NAME_SPACE_K8S}" + configure_namespace "${NAME_SPACE_RBAC_K8S}" + # Renable when namespace termination issue is solved + # install_tekton_pipelines + uninstall_helmchart "${NAME_SPACE_RBAC_K8S}" "${RELEASE_NAME_RBAC}" + cd "${DIR}" + apply_yaml_files "${DIR}" "${NAME_SPACE_RBAC_K8S}" + yq_merge_value_files "${DIR}/value_files/${HELM_CHART_RBAC_VALUE_FILE_NAME}" "${DIR}/value_files/${HELM_CHART_RBAC_GKE_DIFF_VALUE_FILE_NAME}" "/tmp/${HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME}" + mkdir -p "${ARTIFACT_DIR}/${NAME_SPACE_RBAC_K8S}" + cp -a "/tmp/${HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME}" "${ARTIFACT_DIR}/${NAME_SPACE_RBAC_K8S}/" # Save the final value-file into the artifacts directory. + echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE: ${NAME_SPACE_RBAC_K8S}" + helm upgrade -i "${RELEASE_NAME_RBAC}" -n "${NAME_SPACE_RBAC_K8S}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" \ + -f "/tmp/${HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME}" \ + --set global.host="${K8S_CLUSTER_ROUTER_BASE}" \ + --set upstream.backstage.image.repository="${QUAY_REPO}" \ + --set upstream.backstage.image.tag="${TAG_NAME}" \ + --set upstream.ingress.annotations."ingress\.gcp\.kubernetes\.io/pre-shared-cert"="${GKE_CERT_NAME}" +} diff --git a/.ibm/pipelines/cluster/gke/frontend-config.yaml b/.ibm/pipelines/cluster/gke/frontend-config.yaml new file mode 100644 index 0000000000..1f850397b0 --- /dev/null +++ b/.ibm/pipelines/cluster/gke/frontend-config.yaml @@ -0,0 +1,8 @@ +apiVersion: networking.gke.io/v1beta1 +kind: FrontendConfig +metadata: + name: rhdh-gke-ingress-security-config +spec: + sslPolicy: gke-ingress-ssl-policy-https + redirectToHttps: + enabled: true \ No newline at end of file diff --git a/.ibm/pipelines/cluster/gke/gcloud.sh b/.ibm/pipelines/cluster/gke/gcloud.sh new file mode 100755 index 0000000000..2c60f8240d --- /dev/null +++ b/.ibm/pipelines/cluster/gke/gcloud.sh @@ -0,0 +1,37 @@ +gcloud_auth() { + local service_account_name=$1 + local service_account_key_location=$2 + gcloud auth activate-service-account "${service_account_name}" --key-file "${service_account_key_location}" +} + +gcloud_gke_get_credentials() { + local cluster_name=$1 + local cluster_region=$2 + local project=$3 + gcloud container clusters get-credentials "${cluster_name}" --region "${cluster_region}" --project "${project}" +} + +gcloud_ssl_cert_create() { + local cert_name=$1 + local domain=$2 + local project=$3 + + # Capture both stdout and stderr + set +xe + local output=$(gcloud compute ssl-certificates create "${cert_name}" --domains="${domain}" --project="${project}" --global 2>&1) + set -xe + + # Check the return status + if [ $? -eq 0 ]; then + echo "Certificate '${cert_name}' created successfully.\nThe test might fail if the certificate is not obtained from the certificate authority in time." + else + # Check if the error is due to certificate already existing + if echo "$output" | grep -q "already exists"; then + echo "Certificate '${cert_name}' already exists, continuing..." + else + echo "Error creating certificate '${cert_name}':" + echo "$output" + exit 1 + fi + fi +} \ No newline at end of file diff --git a/.ibm/pipelines/cluster/osd-gcp/README.md b/.ibm/pipelines/cluster/osd-gcp/README.md new file mode 100644 index 0000000000..09415035ba --- /dev/null +++ b/.ibm/pipelines/cluster/osd-gcp/README.md @@ -0,0 +1,129 @@ +# 🚀 OpenShift Dedicated (OSD) Management Scripts + +> Automated scripts for managing OpenShift Dedicated clusters on Google Cloud Platform using OCM CLI. + +## 🔧 Prerequisites + +Before you begin, ensure you have: + +- [ ] OCM CLI installed +- [ ] Access to OpenShift Cluster Manager +- [ ] GCP Service Account with appropriate permissions +- [ ] Valid OCM CLIENT_ID and CLIENT_SECRET + +### Setting Up Service Accounts + +#### 1. GCP Service Account +- Obtain the GCP service account JSON from [here](https://vault.ci.openshift.org/ui/vault/secrets/kv/kv/selfservice%2Frhdh-qe%2Fosd-gcp) +- Look for the `gcp_service_account_json` secret +- Save this JSON file as your service account file +- Reference this file in the `--service-account-file` parameter in create-osd.sh + +#### 2. OCM Service Account +1. Visit [Red Hat Console IAM Service Accounts](https://console.redhat.com/iam/service-accounts) +2. Click "Create service account" +3. Fill in the required information +4. Save the generated CLIENT_ID and CLIENT_SECRET +5. Use these credentials in your environment variables + + +## ⚙️ Configuration + +Make scripts executable: +```bash +chmod +x create-osd.sh destroy-osd.sh +``` + +### Required Environment Variables + +```bash +# Set your workspace directory +export WORKSPACE="/path/to/workspace" + +# OCM Credentials +export CLIENT_ID="your_client_id" +export CLIENT_SECRET="your_client_secret" + +# Optional: Custom cluster name +export CLUSTER_NAME="your-cluster-name" +``` + +## 🚀 Usage + +### Creating a Cluster + +```bash +./create-osd.sh +``` + +This will: +1. Create a new OSD cluster on GCP +2. Set up HTPasswd authentication +3. Configure admin user +4. Generate access credentials +5. Create kubeconfig file + +### Destroying Clusters + +```bash +./destroy-osd.sh +``` + +This will remove all clusters matching the specified name pattern. + +## 📖 Scripts Overview + +### `create-osd.sh` + +Creates an OpenShift Dedicated cluster with the following specifications: +- OSD Version: 4.16.16 +- Region: us-east1 +- Provider: GCP +- Subscription: marketplace-gcp + +#### Output Files + +| File | Description | +|------|-------------| +| `cluster-info.name` | Cluster name | +| `cluster-info.id` | Cluster ID | +| `cluster-config.yaml` | Access details and credentials | +| `kubeconfig` | Kubernetes configuration | +| `cluster-info.yaml` | Detailed cluster information | + +### `destroy-osd.sh` + +Handles cluster cleanup: +- Identifies clusters by name pattern +- Initiates deletion process +- Monitors uninstallation progress + +### ⚠️ GitHub Authentication Limitation + +> **Important**: Due to GitHub App limitations, GitHub login functionality will not work in ephemeral environments. + +### 🧪 Running Tests on OSD Cluster + +To run existing tests on an OSD cluster: + +1. Update cluster credentials in OpenShift vault: + - Add new secrets or update the existing one: + - `RHDH_OSD_GCP_CLUSTER_URL`: Your cluster's API URL + - `RHDH_OSD_GCP_CLUSTER_TOKEN`: Your cluster's access token + +2. Modify your `openshift-ci-tests.sh` to use OSD cluster: +```bash +# Add these lines to set_cluster_info function +export K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_OSD_GCP_CLUSTER_URL) +export K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_OSD_GCP_CLUSTER_TOKEN) +``` + +3. Create a Pull Request with these changes to trigger tests on OSD cluster + +## 📝 Notes + +- Default cluster naming: `osdgcp-MMDD` +- Creation time: ~30-45 minutes +- Deletion time: ~15-30 minutes +- Uses latest OpenShift client binaries + diff --git a/.ibm/pipelines/cluster/osd-gcp/create-osd.sh b/.ibm/pipelines/cluster/osd-gcp/create-osd.sh new file mode 100755 index 0000000000..311fbd33ee --- /dev/null +++ b/.ibm/pipelines/cluster/osd-gcp/create-osd.sh @@ -0,0 +1,78 @@ +export OC_URL=https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-client-linux.tar.gz +export OI_URL=https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-install-linux.tar.gz + +export PATH=$WORKSPACE:$PATH + +if [ -n "$CLUSTER_NAME" ]; then + echo $CLUSTER_NAME > $WORKSPACE/cluster-info.name +fi + +if [ -f $WORKSPACE/cluster-info.name ]; then + CLUSTER_NAME="$(cat $WORKSPACE/cluster-info.name)" +else + CLUSTER_NAME="osdgcp-$(date +%m%d)" + echo $CLUSTER_NAME > $WORKSPACE/cluster-info.name +fi + +echo "Working with cluster '$CLUSTER_NAME'" + +ocm login --client-id=$CLIENT_ID --client-secret=$CLIENT_SECRET + +echo "Logged in as $(ocm whoami | jq -rc '.username')" + +OSD_VERSION=4.16.16 +SERVICE_ACCOUNT_FILE=temp + +# OSD_VERSION=${OSD_VERSION:-$(ocm list versions | tail -n1)} +echo "creating OSD_VERSION : $OSD_VERSION" + + +ocm create cluster --ccs --provider gcp --region us-east1 --service-account-file $SERVICE_ACCOUNT_FILE --subscription-type marketplace-gcp --marketplace-gcp-terms --version "$OSD_VERSION" "$CLUSTER_NAME" +CLUSTER_ID=$(ocm list clusters --columns "id,name" | grep $CLUSTER_NAME| cut -d " " -f1) + +echo "CLUSTER_ID : $CLUSTER_ID" + +echo $CLUSTER_ID > $WORKSPACE/cluster-info.id + +if [[ -z "$CLUSTER_ID" ]]; then + echo "Cluster $CLUSTER_NAME not found..."; + exit 0; +fi + +while [[ -z $(ocm cluster status $CLUSTER_ID | grep "State:.*ready") ]]; do + echo "Waiting for cluster $CLUSTER_ID to get ready..."; + sleep 30; +done + +echo "Creating kubeadmin user" +KUBEADMIN_USER=kubeadmin +KUBEADMIN_PASSWORD=$(dd if=/dev/random count=1 2>&1 | sha1sum | base64) +ocm create idp --type htpasswd -c $CLUSTER_ID -n 'kubeadmin' --username $KUBEADMIN_USER --password $KUBEADMIN_PASSWORD +ocm create user $KUBEADMIN_USER -c $CLUSTER_ID --group cluster-admins + +CLUSTER_CONFIG=$WORKSPACE/cluster-config.yaml +echo "Cluster $CLUSTER_ID is ready" +echo " console: $(ocm describe cluster $CLUSTER_ID --json | jq -rc '.console.url')" > $CLUSTER_CONFIG +echo " api_url: $(ocm describe cluster $CLUSTER_ID --json | jq -rc '.api.url')" >> $CLUSTER_CONFIG +echo " $KUBEADMIN_USER: $KUBEADMIN_PASSWORD" >> $CLUSTER_CONFIG +echo " cli: oc login $(ocm describe cluster $CLUSTER_ID --json | jq -rc '.api.url') --username $KUBEADMIN_USER --password $KUBEADMIN_PASSWORD" >> $CLUSTER_CONFIG + +echo +cat $CLUSTER_CONFIG +echo + +export KUBECONFIG=$WORKSPACE/kubeconfig +rm -rvf $KUBECONFIG +retries=50 +until [[ $retries == 0 ]]; do + echo "Attempting to login to get kubeconfig - $retries attempts remaining..." + oc login $(ocm describe cluster $CLUSTER_ID --json | jq -rc '.api.url') --username $KUBEADMIN_USER --password $KUBEADMIN_PASSWORD >/dev/null 2>&1 && break + sleep 30 + retries=$(($retries - 1)) +done +if [[ $retries == 0 ]]; then + echo "Unable to login as $KUBEADMIN_USER!" +else + echo "Successfull logged in as $KUBEADMIN_USER" +fi +ocm describe cluster $CLUSTER_NAME > $WORKSPACE/cluster-info.yaml diff --git a/.ibm/pipelines/cluster/osd-gcp/destroy-osd.sh b/.ibm/pipelines/cluster/osd-gcp/destroy-osd.sh new file mode 100755 index 0000000000..8fe6c74ddf --- /dev/null +++ b/.ibm/pipelines/cluster/osd-gcp/destroy-osd.sh @@ -0,0 +1,29 @@ +export OC_URL=https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-client-linux.tar.gz +export OI_URL=https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-install-linux.tar.gz + +export PATH=$WORKSPACE:$PATH + +CLUSTER_NAME=${CLUSTER_NAME:-osdgcp} + +ocm login --client-id=$CLIENT_ID --client-secret=$CLIENT_SECRET + +echo "Logged in as $(ocm whoami | jq -rc '.username')" + +echo "Looking for clusters that matches '$CLUSTER_NAME'" +CLUSTERS=$(ocm list clusters --columns name --no-headers) +if [ -z $CLUSTERS ]; then + echo "No cluster that matches '$CLUSTER_NAME' found" + exit 0 +fi +for c in $CLUSTERS; do + if [[ $c =~ $CLUSTER_NAME ]]; then + echo "Found $c - Requesting deletion..." + ocm delete /api/clusters_mgmt/v1/clusters/$(ocm describe cluster $c --json | jq -rc .id) + fi +done + +CLUSTER_ID=$(ocm list clusters --columns "id,name" | grep $CLUSTER_NAME| cut -d " " -f1) +while [[ -z $(ocm cluster status $CLUSTER_ID 2>&1 | grep "not found") ]]; do + echo "Waiting for cluster $CLUSTER_ID to be completely uninstalled..."; + sleep 30; +done diff --git a/.ibm/pipelines/env_variables.sh b/.ibm/pipelines/env_variables.sh index 2f720cb578..924321e036 100755 --- a/.ibm/pipelines/env_variables.sh +++ b/.ibm/pipelines/env_variables.sh @@ -4,22 +4,38 @@ set -a # Automatically export all variables #ENVS and Vault Secrets HELM_CHART_VALUE_FILE_NAME="values_showcase.yaml" HELM_CHART_RBAC_VALUE_FILE_NAME="values_showcase-rbac.yaml" +HELM_CHART_K8S_MERGED_VALUE_FILE_NAME="merged-values_showcase_K8S.yaml" +HELM_CHART_RBAC_K8S_MERGED_VALUE_FILE_NAME="merged-values_showcase-rbac_K8S.yaml" +HELM_CHART_AKS_DIFF_VALUE_FILE_NAME="diff-values_showcase_AKS.yaml" +HELM_CHART_RBAC_AKS_DIFF_VALUE_FILE_NAME="diff-values_showcase-rbac_AKS.yaml" +HELM_CHART_GKE_DIFF_VALUE_FILE_NAME="diff-values_showcase_GKE.yaml" +HELM_CHART_RBAC_GKE_DIFF_VALUE_FILE_NAME="diff-values_showcase-rbac_GKE.yaml" HELM_IMAGE_NAME=backstage HELM_REPO_NAME=rhdh-chart HELM_REPO_URL="https://redhat-developer.github.io/rhdh-chart" -K8S_CLUSTER_TOKEN_ENCODED=$(echo -n $K8S_CLUSTER_TOKEN | base64 | tr -d '\n') +K8S_CLUSTER_TOKEN_ENCODED=$(printf "%s" $K8S_CLUSTER_TOKEN | base64 | tr -d '\n') QUAY_REPO="${QUAY_REPO:-janus-idp/backstage-showcase}" RELEASE_NAME=rhdh RELEASE_NAME_RBAC=rhdh-rbac NAME_SPACE="${NAME_SPACE:-showcase}" NAME_SPACE_RBAC="${NAME_SPACE_RBAC:-showcase-rbac}" +NAME_SPACE_RUNTIME="${NAME_SPACE_RUNTIME:-showcase-runtime}" NAME_SPACE_POSTGRES_DB="${NAME_SPACE_POSTGRES_DB:-postgress-external-db}" +NAME_SPACE_RDS="showcase-rds-nightly" CHART_VERSION="2.15.2" -GITHUB_APP_APP_ID=Mzc2ODY2 -GITHUB_APP_CLIENT_ID=SXYxLjdiZDNlZDFmZjY3MmY3ZDg= +GITHUB_APP_APP_ID=$(cat /tmp/secrets/GITHUB_APP_APP_ID) +GITHUB_APP_CLIENT_ID=$(cat /tmp/secrets/GITHUB_APP_CLIENT_ID) GITHUB_APP_PRIVATE_KEY=$(cat /tmp/secrets/GITHUB_APP_PRIVATE_KEY) GITHUB_APP_CLIENT_SECRET=$(cat /tmp/secrets/GITHUB_APP_CLIENT_SECRET) +GITHUB_APP_2_APP_ID=$(cat /tmp/secrets/GITHUB_APP_2_APP_ID) +GITHUB_APP_2_CLIENT_ID=$(cat /tmp/secrets/GITHUB_APP_2_CLIENT_ID) +GITHUB_APP_2_PRIVATE_KEY=$(cat /tmp/secrets/GITHUB_APP_2_PRIVATE_KEY) +GITHUB_APP_2_CLIENT_SECRET=$(cat /tmp/secrets/GITHUB_APP_2_CLIENT_SECRET) +GITHUB_APP_3_APP_ID=$(cat /tmp/secrets/GITHUB_APP_3_APP_ID) +GITHUB_APP_3_CLIENT_ID=$(cat /tmp/secrets/GITHUB_APP_3_CLIENT_ID) +GITHUB_APP_3_PRIVATE_KEY=$(cat /tmp/secrets/GITHUB_APP_3_PRIVATE_KEY) +GITHUB_APP_3_CLIENT_SECRET=$(cat /tmp/secrets/GITHUB_APP_3_CLIENT_SECRET) GITHUB_APP_JANUS_TEST_APP_ID=OTE3NjM5 GITHUB_APP_JANUS_TEST_CLIENT_ID=SXYyM2xpSEdtU1l6SUFEbHFIakw= GITHUB_APP_JANUS_TEST_PRIVATE_KEY=$(cat /tmp/secrets/GITHUB_APP_JANUS_TEST_PRIVATE_KEY) @@ -32,35 +48,92 @@ GITHUB_ORG_2=amFudXMtdGVzdA== GH_USER_ID=$(cat /tmp/secrets/GH_USER_ID) GH_USER_PASS=$(cat /tmp/secrets/GH_USER_PASS) GH_2FA_SECRET=$(cat /tmp/secrets/GH_2FA_SECRET) +GH_USER2_ID=$(cat /tmp/secrets/GH_USER2_ID) +GH_USER2_PASS=$(cat /tmp/secrets/GH_USER2_PASS) +GH_USER2_2FA_SECRET=$(cat /tmp/secrets/GH_USER2_2FA_SECRET) GH_RHDH_QE_USER_TOKEN=$(cat /tmp/secrets/GH_RHDH_QE_USER_TOKEN) GITLAB_TOKEN=$(cat /tmp/secrets/GITLAB_TOKEN) -K8S_CLUSTER_API_SERVER_URL=$(echo -n "$K8S_CLUSTER_URL" | base64 | tr -d '\n') +RHDH_PR_OS_CLUSTER_URL=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_URL) +RHDH_PR_OS_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_TOKEN) +K8S_CLUSTER_API_SERVER_URL=$(printf "%s" "$K8S_CLUSTER_URL" | base64 | tr -d '\n') K8S_SERVICE_ACCOUNT_TOKEN=$K8S_CLUSTER_TOKEN_ENCODED -OCM_CLUSTER_URL=$(echo -n "$K8S_CLUSTER_URL" | base64 | tr -d '\n') +OCM_CLUSTER_URL=$(printf "%s" "$K8S_CLUSTER_URL" | base64 | tr -d '\n') OCM_CLUSTER_TOKEN=$K8S_CLUSTER_TOKEN_ENCODED -KEYCLOAK_BASE_URL='https://keycloak-keycloak.rhdh-pr-os-a9805650830b22c3aee243e51d79565d-0000.us-east.containers.appdomain.cloud' +KEYCLOAK_BASE_URL=$(cat /tmp/secrets/KEYCLOAK_BASE_URL) KEYCLOAK_LOGIN_REALM='myrealm' KEYCLOAK_REALM='myrealm' KEYCLOAK_CLIENT_ID='myclient' KEYCLOAK_CLIENT_SECRET=$(cat /tmp/secrets/KEYCLOAK_CLIENT_SECRET) ACR_SECRET=$(cat /tmp/secrets/ACR_SECRET) -DH_TARGET_URL=aHR0cDovL3Rlc3QtYmFja3N0YWdlLWN1c3RvbWl6YXRpb24tcHJvdmlkZXItc2hvd2Nhc2UtY2kucmhkaC1wci1vcy1hOTgwNTY1MDgzMGIyMmMzYWVlMjQzZTUxZDc5NTY1ZC0wMDAwLnVzLWVhc3QuY29udGFpbmVycy5hcHBkb21haW4uY2xvdWQ= +DH_TARGET_URL=dGVzdC1iYWNrc3RhZ2UtY3VzdG9taXphdGlvbi1wcm92aWRlci1zaG93Y2FzZS1jaS5yaGRoLXByLW9zLWE5ODA1NjUwODMwYjIyYzNhZWUyNDNlNTFkNzk1NjVkLTAwMDAudXMtZWFzdC5jb250YWluZXJzLmFwcGRvbWFpbi5jbG91ZA== GOOGLE_CLIENT_ID=$(cat /tmp/secrets/GOOGLE_CLIENT_ID) GOOGLE_CLIENT_SECRET=$(cat /tmp/secrets/GOOGLE_CLIENT_SECRET) GOOGLE_ACC_COOKIE=$(cat /tmp/secrets/GOOGLE_ACC_COOKIE) GOOGLE_USER_ID=$(cat /tmp/secrets/GOOGLE_USER_ID) GOOGLE_USER_PASS=$(cat /tmp/secrets/GOOGLE_USER_PASS) GOOGLE_2FA_SECRET=$(cat /tmp/secrets/GOOGLE_2FA_SECRET) +RDS_USER='cmhkaHFl' +RDS_PASSWORD=$(cat /tmp/secrets/RDS_PASSWORD) +RDS_1_HOST=$(cat /tmp/secrets/RDS_1_HOST) +RDS_2_HOST=$(cat /tmp/secrets/RDS_2_HOST) +RDS_3_HOST=$(cat /tmp/secrets/RDS_3_HOST) +JUNIT_RESULTS="junit-results.xml" DATA_ROUTER_URL=$(cat /tmp/secrets/DATA_ROUTER_URL) DATA_ROUTER_USERNAME=$(cat /tmp/secrets/DATA_ROUTER_USERNAME) DATA_ROUTER_PASSWORD=$(cat /tmp/secrets/DATA_ROUTER_PASSWORD) DATA_ROUTER_PROJECT="main" +DATA_ROUTER_AUTO_FINALIZATION_TRESHOLD=$(cat /tmp/secrets/DATA_ROUTER_AUTO_FINALIZATION_TRESHOLD) +DATA_ROUTER_NEXUS_HOSTNAME=$(cat /tmp/secrets/DATA_ROUTER_NEXUS_HOSTNAME) REPORTPORTAL_HOSTNAME=$(cat /tmp/secrets/REPORTPORTAL_HOSTNAME) -NEXUS_HOSTNAME=$(cat /tmp/secrets/NEXUS_HOSTNAME) +SLACK_DATA_ROUTER_WEBHOOK_URL=$(cat /tmp/secrets/SLACK_DATA_ROUTER_WEBHOOK_URL) REDIS_TEMP_USER=temp REDIS_TEMP_PASS=test123 +ARM_TENANT_ID=$(cat /tmp/secrets/ARM_TENANT_ID) +ARM_SUBSCRIPTION_ID=$(cat /tmp/secrets/ARM_SUBSCRIPTION_ID) +ARM_CLIENT_ID=$(cat /tmp/secrets/ARM_CLIENT_ID) +ARM_CLIENT_SECRET=$(cat /tmp/secrets/ARM_CLIENT_SECRET) +AKS_NIGHTLY_CLUSTER_NAME=$(cat /tmp/secrets/AKS_NIGHTLY_CLUSTER_NAME) +AKS_NIGHTLY_CLUSTER_RESOURCEGROUP=$(cat /tmp/secrets/AKS_NIGHTLY_CLUSTER_RESOURCEGROUP) +AKS_INSTANCE_DOMAIN_NAME=$(cat /tmp/secrets/AKS_INSTANCE_DOMAIN_NAME) + +GKE_CLUSTER_NAME=$(cat /tmp/secrets/GKE_CLUSTER_NAME) +GKE_CLUSTER_REGION=$(cat /tmp/secrets/GKE_CLUSTER_REGION) +GKE_INSTANCE_DOMAIN_NAME=$(cat /tmp/secrets/GKE_INSTANCE_DOMAIN_NAME) +GKE_SERVICE_ACCOUNT_NAME=$(cat /tmp/secrets/GKE_SERVICE_ACCOUNT_NAME) +GKE_CERT_NAME=$(cat /tmp/secrets/GKE_CERT_NAME) +GOOGLE_CLOUD_PROJECT=$(cat /tmp/secrets/GOOGLE_CLOUD_PROJECT) + +# authentication providers variables +RHSSO76_ADMIN_USERNAME=$(cat /tmp/secrets/RHSSO76_ADMIN_USERNAME) +RHSSO76_ADMIN_PASSWORD=$(cat /tmp/secrets/RHSSO76_ADMIN_PASSWORD) +RHSSO76_DEFAULT_PASSWORD=$(cat /tmp/secrets/RHSSO76_DEFAULT_PASSWORD) +RHSSO76_URL=$(cat /tmp/secrets/RHSSO76_URL) +RHSSO76_CLIENT_SECRET=$(cat /tmp/secrets/RHSSO76_CLIENT_SECRET) +RHSSO76_CLIENT_ID="myclient" +AUTH_PROVIDERS_REALM_NAME="authProviders" + +AZURE_LOGIN_USERNAME=$(cat /tmp/secrets/AZURE_LOGIN_USERNAME) +AZURE_LOGIN_PASSWORD=$(cat /tmp/secrets/AZURE_LOGIN_PASSWORD) +AUTH_PROVIDERS_AZURE_CLIENT_ID=$(cat /tmp/secrets/AUTH_PROVIDERS_AZURE_CLIENT_ID) +AUTH_PROVIDERS_AZURE_CLIENT_SECRET=$(cat /tmp/secrets/AUTH_PROVIDERS_AZURE_CLIENT_SECRET) +AUTH_PROVIDERS_AZURE_TENANT_ID=$(cat /tmp/secrets/AUTH_PROVIDERS_AZURE_TENANT_ID) + +AUTH_PROVIDERS_GH_ORG_NAME="rhdhqeauthorg" +AUTH_ORG_APP_ID=$(cat /tmp/secrets/AUTH_ORG_APP_ID) +AUTH_ORG_CLIENT_ID=$(cat /tmp/secrets/AUTH_ORG_CLIENT_ID) +AUTH_ORG_CLIENT_SECRET=$(cat /tmp/secrets/AUTH_ORG_CLIENT_SECRET) +AUTH_ORG1_PRIVATE_KEY=$(cat /tmp/secrets/AUTH_ORG1_PRIVATE_KEY) +AUTH_ORG_PK=$(cat /tmp/secrets/AUTH_ORG_PK) +AUTH_ORG_WEBHOOK_SECRET=$(cat /tmp/secrets/AUTH_ORG_WEBHOOK_SECRET) +GH_USER_PASSWORD=$(cat /tmp/secrets/GH_USER_PASSWORD) + +AUTH_PROVIDERS_RELEASE="rhdh-auth-providers" +AUTH_PROVIDERS_NAMESPACE="showcase-auth-providers" +STATIC_API_TOKEN="somecicdtoken" +AUTH_PROVIDERS_CHART="rhdh-chart/backstage" + set +a # Stop automatically exporting variables diff --git a/.ibm/pipelines/jobs/aks.sh b/.ibm/pipelines/jobs/aks.sh new file mode 100644 index 0000000000..ddf4d33c56 --- /dev/null +++ b/.ibm/pipelines/jobs/aks.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +handle_aks() { + echo "Starting AKS deployment" + for file in ${DIR}/cluster/aks/*.sh; do source $file; done + + export K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_AKS_CLUSTER_URL) + export K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_AKS_CLUSTER_TOKEN) + export K8S_CLUSTER_ROUTER_BASE=$AKS_INSTANCE_DOMAIN_NAME + export NAME_SPACE_K8S="showcase-k8s-ci-nightly" + export NAME_SPACE_RBAC_K8S="showcase-rbac-k8s-ci-nightly" + + url="https://${K8S_CLUSTER_ROUTER_BASE}" + + az_login + az_aks_start "${AKS_NIGHTLY_CLUSTER_NAME}" "${AKS_NIGHTLY_CLUSTER_RESOURCEGROUP}" + az_aks_approuting_enable "${AKS_NIGHTLY_CLUSTER_NAME}" "${AKS_NIGHTLY_CLUSTER_RESOURCEGROUP}" + az_aks_get_credentials "${AKS_NIGHTLY_CLUSTER_NAME}" "${AKS_NIGHTLY_CLUSTER_RESOURCEGROUP}" + + set_github_app_3_credentials + + initiate_aks_deployment + check_and_test "${RELEASE_NAME}" "${NAME_SPACE_K8S}" "${url}" + delete_namespace "${NAME_SPACE_K8S}" + initiate_rbac_aks_deployment + check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC_K8S}" + delete_namespace "${NAME_SPACE_RBAC_K8S}" +} + + diff --git a/.ibm/pipelines/jobs/gke.sh b/.ibm/pipelines/jobs/gke.sh new file mode 100644 index 0000000000..71e8de697c --- /dev/null +++ b/.ibm/pipelines/jobs/gke.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +handle_gke() { + echo "Starting GKE deployment" + for file in ${DIR}/cluster/gke/*.sh; do source $file; done + + export K8S_CLUSTER_ROUTER_BASE=$GKE_INSTANCE_DOMAIN_NAME + export NAME_SPACE_K8S="showcase-k8s-ci-nightly" + export NAME_SPACE_RBAC_K8S="showcase-rbac-k8s-ci-nightly" + url="https://${K8S_CLUSTER_ROUTER_BASE}" + + gcloud_auth "${GKE_SERVICE_ACCOUNT_NAME}" "/tmp/secrets/GKE_SERVICE_ACCOUNT_KEY" + gcloud_gke_get_credentials "${GKE_CLUSTER_NAME}" "${GKE_CLUSTER_REGION}" "${GOOGLE_CLOUD_PROJECT}" + + set_github_app_3_credentials + + initiate_gke_deployment + check_and_test "${RELEASE_NAME}" "${NAME_SPACE_K8S}" "${url}" + delete_namespace "${NAME_SPACE_K8S}" + initiate_rbac_gke_deployment + check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC_K8S}" + delete_namespace "${NAME_SPACE_RBAC_K8S}" + +} diff --git a/.ibm/pipelines/jobs/main.sh b/.ibm/pipelines/jobs/main.sh new file mode 100644 index 0000000000..027252e91d --- /dev/null +++ b/.ibm/pipelines/jobs/main.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +set -x + +set_namespace() { + # Enable parallel PR testing for main branch by utilizing a pool of namespaces + local namespaces_pool=("pr-1" "pr-2" "pr-3") + local namespace_found=false + # Iterate through namespace pool to find an available set + for ns in "${namespaces_pool[@]}"; do + if ! oc get namespace "showcase-$ns" >/dev/null 2>&1; then + echo "Namespace "showcase-$ns" does not exist, Using NS: showcase-$ns, showcase-rbac-$ns, postgress-external-db-$ns" + export NAME_SPACE="showcase-$ns" + export NAME_SPACE_RBAC="showcase-rbac-$ns" + export NAME_SPACE_POSTGRES_DB="postgress-external-db-$ns" + namespace_found=true + break + fi + done + if ! $namespace_found; then + echo "Error: All namespaces $namespaces_pool already in Use" + exit 1 + fi +} + +handle_main() { + echo "Configuring namespace: ${NAME_SPACE}" + set_github_app_4_credentials + set_namespace + oc_login + + API_SERVER_URL=$(oc whoami --show-server) + ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64) + ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64) + + export K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//') + local url="https://${RELEASE_NAME}-backstage-${NAME_SPACE}.${K8S_CLUSTER_ROUTER_BASE}" + initiate_deployments + deploy_test_backstage_provider "${NAME_SPACE}" + check_and_test "${RELEASE_NAME}" "${NAME_SPACE}" "${url}" + check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC}" "${url}" +} diff --git a/.ibm/pipelines/jobs/ocp-v4-15.sh b/.ibm/pipelines/jobs/ocp-v4-15.sh new file mode 100644 index 0000000000..7bc8d941c1 --- /dev/null +++ b/.ibm/pipelines/jobs/ocp-v4-15.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +handle_ocp_4_15() { + K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_OS_2_CLUSTER_URL) + K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_OS_2_CLUSTER_TOKEN) + + oc_login + + API_SERVER_URL=$(oc whoami --show-server) + ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64) + ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64) + + export K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//') + apply_yaml_files "${DIR}" "${NAME_SPACE}" + deploy_test_backstage_provider "${NAME_SPACE}" + local url="https://${release_name}-backstage-${namespace}.${K8S_CLUSTER_ROUTER_BASE}" + + initiate_deployments + check_and_test "${RELEASE_NAME}" "${NAME_SPACE}" "${url}" + check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC}" "${url}" +} diff --git a/.ibm/pipelines/jobs/ocp-v4-16.sh b/.ibm/pipelines/jobs/ocp-v4-16.sh new file mode 100644 index 0000000000..c8c8f8ed4f --- /dev/null +++ b/.ibm/pipelines/jobs/ocp-v4-16.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +handle_ocp_4_16() { + K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_OS_1_CLUSTER_URL) + K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_OS_1_CLUSTER_TOKEN) + + oc_login + + API_SERVER_URL=$(oc whoami --show-server) + ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64) + ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64) + + export K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//') + apply_yaml_files "${DIR}" "${NAME_SPACE}" + deploy_test_backstage_provider "${NAME_SPACE}" + local url="https://${release_name}-backstage-${namespace}.${K8S_CLUSTER_ROUTER_BASE}" + + initiate_deployments + check_and_test "${RELEASE_NAME}" "${NAME_SPACE}" "${url}" + check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC}" "${url}" +} diff --git a/.ibm/pipelines/jobs/operator.sh b/.ibm/pipelines/jobs/operator.sh new file mode 100644 index 0000000000..58b70c0442 --- /dev/null +++ b/.ibm/pipelines/jobs/operator.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +handle_operator() { + oc_login + + API_SERVER_URL=$(oc whoami --show-server) + ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64) + ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64) + + apply_yaml_files "${DIR}" "${NAME_SPACE}" + deploy_test_backstage_provider "${NAME_SPACE}" +} diff --git a/.ibm/pipelines/jobs/periodic.sh b/.ibm/pipelines/jobs/periodic.sh new file mode 100644 index 0000000000..921eb7fb20 --- /dev/null +++ b/.ibm/pipelines/jobs/periodic.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +handle_nightly() { + export NAME_SPACE="showcase-ci-nightly" + export NAME_SPACE_RBAC="showcase-rbac-nightly" + export NAME_SPACE_POSTGRES_DB="postgress-external-db-nightly" + export NAME_SPACE_K8S="showcase-k8s-ci-nightly" + export NAME_SPACE_RBAC_K8S="showcase-rbac-k8s-ci-nightly" + + oc_login + + API_SERVER_URL=$(oc whoami --show-server) + ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64) + ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64) + + export K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//') + + configure_namespace "${NAME_SPACE}" + deploy_test_backstage_provider "${NAME_SPACE}" + local url="https://${RELEASE_NAME}-backstage-${NAME_SPACE}.${K8S_CLUSTER_ROUTER_BASE}" + install_pipelines_operator + sleep 20 # wait for Pipeline Operator/Tekton pipelines to be ready + oc apply -f "$dir/resources/pipeline-run/hello-world-pipeline.yaml" + oc apply -f "$dir/resources/pipeline-run/hello-world-pipeline-run.yaml" + initiate_deployments + check_and_test "${RELEASE_NAME}" "${NAME_SPACE}" "${url}" + check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC}" "${url}" + + # Only test TLS config with RDS and Change configuration at runtime in nightly jobs + initiate_rds_deployment "${RELEASE_NAME}" "${NAME_SPACE_RDS}" + check_and_test "${RELEASE_NAME}" "${NAME_SPACE_RDS}" "${url}" + + # Deploy `showcase-runtime` to run tests that require configuration changes at runtime + configure_namespace "${NAME_SPACE_RUNTIME}" + uninstall_helmchart "${NAME_SPACE_RUNTIME}" "${RELEASE_NAME}" + oc apply -f "$DIR/resources/redis-cache/redis-deployment.yaml" --namespace="${NAME_SPACE_RUNTIME}" + apply_yaml_files "${DIR}" "${NAME_SPACE_RUNTIME}" + helm upgrade -i "${RELEASE_NAME}" -n "${NAME_SPACE_RUNTIME}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "${DIR}/value_files/${HELM_CHART_VALUE_FILE_NAME}" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}" + check_and_test "${RELEASE_NAME}" "${NAME_SPACE_RUNTIME}" "${url}" +} diff --git a/.ibm/pipelines/openshift-ci-tests.sh b/.ibm/pipelines/openshift-ci-tests.sh index d039b797ef..ca3dfcd8e3 100755 --- a/.ibm/pipelines/openshift-ci-tests.sh +++ b/.ibm/pipelines/openshift-ci-tests.sh @@ -4,384 +4,86 @@ set -xe export PS4='[$(date "+%Y-%m-%d %H:%M:%S")] ' # logs timestamp for every cmd. LOGFILE="test-log" -JUNIT_RESULTS="junit-results.xml" -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +export DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" secret_name="rhdh-k8s-plugin-secret" OVERALL_RESULT=0 cleanup() { echo "Cleaning up before exiting" - rm -rf ~/tmpbin -} - -trap cleanup EXIT - -source "${DIR}/utils.sh" - -set_cluster_info() { - export K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_URL) - export K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_TOKEN) - - if [[ "$JOB_NAME" == *ocp-v4-14 ]]; then - K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_OS_1_CLUSTER_URL) - K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_OS_1_CLUSTER_TOKEN) - elif [[ "$JOB_NAME" == *ocp-v4-13 ]]; then - K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_OS_2_CLUSTER_URL) - K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_OS_2_CLUSTER_TOKEN) - fi -} - -add_helm_repos() { - helm version - - local repos=( - "bitnami=https://charts.bitnami.com/bitnami" - "backstage=https://backstage.github.io/charts" - "${HELM_REPO_NAME}=${HELM_REPO_URL}" - ) - - for repo in "${repos[@]}"; do - local key="${repo%%=*}" - local value="${repo##*=}" - - if ! helm repo list | grep -q "^$key"; then - helm repo add "$key" "$value" - else - echo "Repository $key already exists - updating repository instead." - fi - done - - helm repo update -} - -install_oc() { - if command -v oc >/dev/null 2>&1; then - echo "oc is already installed." - else - curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/linux/oc.tar.gz - tar -xf oc.tar.gz - mv oc /usr/local/bin/ - rm oc.tar.gz - echo "oc installed successfully." - fi -} - -install_helm() { - if command -v helm >/dev/null 2>&1; then - echo "Helm is already installed." - else - echo "Installing Helm 3 client" - mkdir ~/tmpbin && cd ~/tmpbin - curl -sL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash -f - export PATH=$(pwd):$PATH - echo "Helm client installed successfully." - fi -} - -uninstall_helmchart() { - local project=$1 - local release=$2 - if helm list -n "${project}" | grep -q "${release}"; then - echo "Chart already exists. Removing it before install." - helm uninstall "${release}" -n "${project}" - fi -} - -configure_namespace() { - local project=$1 - if oc get namespace "${project}" >/dev/null 2>&1; then - echo "Namespace ${project} already exists! refreshing namespace" - oc delete namespace "${project}" - fi - oc create namespace "${project}" - oc config set-context --current --namespace="${project}" -} - -configure_external_postgres_db() { - local project=$1 - oc apply -f "${DIR}/resources/postgres-db/postgres.yaml" --namespace="${NAME_SPACE_POSTGRES_DB}" - sleep 5 - - oc get secret postgress-external-db-cluster-cert -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath='{.data.ca\.crt}' | base64 --decode > postgres-ca - oc get secret postgress-external-db-cluster-cert -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath='{.data.tls\.crt}' | base64 --decode > postgres-tls-crt - oc get secret postgress-external-db-cluster-cert -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath='{.data.tls\.key}' | base64 --decode > postgres-tsl-key - - oc create secret generic postgress-external-db-cluster-cert \ - --from-file=ca.crt=postgres-ca \ - --from-file=tls.crt=postgres-tls-crt \ - --from-file=tls.key=postgres-tsl-key \ - --dry-run=client -o yaml | oc apply -f - --namespace="${project}" - - POSTGRES_PASSWORD=$(oc get secret/postgress-external-db-pguser-janus-idp -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath={.data.password}) - sed -i "s|POSTGRES_PASSWORD:.*|POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" - POSTGRES_HOST=$(echo -n "postgress-external-db-primary.$NAME_SPACE_POSTGRES_DB.svc.cluster.local" | base64 | tr -d '\n') - sed -i "s|POSTGRES_HOST:.*|POSTGRES_HOST: ${POSTGRES_HOST}|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" - oc apply -f "${DIR}/resources/postgres-db/postgres-cred.yaml" --namespace="${project}" -} - -apply_yaml_files() { - local dir=$1 - local project=$2 - echo "Applying YAML files to namespace ${project}" - - oc config set-context --current --namespace="${project}" - - local files=( - "$dir/resources/service_account/service-account-rhdh.yaml" - "$dir/resources/cluster_role_binding/cluster-role-binding-k8s.yaml" - "$dir/resources/cluster_role/cluster-role-k8s.yaml" - "$dir/resources/cluster_role/cluster-role-ocm.yaml" - "$dir/resources/deployment/deployment-test-app-component.yaml" - "$dir/auth/secrets-rhdh-secrets.yaml" - ) - - for file in "${files[@]}"; do - sed -i "s/namespace:.*/namespace: ${project}/g" "$file" - done - - sed -i "s/backstage.io\/kubernetes-id:.*/backstage.io\/kubernetes-id: ${K8S_PLUGIN_ANNOTATION}/g" "$dir/resources/deployment/deployment-test-app-component.yaml" - - for key in GITHUB_APP_APP_ID GITHUB_APP_CLIENT_ID GITHUB_APP_PRIVATE_KEY GITHUB_APP_CLIENT_SECRET GITHUB_APP_JANUS_TEST_APP_ID GITHUB_APP_JANUS_TEST_CLIENT_ID GITHUB_APP_JANUS_TEST_CLIENT_SECRET GITHUB_APP_JANUS_TEST_PRIVATE_KEY GITHUB_APP_WEBHOOK_URL GITHUB_APP_WEBHOOK_SECRET KEYCLOAK_CLIENT_SECRET ACR_SECRET GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET K8S_CLUSTER_TOKEN_ENCODED OCM_CLUSTER_URL GITLAB_TOKEN; do - sed -i "s|${key}:.*|${key}: ${!key}|g" "$dir/auth/secrets-rhdh-secrets.yaml" - done - - oc apply -f "$dir/resources/service_account/service-account-rhdh.yaml" --namespace="${project}" - oc apply -f "$dir/auth/service-account-rhdh-secret.yaml" --namespace="${project}" - oc apply -f "$dir/auth/secrets-rhdh-secrets.yaml" --namespace="${project}" - oc apply -f "$dir/resources/deployment/deployment-test-app-component.yaml" --namespace="${project}" - oc new-app https://github.com/janus-qe/test-backstage-customization-provider --namespace="${project}" - oc expose svc/test-backstage-customization-provider --namespace="${project}" - oc apply -f "$dir/resources/cluster_role/cluster-role-k8s.yaml" --namespace="${project}" - oc apply -f "$dir/resources/cluster_role_binding/cluster-role-binding-k8s.yaml" --namespace="${project}" - oc apply -f "$dir/resources/cluster_role/cluster-role-ocm.yaml" --namespace="${project}" - oc apply -f "$dir/resources/cluster_role_binding/cluster-role-binding-ocm.yaml" --namespace="${project}" - - sed -i "s/K8S_CLUSTER_API_SERVER_URL:.*/K8S_CLUSTER_API_SERVER_URL: ${ENCODED_API_SERVER_URL}/g" "$dir/auth/secrets-rhdh-secrets.yaml" - sed -i "s/K8S_CLUSTER_NAME:.*/K8S_CLUSTER_NAME: ${ENCODED_CLUSTER_NAME}/g" "$dir/auth/secrets-rhdh-secrets.yaml" - - token=$(oc get secret "${secret_name}" -n "${project}" -o=jsonpath='{.data.token}') - sed -i "s/OCM_CLUSTER_TOKEN: .*/OCM_CLUSTER_TOKEN: ${token}/" "$dir/auth/secrets-rhdh-secrets.yaml" - - if [[ "${project}" == "showcase-rbac" || "${project}" == "showcase-rbac-nightly" || "${project}" == "showcase-rbac-1-2-x" ]]; then - oc apply -f "$dir/resources/config_map/configmap-app-config-rhdh-rbac.yaml" --namespace="${project}" - else - oc apply -f "$dir/resources/config_map/configmap-app-config-rhdh.yaml" --namespace="${project}" - fi - oc apply -f "$dir/resources/config_map/configmap-rbac-policy-rhdh.yaml" --namespace="${project}" - oc apply -f "$dir/auth/secrets-rhdh-secrets.yaml" --namespace="${project}" - - sleep 20 # wait for Pipeline Operator to be ready - oc apply -f "$dir/resources/pipeline-run/hello-world-pipeline.yaml" - oc apply -f "$dir/resources/pipeline-run/hello-world-pipeline-run.yaml" -} - -droute_send() { - # Skipping ReportPortal for nightly jobs on OCP v4.14 and v4.13 for now, as new clusters are not behind the RH VPN. - if [[ "$JOB_NAME" == *ocp-v4* ]]; then - return 0 - fi - - local release_name=$1 - local project=$2 - local droute_project="droute" - local droute_pod_name="droute-centos" - METEDATA_OUTPUT="data_router_metadata_output.json" - - # Remove properties (only used for skipped test and invalidates the file if empty) - sed -i '//,/<\/properties>/d' "${ARTIFACT_DIR}/${project}/${JUNIT_RESULTS}" - - JOB_BASE_URL="https://prow.ci.openshift.org/view/gs/test-platform-results" - if [ -n "${PULL_NUMBER:-}" ]; then - JOB_URL="${JOB_BASE_URL}/pr-logs/pull/${REPO_OWNER}_${REPO_NAME}/${PULL_NUMBER}/${JOB_NAME}/${BUILD_ID}" - else - JOB_URL="${JOB_BASE_URL}/logs/${JOB_NAME}/${BUILD_ID}" - fi - - jq \ - --arg hostname "$REPORTPORTAL_HOSTNAME" \ - --arg project "$DATA_ROUTER_PROJECT" \ - --arg name "$JOB_NAME" \ - --arg description "[View job run details](${JOB_URL})" \ - --arg key1 "job_type" \ - --arg value1 "$JOB_TYPE" \ - --arg key2 "pr" \ - --arg value2 "$GIT_PR_NUMBER" \ - '.targets.reportportal.config.hostname = $hostname | - .targets.reportportal.config.project = $project | - .targets.reportportal.processing.launch.name = $name | - .targets.reportportal.processing.launch.description = $description | - .targets.reportportal.processing.launch.attributes += [ - {"key": $key1, "value": $value1}, - {"key": $key2, "value": $value2} - ]' data_router/data_router_metadata_template.json > "${ARTIFACT_DIR}/${project}/${METEDATA_OUTPUT}" - - oc rsync -n "${droute_project}" "${ARTIFACT_DIR}/${project}/" "${droute_project}/${droute_pod_name}:/tmp/droute" - - oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c " - curl -fsSLk -o /tmp/droute-linux-amd64 'https://${NEXUS_HOSTNAME}/nexus/repository/dno-raw/droute-client/1.1/droute-linux-amd64' && chmod +x /tmp/droute-linux-amd64" - - oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c " - /tmp/droute-linux-amd64 send --metadata /tmp/droute/${METEDATA_OUTPUT} \ - --url '${DATA_ROUTER_URL}' \ - --username '${DATA_ROUTER_USERNAME}' \ - --password '${DATA_ROUTER_PASSWORD}' \ - --results '/tmp/droute/${JUNIT_RESULTS}' \ - --attachments '/tmp/droute/attachments' \ - --verbose" - -} - -run_tests() { - local release_name=$1 - local project=$2 - cd "${DIR}/../../e2e-tests" - yarn install - yarn playwright install - - Xvfb :99 & - export DISPLAY=:99 - - ( - set -e - echo "Using PR container image: ${TAG_NAME}" - yarn "$project" - ) |& tee "/tmp/${LOGFILE}" - - local RESULT=${PIPESTATUS[0]} - - pkill Xvfb - - mkdir -p "${ARTIFACT_DIR}/${project}/test-results" - mkdir -p "${ARTIFACT_DIR}/${project}/attachments/screenshots" - cp -a /tmp/backstage-showcase/e2e-tests/test-results/* "${ARTIFACT_DIR}/${project}/test-results" - cp -a /tmp/backstage-showcase/e2e-tests/${JUNIT_RESULTS} "${ARTIFACT_DIR}/${project}/${JUNIT_RESULTS}" - - if [ -d "/tmp/backstage-showcase/e2e-tests/screenshots" ]; then - cp -a /tmp/backstage-showcase/e2e-tests/screenshots/* "${ARTIFACT_DIR}/${project}/attachments/screenshots/" - fi - - ansi2html <"/tmp/${LOGFILE}" >"/tmp/${LOGFILE}.html" - cp -a "/tmp/${LOGFILE}.html" "${ARTIFACT_DIR}/${project}" - cp -a /tmp/backstage-showcase/e2e-tests/playwright-report/* "${ARTIFACT_DIR}/${project}" - - droute_send "${release_name}" "${project}" - - echo "${project} RESULT: ${RESULT}" - if [ "${RESULT}" -ne 0 ]; then - OVERALL_RESULT=1 - fi -} - -check_backstage_running() { - local release_name=$1 - local namespace=$2 - local url="https://${release_name}-backstage-${namespace}.${K8S_CLUSTER_ROUTER_BASE}" - - local max_attempts=30 - local wait_seconds=30 - - echo "Checking if Backstage is up and running at ${url}" - - for ((i = 1; i <= max_attempts; i++)); do - local http_status - http_status=$(curl --insecure -I -s "${url}" | grep HTTP | awk '{print $2}') - - if [ "${http_status}" -eq 200 ]; then - echo "Backstage is up and running!" - export BASE_URL="${url}" - echo "######## BASE URL ########" - echo "${BASE_URL}" - return 0 - else - echo "Attempt ${i} of ${max_attempts}: Backstage not yet available (HTTP Status: ${http_status})" - sleep "${wait_seconds}" - fi - done - - echo "Failed to reach Backstage at ${BASE_URL} after ${max_attempts} attempts." | tee -a "/tmp/${LOGFILE}" - cp -a "/tmp/${LOGFILE}" "${ARTIFACT_DIR}/${namespace}/" - return 1 -} - -install_pipelines_operator() { - local dir=$1 - DISPLAY_NAME="Red Hat OpenShift Pipelines" - - if oc get csv -n "openshift-operators" | grep -q "${DISPLAY_NAME}"; then - echo "Red Hat OpenShift Pipelines operator is already installed." - else - echo "Red Hat OpenShift Pipelines operator is not installed. Installing..." - oc apply -f "${dir}/resources/pipeline-run/pipelines-operator.yaml" + if [[ "$JOB_NAME" == *aks* ]]; then + az_aks_stop "${AKS_NIGHTLY_CLUSTER_NAME}" "${AKS_NIGHTLY_CLUSTER_RESOURCEGROUP}" + elif [[ "$JOB_NAME" == *pull-*-main-e2e-tests* ]]; then + # Cleanup namespaces after main branch PR e2e tests execution. + delete_namespace "${NAME_SPACE}" + delete_namespace "${NAME_SPACE_POSTGRES_DB}" + delete_namespace "${NAME_SPACE_RBAC}" fi + rm -rf ~/tmpbin } -initiate_deployments() { - add_helm_repos - configure_namespace "${NAME_SPACE}" - install_pipelines_operator "${DIR}" - install_helm - uninstall_helmchart "${NAME_SPACE}" "${RELEASE_NAME}" - - # Deploy redis cache db. - oc apply -f "$DIR/resources/redis-cache/redis-deployment.yaml" --namespace="${NAME_SPACE}" - - cd "${DIR}" - apply_yaml_files "${DIR}" "${NAME_SPACE}" - echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE : ${NAME_SPACE}" - helm upgrade -i "${RELEASE_NAME}" -n "${NAME_SPACE}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "${DIR}/value_files/${HELM_CHART_VALUE_FILE_NAME}" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}" +trap cleanup EXIT INT ERR - configure_namespace "${NAME_SPACE_POSTGRES_DB}" - configure_namespace "${NAME_SPACE_RBAC}" - configure_external_postgres_db "${NAME_SPACE_RBAC}" +export K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_URL) +export K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_TOKEN) - - install_pipelines_operator "${DIR}" - uninstall_helmchart "${NAME_SPACE_RBAC}" "${RELEASE_NAME_RBAC}" - apply_yaml_files "${DIR}" "${NAME_SPACE_RBAC}" - echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE : ${RELEASE_NAME_RBAC}" - helm upgrade -i "${RELEASE_NAME_RBAC}" -n "${NAME_SPACE_RBAC}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "${DIR}/value_files/${HELM_CHART_RBAC_VALUE_FILE_NAME}" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}" -} - -check_and_test() { - local release_name=$1 - local namespace=$2 - if check_backstage_running "${release_name}" "${namespace}"; then - echo "Display pods for verification..." - oc get pods -n "${namespace}" - run_tests "${release_name}" "${namespace}" - else - echo "Backstage is not running. Exiting..." - OVERALL_RESULT=1 - fi - save_all_pod_logs $namespace -} +source "${DIR}/env_variables.sh" +echo "Loaded env_variables.sh" +source "${DIR}/utils.sh" +echo "Loaded utils.sh" +source "${DIR}/jobs/aks.sh" +echo "Loaded aks.sh" +source "${DIR}/jobs/gke.sh" +echo "Loaded gke.sh" +source "${DIR}/jobs/main.sh" +echo "Loaded main.sh" +source "${DIR}/jobs/ocp-v4-15.sh" +echo "Loaded ocp-v4-15.sh" +source "${DIR}/jobs/ocp-v4-16.sh" +echo "Loaded ocp-v4-16.sh" +source "${DIR}/jobs/operator.sh" +echo "Loaded operator.sh" +source "${DIR}/jobs/periodic.sh" +echo "Loaded periodic.sh" main() { echo "Log file: ${LOGFILE}" - set_cluster_info - source "${DIR}/env_variables.sh" - if [[ "$JOB_NAME" == *periodic-* ]]; then - NAME_SPACE="showcase-ci-nightly" - NAME_SPACE_RBAC="showcase-rbac-nightly" - NAME_SPACE_POSTGRES_DB="postgress-external-db-nightly" - fi - - install_oc - oc login --token="${K8S_CLUSTER_TOKEN}" --server="${K8S_CLUSTER_URL}" - echo "OCP version: $(oc version)" - - API_SERVER_URL=$(oc whoami --show-server) - K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//') - - echo "K8S_CLUSTER_ROUTER_BASE : $K8S_CLUSTER_ROUTER_BASE" - - ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64) - ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64) + echo "JOB_NAME : $JOB_NAME" + + case "$JOB_NAME" in + *aks*) + echo "Calling handle_aks" + handle_aks + ;; + *gke*) + echo "Calling handle_gke" + handle_gke + ;; + *periodic*) + echo "Calling handle_periodic" + handle_nightly + ;; + *pull-*-main-e2e-tests*) + echo "Calling handle_main" + handle_main + ;; + *ocp-v4-16*) + echo "Calling handle_ocp_v4_16" + handle_ocp_v4_16 + ;; + *ocp-v4-15*) + echo "Calling handle_ocp_v4_15" + handle_ocp_v4_15 + ;; + *operator*) + echo "Calling Operator" + handle_operator + ;; + esac + +echo "K8S_CLUSTER_ROUTER_BASE : $K8S_CLUSTER_ROUTER_BASE" +echo "Main script completed with result: ${OVERALL_RESULT}" +exit "${OVERALL_RESULT}" - initiate_deployments - check_and_test "${RELEASE_NAME}" "${NAME_SPACE}" - check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC}" - exit "${OVERALL_RESULT}" } main diff --git a/.ibm/pipelines/resources/cluster_role/cluster-role-k8s.yaml b/.ibm/pipelines/resources/cluster_role/cluster-role-k8s.yaml index 4409d5619d..3106a4262e 100644 --- a/.ibm/pipelines/resources/cluster_role/cluster-role-k8s.yaml +++ b/.ibm/pipelines/resources/cluster_role/cluster-role-k8s.yaml @@ -74,7 +74,7 @@ rules: verbs: - get - list - # Additional permissions for the @janus-idp/backstage-plugin-tekton + # Additional permissions for the @backstage-community/plugin-tekton - apiGroups: - tekton.dev resources: diff --git a/.ibm/pipelines/resources/cluster_role_binding/cluster-role-binding-ocm.yaml b/.ibm/pipelines/resources/cluster_role_binding/cluster-role-binding-ocm.yaml index 1caf7d04d6..cb8631b32c 100644 --- a/.ibm/pipelines/resources/cluster_role_binding/cluster-role-binding-ocm.yaml +++ b/.ibm/pipelines/resources/cluster_role_binding/cluster-role-binding-ocm.yaml @@ -15,14 +15,29 @@ subjects: namespace: showcase-rbac - kind: ServiceAccount name: rhdh-k8s-plugin - namespace: showcase-rbac + namespace: showcase-ci-nightly - kind: ServiceAccount name: rhdh-k8s-plugin - namespace: showcase-ci-nightly + namespace: showcase-rbac-nightly - kind: ServiceAccount name: rhdh-k8s-plugin namespace: showcase-1-2-x - kind: ServiceAccount name: rhdh-k8s-plugin namespace: showcase-rbac-1-2-x + - kind: ServiceAccount + name: rhdh-k8s-plugin + namespace: showcase-1-3-x + - kind: ServiceAccount + name: rhdh-k8s-plugin + namespace: showcase-rbac-1-3-x + - kind: ServiceAccount + name: rhdh-k8s-plugin + namespace: showcase-pr-1 + - kind: ServiceAccount + name: rhdh-k8s-plugin + namespace: showcase-pr-2 + - kind: ServiceAccount + name: rhdh-k8s-plugin + namespace: showcase-pr-3 diff --git a/.ibm/pipelines/resources/config_map/app-config-rhdh-rbac.yaml b/.ibm/pipelines/resources/config_map/app-config-rhdh-rbac.yaml new file mode 100644 index 0000000000..70e61421b9 --- /dev/null +++ b/.ibm/pipelines/resources/config_map/app-config-rhdh-rbac.yaml @@ -0,0 +1,111 @@ +app: + title: Red Hat Developer Hub +backend: + auth: + keys: + - secret: temp +integrations: + # Plugin: GitHub + github: + - host: github.com + apps: + - appId: ${GITHUB_APP_APP_ID} + clientId: ${GITHUB_APP_CLIENT_ID} + clientSecret: ${GITHUB_APP_CLIENT_SECRET} + webhookUrl: ${GITHUB_APP_WEBHOOK_URL} + webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} + privateKey: | + ${GITHUB_APP_PRIVATE_KEY} + bitbucketServer: + - host: bitbucket.com + apiBaseUrl: temp + username: temp + password: temp + gitlab: + - host: gitlab.com + token: temp +auth: + # see https://backstage.io/docs/auth/ to learn about auth providers + environment: development + providers: + # Plugin: GitHub + github: + development: + clientId: ${GITHUB_APP_CLIENT_ID} + clientSecret: ${GITHUB_APP_CLIENT_SECRET} + google: + development: + clientId: ${GOOGLE_CLIENT_ID} + clientSecret: ${GOOGLE_CLIENT_SECRET} +proxy: + skipInvalidProxies: true + # endpoints: {} + endpoints: + # Other Proxies + # customize developer hub instance + '/developer-hub': + target: ${DH_TARGET_URL} + changeOrigin: true + # Change to "false" in case of using self hosted cluster with a self-signed certificate + secure: false + '/acr/api': + target: 'https://rhdhqetest.azurecr.io/acr/v1/' + changeOrigin: true + headers: + # If you use Bearer Token for authorization, please replace the 'Basic' with 'Bearer' in the following line. + Authorization: '${ACR_SECRET}' + # Change to "false" in case of using self hosted artifactory instance with a self-signed certificate + secure: false +catalog: + import: + entityFilename: catalog-info.yaml + # pullRequestBranchName: rhdh-integration + pullRequestBranchName: backstage-integration + rules: + - allow: [API, Component, Group, Location, Resource, System, Template] + locations: + - type: url + target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml + - type: url + target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates.yaml + - type: url + target: https://github.com/janus-test/janus-test-3-bulk-import/blob/main/catalog-info.yaml + - type: url + target: https://github.com/janus-qe/rhdh-test/blob/main/user.yml + rules: + - allow: [User] + - type: url + target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml + rules: + - allow: [User, Group] + providers: + githubOrg: + id: production + githubUrl: "${GITHUB_URL}" + orgs: ["${GITHUB_ORG}", "${GITHUB_ORG_2}"] +dynatrace: + baseUrl: temp +argocd: + appLocatorMethods: + - type: 'config' + instances: + - name: argoInstance1 + url: temp + token: temp + - name: argoInstance2 + url: temp + token: temp +permission: + enabled: true + rbac: + maxDepth: 1 + policyFileReload: true + policies-csv-file: './rbac/rbac-policy.csv' + conditionalPoliciesFile: './rbac-conditions/conditional-policies.yaml' + pluginsWithPermission: + - catalog + - permission + - scaffolder + admin: + users: + - name: user:default/rhdh-qe diff --git a/.ibm/pipelines/resources/config_map/app-config-rhdh.yaml b/.ibm/pipelines/resources/config_map/app-config-rhdh.yaml new file mode 100644 index 0000000000..ad49b0850c --- /dev/null +++ b/.ibm/pipelines/resources/config_map/app-config-rhdh.yaml @@ -0,0 +1,186 @@ +app: + title: Red Hat Developer Hub + branding: + fullLogo: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDIwMDEwOTA0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSLzIwMDEvUkVDLVNWRy0yMDAxMDkwNC9EVEQvc3ZnMTAuZHRkIj4KPCEtLSBDcmVhdGVkIHVzaW5nIEtyaXRhOiBodHRwczovL2tyaXRhLm9yZyAtLT4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIAogICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgICB4bWxuczprcml0YT0iaHR0cDovL2tyaXRhLm9yZy9uYW1lc3BhY2VzL3N2Zy9rcml0YSIKICAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgIHdpZHRoPSIxNjBwdCIKICAgIGhlaWdodD0iODBwdCIKICAgIHZpZXdCb3g9IjAgMCAxNjAgODAiPgo8ZGVmcy8+Cjx0ZXh0IGlkPSJzaGFwZTAiIGtyaXRhOnVzZVJpY2hUZXh0PSJ0cnVlIiB0ZXh0LXJlbmRlcmluZz0iYXV0byIga3JpdGE6dGV4dFZlcnNpb249IjMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjE3NzMyMDYxNTAzNDE1NSwgNTQuMjYyNSkiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMCIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJiZXZlbCIgbGV0dGVyLXNwYWNpbmc9IjAiIHdvcmQtc3BhY2luZz0iMCIgc3R5bGU9InRleHQtYWxpZ246IHN0YXJ0O3RleHQtYWxpZ24tbGFzdDogYXV0bztmb250LWZhbWlseTogUmVkIEhhdCBEaXNwbGF5O2ZvbnQtc2l6ZTogNDA7Zm9udC13ZWlnaHQ6IDcwMDsiPjx0c3BhbiB4PSIwIj5RRTwvdHNwYW4+PC90ZXh0Pjx0ZXh0IGlkPSJzaGFwZTEiIGtyaXRhOnVzZVJpY2hUZXh0PSJ0cnVlIiB0ZXh0LXJlbmRlcmluZz0iYXV0byIga3JpdGE6dGV4dFZlcnNpb249IjMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU3LjU2NDgyMDYxNTAzNDIsIDM1LjcyOTY4NzUpIiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMCIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAiIHN0cm9rZS1saW5lY2FwPSJzcXVhcmUiIHN0cm9rZS1saW5lam9pbj0iYmV2ZWwiIGxldHRlci1zcGFjaW5nPSIwIiB3b3JkLXNwYWNpbmc9IjAiIHN0eWxlPSJ0ZXh0LWFsaWduOiBzdGFydDt0ZXh0LWFsaWduLWxhc3Q6IGF1dG87Zm9udC1mYW1pbHk6IFJlZCBIYXQgVGV4dDtmb250LXNpemU6IDE0O2ZvbnQtd2VpZ2h0OiA3MDA7Ij48dHNwYW4geD0iMCI+UmVkIEhhdDwvdHNwYW4+PHRzcGFuIHg9IjAiIGR5PSIxOC41MTU2MjUiPkRldmVsb3BlciBIdWI8L3RzcGFuPjwvdGV4dD4KPC9zdmc+Cg==" + iconLogo: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDIwMDEwOTA0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSLzIwMDEvUkVDLVNWRy0yMDAxMDkwNC9EVEQvc3ZnMTAuZHRkIj4KPCEtLSBDcmVhdGVkIHVzaW5nIEtyaXRhOiBodHRwczovL2tyaXRhLm9yZyAtLT4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIAogICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgICB4bWxuczprcml0YT0iaHR0cDovL2tyaXRhLm9yZy9uYW1lc3BhY2VzL3N2Zy9rcml0YSIKICAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgIHdpZHRoPSI4MHB0IgogICAgaGVpZ2h0PSI4MHB0IgogICAgdmlld0JveD0iMCAwIDgwIDgwIj4KPGRlZnMvPgo8dGV4dCBpZD0ic2hhcGUwIiBrcml0YTp1c2VSaWNoVGV4dD0idHJ1ZSIgdGV4dC1yZW5kZXJpbmc9ImF1dG8iIGtyaXRhOnRleHRWZXJzaW9uPSIzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxLjU5OTk5OTk5OTk5OTk5LCA2Mi44MTI1KSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIiBzdHJva2UtbGluZWpvaW49ImJldmVsIiBsZXR0ZXItc3BhY2luZz0iMCIgd29yZC1zcGFjaW5nPSIwIiBzdHlsZT0idGV4dC1hbGlnbjogc3RhcnQ7dGV4dC1hbGlnbi1sYXN0OiBhdXRvO2ZvbnQtZmFtaWx5OiBSZWQgSGF0IE1vbm87Zm9udC1zaXplOiA2NDtmb250LXdlaWdodDogNzAwOyI+PHRzcGFuIHg9IjAiPlFFPC90c3Bhbj48L3RleHQ+Cjwvc3ZnPgo=" + theme: + light: + primaryColor: "#2A61A7" + headerColor1: "rgb(216, 98, 208)" + headerColor2: "rgb(216, 164, 98)" + navigationIndicatorColor: "rgb(98, 216, 105)" + dark: + primaryColor: '#DC6ED9' + headerColor1: 'rgb(190, 122, 45)' + headerColor2: 'rgb(45, 190, 50)' + navigationIndicatorColor: 'rgb(45, 113, 190)' +dynamicPlugins: + rootDirectory: dynamic-plugins-root + frontend: + default.main-menu-items: + menuItems: + default.list: + title: References + icon: bookmarks + default.apis: + parent: default.list + default.learning-path: + parent: default.list + backstage.plugin-techdocs: + menuItems: + favorites: + title: Favorites + icon: star + priority: 10 + docs: + parent: favorites + priority: 1 + pataknight.backstage-plugin-rhdh-qe-theme: + appIcons: + - importName: LightIcon + name: lightIcon + - importName: DarkIcon + name: darkIcon + themes: + - icon: lightIcon + id: light-dynamic + importName: lightThemeProvider + title: Light Dynamic + variant: light + - icon: darkIcon + id: dark-dynamic + importName: darkThemeProvider + title: Dark Dynamic + variant: dark +backend: + reading: + allow: + - host: 'github.com' + - host: ${DH_TARGET_URL} + auth: + keys: + - secret: temp + cache: + store: redis + connection: redis://${REDIS_USERNAME}:${REDIS_PASSWORD}@redis:6379 + useRedisSets: true +integrations: + # Plugin: GitHub + github: + - host: github.com + apps: + - appId: ${GITHUB_APP_APP_ID} + clientId: ${GITHUB_APP_CLIENT_ID} + clientSecret: ${GITHUB_APP_CLIENT_SECRET} + webhookUrl: ${GITHUB_APP_WEBHOOK_URL} + webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} + privateKey: | + ${GITHUB_APP_PRIVATE_KEY} + - appId: ${GITHUB_APP_JANUS_TEST_APP_ID} + clientId: ${GITHUB_APP_JANUS_TEST_CLIENT_ID} + clientSecret: ${GITHUB_APP_JANUS_TEST_CLIENT_SECRET} + webhookUrl: ${GITHUB_APP_WEBHOOK_URL} + webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} + privateKey: | + ${GITHUB_APP_JANUS_TEST_PRIVATE_KEY} + bitbucketServer: + - host: bitbucket.com + apiBaseUrl: temp + username: temp + password: temp + gitlab: + - host: gitlab.com + token: ${GITLAB_TOKEN} +auth: + environment: development + providers: + guest: + dangerouslyAllowOutsideDevelopment: true + # Plugin: GitHub + github: + development: + clientId: ${GITHUB_APP_CLIENT_ID} + clientSecret: ${GITHUB_APP_CLIENT_SECRET} + google: + development: + clientId: ${GOOGLE_CLIENT_ID} + clientSecret: ${GOOGLE_CLIENT_SECRET} +techRadar: + url: "http://${DH_TARGET_URL}/tech-radar" +proxy: + skipInvalidProxies: true + # endpoints: {} + endpoints: + # Other Proxies + '/acr/api': + target: 'https://rhdhqetest.azurecr.io/acr/v1/' + changeOrigin: true + headers: + # If you use Bearer Token for authorization, please replace the 'Basic' with 'Bearer' in the following line. + Authorization: '${ACR_SECRET}' + # Change to "false" in case of using self hosted artifactory instance with a self-signed certificate + secure: false + '/quay/api': + target: https://quay.io/ + headers: + X-Requested-With: 'XMLHttpRequest' + changeOrigin: true + secure: true +catalog: + import: + entityFilename: catalog-info.yaml + # pullRequestBranchName: rhdh-integration + pullRequestBranchName: backstage-integration + rules: + - allow: [API, Component, Group, Location, Resource, System, Template] + locations: + - type: url + target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml + - type: url + target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates.yaml + - type: url + target: https://github.com/janus-qe/acr-catalog/blob/main/catalog-info.yaml + - type: url + target: https://github.com/janus-qe/rhdh-test/blob/main/user.yml + rules: + - allow: [User] + - type: url + target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml + rules: + - allow: [User, Group] + providers: + github: + providerId: + organization: '${GITHUB_ORG}' + schedule: + frequency: { minutes: 30} + timeout: { minutes: 30} + githubOrg: + id: production + githubUrl: "${GITHUB_URL}" + orgs: ["${GITHUB_ORG}", "${GITHUB_ORG_2}"] + gitlab: + my-test-provider: + group: rhdhqetest + host: gitlab.com + schedule: + frequency: + minutes: 1 + initialDelay: + seconds: 15 + timeout: + minutes: 1 +dynatrace: + baseUrl: temp +argocd: + appLocatorMethods: + - type: 'config' + instances: + - name: argoInstance1 + url: temp + token: temp + - name: argoInstance2 + url: temp + token: temp +permission: + enabled: false \ No newline at end of file diff --git a/.ibm/pipelines/resources/config_map/configmap-app-config-rhdh-rbac.yaml b/.ibm/pipelines/resources/config_map/configmap-app-config-rhdh-rbac.yaml deleted file mode 100644 index 27f2557a37..0000000000 --- a/.ibm/pipelines/resources/config_map/configmap-app-config-rhdh-rbac.yaml +++ /dev/null @@ -1,111 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: app-config-rhdh - -data: - app-config-rhdh.yaml: | - app: - title: Red Hat Developer Hub - backend: - auth: - keys: - - secret: temp - integrations: - # Plugin: GitHub - github: - - host: github.com - apps: - - appId: ${GITHUB_APP_APP_ID} - clientId: ${GITHUB_APP_CLIENT_ID} - clientSecret: ${GITHUB_APP_CLIENT_SECRET} - webhookUrl: ${GITHUB_APP_WEBHOOK_URL} - webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} - privateKey: | - ${GITHUB_APP_PRIVATE_KEY} - bitbucketServer: - - host: bitbucket.com - apiBaseUrl: temp - username: temp - password: temp - gitlab: - - host: gitlab.com - token: temp - auth: - # see https://backstage.io/docs/auth/ to learn about auth providers - environment: development - providers: - # Plugin: GitHub - github: - development: - clientId: ${GITHUB_APP_CLIENT_ID} - clientSecret: ${GITHUB_APP_CLIENT_SECRET} - google: - development: - clientId: ${GOOGLE_CLIENT_ID} - clientSecret: ${GOOGLE_CLIENT_SECRET} - - proxy: - skipInvalidProxies: true - # endpoints: {} - endpoints: - # Other Proxies - # customize developer hub instance - '/developer-hub': - target: ${DH_TARGET_URL} - changeOrigin: true - # Change to "false" in case of using self hosted cluster with a self-signed certificate - secure: false - '/acr/api': - target: 'https://rhdhqetest.azurecr.io/acr/v1/' - changeOrigin: true - headers: - # If you use Bearer Token for authorization, please replace the 'Basic' with 'Bearer' in the following line. - Authorization: '${ACR_SECRET}' - # Change to "false" in case of using self hosted artifactory instance with a self-signed certificate - secure: false - - catalog: - import: - entityFilename: catalog-info.yaml - # pullRequestBranchName: rhdh-integration - pullRequestBranchName: backstage-integration - rules: - - allow: [API, Component, Group, Location, Resource, System, Template] - locations: - - type: url - target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml - - type: url - target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates.yaml - - type: url - target: https://github.com/janus-qe/acr-catalog/blob/main/catalog-info.yaml - - type: url - target: https://github.com/janus-qe/rhdh-test/blob/main/user.yml - rules: - - allow: [User] - - type: url - target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml - rules: - - allow: [User, Group] - - - dynatrace: - baseUrl: temp - argocd: - appLocatorMethods: - - type: 'config' - instances: - - name: argoInstance1 - url: temp - token: temp - - name: argoInstance2 - url: temp - token: temp - permission: - enabled: true - rbac: - policies-csv-file: './rbac/rbac-policy.csv' - admin: - users: - - name: user:default/rhdh-qe - diff --git a/.ibm/pipelines/resources/config_map/configmap-app-config-rhdh.yaml b/.ibm/pipelines/resources/config_map/configmap-app-config-rhdh.yaml deleted file mode 100644 index 0bc34ae336..0000000000 --- a/.ibm/pipelines/resources/config_map/configmap-app-config-rhdh.yaml +++ /dev/null @@ -1,153 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: app-config-rhdh - -data: - app-config-rhdh.yaml: | - app: - title: Red Hat Developer Hub - branding: - fullLogo: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDIwMDEwOTA0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSLzIwMDEvUkVDLVNWRy0yMDAxMDkwNC9EVEQvc3ZnMTAuZHRkIj4KPCEtLSBDcmVhdGVkIHVzaW5nIEtyaXRhOiBodHRwczovL2tyaXRhLm9yZyAtLT4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIAogICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgICB4bWxuczprcml0YT0iaHR0cDovL2tyaXRhLm9yZy9uYW1lc3BhY2VzL3N2Zy9rcml0YSIKICAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgIHdpZHRoPSIxNjBwdCIKICAgIGhlaWdodD0iODBwdCIKICAgIHZpZXdCb3g9IjAgMCAxNjAgODAiPgo8ZGVmcy8+Cjx0ZXh0IGlkPSJzaGFwZTAiIGtyaXRhOnVzZVJpY2hUZXh0PSJ0cnVlIiB0ZXh0LXJlbmRlcmluZz0iYXV0byIga3JpdGE6dGV4dFZlcnNpb249IjMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjE3NzMyMDYxNTAzNDE1NSwgNTQuMjYyNSkiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMCIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJiZXZlbCIgbGV0dGVyLXNwYWNpbmc9IjAiIHdvcmQtc3BhY2luZz0iMCIgc3R5bGU9InRleHQtYWxpZ246IHN0YXJ0O3RleHQtYWxpZ24tbGFzdDogYXV0bztmb250LWZhbWlseTogUmVkIEhhdCBEaXNwbGF5O2ZvbnQtc2l6ZTogNDA7Zm9udC13ZWlnaHQ6IDcwMDsiPjx0c3BhbiB4PSIwIj5RRTwvdHNwYW4+PC90ZXh0Pjx0ZXh0IGlkPSJzaGFwZTEiIGtyaXRhOnVzZVJpY2hUZXh0PSJ0cnVlIiB0ZXh0LXJlbmRlcmluZz0iYXV0byIga3JpdGE6dGV4dFZlcnNpb249IjMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU3LjU2NDgyMDYxNTAzNDIsIDM1LjcyOTY4NzUpIiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMCIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAiIHN0cm9rZS1saW5lY2FwPSJzcXVhcmUiIHN0cm9rZS1saW5lam9pbj0iYmV2ZWwiIGxldHRlci1zcGFjaW5nPSIwIiB3b3JkLXNwYWNpbmc9IjAiIHN0eWxlPSJ0ZXh0LWFsaWduOiBzdGFydDt0ZXh0LWFsaWduLWxhc3Q6IGF1dG87Zm9udC1mYW1pbHk6IFJlZCBIYXQgVGV4dDtmb250LXNpemU6IDE0O2ZvbnQtd2VpZ2h0OiA3MDA7Ij48dHNwYW4geD0iMCI+UmVkIEhhdDwvdHNwYW4+PHRzcGFuIHg9IjAiIGR5PSIxOC41MTU2MjUiPkRldmVsb3BlciBIdWI8L3RzcGFuPjwvdGV4dD4KPC9zdmc+Cg==" - iconLogo: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDIwMDEwOTA0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSLzIwMDEvUkVDLVNWRy0yMDAxMDkwNC9EVEQvc3ZnMTAuZHRkIj4KPCEtLSBDcmVhdGVkIHVzaW5nIEtyaXRhOiBodHRwczovL2tyaXRhLm9yZyAtLT4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIAogICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgICB4bWxuczprcml0YT0iaHR0cDovL2tyaXRhLm9yZy9uYW1lc3BhY2VzL3N2Zy9rcml0YSIKICAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgIHdpZHRoPSI4MHB0IgogICAgaGVpZ2h0PSI4MHB0IgogICAgdmlld0JveD0iMCAwIDgwIDgwIj4KPGRlZnMvPgo8dGV4dCBpZD0ic2hhcGUwIiBrcml0YTp1c2VSaWNoVGV4dD0idHJ1ZSIgdGV4dC1yZW5kZXJpbmc9ImF1dG8iIGtyaXRhOnRleHRWZXJzaW9uPSIzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxLjU5OTk5OTk5OTk5OTk5LCA2Mi44MTI1KSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0ic3F1YXJlIiBzdHJva2UtbGluZWpvaW49ImJldmVsIiBsZXR0ZXItc3BhY2luZz0iMCIgd29yZC1zcGFjaW5nPSIwIiBzdHlsZT0idGV4dC1hbGlnbjogc3RhcnQ7dGV4dC1hbGlnbi1sYXN0OiBhdXRvO2ZvbnQtZmFtaWx5OiBSZWQgSGF0IE1vbm87Zm9udC1zaXplOiA2NDtmb250LXdlaWdodDogNzAwOyI+PHRzcGFuIHg9IjAiPlFFPC90c3Bhbj48L3RleHQ+Cjwvc3ZnPgo=" - theme: - light: - primaryColor: "rgb(255, 95, 21)" - headerColor1: "rgb(248, 248, 248)" - headerColor2: "rgb(248, 248, 248)" - navigationIndicatorColor: "rgb(255,95,21)" - dark: - primaryColor: '#ab75cf' - headerColor1: 'rgb(0, 0, 208)' - headerColor2: 'rgb(255, 246, 140)' - navigationIndicatorColor: 'rgb(244, 238, 169)' - backend: - auth: - keys: - - secret: temp - cache: - store: redis - connection: redis://${REDIS_USERNAME}:${REDIS_PASSWORD}@redis:6379 - useRedisSets: true - integrations: - # Plugin: GitHub - github: - - host: github.com - apps: - - appId: ${GITHUB_APP_APP_ID} - clientId: ${GITHUB_APP_CLIENT_ID} - clientSecret: ${GITHUB_APP_CLIENT_SECRET} - webhookUrl: ${GITHUB_APP_WEBHOOK_URL} - webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} - privateKey: | - ${GITHUB_APP_PRIVATE_KEY} - - appId: ${GITHUB_APP_JANUS_TEST_APP_ID} - clientId: ${GITHUB_APP_JANUS_TEST_CLIENT_ID} - clientSecret: ${GITHUB_APP_JANUS_TEST_CLIENT_SECRET} - webhookUrl: ${GITHUB_APP_WEBHOOK_URL} - webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} - privateKey: | - ${GITHUB_APP_JANUS_TEST_PRIVATE_KEY} - bitbucketServer: - - host: bitbucket.com - apiBaseUrl: temp - username: temp - password: temp - gitlab: - - host: gitlab.com - token: ${GITLAB_TOKEN} - auth: - # see https://backstage.io/docs/auth/ to learn about auth providers - environment: development - providers: - # Plugin: GitHub - github: - development: - clientId: ${GITHUB_APP_CLIENT_ID} - clientSecret: ${GITHUB_APP_CLIENT_SECRET} - google: - development: - clientId: ${GOOGLE_CLIENT_ID} - clientSecret: ${GOOGLE_CLIENT_SECRET} - guest: - dangerouslyAllowOutsideDevelopment: true - - proxy: - skipInvalidProxies: true - # endpoints: {} - endpoints: - # Other Proxies - # customize developer hub instance - '/developer-hub': - target: ${DH_TARGET_URL} - changeOrigin: true - # Change to "false" in case of using self hosted cluster with a self-signed certificate - secure: false - '/acr/api': - target: 'https://rhdhqetest.azurecr.io/acr/v1/' - changeOrigin: true - headers: - # If you use Bearer Token for authorization, please replace the 'Basic' with 'Bearer' in the following line. - Authorization: '${ACR_SECRET}' - # Change to "false" in case of using self hosted artifactory instance with a self-signed certificate - secure: false - - catalog: - import: - entityFilename: catalog-info.yaml - # pullRequestBranchName: rhdh-integration - pullRequestBranchName: backstage-integration - rules: - - allow: [API, Component, Group, Location, Resource, System, Template] - locations: - - type: url - target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml - - type: url - target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates.yaml - - type: url - target: https://github.com/janus-qe/acr-catalog/blob/main/catalog-info.yaml - - type: url - target: https://github.com/janus-qe/rhdh-test/blob/main/user.yml - rules: - - allow: [User] - - type: url - target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml - rules: - - allow: [User, Group] - providers: - githubOrg: - id: production - githubUrl: "${GITHUB_URL}" - orgs: ["${GITHUB_ORG}", "${GITHUB_ORG_2}"] - - gitlab: - my-test-provider: - group: rhdhqetest - host: gitlab.com - schedule: - frequency: - minutes: 1 - initialDelay: - seconds: 15 - timeout: - minutes: 1 - - dynatrace: - baseUrl: temp - argocd: - appLocatorMethods: - - type: 'config' - instances: - - name: argoInstance1 - url: temp - token: temp - - name: argoInstance2 - url: temp - token: temp - permission: - enabled: false - rbac: - policies-csv-file: './rbac/rbac-policy.csv' - admin: - users: - - name: user:default/rhdh-qe diff --git a/.ibm/pipelines/resources/config_map/configmap-rbac-policy-rhdh.yaml b/.ibm/pipelines/resources/config_map/configmap-rbac-policy-rhdh.yaml deleted file mode 100644 index 5c79eefad2..0000000000 --- a/.ibm/pipelines/resources/config_map/configmap-rbac-policy-rhdh.yaml +++ /dev/null @@ -1,22 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: rbac-policy -data: - rbac-policy.csv: | - p, role:default/guests, catalog.entity.create, create, allow - p, role:default/team_a, catalog-entity, read, allow - g, user:xyz/user, role:xyz/team_a - - p, role:xyz/team_a, catalog-entity, read, allow - p, role:xyz/team_a, catalog.entity.create, create, allow - p, role:xyz/team_a, catalog.location.create, create, allow - p, role:xyz/team_a, catalog.location.read, read, allow - - p, role:default/rbac_admin, kubernetes.proxy, use, allow - p, role:default/rbac_admin, catalog-entity, read, allow - p, role:default/rbac_admin, catalog.entity.create, create, allow - p, role:default/rbac_admin, catalog.location.create, create, allow - p, role:default/rbac_admin, catalog.location.read, read, allow - p, role:default/rbac_admin, policy-entity, read, allow - p, role:default/rbac_admin, policy-entity, create, allow diff --git a/.ibm/pipelines/resources/config_map/rbac-policy.csv b/.ibm/pipelines/resources/config_map/rbac-policy.csv new file mode 100644 index 0000000000..6a5a94d832 --- /dev/null +++ b/.ibm/pipelines/resources/config_map/rbac-policy.csv @@ -0,0 +1,20 @@ +p, role:default/guests, catalog.entity.create, create, allow +p, role:default/team_a, catalog-entity, read, allow +g, user:xyz/user, role:xyz/team_a +g, group:janus-qe/rhdh-qe-2-team, role:default/test2-role + +p, role:xyz/team_a, catalog-entity, read, allow +p, role:xyz/team_a, catalog.entity.create, create, allow +p, role:xyz/team_a, catalog.location.create, create, allow +p, role:xyz/team_a, catalog.location.read, read, allow + +g, user:default/rhdh-qe-user, role:default/qe_rbac_admin +p, role:default/qe_rbac_admin, kubernetes.proxy, use, allow +p, role:default/qe_rbac_admin, catalog.entity.create, create, allow +p, role:default/qe_rbac_admin, catalog.location.create, create, allow +p, role:default/qe_rbac_admin, catalog.location.read, read, allow + +p, role:default/bulk_import, bulk.import, use, allow +p, role:default/bulk_import, catalog.location.create, create, allow +p, role:default/bulk_import, catalog.entity.create, create, allow +g, group:janus-qe/rhdh-qe-2-team, role:default/bulk_import \ No newline at end of file diff --git a/.ibm/pipelines/resources/deployment/deployment-test-app-component.yaml b/.ibm/pipelines/resources/deployment/deployment-test-app-component.yaml deleted file mode 100644 index 3f7260e8aa..0000000000 --- a/.ibm/pipelines/resources/deployment/deployment-test-app-component.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-app - annotations: - app.openshift.io/vcs-uri: "https://github.com/janus-qe/test-bs-nodejs" - app.openshift.io/vcs-ref: main - labels: - backstage.io/kubernetes-id: developer-hub - app.openshift.io/runtime: perl -spec: - replicas: 2 - selector: - matchLabels: - app: test-app - template: - metadata: - labels: - app: test-app - backstage.io/kubernetes-id: developer-hub - spec: - containers: - - name: ubuntu - image: ubuntu - command: - - /bin/sh - args: - - -c - - "tail -f /dev/null" diff --git a/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline-run.yaml b/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline-run.yaml index e2e252be15..8149dceae9 100644 --- a/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline-run.yaml +++ b/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline-run.yaml @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: hello-world-pipeline-run diff --git a/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline.yaml b/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline.yaml index 7fc8942951..ff749b4a74 100644 --- a/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline.yaml +++ b/.ibm/pipelines/resources/pipeline-run/hello-world-pipeline.yaml @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: hello-world-pipeline diff --git a/.ibm/pipelines/resources/postgres-db/dynamic-plugins-root-PVC.yaml b/.ibm/pipelines/resources/postgres-db/dynamic-plugins-root-PVC.yaml new file mode 100644 index 0000000000..b5e2fb83dc --- /dev/null +++ b/.ibm/pipelines/resources/postgres-db/dynamic-plugins-root-PVC.yaml @@ -0,0 +1,10 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: rhdh-dynamic-plugins-root +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/.ibm/pipelines/resources/postgres-db/postgres-cred.yaml b/.ibm/pipelines/resources/postgres-db/postgres-cred.yaml index 1a4b243387..ea4fedf2cb 100644 --- a/.ibm/pipelines/resources/postgres-db/postgres-cred.yaml +++ b/.ibm/pipelines/resources/postgres-db/postgres-cred.yaml @@ -8,3 +8,4 @@ data: POSTGRES_USER: amFudXMtaWRw POSTGRES_HOST: dG1w PGSSLMODE: cmVxdWlyZQ== + NODE_EXTRA_CA_CERTS: L29wdC9hcHAtcm9vdC9zcmMvcG9zdGdyZXMtY3J0LnBlbQ== diff --git a/.ibm/pipelines/resources/postgres-db/postgres-crt-rds.yaml b/.ibm/pipelines/resources/postgres-db/postgres-crt-rds.yaml new file mode 100644 index 0000000000..f073f350b9 --- /dev/null +++ b/.ibm/pipelines/resources/postgres-db/postgres-crt-rds.yaml @@ -0,0 +1,2535 @@ +apiVersion: v1 +kind: Secret +metadata: + name: postgres-crt +type: Opaque +stringData: + postgres-crt.pem: |- + -----BEGIN CERTIFICATE----- + MIIEEjCCAvqgAwIBAgIJAM2ZN/+nPi27MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD + VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi + MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h + em9uIFJEUzEmMCQGA1UEAwwdQW1hem9uIFJEUyBhZi1zb3V0aC0xIFJvb3QgQ0Ew + HhcNMTkxMDI4MTgwNTU4WhcNMjQxMDI2MTgwNTU4WjCBlTELMAkGA1UEBhMCVVMx + EDAOBgNVBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoM + GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx + JjAkBgNVBAMMHUFtYXpvbiBSRFMgYWYtc291dGgtMSBSb290IENBMIIBIjANBgkq + hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR2351uPMZaJk2gMGT+1sk8HE9MQh2rc + /sCnbxGn2p1c7Oi9aBbd/GiFijeJb2BXvHU+TOq3d3Jjqepq8tapXVt4ojbTJNyC + J5E7r7KjTktKdLxtBE1MK25aY+IRJjtdU6vG3KiPKUT1naO3xs3yt0F76WVuFivd + 9OHv2a+KHvPkRUWIxpmAHuMY9SIIMmEZtVE7YZGx5ah0iO4JzItHcbVR0y0PBH55 + arpFBddpIVHCacp1FUPxSEWkOpI7q0AaU4xfX0fe1BV5HZYRKpBOIp1TtZWvJD+X + jGUtL1BEsT5vN5g9MkqdtYrC+3SNpAk4VtpvJrdjraI/hhvfeXNnAwIDAQABo2Mw + YTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUEEi/ + WWMcBJsoGXg+EZwkQ0MscZQwHwYDVR0jBBgwFoAUEEi/WWMcBJsoGXg+EZwkQ0Ms + cZQwDQYJKoZIhvcNAQELBQADggEBAGDZ5js5Pc/gC58LJrwMPXFhJDBS8QuDm23C + FFUdlqucskwOS3907ErK1ZkmVJCIqFLArHqskFXMAkRZ2PNR7RjWLqBs+0znG5yH + hRKb4DXzhUFQ18UBRcvT6V6zN97HTRsEEaNhM/7k8YLe7P8vfNZ28VIoJIGGgv9D + wQBBvkxQ71oOmAG0AwaGD0ORGUfbYry9Dz4a4IcUsZyRWRMADixgrFv6VuETp26s + /+z+iqNaGWlELBKh3iQCT6Y/1UnkPLO42bxrCSyOvshdkYN58Q2gMTE1SVTqyo8G + Lw8lLAz9bnvUSgHzB3jRrSx6ggF/WRMRYlR++y6LXP4SAsSAaC0= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEEjCCAvqgAwIBAgIJAJYM4LxvTZA6MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD + VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi + MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h + em9uIFJEUzEmMCQGA1UEAwwdQW1hem9uIFJEUyBldS1zb3V0aC0xIFJvb3QgQ0Ew + HhcNMTkxMDMwMjAyMDM2WhcNMjQxMDI4MjAyMDM2WjCBlTELMAkGA1UEBhMCVVMx + EDAOBgNVBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoM + GUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMx + JjAkBgNVBAMMHUFtYXpvbiBSRFMgZXUtc291dGgtMSBSb290IENBMIIBIjANBgkq + hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqM921jXCXeqpRNCS9CBPOe5N7gMaEt+D + s5uR3riZbqzRlHGiF1jZihkXfHAIQewDwy+Yz+Oec1aEZCQMhUHxZJPusuX0cJfj + b+UluFqHIijL2TfXJ3D0PVLLoNTQJZ8+GAPECyojAaNuoHbdVqxhOcznMsXIXVFq + yVLKDGvyKkJjai/iSPDrQMXufg3kWt0ISjNLvsG5IFXgP4gttsM8i0yvRd4QcHoo + DjvH7V3cS+CQqW5SnDrGnHToB0RLskE1ET+oNOfeN9PWOxQprMOX/zmJhnJQlTqD + QP7jcf7SddxrKFjuziFiouskJJyNDsMjt1Lf60+oHZhed2ogTeifGwIDAQABo2Mw + YTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUFBAF + cgJe/BBuZiGeZ8STfpkgRYQwHwYDVR0jBBgwFoAUFBAFcgJe/BBuZiGeZ8STfpkg + RYQwDQYJKoZIhvcNAQELBQADggEBAKAYUtlvDuX2UpZW9i1QgsjFuy/ErbW0dLHU + e/IcFtju2z6RLZ+uF+5A8Kme7IKG1hgt8s+w9TRVQS/7ukQzoK3TaN6XKXRosjtc + o9Rm4gYWM8bmglzY1TPNaiI4HC7546hSwJhubjN0bXCuj/0sHD6w2DkiGuwKNAef + yTu5vZhPkeNyXLykxkzz7bNp2/PtMBnzIp+WpS7uUDmWyScGPohKMq5PqvL59z+L + ZI3CYeMZrJ5VpXUg3fNNIz/83N3G0sk7wr0ohs/kHTP7xPOYB0zD7Ku4HA0Q9Swf + WX0qr6UQgTPMjfYDLffI7aEId0gxKw1eGYc6Cq5JAZ3ipi/cBFc= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZUxCzAJBgNVBAYTAlVT + MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK + DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT + MSYwJAYDVQQDDB1BbWF6b24gUkRTIGFmLXNvdXRoLTEgUm9vdCBDQTAeFw0xOTEw + MjgxODA2NTNaFw0yNDEwMjgxODA2NTNaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UE + CAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9u + IFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEhMB8GA1UE + AwwYQW1hem9uIFJEUyBhZi1zb3V0aC0xIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC + AQ8AMIIBCgKCAQEAvtV1OqmFa8zCVQSKOvPUJERLVFtd4rZmDpImc5rIoeBk7w/P + 9lcKUJjO8R/w1a2lJXx3oQ81tiY0Piw6TpT62YWVRMWrOw8+Vxq1dNaDSFp9I8d0 + UHillSSbOk6FOrPDp+R6AwbGFqUDebbN5LFFoDKbhNmH1BVS0a6YNKpGigLRqhka + cClPslWtPqtjbaP3Jbxl26zWzLo7OtZl98dR225pq8aApNBwmtgA7Gh60HK/cX0t + 32W94n8D+GKSg6R4MKredVFqRTi9hCCNUu0sxYPoELuM+mHiqB5NPjtm92EzCWs+ + +vgWhMc6GxG+82QSWx1Vj8sgLqtE/vLrWddf5QIDAQABo2YwZDAOBgNVHQ8BAf8E + BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuLB4gYVJrSKJj/Gz + pqc6yeA+RcAwHwYDVR0jBBgwFoAUEEi/WWMcBJsoGXg+EZwkQ0MscZQwDQYJKoZI + hvcNAQELBQADggEBABauYOZxUhe9/RhzGJ8MsWCz8eKcyDVd4FCnY6Qh+9wcmYNT + LtnD88LACtJKb/b81qYzcB0Em6+zVJ3Z9jznfr6buItE6es9wAoja22Xgv44BTHL + rimbgMwpTt3uEMXDffaS0Ww6YWb3pSE0XYI2ISMWz+xRERRf+QqktSaL39zuiaW5 + tfZMre+YhohRa/F0ZQl3RCd6yFcLx4UoSPqQsUl97WhYzwAxZZfwvLJXOc4ATt3u + VlCUylNDkaZztDJc/yN5XQoK9W5nOt2cLu513MGYKbuarQr8f+gYU8S+qOyuSRSP + NRITzwCRVnsJE+2JmcRInn/NcanB7uOGqTvJ9+c= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZUxCzAJBgNVBAYTAlVT + MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK + DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT + MSYwJAYDVQQDDB1BbWF6b24gUkRTIGV1LXNvdXRoLTEgUm9vdCBDQTAeFw0xOTEw + MzAyMDIxMzBaFw0yNDEwMzAyMDIxMzBaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UE + CAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9u + IFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzEhMB8GA1UE + AwwYQW1hem9uIFJEUyBldS1zb3V0aC0xIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC + AQ8AMIIBCgKCAQEAtEyjYcajx6xImJn8Vz1zjdmL4ANPgQXwF7+tF7xccmNAZETb + bzb3I9i5fZlmrRaVznX+9biXVaGxYzIUIR3huQ3Q283KsDYnVuGa3mk690vhvJbB + QIPgKa5mVwJppnuJm78KqaSpi0vxyCPe3h8h6LLFawVyWrYNZ4okli1/U582eef8 + RzJp/Ear3KgHOLIiCdPDF0rjOdCG1MOlDLixVnPn9IYOciqO+VivXBg+jtfc5J+L + AaPm0/Yx4uELt1tkbWkm4BvTU/gBOODnYziITZM0l6Fgwvbwgq5duAtKW+h031lC + 37rEvrclqcp4wrsUYcLAWX79ZyKIlRxcAdvEhQIDAQABo2YwZDAOBgNVHQ8BAf8E + BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU7zPyc0azQxnBCe7D + b9KAadH1QSEwHwYDVR0jBBgwFoAUFBAFcgJe/BBuZiGeZ8STfpkgRYQwDQYJKoZI + hvcNAQELBQADggEBAFGaNiYxg7yC/xauXPlaqLCtwbm2dKyK9nIFbF/7be8mk7Q3 + MOA0of1vGHPLVQLr6bJJpD9MAbUcm4cPAwWaxwcNpxOjYOFDaq10PCK4eRAxZWwF + NJRIRmGsl8NEsMNTMCy8X+Kyw5EzH4vWFl5Uf2bGKOeFg0zt43jWQVOX6C+aL3Cd + pRS5MhmYpxMG8irrNOxf4NVFE2zpJOCm3bn0STLhkDcV/ww4zMzObTJhiIb5wSWn + EXKKWhUXuRt7A2y1KJtXpTbSRHQxE++69Go1tWhXtRiULCJtf7wF2Ksm0RR/AdXT + 1uR1vKyH5KBJPX3ppYkQDukoHTFR0CpB+G84NLo= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/jCCAuagAwIBAgIQdOCSuA9psBpQd8EI368/0DANBgkqhkiG9w0BAQsFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIHNhLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTE5MTgwNjI2WhgPMjA2MTA1MTkxOTA2MjZaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgc2EtZWFzdC0xIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN6ftL6w8v3dB2yW + LjCxSP1D7ZsOTeLZOSCz1Zv0Gkd0XLhil5MdHOHBvwH/DrXqFU2oGzCRuAy+aZis + DardJU6ChyIQIciXCO37f0K23edhtpXuruTLLwUwzeEPdcnLPCX+sWEn9Y5FPnVm + pCd6J8edH2IfSGoa9LdErkpuESXdidLym/w0tWG/O2By4TabkNSmpdrCL00cqI+c + prA8Bx1jX8/9sY0gpAovtuFaRN+Ivg3PAnWuhqiSYyQ5nC2qDparOWuDiOhpY56E + EgmTvjwqMMjNtExfYx6Rv2Ndu50TriiNKEZBzEtkekwXInTupmYTvc7U83P/959V + UiQ+WSMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU4uYHdH0+ + bUeh81Eq2l5/RJbW+vswDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB + AQBhxcExJ+w74bvDknrPZDRgTeMLYgbVJjx2ExH7/Ac5FZZWcpUpFwWMIJJxtewI + AnhryzM3tQYYd4CG9O+Iu0+h/VVfW7e4O3joWVkxNMb820kQSEwvZfA78aItGwOY + WSaFNVRyloVicZRNJSyb1UL9EiJ9ldhxm4LTT0ax+4ontI7zTx6n6h8Sr6r/UOvX + d9T5aUUENWeo6M9jGupHNn3BobtL7BZm2oS8wX8IVYj4tl0q5T89zDi2x0MxbsIV + 5ZjwqBQ5JWKv7ASGPb+z286RjPA9R2knF4lJVZrYuNV90rHvI/ECyt/JrDqeljGL + BLl1W/UsvZo6ldLIpoMbbrb5 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEBDCCAuygAwIBAgIQUfVbqapkLYpUqcLajpTJWzANBgkqhkiG9w0BAQsFADCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIG1lLWNlbnRyYWwtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNV + BAcMB1NlYXR0bGUwIBcNMjIwNTA2MjMyMDA5WhgPMjA2MjA1MDcwMDIwMDlaMIGa + MQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5j + LjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMzAxBgNVBAMMKkFt + YXpvbiBSRFMgbWUtY2VudHJhbC0xIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJIeovu3 + ewI9FVitXMQzvkh34aQ6WyI4NO3YepfJaePiv3cnyFGYHN2S1cR3UQcLWgypP5va + j6bfroqwGbCbZZcb+6cyOB4ceKO9Ws1UkcaGHnNDcy5gXR7aCW2OGTUfinUuhd2d + 5bOGgV7JsPbpw0bwJ156+MwfOK40OLCWVbzy8B1kITs4RUPNa/ZJnvIbiMu9rdj4 + 8y7GSFJLnKCjlOFUkNI5LcaYvI1+ybuNgphT3nuu5ZirvTswGakGUT/Q0J3dxP0J + pDfg5Sj/2G4gXiaM0LppVOoU5yEwVewhQ250l0eQAqSrwPqAkdTg9ng360zqCFPE + JPPcgI1tdGUgneECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU + /2AJVxWdZxc8eJgdpbwpW7b0f7IwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB + CwUAA4IBAQBYm63jTu2qYKJ94gKnqc+oUgqmb1mTXmgmp/lXDbxonjszJDOXFbri + 3CCO7xB2sg9bd5YWY8sGKHaWmENj3FZpCmoefbUx++8D7Mny95Cz8R32rNcwsPTl + ebpd9A/Oaw5ug6M0x/cNr0qzF8Wk9Dx+nFEimp8RYQdKvLDfNFZHjPa1itnTiD8M + TorAqj+VwnUGHOYBsT/0NY12tnwXdD+ATWfpEHdOXV+kTMqFFwDyhfgRVNpTc+os + ygr8SwhnSCpJPB/EYl2S7r+tgAbJOkuwUvGT4pTqrzDQEhwE7swgepnHC87zhf6l + qN6mVpSnQKQLm6Ob5TeCEFgcyElsF5bH + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjSgAwIBAgIRAOxu0I1QuMAhIeszB3fJIlkwCgYIKoZIzj0EAwMwgZYx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h + em9uIFJEUyB1cy13ZXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTI0MjIwNjU5WhgPMjEyMTA1MjQyMzA2NTlaMIGWMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS + RFMgdXMtd2VzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEz4bylRcGqqDWdP7gQIIoTHdBK6FNtKH1 + 4SkEIXRXkYDmRvL9Bci1MuGrwuvrka5TDj4b7e+csY0llEzHpKfq6nJPFljoYYP9 + uqHFkv77nOpJJ633KOr8IxmeHW5RXgrZo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G + A1UdDgQWBBQQikVz8wmjd9eDFRXzBIU8OseiGzAOBgNVHQ8BAf8EBAMCAYYwCgYI + KoZIzj0EAwMDaAAwZQIwf06Mcrpw1O0EBLBBrp84m37NYtOkE/0Z0O+C7D41wnXi + EQdn6PXUVgdD23Gj82SrAjEAklhKs+liO1PtN15yeZR1Io98nFve+lLptaLakZcH + +hfFuUtCqMbaI8CdvJlKnPqT + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCTCCA/GgAwIBAgIRALyWMTyCebLZOGcZZQmkmfcwDQYJKoZIhvcNAQEMBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1ub3J0aGVhc3QtMyBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTI0MjAyODAzWhgPMjEyMTA1MjQyMTI4MDNa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtbm9ydGhlYXN0LTMgUm9vdCBDQSBSU0E0MDk2IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA + wGFiyDyCrGqgdn4fXG12cxKAAfVvhMea1mw5h9CVRoavkPqhzQpAitSOuMB9DeiP + wQyqcsiGl/cTEau4L+AUBG8b9v26RlY48exUYBXj8CieYntOT9iNw5WtdYJa3kF/ + JxgI+HDMzE9cmHDs5DOO3S0uwZVyra/xE1ymfSlpOeUIOTpHRJv97CBUEpaZMUW5 + Sr6GruuOwFVpO5FX3A/jQlcS+UN4GjSRgDUJuqg6RRQldEZGCVCCmodbByvI2fGm + reGpsPJD54KkmAX08nOR8e5hkGoHxq0m2DLD4SrOFmt65vG47qnuwplWJjtk9B3Z + 9wDoopwZLBOtlkPIkUllWm1P8EuHC1IKOA+wSP6XdT7cy8S77wgyHzR0ynxv7q/l + vlZtH30wnNqFI0y9FeogD0TGMCHcnGqfBSicJXPy9T4fU6f0r1HwqKwPp2GArwe7 + dnqLTj2D7M9MyVtFjEs6gfGWXmu1y5uDrf+CszurE8Cycoma+OfjjuVQgWOCy7Nd + jJswPxAroTzVfpgoxXza4ShUY10woZu0/J+HmNmqK7lh4NS75q1tz75in8uTZDkV + be7GK+SEusTrRgcf3tlgPjSTWG3veNzFDF2Vn1GLJXmuZfhdlVQDBNXW4MNREExS + dG57kJjICpT+r8X+si+5j51gRzkSnMYs7VHulpxfcwECAwEAAaNCMEAwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQU4JWOpDBmUBuWKvGPZelw87ezhL8wDgYDVR0P + AQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQBRNLMql7itvXSEFQRAnyOjivHz + l5IlWVQjAbOUr6ogZcwvK6YpxNAFW5zQr8F+fdkiypLz1kk5irx9TIpff0BWC9hQ + /odMPO8Gxn8+COlSvc+dLsF2Dax3Hvz0zLeKMo+cYisJOzpdR/eKd0/AmFdkvQoM + AOK9n0yYvVJU2IrSgeJBiiCarpKSeAktEVQ4rvyacQGr+QAPkkjRwm+5LHZKK43W + nNnggRli9N/27qYtc5bgr3AaQEhEXMI4RxPRXCLsod0ehMGWyRRK728a+6PMMJAJ + WHOU0x7LCEMPP/bvpLj3BdvSGqNor4ZtyXEbwREry1uzsgODeRRns5acPwTM6ff+ + CmxO2NZ0OktIUSYRmf6H/ZFlZrIhV8uWaIwEJDz71qvj7buhQ+RFDZ9CNL64C0X6 + mf0zJGEpddjANHaaVky+F4gYMtEy2K2Lcm4JGTdyIzUoIe+atzCnRp0QeIcuWtF+ + s8AjDYCVFNypcMmqbRmNpITSnOoCHSRuVkY3gutVoYyMLbp8Jm9SJnCIlEWTA6Rm + wADOMGZJVn5/XRTRuetVOB3KlQDjs9OO01XN5NzGSZO2KT9ngAUfh9Eqhf1iRWSP + nZlRbQ2NRCuY/oJ5N59mLGxnNJSE7giEKEBRhTQ/XEPIUYAUPD5fca0arKRJwbol + l9Se1Hsq0ZU5f+OZKQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + 5zT5+Bs= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + Hing + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/zCCAuegAwIBAgIRAI+asxQA/MB1cGyyrC0MPpkwDQYJKoZIhvcNAQELBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyBjYS13ZXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIzMDkxMzIwMjEzNFoYDzIwNjMwOTEzMjEyMTMzWjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGNhLXdlc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMHvQITTZcfl2O + yfzRIAPKwzzlc8eXWdXef7VUsbezg3lm9RC+vArO4JuAzta/aLw1D94wPSRm9JXX + NkP3obO6Ql80/0doooU6BAPceD0xmEWC4aCFT/5KWsD6Sy2/Rjwq3NKBTwzxLwYK + GqVsBp8AdrzDTmdRETC+Dg2czEo32mTDAA1uMgqrz6xxeTYroj8NTSTp6jfE6C0n + YgzYmVQCEIjHqI49j7k3jfT3P2skCVKGJwQzoZnerFacKzXsDB18uIqU7NaMc2cX + kOd0gRqpyKOzAHU2m5/S4jw4UHdkoI3E7nkayuen8ZPKH2YqWtTXUrXGhSTT34nX + yiFgu+vTAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHzz1NTd + TOm9zAv4d8l6XCFKSdJfMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC + AQEAodBvd0cvXQYhFBef2evnuI9XA+AC/Q9P1nYtbp5MPA4aFhy5v9rjW8wwJX14 + l+ltd2o3tz8PFDBZ1NX2ooiWVlZthQxKn1/xDVKsTXHbYUXItPQ3jI5IscB5IML8 + oCzAbkoLXsSPNOVFP5P4l4cZEMqHGRnBag7hLJZvmvzZSBnz+ioC2jpjVluF8kDX + fQGNjqPECik68CqbSV0SaQ0cgEoYTDjwON5ZLBeS8sxR2abE/gsj4VFYl5w/uEBd + w3Tt9uGfIy+wd2tNj6isGC6PcbPMjA31jd+ifs2yNzigqkcYTTWFtnvh4a8xiecm + GHu2EgH0Jqzz500N7L3uQdPkdg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCTCCA/GgAwIBAgIRALnItUH64VieFPvDUCOG5E0wDQYJKoZIhvcNAQEMBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtNSBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjQwNTE1MjE1MDQxWhgPMjEyNDA1MTUyMjUwNDFa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtc291dGhlYXN0LTUgUm9vdCBDQSBSU0E0MDk2IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA + u2Bc0RjN0vB7EM+h0yts1jSqzDd1v5FcxCDbC7vKPVCq/1pYNTIxQj77HiMcYtvL + Bfi9AQFibU1C9gN62kUmSe0QaNGqQL2g/6YpB4qI8psIsCt3aIigbhwEEpebhIU/ + vhr/pvLKhkQOSLxJVlX0j18hU5RVqOefCdFm9FmjFLge/m1Yzv2aFifRKIzdtkfp + 4VZBzh7EzP6lxkU3SAcW9yRu/t4oY274ICnGisv2TR15hHlP0wUP6p5S3ot2q/xJ + 57x8nzI3kQyC6a+n+kSzZzITboKWrsx3Jd2PdB4VC84P/YoAC3cwfmacmQVT01c8 + io1eO+BxCtWUNbwCv0Hd10bHI18rVzJhJPb3xg1i1Sc3sbcrADOONsuhxqwffjUe + XdVMdsjX2mYxQ520qnh5DwQkx3JyW6QwI/ueU9xbMuPTwAauXil7B9qx1IDViYUw + BvMDnxYbYHlDezYIc4WoNoA2KflMnNtN2WDiM7tvQKmWI8yYZrNdnqBD0HYR+neP + z69Tqy8i24CDoR9o3s5LxR58SgFPqu9RWu8uL6vfNLL2M8qQ4VueOWSyzRs9b3W5 + GVjA4U1CxlF3EirHEjciq6UEXr5+ZVf79iXGOwBVDzuim1LYfoTBgkMXKxyEzWYT + QCzf6VPW4x7eMQIriLl18YocHrqJQ7+BfMziYjOh0rcCAwEAAaNCMEAwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQUQdyu9F6eLFuxe437iU/GXyFHU1owDgYDVR0P + AQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQCbbNUJRQ1gy1lKxCoszcyujCI5 + df0EGdadQL6BgaXws/uCFvHepB5lO62InAMTURCREeRtrCNyn1rEKnsqhAW0UokQ + Z+YOHcclgPsXmSQVjIUgnlE45mrPS/9mO8TzhCI3wyiELp6oa67RSiJ1Qcsypa4z + zHDkYdhFW3sxY8i2p2tqdkJz1ZEQd7FIpX+vrBVIkoqtGAn4urLaMq4CTNJCNepR + s4OGaoQVY43q2kcguRPDZVOFK5+GlrC2AzHMSVt5fFSCchgYxBZsS3UIVKm8YJ7v + 1h85RwtNCHwwDt1uP43yLp5qfUmsfeaNmZiOk9AawxPCmy6XaSkQcLz+CQhG9T4W + siQMg6tagIUw1e4zFm7GXmeOCPc//ycGNDXgprMQzjK+AT4ed8iK+JnWlheMq5uf + XxQDSfakuAIEgJWPAzebjCo33O2j1PQfzbt1Ahs7f+gFczizfpatYkXcOTmLfG1l + QKj9jVNOIQSJt5PxH+QTDWQtkX/tGp/HS5a3dWusW/TnC3yakGqqfGx3cB/E00gF + geg0LYo1uOBjIYQbkp3Z6NKfcc/nb0ksV7feKm5f3rSO8NnA0Ou8YHb84LYDLYDf + VSR9SwSBhGw31otMTAsJdNTHJwfCcxfGtIvUfAsWUAh6qSo4es/hUV60pj01VWpq + Er+ItMFHuoSTmx18bw== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRANxgyBbnxgTEOpDul2ZnC0UwDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtMyBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNjEwMTgxOTA3WhgPMjA2MTA2MTAxOTE5MDda + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtc291dGhlYXN0LTMgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + xnwSDAChrMkfk5TA4Dk8hKzStDlSlONzmd3fTG0Wqr5+x3EmFT6Ksiu/WIwEl9J2 + K98UI7vYyuZfCxUKb1iMPeBdVGqk0zb92GpURd+Iz/+K1ps9ZLeGBkzR8mBmAi1S + OfpwKiTBzIv6E8twhEn4IUpHsdcuX/2Y78uESpJyM8O5CpkG0JaV9FNEbDkJeBUQ + Ao2qqNcH4R0Qcr5pyeqA9Zto1RswgL06BQMI9dTpfwSP5VvkvcNUaLl7Zv5WzLQE + JzORWePvdPzzvWEkY/3FPjxBypuYwssKaERW0fkPDmPtykktP9W/oJolKUFI6pXp + y+Y6p6/AVdnQD2zZjW5FhQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBT+jEKs96LC+/X4BZkUYUkzPfXdqTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBAIGQqgqcQ6XSGkmNebzR6DhadTbfDmbYeN5N0Vuzv+Tdmufb + tMGjdjnYMg4B+IVnTKQb+Ox3pL9gbX6KglGK8HupobmIRtwKVth+gYYz3m0SL/Nk + haWPYzOm0x3tJm8jSdufJcEob4/ATce9JwseLl76pSWdl5A4lLjnhPPKudUDfH+1 + BLNUi3lxpp6GkC8aWUPtupnhZuXddolTLOuA3GwTZySI44NfaFRm+o83N1jp+EwD + 6e94M4cTRzjUv6J3MZmSbdtQP/Tk1uz2K4bQZGP0PZC3bVpqiesdE/xr+wbu8uHr + cM1JXH0AmXf1yIkTgyWzmvt0k1/vgcw5ixAqvvE= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEATCCAumgAwIBAgIRAMhw98EQU18mIji+unM2YH8wDQYJKoZIhvcNAQELBQAw + gZgxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTExMC8GA1UEAwwo + QW1hem9uIFJEUyBhcC1zb3V0aC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTAgFw0yMjA2MDYyMTQyMjJaGA8yMDYyMDYwNjIyNDIyMlowgZgx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTExMC8GA1UEAwwoQW1h + em9uIFJEUyBhcC1zb3V0aC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwH + U2VhdHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIeeRoLfTm+7 + vqm7ZlFSx+1/CGYHyYrOOryM4/Z3dqYVHFMgWTR7V3ziO8RZ6yUanrRcWVX3PZbF + AfX0KFE8OgLsXEZIX8odSrq86+/Th5eZOchB2fDBsUB7GuN2rvFBbM8lTI9ivVOU + lbuTnYyb55nOXN7TpmH2bK+z5c1y9RVC5iQsNAl6IJNvSN8VCqXh31eK5MlKB4DT + +Y3OivCrSGsjM+UR59uZmwuFB1h+icE+U0p9Ct3Mjq3MzSX5tQb6ElTNGlfmyGpW + Kh7GQ5XU1KaKNZXoJ37H53woNSlq56bpVrKI4uv7ATpdpFubOnSLtpsKlpLdR3sy + Ws245200pC8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUp0ki + 6+eWvsnBjQhMxwMW5pwn7DgwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA + A4IBAQB2V8lv0aqbYQpj/bmVv/83QfE4vOxKCJAHv7DQ35cJsTyBdF+8pBczzi3t + 3VNL5IUgW6WkyuUOWnE0eqAFOUVj0yTS1jSAtfl3vOOzGJZmWBbqm9BKEdu1D8O6 + sB8bnomwiab2tNDHPmUslpdDqdabbkWwNWzLJ97oGFZ7KNODMEPXWKWNxg33iHfS + /nlmnrTVI3XgaNK9qLZiUrxu9Yz5gxi/1K+sG9/Dajd32ZxjRwDipOLiZbiXQrsd + qzIMY4GcWf3g1gHL5mCTfk7dG22h/rhPyGV0svaDnsb+hOt6sv1McMN6Y3Ou0mtM + /UaAXojREmJmTSCNvs2aBny3/2sy + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjSgAwIBAgIRAMnRxsKLYscJV8Qv5pWbL7swCgYIKoZIzj0EAwMwgZYx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h + em9uIFJEUyBzYS1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTE5MTgxNjAxWhgPMjEyMTA1MTkxOTE2MDFaMIGWMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS + RFMgc2EtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEjFOCZgTNVKxLKhUxffiDEvTLFhrmIqdO + dKqVdgDoELEzIHWDdC+19aDPitbCYtBVHl65ITu/9pn6mMUl5hhUNtfZuc6A+Iw1 + sBe0v0qI3y9Q9HdQYrGgeHDh8M5P7E2ho0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G + A1UdDgQWBBS5L7/8M0TzoBZk39Ps7BkfTB4yJTAOBgNVHQ8BAf8EBAMCAYYwCgYI + KoZIzj0EAwMDaAAwZQIwI43O0NtWKTgnVv9z0LO5UMZYgSve7GvGTwqktZYCMObE + rUI4QerXM9D6JwLy09mqAjEAypfkdLyVWtaElVDUyHFkihAS1I1oUxaaDrynLNQK + Ou/Ay+ns+J+GyvyDUjBpVVW1 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIF/jCCA+agAwIBAgIQR71Z8lTO5Sj+as2jB7IWXzANBgkqhkiG9w0BAQwFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIHVzLXdlc3QtMiBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTI0MjIwMzIwWhgPMjEyMTA1MjQyMzAzMjBaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgdXMtd2VzdC0yIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM977bHIs1WJijrS + XQMfUOhmlJjr2v0K0UjPl52sE1TJ76H8umo1yR4T7Whkd9IwBHNGKXCJtJmMr9zp + fB38eLTu+5ydUAXdFuZpRMKBWwPVe37AdJRKqn5beS8HQjd3JXAgGKUNNuE92iqF + qi2fIqFMpnJXWo0FIW6s2Dl2zkORd7tH0DygcRi7lgVxCsw1BJQhFJon3y+IV8/F + bnbUXSNSDUnDW2EhvWSD8L+t4eiXYsozhDAzhBvojpxhPH9OB7vqFYw5qxFx+G0t + lSLX5iWi1jzzc3XyGnB6WInZDVbvnvJ4BGZ+dTRpOCvsoMIn9bz4EQTvu243c7aU + HbS/kvnCASNt+zk7C6lbmaq0AGNztwNj85Opn2enFciWZVnnJ/4OeefUWQxD0EPp + SjEd9Cn2IHzkBZrHCg+lWZJQBKbUVS0lLIMSsLQQ6WvR38jY7D2nxM1A93xWxwpt + ZtQnYRCVXH6zt2OwDAFePInWwxUjR5t/wu3XxPgpSfrmTi3WYtr1wFypAJ811e/P + yBtswWUQ6BNJQvy+KnOEeGfOwmtdDFYR+GOCfvCihzrKJrxOtHIieehR5Iw3cbXG + sm4pDzfMUVvDDz6C2M6PRlJhhClbatHCjik9hxFYEsAlqtVVK9pxaz9i8hOqSFQq + kJSQsgWw+oM/B2CyjcSqkSQEu8RLAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFPmrdxpRRgu3IcaB5BTqlprcKdTsMA4GA1UdDwEB/wQEAwIBhjAN + BgkqhkiG9w0BAQwFAAOCAgEAVdlxWjPvVKky3kn8ZizeM4D+EsLw9dWLau2UD/ls + zwDCFoT6euagVeCknrn+YEl7g20CRYT9iaonGoMUPuMR/cdtPL1W/Rf40PSrGf9q + QuxavWiHLEXOQTCtCaVZMokkvjuuLNDXyZnstgECuiZECTwhexUF4oiuhyGk9o01 + QMaiz4HX4lgk0ozALUvEzaNd9gWEwD2qe+rq9cQMTVq3IArUkvTIftZUaVUMzr0O + ed1+zAsNa9nJhURJ/6anJPJjbQgb5qA1asFcp9UaMT1ku36U3gnR1T/BdgG2jX3X + Um0UcaGNVPrH1ukInWW743pxWQb7/2sumEEMVh+jWbB18SAyLI4WIh4lkurdifzS + IuTFp8TEx+MouISFhz/vJDWZ84tqoLVjkEcP6oDypq9lFoEzHDJv3V1CYcIgOusT + k1jm9P7BXdTG7TYzUaTb9USb6bkqkD9EwJAOSs7DI94aE6rsSws2yAHavjAMfuMZ + sDAZvkqS2Qg2Z2+CI6wUZn7mzkJXbZoqRjDvChDXEB1mIhzVXhiNW/CR5WKVDvlj + 9v1sdGByh2pbxcLQtVaq/5coM4ANgphoNz3pOYUPWHS+JUrIivBZ+JobjXcxr3SN + 9iDzcu5/FVVNbq7+KN/nvPMngT+gduEN5m+EBjm8GukJymFG0m6BENRA0QSDqZ7k + zDY= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRAK5EYG3iHserxMqgg+0EFjgwDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1ub3J0aGVhc3QtMyBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTI0MjAyMzE2WhgPMjA2MTA1MjQyMTIzMTZa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtbm9ydGhlYXN0LTMgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + s1L6TtB84LGraLHVC+rGPhLBW2P0oN/91Rq3AnYwqDOuTom7agANwEjvLq7dSRG/ + sIfZsSV/ABTgArZ5sCmLjHFZAo8Kd45yA9byx20RcYtAG8IZl+q1Cri+s0XefzyO + U6mlfXZkVe6lzjlfXBkrlE/+5ifVbJK4dqOS1t9cWIpgKqv5fbE6Qbq4LVT+5/WM + Vd2BOljuBMGMzdZubqFKFq4mzTuIYfnBm7SmHlZfTdfBYPP1ScNuhpjuzw4n3NCR + EdU6dQv04Q6th4r7eiOCwbWI9LkmVbvBe3ylhH63lApC7MiiPYLlB13xBubVHVhV + q1NHoNTi+zA3MN9HWicRxQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBSuxoqm0/wjNiZLvqv+JlQwsDvTPDAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBAFfTK/j5kv90uIbM8VaFdVbr/6weKTwehafT0pAk1bfLVX+7 + uf8oHgYiyKTTl0DFQicXejghXTeyzwoEkWSR8c6XkhD5vYG3oESqmt/RGvvoxz11 + rHHy7yHYu7RIUc3VQG60c4qxXv/1mWySGwVwJrnuyNT9KZXPevu3jVaWOVHEILaK + HvzQ2YEcWBPmde/zEseO2QeeGF8FL45Q1d66wqIP4nNUd2pCjeTS5SpB0MMx7yi9 + ki1OH1pv8tOuIdimtZ7wkdB8+JSZoaJ81b8sRrydRwJyvB88rftuI3YB4WwGuONT + ZezUPsmaoK69B0RChB0ofDpAaviF9V3xOWvVZfo= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + 1axqeKpI0F5SBUPsaVNYY2uNFg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECDCCAvCgAwIBAgIQCREfzzVyDTMcNME+gWnTCTANBgkqhkiG9w0BAQsFADCB + nDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTUwMwYDVQQDDCxB + bWF6b24gUkRTIGFwLXNvdXRoZWFzdC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4G + A1UEBwwHU2VhdHRsZTAgFw0yMTA1MjQyMDQyMzNaGA8yMDYxMDUyNDIxNDIzM1ow + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDL + 1MT6br3L/4Pq87DPXtcjlXN3cnbNk2YqRAZHJayStTz8VtsFcGPJOpk14geRVeVk + e9uKFHRbcyr/RM4owrJTj5X4qcEuATYZbo6ou/rW2kYzuWFZpFp7lqm0vasV4Z9F + fChlhwkNks0UbM3G+psCSMNSoF19ERunj7w2c4E62LwujkeYLvKGNepjnaH10TJL + 2krpERd+ZQ4jIpObtRcMH++bTrvklc+ei8W9lqrVOJL+89v2piN3Ecdd389uphst + qQdb1BBVXbhUrtuGHgVf7zKqN1SkCoktoWxVuOprVWhSvr7akaWeq0UmlvbEsujU + vADqxGMcJFyCzxx3CkJjAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O + BBYEFFk8UJmlhoxFT3PP12PvhvazHjT4MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG + 9w0BAQsFAAOCAQEAfFtr2lGoWVXmWAsIo2NYre7kzL8Xb9Tx7desKxCCz5HOOvIr + 8JMB1YK6A7IOvQsLJQ/f1UnKRh3X3mJZjKIywfrMSh0FiDf+rjcEzXxw2dGtUem4 + A+WMvIA3jwxnJ90OQj5rQ8bg3iPtE6eojzo9vWQGw/Vu48Dtw1DJo9210Lq/6hze + hPhNkFh8fMXNT7Q1Wz/TJqJElyAQGNOXhyGpHKeb0jHMMhsy5UNoW5hLeMS5ffao + TBFWEJ1gVfxIU9QRxSh+62m46JIg+dwDlWv8Aww14KgepspRbMqDuaM2cinoejv6 + t3dyOyHHrsOyv3ffZUKtQhQbQr+sUcL89lARsg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/zCCAuegAwIBAgIRAIJLTMpzGNxqHZ4t+c1MlCIwDQYJKoZIhvcNAQELBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyBhcC1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyNTIxMzAzM1oYDzIwNjEwNTI1MjIzMDMzWjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGFwLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtdHut0ZhJ9Nn2 + MpVafFcwHdoEzx06okmmhjJsNy4l9QYVeh0UUoek0SufRNMRF4d5ibzpgZol0Y92 + /qKWNe0jNxhEj6sXyHsHPeYtNBPuDMzThfbvsLK8z7pBP7vVyGPGuppqW/6m4ZBB + lcc9fsf7xpZ689iSgoyjiT6J5wlVgmCx8hFYc/uvcRtfd8jAHvheug7QJ3zZmIye + V4htOW+fRVWnBjf40Q+7uTv790UAqs0Zboj4Yil+hER0ibG62y1g71XcCyvcVpto + 2/XW7Y9NCgMNqQ7fGN3wR1gjtSYPd7DO32LTzYhutyvfbpAZjsAHnoObmoljcgXI + QjfBcCFpAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJI3aWLg + CS5xqU5WYVaeT5s8lpO0MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC + AQEAUwATpJOcGVOs3hZAgJwznWOoTzOVJKfrqBum7lvkVH1vBwxBl9CahaKj3ZOt + YYp2qJzhDUWludL164DL4ZjS6eRedLRviyy5cRy0581l1MxPWTThs27z+lCC14RL + PJZNVYYdl7Jy9Q5NsQ0RBINUKYlRY6OqGDySWyuMPgno2GPbE8aynMdKP+f6G/uE + YHOf08gFDqTsbyfa70ztgVEJaRooVf5JJq4UQtpDvVswW2reT96qi6tXPKHN5qp3 + 3wI0I1Mp4ePmiBKku2dwYzPfrJK/pQlvu0Gu5lKOQ65QdotwLAAoaFqrf9za1yYs + INUkHLWIxDds+4OHNYcerGp5Dw== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCTCCA/GgAwIBAgIRAIO6ldra1KZvNWJ0TA1ihXEwDQYJKoZIhvcNAQEMBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTIxMjE0NTA1WhgPMjEyMTA1MjEyMjQ1MDVa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtc291dGhlYXN0LTEgUm9vdCBDQSBSU0E0MDk2IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA + sDN52Si9pFSyZ1ruh3xAN0nVqEs960o2IK5CPu/ZfshFmzAwnx/MM8EHt/jMeZtj + SM58LADAsNDL01ELpFZATjgZQ6xNAyXRXE7RiTRUvNkK7O3o2qAGbLnJq/UqF7Sw + LRnB8V6hYOv+2EjVnohtGCn9SUFGZtYDjWXsLd4ML4Zpxv0a5LK7oEC7AHzbUR7R + jsjkrXqSv7GE7bvhSOhMkmgxgj1F3J0b0jdQdtyyj109aO0ATUmIvf+Bzadg5AI2 + A9UA+TUcGeebhpHu8AP1Hf56XIlzPpaQv3ZJ4vzoLaVNUC7XKzAl1dlvCl7Klg/C + 84qmbD/tjZ6GHtzpLKgg7kQEV7mRoXq8X4wDX2AFPPQl2fv+Kbe+JODqm5ZjGegm + uskABBi8IFv1hYx9jEulZPxC6uD/09W2+niFm3pirnlWS83BwVDTUBzF+CooUIMT + jhWkIIZGDDgMJTzouBHfoSJtS1KpUZi99m2WyVs21MNKHeWAbs+zmI6TO5iiMC+T + uB8spaOiHFO1573Fmeer4sy3YA6qVoqVl6jjTQqOdy3frAMbCkwH22/crV8YA+08 + hLeHXrMK+6XUvU+EtHAM3VzcrLbuYJUI2XJbzTj5g0Eb8I8JWsHvWHR5K7Z7gceR + 78AzxQmoGEfV6KABNWKsgoCQnfb1BidDJIe3BsI0A6UCAwEAAaNCMEAwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQUABp0MlB14MSHgAcuNSOhs3MOlUcwDgYDVR0P + AQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQCv4CIOBSQi/QR9NxdRgVAG/pAh + tFJhV7OWb/wqwsNKFDtg6tTxwaahdCfWpGWId15OUe7G9LoPiKiwM9C92n0ZeHRz + 4ewbrQVo7Eu1JI1wf0rnZJISL72hVYKmlvaWaacHhWxvsbKLrB7vt6Cknxa+S993 + Kf8i2Psw8j5886gaxhiUtzMTBwoDWak8ZaK7m3Y6C6hXQk08+3pnIornVSFJ9dlS + PAqt5UPwWmrEfF+0uIDORlT+cvrAwgSp7nUF1q8iasledycZ/BxFgQqzNwnkBDwQ + Z/aM52ArGsTzfMhkZRz9HIEhz1/0mJw8gZtDVQroD8778h8zsx2SrIz7eWQ6uWsD + QEeSWXpcheiUtEfzkDImjr2DLbwbA23c9LoexUD10nwohhoiQQg77LmvBVxeu7WU + E63JqaYUlOLOzEmNJp85zekIgR8UTkO7Gc+5BD7P4noYscI7pPOL5rP7YLg15ZFi + ega+G53NTckRXz4metsd8XFWloDjZJJq4FfD60VuxgXzoMNT9wpFTNSH42PR2s9L + I1vcl3w8yNccs9se2utM2nLsItZ3J0m/+QSRiw9hbrTYTcM9sXki0DtH2kyIOwYf + lOrGJDiYOIrXSQK36H0gQ+8omlrUTvUj4msvkXuQjlfgx6sgp2duOAfnGxE7uHnc + UhnJzzoe6M+LfGHkVQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICuDCCAj2gAwIBAgIQSAG6j2WHtWUUuLGJTPb1nTAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLW5vcnRoZWFzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyMDE2MzgyNloYDzIxMjEwNTIwMTczODI2WjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLW5vcnRoZWFzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE2eqwU4FOzW8RV1W381Bd + olhDOrqoMqzWli21oDUt7y8OnXM/lmAuOS6sr8Nt61BLVbONdbr+jgCYw75KabrK + ZGg3siqvMOgabIKkKuXO14wtrGyGDt7dnKXg5ERGYOZlo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBS1Acp2WYxOcblv5ikZ3ZIbRCCW+zAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAJL84J08PBprxmsAKPTotBuVI3MyW1r8 + xQ0i8lgCQUf8GcmYjQ0jI4oZyv+TuYJAcwIxAP9Xpzq0Docxb+4N1qVhpiOfWt1O + FnemFiy9m1l+wv6p3riQMPV7mBVpklmijkIv3Q== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRALZLcqCVIJ25maDPE3sbPCIwDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTIxMjEzOTM5WhgPMjA2MTA1MjEyMjM5Mzla + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtc291dGhlYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + ypKc+6FfGx6Gl6fQ78WYS29QoKgQiur58oxR3zltWeg5fqh9Z85K5S3UbRSTqWWu + Xcfnkz0/FS07qHX+nWAGU27JiQb4YYqhjZNOAq8q0+ptFHJ6V7lyOqXBq5xOzO8f + +0DlbJSsy7GEtJp7d7QCM3M5KVY9dENVZUKeJwa8PC5StvwPx4jcLeZRJC2rAVDG + SW7NAInbATvr9ssSh03JqjXb+HDyywiqoQ7EVLtmtXWimX+0b3/2vhqcH5jgcKC9 + IGFydrjPbv4kwMrKnm6XlPZ9L0/3FMzanXPGd64LQVy51SI4d5Xymn0Mw2kMX8s6 + Nf05OsWcDzJ1n6/Q1qHSxQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBRmaIc8eNwGP7i6P7AJrNQuK6OpFzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBAIBeHfGwz3S2zwIUIpqEEI5/sMySDeS+3nJR+woWAHeO0C8i + BJdDh+kzzkP0JkWpr/4NWz84/IdYo1lqASd1Kopz9aT1+iROXaWr43CtbzjXb7/X + Zv7eZZFC8/lS5SROq42pPWl4ekbR0w8XGQElmHYcWS41LBfKeHCUwv83ATF0XQ6I + 4t+9YSqZHzj4vvedrvcRInzmwWJaal9s7Z6GuwTGmnMsN3LkhZ+/GD6oW3pU/Pyh + EtWqffjsLhfcdCs3gG8x9BbkcJPH5aPAVkPn4wc8wuXg6xxb9YGsQuY930GWTYRf + schbgjsuqznW4HHakq4WNhs1UdTSTKkRdZz7FUQ= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEDzCCAvegAwIBAgIRAM2zAbhyckaqRim63b+Tib8wDQYJKoZIhvcNAQELBQAw + gZ8xCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE4MDYGA1UEAwwv + QW1hem9uIFJEUyBQcmV2aWV3IHVzLWVhc3QtMiBSb290IENBIFJTQTIwNDggRzEx + EDAOBgNVBAcMB1NlYXR0bGUwIBcNMjEwNTE4MjA0OTQ1WhgPMjA2MTA1MTgyMTQ5 + NDVaMIGfMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNl + cywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExODA2BgNV + BAMML0FtYXpvbiBSRFMgUHJldmlldyB1cy1lYXN0LTIgUm9vdCBDQSBSU0EyMDQ4 + IEcxMRAwDgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEA1ybjQMH1MkbvfKsWJaCTXeCSN1SG5UYid+Twe+TjuSqaXWonyp4WRR5z + tlkqq+L2MWUeQQAX3S17ivo/t84mpZ3Rla0cx39SJtP3BiA2BwfUKRjhPwOjmk7j + 3zrcJjV5k1vSeLNOfFFSlwyDiVyLAE61lO6onBx+cRjelu0egMGq6WyFVidTdCmT + Q9Zw3W6LTrnPvPmEyjHy2yCHzH3E50KSd/5k4MliV4QTujnxYexI2eR8F8YQC4m3 + DYjXt/MicbqA366SOoJA50JbgpuVv62+LSBu56FpzY12wubmDZsdn4lsfYKiWxUy + uc83a2fRXsJZ1d3whxrl20VFtLFHFQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/ + MB0GA1UdDgQWBBRC0ytKmDYbfz0Bz0Psd4lRQV3aNTAOBgNVHQ8BAf8EBAMCAYYw + DQYJKoZIhvcNAQELBQADggEBAGv8qZu4uaeoF6zsbumauz6ea6tdcWt+hGFuwGrb + tRbI85ucAmVSX06x59DJClsb4MPhL1XmqO3RxVMIVVfRwRHWOsZQPnXm8OYQ2sny + rYuFln1COOz1U/KflZjgJmxbn8x4lYiTPZRLarG0V/OsCmnLkQLPtEl/spMu8Un7 + r3K8SkbWN80gg17Q8EV5mnFwycUx9xsTAaFItuG0en9bGsMgMmy+ZsDmTRbL+lcX + Fq8r4LT4QjrFz0shrzCwuuM4GmcYtBSxlacl+HxYEtAs5k10tmzRf6OYlY33tGf6 + 1tkYvKryxDPF/EDgGp/LiBwx6ixYMBfISoYASt4V/ylAlHA= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtTCCAjqgAwIBAgIRAK9BSZU6nIe6jqfODmuVctYwCgYIKoZIzj0EAwMwgZkx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEyMDAGA1UEAwwpQW1h + em9uIFJEUyBjYS1jZW50cmFsLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTIxMjIxMzA5WhgPMjEyMTA1MjEyMzEzMDlaMIGZMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMjAwBgNVBAMMKUFtYXpv + biBSRFMgY2EtY2VudHJhbC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEUkEERcgxneT5H+P+fERcbGmf + bVx+M7rNWtgWUr6w+OBENebQA9ozTkeSg4c4M+qdYSObFqjxITdYxT1z/nHz1gyx + OKAhLjWu+nkbRefqy3RwXaWT680uUaAP6ccnkZOMo0IwQDAPBgNVHRMBAf8EBTAD + AQH/MB0GA1UdDgQWBBSN6fxlg0s5Wny08uRBYZcQ3TUoyzAOBgNVHQ8BAf8EBAMC + AYYwCgYIKoZIzj0EAwMDaQAwZgIxAORaz+MBVoFBTmZ93j2G2vYTwA6T5hWzBWrx + CrI54pKn5g6At56DBrkjrwZF5T1enAIxAJe/LZ9xpDkAdxDgGJFN8gZYLRWc0NRy + Rb4hihy5vj9L+w9uKc9VfEBIFuhT7Z3ljg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEADCCAuigAwIBAgIQB/57HSuaqUkLaasdjxUdPjANBgkqhkiG9w0BAQsFADCB + mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB + bWF6b24gUkRTIGFwLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUxOTE3NDAzNFoYDzIwNjEwNTE5MTg0MDM0WjCBmDEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6 + b24gUkRTIGFwLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtbkaoVsUS76o + TgLFmcnaB8cswBk1M3Bf4IVRcwWT3a1HeJSnaJUqWHCJ+u3ip/zGVOYl0gN1MgBb + MuQRIJiB95zGVcIa6HZtx00VezDTr3jgGWRHmRjNVCCHGmxOZWvJjsIE1xavT/1j + QYV/ph4EZEIZ/qPq7e3rHohJaHDe23Z7QM9kbyqp2hANG2JtU/iUhCxqgqUHNozV + Zd0l5K6KnltZQoBhhekKgyiHqdTrH8fWajYl5seD71bs0Axowb+Oh0rwmrws3Db2 + Dh+oc2PwREnjHeca9/1C6J2vhY+V0LGaJmnnIuOANrslx2+bgMlyhf9j0Bv8AwSi + dSWsobOhNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQb7vJT + VciLN72yJGhaRKLn6Krn2TAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD + ggEBAAxEj8N9GslReAQnNOBpGl8SLgCMTejQ6AW/bapQvzxrZrfVOZOYwp/5oV0f + 9S1jcGysDM+DrmfUJNzWxq2Y586R94WtpH4UpJDGqZp+FuOVJL313te4609kopzO + lDdmd+8z61+0Au93wB1rMiEfnIMkOEyt7D2eTFJfJRKNmnPrd8RjimRDlFgcLWJA + 3E8wca67Lz/G0eAeLhRHIXv429y8RRXDtKNNz0wA2RwURWIxyPjn1fHjA9SPDkeW + E1Bq7gZj+tBnrqz+ra3yjZ2blss6Ds3/uRY6NYqseFTZWmQWT7FolZEnT9vMUitW + I0VynUbShVpGf6946e0vgaaKw20= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/jCCAuagAwIBAgIQGyUVTaVjYJvWhroVEiHPpDANBgkqhkiG9w0BAQsFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIHVzLXdlc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTE5MTkwNDA2WhgPMjA2MTA1MTkyMDA0MDZaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgdXMtd2VzdC0xIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANhyXpJ0t4nigRDZ + EwNtFOem1rM1k8k5XmziHKDvDk831p7QsX9ZOxl/BT59Pu/P+6W6SvasIyKls1sW + FJIjFF+6xRQcpoE5L5evMgN/JXahpKGeQJPOX9UEXVW5B8yi+/dyUitFT7YK5LZA + MqWBN/LtHVPa8UmE88RCDLiKkqiv229tmwZtWT7nlMTTCqiAHMFcryZHx0pf9VPh + x/iPV8p2gBJnuPwcz7z1kRKNmJ8/cWaY+9w4q7AYlAMaq/rzEqDaN2XXevdpsYAK + TMMj2kji4x1oZO50+VPNfBl5ZgJc92qz1ocF95SAwMfOUsP8AIRZkf0CILJYlgzk + /6u6qZECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm5jfcS9o + +LwL517HpB6hG+PmpBswDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB + AQAcQ6lsqxi63MtpGk9XK8mCxGRLCad51+MF6gcNz6i6PAqhPOoKCoFqdj4cEQTF + F8dCfa3pvfJhxV6RIh+t5FCk/y6bWT8Ls/fYKVo6FhHj57bcemWsw/Z0XnROdVfK + Yqbc7zvjCPmwPHEqYBhjU34NcY4UF9yPmlLOL8uO1JKXa3CAR0htIoW4Pbmo6sA4 + 6P0co/clW+3zzsQ92yUCjYmRNeSbdXbPfz3K/RtFfZ8jMtriRGuO7KNxp8MqrUho + HK8O0mlSUxGXBZMNicfo7qY8FD21GIPH9w5fp5oiAl7lqFzt3E3sCLD3IiVJmxbf + fUwpGd1XZBBSdIxysRLM6j48 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrTCCAjOgAwIBAgIQU+PAILXGkpoTcpF200VD/jAKBggqhkjOPQQDAzCBljEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMS8wLQYDVQQDDCZBbWF6 + b24gUkRTIGFwLWVhc3QtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTAgFw0yMTA1MjUyMTQ1MTFaGA8yMTIxMDUyNTIyNDUxMVowgZYxCzAJBgNV + BAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYD + VQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1hem9uIFJE + UyBhcC1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0bGUw + djAQBgcqhkjOPQIBBgUrgQQAIgNiAAT3tFKE8Kw1sGQAvNLlLhd8OcGhlc7MiW/s + NXm3pOiCT4vZpawKvHBzD76Kcv+ZZzHRxQEmG1/muDzZGlKR32h8AAj+NNO2Wy3d + CKTtYMiVF6Z2zjtuSkZQdjuQbe4eQ7qjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD + VR0OBBYEFAiSQOp16Vv0Ohpvqcbd2j5RmhYNMA4GA1UdDwEB/wQEAwIBhjAKBggq + hkjOPQQDAwNoADBlAjBVsi+5Ape0kOhMt/WFkANkslD4qXA5uqhrfAtH29Xzz2NV + tR7akiA771OaIGB/6xsCMQCZt2egCtbX7J0WkuZ2KivTh66jecJr5DHvAP4X2xtS + F/5pS+AUhcKTEGjI9jDH3ew= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICuDCCAj2gAwIBAgIQT5mGlavQzFHsB7hV6Mmy6TAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyNDIwNTAxNVoYDzIxMjEwNTI0MjE1MDE1WjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEcm4BBBjYK7clwm0HJRWS + flt3iYwoJbIXiXn9c1y3E+Vb7bmuyKhS4eO8mwO4GefUcXObRfoHY2TZLhMJLVBQ + 7MN2xDc0RtZNj07BbGD3VAIFRTDX0mH9UNYd0JQM3t/Oo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBRrd5ITedfAwrGo4FA9UaDaGFK3rjAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAPBNqmVv1IIA3EZyQ6XuVf4gj79/DMO8 + bkicNS1EcBpUqbSuU4Zwt2BYc8c/t7KVOQIxAOHoWkoKZPiKyCxfMtJpCZySUG+n + sXgB/LOyWE5BJcXUfm+T1ckeNoWeUUMOLmnJjg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRAJcDeinvdNrDQBeJ8+t38WQwDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtNCBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjIwNTI1MTY0OTE2WhgPMjA2MjA1MjUxNzQ5MTZa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtc291dGhlYXN0LTQgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + k8DBNkr9tMoIM0NHoFiO7cQfSX0cOMhEuk/CHt0fFx95IBytx7GHCnNzpM27O5z6 + x6iRhfNnx+B6CrGyCzOjxvPizneY+h+9zfvNz9jj7L1I2uYMuiNyOKR6FkHR46CT + 1CiArfVLLPaTqgD/rQjS0GL2sLHS/0dmYipzynnZcs613XT0rAWdYDYgxDq7r/Yi + Xge5AkWQFkMUq3nOYDLCyGGfQqWKkwv6lZUHLCDKf+Y0Uvsrj8YGCI1O8mF0qPCQ + lmlfaDvbuBu1AV+aabmkvyFj3b8KRIlNLEtQ4N8KGYR2Jdb82S4YUGIOAt4wuuFt + 1B7AUDLk3V/u+HTWiwfoLQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBSNpcjz6ArWBtAA+Gz6kyyZxrrgdDAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBAGJEd7UgOzHYIcQRSF7nSYyjLROyalaIV9AX4WXW/Cqlul1c + MblP5etDZm7A/thliZIWAuyqv2bNicmS3xKvNy6/QYi1YgxZyy/qwJ3NdFl067W0 + t8nGo29B+EVK94IPjzFHWShuoktIgp+dmpijB7wkTIk8SmIoe9yuY4+hzgqk+bo4 + ms2SOXSN1DoQ75Xv+YmztbnZM8MuWhL1T7hA4AMorzTQLJ9Pof8SpSdMHeDsHp0R + 01jogNFkwy25nw7cL62nufSuH2fPYGWXyNDg+y42wKsKWYXLRgUQuDVEJ2OmTFMB + T0Vf7VuNijfIA9hkN2d3K53m/9z5WjGPSdOjGhg= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/jCCAuagAwIBAgIQRiwspKyrO0xoxDgSkqLZczANBgkqhkiG9w0BAQsFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIHVzLXdlc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTI0MjE1OTAwWhgPMjA2MTA1MjQyMjU5MDBaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgdXMtd2VzdC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL53Jk3GsKiu+4bx + jDfsevWbwPCNJ3H08Zp7GWhvI3Tgi39opfHYv2ku2BKFjK8N2L6RvNPSR8yplv5j + Y0tK0U+XVNl8o0ibhqRDhbTuh6KL8CFINWYzAajuxFS+CF0U6c1Q3tXLBdALxA7l + FlXJ71QrP06W31kRe7kvgrvO7qWU3/OzUf9qYw4LSiR1/VkvvRCTqcVNw09clw/M + Jbw6FSgweN65M9j7zPbjGAXSHkXyxH1Erin2fa+B9PE4ZDgX9cp2C1DHewYJQL/g + SepwwcudVNRN1ibKH7kpMrgPnaNIVNx5sXVsTjk6q2ZqYw3SVHegltJpLy/cZReP + mlivF2kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUmTcQd6o1 + CuS65MjBrMwQ9JJjmBwwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB + AQAKSDSIzl956wVddPThf2VAzI8syw9ngSwsEHZvxVGHBvu5gg618rDyguVCYX9L + 4Kw/xJrk6S3qxOS2ZDyBcOpsrBskgahDFIunzoRP3a18ARQVq55LVgfwSDQiunch + Bd05cnFGLoiLkR5rrkgYaP2ftn3gRBRaf0y0S3JXZ2XB3sMZxGxavYq9mfiEcwB0 + LMTMQ1NYzahIeG6Jm3LqRqR8HkzP/Ztq4dT2AtSLvFebbNMiWqeqT7OcYp94HTYT + zqrtaVdUg9bwyAUCDgy0GV9RHDIdNAOInU/4LEETovrtuBU7Z1q4tcHXvN6Hd1H8 + gMb0mCG5I393qW5hFsA/diFb + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRAPQAvihfjBg/JDbj6U64K98wDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1ub3J0aGVhc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTIwMTYyODQxWhgPMjA2MTA1MjAxNzI4NDFa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtbm9ydGhlYXN0LTIgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + vJ9lgyksCxkBlY40qOzI1TCj/Q0FVGuPL/Z1Mw2YN0l+41BDv0FHApjTUkIKOeIP + nwDwpXTa3NjYbk3cOZ/fpH2rYJ++Fte6PNDGPgKppVCUh6x3jiVZ1L7wOgnTdK1Q + Trw8440IDS5eLykRHvz8OmwvYDl0iIrt832V0QyOlHTGt6ZJ/aTQKl12Fy3QBLv7 + stClPzvHTrgWqVU6uidSYoDtzHbU7Vda7YH0wD9IUoMBf7Tu0rqcE4uH47s2XYkc + SdLEoOg/Ngs7Y9B1y1GCyj3Ux7hnyvCoRTw014QyNB7dTatFMDvYlrRDGG14KeiU + UL7Vo/+EejWI31eXNLw84wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBQkgTWFsNg6wA3HbbihDQ4vpt1E2zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBAGz1Asiw7hn5WYUj8RpOCzpE0h/oBZcnxP8wulzZ5Xd0YxWO + 0jYUcUk3tTQy1QvoY+Q5aCjg6vFv+oFBAxkib/SmZzp4xLisZIGlzpJQuAgRkwWA + 6BVMgRS+AaOMQ6wKPgz1x4v6T0cIELZEPq3piGxvvqkcLZKdCaeC3wCS6sxuafzZ + 4qA3zMwWuLOzRftgX2hQto7d/2YkRXga7jSvQl3id/EI+xrYoH6zIWgjdU1AUaNq + NGT7DIo47vVMfnd9HFZNhREsd4GJE83I+JhTqIxiKPNxrKgESzyADmNPt0gXDnHo + tbV1pMZz5HpJtjnP/qVZhEK5oB0tqlKPv9yx074= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICuTCCAj6gAwIBAgIRAKp1Rn3aL/g/6oiHVIXtCq8wCgYIKoZIzj0EAwMwgZsx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE0MDIGA1UEAwwrQW1h + em9uIFJEUyBhcC1ub3J0aGVhc3QtMyBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTAgFw0yMTA1MjQyMDMyMTdaGA8yMTIxMDUyNDIxMzIxN1owgZsx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE0MDIGA1UEAwwrQW1h + em9uIFJEUyBhcC1ub3J0aGVhc3QtMyBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGTYWPILeBJXfcL3Dz4z + EWMUq78xB1HpjBwHoTURYfcMd5r96BTVG6yaUBWnAVCMeeD6yTG9a1eVGNhG14Hk + ZAEjgLiNB7RRbEG5JZ/XV7W/vODh09WCst2y9SLKsdgeAaNCMEAwDwYDVR0TAQH/ + BAUwAwEB/zAdBgNVHQ4EFgQUoE0qZHmDCDB+Bnm8GUa/evpfPwgwDgYDVR0PAQH/ + BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCnil5MMwhY3qoXv0xvcKZGxGPaBV15 + 0CCssCKn0oVtdJQfJQ3Jrf3RSaEyijXIJsoCMQC35iJi4cWoNX3N/qfgnHohW52O + B5dg0DYMqy5cNZ40+UcAanRMyqNQ6P7fy3umGco= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtzCCAj2gAwIBAgIQPXnDTPegvJrI98qz8WxrMjAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIEJldGEgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUxODIxNDAxMloYDzIxMjEwNTE4MjI0MDEyWjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIEJldGEgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEI0sR7gwutK5AB46hM761 + gcLTGBIYlURSEoM1jcBwy56CL+3CJKZwLLyJ7qoOKfWbu5GsVLUTWS8MV6Nw33cx + 2KQD2svb694wi+Px2f4n9+XHkEFQw8BbiodDD7RZA70fo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBTQSioOvnVLEMXwNSDg+zgln/vAkjAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIxAMwu1hqm5Bc98uE/E0B5iMYbBQ4kpMxO + tP8FTfz5UR37HUn26nXE0puj6S/Ffj4oJgIwXI7s2c26tFQeqzq6u3lrNJHp5jC9 + Uxlo/hEJOLoDj5jnpxo8dMAtCNoQPaHdfL0P + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + Luw= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjWgAwIBAgIQGKVv+5VuzEZEBzJ+bVfx2zAKBggqhkjOPQQDAzCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGFwLXNvdXRoLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTE5MTc1MDU5WhgPMjEyMTA1MTkxODUwNTlaMIGXMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS + RFMgYXAtc291dGgtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs + ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMqdLJ0tZF/DGFZTKZDrGRJZID8ivC2I + JRCYTWweZKCKSCAzoiuGGHzJhr5RlLHQf/QgmFcgXsdmO2n3CggzhA4tOD9Ip7Lk + P05eHd2UPInyPCHRgmGjGb0Z+RdQ6zkitKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUC1yhRgVqU5bR8cGzOUCIxRpl4EYwDgYDVR0PAQH/BAQDAgGGMAoG + CCqGSM49BAMDA2cAMGQCMG0c/zLGECRPzGKJvYCkpFTCUvdP4J74YP0v/dPvKojL + t/BrR1Tg4xlfhaib7hPc7wIwFvgqHes20CubQnZmswbTKLUrgSUW4/lcKFpouFd2 + t2/ewfi/0VhkeUW+IiHhOMdU + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCTCCA/GgAwIBAgIRAOXxJuyXVkbfhZCkS/dOpfEwDQYJKoZIhvcNAQEMBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1ub3J0aGVhc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTI1MjE1OTEwWhgPMjEyMTA1MjUyMjU5MTBa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtbm9ydGhlYXN0LTEgUm9vdCBDQSBSU0E0MDk2IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA + xiP4RDYm4tIS12hGgn1csfO8onQDmK5SZDswUpl0HIKXOUVVWkHNlINkVxbdqpqH + FhbyZmNN6F/EWopotMDKe1B+NLrjNQf4zefv2vyKvPHJXhxoKmfyuTd5Wk8k1F7I + lNwLQzznB+ElhrLIDJl9Ro8t31YBBNFRGAGEnxyACFGcdkjlsa52UwfYrwreEg2l + gW5AzqHgjFfj9QRLydeU/n4bHm0F1adMsV7P3rVwilcUlqsENDwXnWyPEyv3sw6F + wNemLEs1129mB77fwvySb+lLNGsnzr8w4wdioZ74co+T9z2ca+eUiP+EQccVw1Is + D4Fh57IjPa6Wuc4mwiUYKkKY63+38aCfEWb0Qoi+zW+mE9nek6MOQ914cN12u5LX + dBoYopphRO5YmubSN4xcBy405nIdSdbrAVWwxXnVVyjqjknmNeqQsPZaxAhdoKhV + AqxNr8AUAdOAO6Sz3MslmcLlDXFihrEEOeUbpg/m1mSUUHGbu966ajTG1FuEHHwS + 7WB52yxoJo/tHvt9nAWnh3uH5BHmS8zn6s6CGweWKbX5yICnZ1QFR1e4pogxX39v + XD6YcNOO+Vn+HY4nXmjgSYVC7l+eeP8eduMg1xJujzjrbmrXU+d+cBObgdTOAlpa + JFHaGwYw1osAwPCo9cZ2f04yitBfj9aPFia8ASKldakCAwEAAaNCMEAwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQUqKS+ltlior0SyZKYAkJ/efv55towDgYDVR0P + AQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQAdElvp8bW4B+Cv+1WSN87dg6TN + wGyIjJ14/QYURgyrZiYpUmZpj+/pJmprSWXu4KNyqHftmaidu7cdjL5nCAvAfnY5 + /6eDDbX4j8Gt9fb/6H9y0O0dn3mUPSEKG0crR+JRFAtPhn/2FNvst2P82yguWLv0 + pHjHVUVcq+HqDMtUIJsTPYjSh9Iy77Q6TOZKln9dyDOWJpCSkiUWQtMAKbCSlvzd + zTs/ahqpT+zLfGR1SR+T3snZHgQnbnemmz/XtlKl52NxccARwfcEEKaCRQyGq/pR + 0PVZasyJS9JY4JfQs4YOdeOt4UMZ8BmW1+BQWGSkkb0QIRl8CszoKofucAlqdPcO + IT/ZaMVhI580LFGWiQIizWFskX6lqbCyHqJB3LDl8gJISB5vNTHOHpvpMOMs5PYt + cRl5Mrksx5MKMqG7y5R734nMlZxQIHjL5FOoOxTBp9KeWIL/Ib89T2QDaLw1SQ+w + ihqWBJ4ZdrIMWYpP3WqM+MXWk7WAem+xsFJdR+MDgOOuobVQTy5dGBlPks/6gpjm + rO9TjfQ36ppJ3b7LdKUPeRfnYmlR5RU4oyYJ//uLbClI443RZAgxaCXX/nyc12lr + eVLUMNF2abLX4/VF63m2/Z9ACgMRfqGshPssn1NN33OonrotQoj4S3N9ZrjvzKt8 + iHcaqd60QKpfiH2A3A== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICuDCCAj2gAwIBAgIQPaVGRuu86nh/ylZVCLB0MzAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLW5vcnRoZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyNTIyMDMxNloYDzIxMjEwNTI1MjMwMzE2WjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLW5vcnRoZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEexNURoB9KE93MEtEAlJG + obz4LS/pD2hc8Gczix1WhVvpJ8bN5zCDXaKdnDMCebetyRQsmQ2LYlfmCwpZwSDu + 0zowB11Pt3I5Avu2EEcuKTlKIDMBeZ1WWuOd3Tf7MEAMo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBSaYbZPBvFLikSAjpa8mRJvyArMxzAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAOEJkuh3Zjb7Ih/zuNRd1RBqmIYcnyw0 + nwUZczKXry+9XebYj3VQxSRNadrarPWVqgIxAMg1dyGoDAYjY/L/9YElyMnvHltO + PwpJShmqHvCLc/mXMgjjYb/akK7yGthvW6j/uQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCDCCA/CgAwIBAgIQChu3v5W1Doil3v6pgRIcVzANBgkqhkiG9w0BAQwFADCB + nDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTUwMwYDVQQDDCxB + bWF6b24gUkRTIEJldGEgdXMtZWFzdC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4G + A1UEBwwHU2VhdHRsZTAgFw0yMTA1MTgyMTM0MTVaGA8yMTIxMDUxODIyMzQxNVow + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBCZXRhIHVzLWVhc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1 + FUGQ5tf3OwpDR6hGBxhUcrkwKZhaXP+1St1lSOQvjG8wXT3RkKzRGMvb7Ee0kzqI + mzKKe4ASIhtV3UUWdlNmP0EA3XKnif6N79MismTeGkDj75Yzp5A6tSvqByCgxIjK + JqpJrch3Dszoyn8+XhwDxMZtkUa5nQVdJgPzJ6ltsQ8E4SWLyLtTu0S63jJDkqYY + S7cQblk7y7fel+Vn+LS5dGTdRRhMvSzEnb6mkVBaVzRyVX90FNUED06e8q+gU8Ob + htvQlf9/kRzHwRAdls2YBhH40ZeyhpUC7vdtPwlmIyvW5CZ/QiG0yglixnL6xahL + pbmTuTSA/Oqz4UGQZv2WzHe1lD2gRHhtFX2poQZeNQX8wO9IcUhrH5XurW/G9Xwl + Sat9CMPERQn4KC3HSkat4ir2xaEUrjfg6c4XsGyh2Pk/LZ0gLKum0dyWYpWP4JmM + RQNjrInXPbMhzQObozCyFT7jYegS/3cppdyy+K1K7434wzQGLU1gYXDKFnXwkX8R + bRKgx2pHNbH5lUddjnNt75+e8m83ygSq/ZNBUz2Ur6W2s0pl6aBjwaDES4VfWYlI + jokcmrGvJNDfQWygb1k00eF2bzNeNCHwgWsuo3HSxVgc/WGsbcGrTlDKfz+g3ich + bXUeUidPhRiv5UQIVCLIHpHuin3bj9lQO/0t6p+tAQIDAQABo0IwQDAPBgNVHRMB + Af8EBTADAQH/MB0GA1UdDgQWBBSFmMBgm5IsRv3hLrvDPIhcPweXYTAOBgNVHQ8B + Af8EBAMCAYYwDQYJKoZIhvcNAQEMBQADggIBAAa2EuozymOsQDJlEi7TqnyA2OhT + GXPfYqCyMJVkfrqNgcnsNpCAiNEiZbb+8sIPXnT8Ay8hrwJYEObJ5b7MHXpLuyft + z0Pu1oFLKnQxKjNxrIsCvaB4CRRdYjm1q7EqGhMGv76se9stOxkOqO9it31w/LoU + ENDk7GLsSqsV1OzYLhaH8t+MaNP6rZTSNuPrHwbV3CtBFl2TAZ7iKgKOhdFz1Hh9 + Pez0lG+oKi4mHZ7ajov6PD0W7njn5KqzCAkJR6OYmlNVPjir+c/vUtEs0j+owsMl + g7KE5g4ZpTRShyh5BjCFRK2tv0tkqafzNtxrKC5XNpEkqqVTCnLcKG+OplIEadtr + C7UWf4HyhCiR+xIyxFyR05p3uY/QQU/5uza7GlK0J+U1sBUytx7BZ+Fo8KQfPPqV + CqDCaYUksoJcnJE/KeoksyqNQys7sDGJhkd0NeUGDrFLKHSLhIwAMbEWnqGxvhli + E7sP2E5rI/I9Y9zTbLIiI8pfeZlFF8DBdoP/Hzg8pqsiE/yiXSFTKByDwKzGwNqz + F0VoFdIZcIbLdDbzlQitgGpJtvEL7HseB0WH7B2PMMD8KPJlYvPveO3/6OLzCsav + +CAkvk47NQViKMsUTKOA0JDCW+u981YRozxa3K081snhSiSe83zIPBz1ikldXxO9 + 6YYLNPRrj3mi9T/f + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjSgAwIBAgIRAMkvdFnVDb0mWWFiXqnKH68wCgYIKoZIzj0EAwMwgZYx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h + em9uIFJEUyB1cy13ZXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTE5MTkxMzI0WhgPMjEyMTA1MTkyMDEzMjRaMIGWMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS + RFMgdXMtd2VzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEy86DB+9th/0A5VcWqMSWDxIUblWTt/R0 + ao6Z2l3vf2YDF2wt1A2NIOGpfQ5+WAOJO/IQmnV9LhYo+kacB8sOnXdQa6biZZkR + IyouUfikVQAKWEJnh1Cuo5YMM4E2sUt5o0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G + A1UdDgQWBBQ8u3OnecANmG8OoT7KLWDuFzZwBTAOBgNVHQ8BAf8EBAMCAYYwCgYI + KoZIzj0EAwMDaAAwZQIwQ817qkb7mWJFnieRAN+m9W3E0FLVKaV3zC5aYJUk2fcZ + TaUx3oLp3jPLGvY5+wgeAjEA6wAicAki4ZiDfxvAIuYiIe1OS/7H5RA++R8BH6qG + iRzUBM/FItFpnkus7u/eTkvo + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrzCCAjWgAwIBAgIQS/+Ryfgb/IOVEa1pWoe8oTAKBggqhkjOPQQDAzCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGFwLXNvdXRoLTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjIwNjA2MjE1NDQyWhgPMjEyMjA2MDYyMjU0NDJaMIGXMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS + RFMgYXAtc291dGgtMiBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs + ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDsX6fhdUWBQpYTdseBD/P3s96Dtw2Iw + OrXKNToCnmX5nMkUGdRn9qKNiz1pw3EPzaPxShbYwQ7LYP09ENK/JN4QQjxMihxC + jLFxS85nhBQQQGRCWikDAe38mD8fSvREQKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUIh1xZiseQYFjPYKJmGbruAgRH+AwDgYDVR0PAQH/BAQDAgGGMAoG + CCqGSM49BAMDA2gAMGUCMFudS4zLy+UUGrtgNLtRMcu/DZ9BUzV4NdHxo0bkG44O + thnjl4+wTKI6VbyAbj2rkgIxAOHps8NMITU5DpyiMnKTxV8ubb/WGHrLl0BjB8Lw + ETVJk5DNuZvsIIcm7ykk6iL4Tw== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGBDCCA+ygAwIBAgIQDcEmNIAVrDpUw5cH5ynutDANBgkqhkiG9w0BAQwFADCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIG1lLWNlbnRyYWwtMSBSb290IENBIFJTQTQwOTYgRzExEDAOBgNV + BAcMB1NlYXR0bGUwIBcNMjIwNTA3MDA0MDIzWhgPMjEyMjA1MDcwMTQwMjNaMIGa + MQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5j + LjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMzAxBgNVBAMMKkFt + YXpvbiBSRFMgbWUtY2VudHJhbC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UE + BwwHU2VhdHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKvADk8t + Fl9bFlU5sajLPPDSOUpPAkKs6iPlz+27o1GJC88THcOvf3x0nVAcu9WYe9Qaas+4 + j4a0vv51agqyODRD/SNi2HnqW7DbtLPAm6KBHe4twl28ItB/JD5g7u1oPAHFoXMS + cH1CZEAs5RtlZGzJhcBXLFsHNv/7+SCLyZ7+2XFh9OrtgU4wMzkHoRNndhfwV5bu + 17bPTwuH+VxH37zXf1mQ/KjhuJos0C9dL0FpjYBAuyZTAWhZKs8dpSe4DI544z4w + gkwUB4bC2nA1TBzsywEAHyNuZ/xRjNpWvx0ToWAA2iFJqC3VO3iKcnBplMvaUuMt + jwzVSNBnKcoabXCZL2XDLt4YTZR8FSwz05IvsmwcPB7uNTBXq3T9sjejW8QQK3vT + tzyfLq4jKmQE7PoS6cqYm+hEPm2hDaC/WP9bp3FdEJxZlPH26fq1b7BWYWhQ9pBA + Nv9zTnzdR1xohTyOJBUFQ81ybEzabqXqVXUIANqIOaNcTB09/sLJ7+zuMhp3mwBu + LtjfJv8PLuT1r63bU3seROhKA98b5KfzjvbvPSg3vws78JQyoYGbqNyDfyjVjg3U + v//AdVuPie6PNtdrW3upZY4Qti5IjP9e3kimaJ+KAtTgMRG56W0WxD3SP7+YGGbG + KhntDOkKsN39hLpn9UOafTIqFu7kIaueEy/NAgMBAAGjQjBAMA8GA1UdEwEB/wQF + MAMBAf8wHQYDVR0OBBYEFHAems86dTwdZbLe8AaPy3kfIUVoMA4GA1UdDwEB/wQE + AwIBhjANBgkqhkiG9w0BAQwFAAOCAgEAOBHpp0ICx81kmeoBcZTrMdJs2gnhcd85 + FoSCjXx9H5XE5rmN/lQcxxOgj8hr3uPuLdLHu+i6THAyzjrl2NA1FWiqpfeECGmy + 0jm7iZsYORgGQYp/VKnDrwnKNSqlZvOuRr0kfUexwFlr34Y4VmupvEOK/RdGsd3S + +3hiemcHse9ST/sJLHx962AWMkN86UHPscJEe4+eT3f2Wyzg6La8ARwdWZSNS+WH + ZfybrncMmuiXuUdHv9XspPsqhKgtHhcYeXOGUtrwQPLe3+VJZ0LVxhlTWr9951GZ + GfmWwTV/9VsyKVaCFIXeQ6L+gjcKyEzYF8wpMtQlSc7FFqwgC4bKxvMBSaRy88Nr + lV2+tJD/fr8zGUeBK44Emon0HKDBWGX+/Hq1ZIv0Da0S+j6LbA4fusWxtGfuGha+ + luhHgVInCpALIOamiBEdGhILkoTtx7JrYppt3/Raqg9gUNCOOYlCvGhqX7DXeEfL + DGabooiY2FNWot6h04JE9nqGj5QqT8D6t/TL1nzxhRPzbcSDIHUd/b5R+a0bAA+7 + YTU6JqzEVCWKEIEynYmqikgLMGB/OzWsgyEL6822QW6hJAQ78XpbNeCzrICF4+GC + 7KShLnwuWoWpAb26268lvOEvCTFM47VC6jNQl97md+2SA9Ma81C9wflid2M83Wle + cuLMVcQZceE= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEADCCAuigAwIBAgIQAhAteLRCvizAElaWORFU2zANBgkqhkiG9w0BAQsFADCB + mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB + bWF6b24gUkRTIG1lLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyMDE3MDkxNloYDzIwNjEwNTIwMTgwOTE2WjCBmDEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6 + b24gUkRTIG1lLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+qg7JAcOVKjh + N83SACnBFZPyB63EusfDr/0V9ZdL8lKcmZX9sv/CqoBo3N0EvBqHQqUUX6JvFb7F + XrMUZ740kr28gSRALfXTFgNODjXeDsCtEkKRTkac/UM8xXHn+hR7UFRPHS3e0GzI + iLiwQWDkr0Op74W8aM0CfaVKvh2bp4BI1jJbdDnQ9OKXpOxNHGUf0ZGb7TkNPkgI + b2CBAc8J5o3H9lfw4uiyvl6Fz5JoP+A+zPELAioYBXDrbE7wJeqQDJrETWqR9VEK + BXURCkVnHeaJy123MpAX2ozf4pqk0V0LOEOZRS29I+USF5DcWr7QIXR/w2I8ws1Q + 7ys+qbE+kQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQFJ16n + 1EcCMOIhoZs/F9sR+Jy++zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD + ggEBAOc5nXbT3XTDEZsxX2iD15YrQvmL5m13B3ImZWpx/pqmObsgx3/dg75rF2nQ + qS+Vl+f/HLh516pj2BPP/yWCq12TRYigGav8UH0qdT3CAClYy2o+zAzUJHm84oiB + ud+6pFVGkbqpsY+QMpJUbZWu52KViBpJMYsUEy+9cnPSFRVuRAHjYynSiLk2ZEjb + Wkdc4x0nOZR5tP0FgrX0Ve2KcjFwVQJVZLgOUqmFYQ/G0TIIGTNh9tcmR7yp+xJR + A2tbPV2Z6m9Yxx4E8lLEPNuoeouJ/GR4CkMEmF8cLwM310t174o3lKKUXJ4Vs2HO + Wj2uN6R9oI+jGLMSswTzCNV1vgc= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtjCCAj2gAwIBAgIQM+ObZzo0HZj7HpGdeMmx/zAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC01IFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTI0MDUxNTIxNTA0NloYDzIxMjQwNTE1MjI1MDQ2WjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC01IFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEhSrJY/MXuQyTqK1dnLK6 + uWUx/KxsGCMCBXKthi0spP90CjfOYYxDcGD7zgUtk+LCEK2vneuewAPhlUgqXzaZ + PYDzk2WUznIPiIBvVo32U4vUnV/vSWqzhSKevsOakiPso0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBRw/PJZ4fwnZo25vVSB80KtyKWqmTAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDZwAwZAIwLNcaZNOvCLTumHlJydm+9lB6bcxnaLmb + esoToveXQABKl84kGNI1gaDKOvvLsPbWAjBIqfDMb83RXw7q2C501W5hzsbZ1ZQs + 8+tffIuCrMMGWDLqoUksWJHiocLOfe9gwm4= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICuDCCAj6gAwIBAgIRAOocLeZWjYkG/EbHmscuy8gwCgYIKoZIzj0EAwMwgZsx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE0MDIGA1UEAwwrQW1h + em9uIFJEUyBhcC1zb3V0aGVhc3QtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTAgFw0yMTA1MjEyMTUwMDFaGA8yMTIxMDUyMTIyNTAwMVowgZsx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE0MDIGA1UEAwwrQW1h + em9uIFJEUyBhcC1zb3V0aGVhc3QtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCEr3jq1KtRncnZfK5cq + btY0nW6ZG3FMbh7XwBIR6Ca0f8llGZ4vJEC1pXgiM/4Dh045B9ZIzNrR54rYOIfa + 2NcYZ7mk06DjIQML64hbAxbQzOAuNzLPx268MrlL2uW2XaNCMEAwDwYDVR0TAQH/ + BAUwAwEB/zAdBgNVHQ4EFgQUln75pChychwN4RfHl+tOinMrfVowDgYDVR0PAQH/ + BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMGiyPINRU1mwZ4Crw01vpuPvxZxb2IOr + yX3RNlOIu4We1H+5dQk5tIvH8KGYFbWEpAIxAO9NZ6/j9osMhLgZ0yj0WVjb+uZx + YlZR9fyFisY/jNfX7QhSk+nrc3SFLRUNtpXrng== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEBTCCAu2gAwIBAgIRAKiaRZatN8eiz9p0s0lu0rQwDQYJKoZIhvcNAQELBQAw + gZoxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEzMDEGA1UEAwwq + QW1hem9uIFJEUyBjYS1jZW50cmFsLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYD + VQQHDAdTZWF0dGxlMCAXDTIxMDUyMTIyMDIzNVoYDzIwNjEwNTIxMjMwMjM1WjCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIGNhLWNlbnRyYWwtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNV + BAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCygVMf + qB865IR9qYRBRFHn4eAqGJOCFx+UbraQZmjr/mnRqSkY+nhbM7Pn/DWOrRnxoh+w + q5F9ZxdZ5D5T1v6kljVwxyfFgHItyyyIL0YS7e2h7cRRscCM+75kMedAP7icb4YN + LfWBqfKHbHIOqvvQK8T6+Emu/QlG2B5LvuErrop9K0KinhITekpVIO4HCN61cuOe + CADBKF/5uUJHwS9pWw3uUbpGUwsLBuhJzCY/OpJlDqC8Y9aToi2Ivl5u3/Q/sKjr + 6AZb9lx4q3J2z7tJDrm5MHYwV74elGSXoeoG8nODUqjgklIWAPrt6lQ3WJpO2kug + 8RhCdSbWkcXHfX95AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE + FOIxhqTPkKVqKBZvMWtKewKWDvDBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B + AQsFAAOCAQEAqoItII89lOl4TKvg0I1EinxafZLXIheLcdGCxpjRxlZ9QMQUN3yb + y/8uFKBL0otbQgJEoGhxm4h0tp54g28M6TN1U0332dwkjYxUNwvzrMaV5Na55I2Z + 1hq4GB3NMXW+PvdtsgVOZbEN+zOyOZ5MvJHEQVkT3YRnf6avsdntltcRzHJ16pJc + Y8rR7yWwPXh1lPaPkxddrCtwayyGxNbNmRybjR48uHRhwu7v2WuAMdChL8H8bp89 + TQLMrMHgSbZfee9hKhO4Zebelf1/cslRSrhkG0ESq6G5MUINj6lMg2g6F0F7Xz2v + ncD/vuRN5P+vT8th/oZ0Q2Gc68Pun0cn/g== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/zCCAuegAwIBAgIRAJYlnmkGRj4ju/2jBQsnXJYwDQYJKoZIhvcNAQELBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyB1cy1lYXN0LTIgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyMTIzMDQ0NFoYDzIwNjEwNTIyMDAwNDQ0WjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIHVzLWVhc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC74V3eigv+pCj5 + nqDBqplY0Jp16pTeNB06IKbzb4MOTvNde6QjsZxrE1xUmprT8LxQqN9tI3aDYEYk + b9v4F99WtQVgCv3Y34tYKX9NwWQgwS1vQwnIR8zOFBYqsAsHEkeJuSqAB12AYUSd + Zv2RVFjiFmYJho2X30IrSLQfS/IE3KV7fCyMMm154+/K1Z2IJlcissydEAwgsUHw + edrE6CxJVkkJ3EvIgG4ugK/suxd8eEMztaQYJwSdN8TdfT59LFuSPl7zmF3fIBdJ + //WexcQmGabaJ7Xnx+6o2HTfkP8Zzzzaq8fvjAcvA7gyFH5EP26G2ZqMG+0y4pTx + SPVTrQEXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIWWuNEF + sUMOC82XlfJeqazzrkPDMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC + AQEAgClmxcJaQTGpEZmjElL8G2Zc8lGc+ylGjiNlSIw8X25/bcLRptbDA90nuP+q + zXAMhEf0ccbdpwxG/P5a8JipmHgqQLHfpkvaXx+0CuP++3k+chAJ3Gk5XtY587jX + +MJfrPgjFt7vmMaKmynndf+NaIJAYczjhJj6xjPWmGrjM3MlTa9XesmelMwP3jep + bApIWAvCYVjGndbK9byyMq1nyj0TUzB8oJZQooaR3MMjHTmADuVBylWzkRMxbKPl + 4Nlsk4Ef1JvIWBCzsMt+X17nuKfEatRfp3c9tbpGlAE/DSP0W2/Lnayxr4RpE9ds + ICF35uSis/7ZlsftODUe8wtpkQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjOgAwIBAgIQS7vMpOTVq2Jw457NdZ2ffjAKBggqhkjOPQQDAzCBljEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMS8wLQYDVQQDDCZBbWF6 + b24gUkRTIGNhLXdlc3QtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTAgFw0yMzA5MTkyMjExNDNaGA8yMTIzMDkxOTIzMTE0M1owgZYxCzAJBgNV + BAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYD + VQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1hem9uIFJE + UyBjYS13ZXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0bGUw + djAQBgcqhkjOPQIBBgUrgQQAIgNiAARdgGSs/F2lpWKqS1ZpcmatFED1JurmNbXG + Sqhv1A/geHrKCS15MPwjtnfZiujYKY4fNkCCUseoGDwkC4281nwkokvnfWR1/cXy + LxfACoXNxsI4b+37CezSUBl48/5p1/OjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD + VR0OBBYEFFhLokGBuJGwKJhZcYSYKyZIitJtMA4GA1UdDwEB/wQEAwIBhjAKBggq + hkjOPQQDAwNpADBmAjEA8aQQlzJRHbqFsRY4O3u/cN0T8dzjcqnYn4NV1w+jvhzt + QPJLB+ggGyQhoFR6G2UrAjEA0be8OP5MWXD8d01KKbo5Dpy6TwukF5qoJmkFJKS3 + bKfEMvFWxXoV06HNZFWdI80u + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + Pqj2 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + KDPtFEk= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtzCCAj2gAwIBAgIQVZ5Y/KqjR4XLou8MCD5pOjAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC00IFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIyMDUyNTE2NTgzM1oYDzIxMjIwNTI1MTc1ODMzWjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC00IFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbo473OmpD5vkckdJajXg + brhmNFyoSa0WCY1njuZC2zMFp3zP6rX4I1r3imrYnJd9pFH/aSiV/r6L5ACE5RPx + 4qdg5SQ7JJUaZc3DWsTOiOed7BCZSzM+KTYK/2QzDMApo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBTmogc06+1knsej1ltKUOdWFvwgsjAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIxAIs7TlLMbGTWNXpGiKf9DxaM07d/iDHe + F/Vv/wyWSTGdobxBL6iArQNVXz0Gr4dvPAIwd0rsoa6R0x5mtvhdRPtM37FYrbHJ + pbV+OMusQqcSLseunLBoCHenvJW0QOCQ8EDY + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGBTCCA+2gAwIBAgIRAO9dVdiLTEGO8kjUFExJmgowDQYJKoZIhvcNAQEMBQAw + gZoxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEzMDEGA1UEAwwq + QW1hem9uIFJEUyBpbC1jZW50cmFsLTEgUm9vdCBDQSBSU0E0MDk2IEcxMRAwDgYD + VQQHDAdTZWF0dGxlMCAXDTIyMTIwMjIwMjYwOFoYDzIxMjIxMjAyMjEyNjA4WjCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIGlsLWNlbnRyYWwtMSBSb290IENBIFJTQTQwOTYgRzExEDAOBgNV + BAcMB1NlYXR0bGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDkVHmJ + bUc8CNDGBcgPmXHSHj5dS1PDnnpk3doCu6pahyYXW8tqAOmOqsDuNz48exY7YVy4 + u9I9OPBeTYB9ZUKwxq+1ZNLsr1cwVz5DdOyDREVFOjlU4rvw0eTgzhP5yw/d+Ai/ + +WmPebZG0irwPKN2f60W/KJ45UNtR+30MT8ugfnPuSHWjjV+dqCOCp/mj8nOCckn + k8GoREwjuTFJMKInpQUC0BaVVX6LiIdgtoLY4wdx00EqNBuROoRTAvrked0jvm7J + UI39CSYxhNZJ9F6LdESZXjI4u2apfNQeSoy6WptxFHr+kh2yss1B2KT6lbwGjwWm + l9HODk9kbBNSy2NeewAms36q+p8wSLPavL28IRfK0UaBAiN1hr2a/2RDGCwOJmw6 + 5erRC5IIX5kCStyXPEGhVPp18EvMuBd37eLIxjZBBO8AIDf4Ue8QmxSeZH0cT204 + 3/Bd6XR6+Up9iMTxkHr1URcL1AR8Zd62lg/lbEfxePNMK9mQGxKP8eTMG5AjtW9G + TatEoRclgE0wZQalXHmKpBNshyYdGqQZhzL1MxCxWzfHNgZkTKIsdzxrjnP7RiBR + jdRH0YhXn6Y906QfLwMCaufwfQ5J8+nj/tu7nG138kSxsu6VUkhnQJhUcUsxuHD/ + NnBx0KGVEldtZiZf7ccgtRVp1lA0OrVtq3ZLMQIDAQABo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBQ2WC3p8rWeE2N0S4Om01KsNLpk/jAOBgNVHQ8BAf8E + BAMCAYYwDQYJKoZIhvcNAQEMBQADggIBAFFEVDt45Obr6Ax9E4RMgsKjj4QjMFB9 + wHev1jL7hezl/ULrHuWxjIusaIZEIcKfn+v2aWtqOq13P3ht7jV5KsV29CmFuCdQ + q3PWiAXVs+hnMskTOmGMDnptqd6/UuSIha8mlOKKAvnmRQJvfX9hIfb/b/mVyKWD + uvTTmcy3cOTJY5ZIWGyzuvmcqA0YNcb7rkJt/iaLq4RX3/ofq4y4w36hefbcvj++ + pXHOmXk3dAej3y6SMBOUcGMyCJcCluRPNYKDTLn+fitcPxPC3JG7fI5bxQ0D6Hpa + qbyGBQu96sfahQyMc+//H8EYlo4b0vPeS5RFFXJS/VBf0AyNT4vVc7H17Q6KjeNp + wEARqsIa7UalHx9MnxrQ/LSTTxiC8qmDkIFuQtw8iQMN0SoL5S0eCZNRD31awgaY + y1PvY8JMN549ugIUjOXnown/OxharLW1evWUraU5rArq3JfeFpPXl4K/u10T5SCL + iJRoxFilGPMFE3hvnmbi5rEy8wRUn7TpLb4I4s/CB/lT2qZTPqvQHwxKCnMm9BKF + NHb4rLL5dCvUi5NJ6fQ/exOoGdOVSfT7jqFeq2TtNunERSz9vpriweliB6iIe1Al + Thj8aEs1GqA764rLVGA+vUe18NhjJm9EemrdIzjSQFy/NdbN/DMaHqEzJogWloAI + izQWYnCS19TJ + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICvTCCAkOgAwIBAgIQCIY7E/bFvFN2lK9Kckb0dTAKBggqhkjOPQQDAzCBnjEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTcwNQYDVQQDDC5BbWF6 + b24gUkRTIFByZXZpZXcgdXMtZWFzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYD + VQQHDAdTZWF0dGxlMCAXDTIxMDUxODIxMDUxMFoYDzIxMjEwNTE4MjIwNTEwWjCB + njELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTcwNQYDVQQDDC5B + bWF6b24gUkRTIFByZXZpZXcgdXMtZWFzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMI0hzf1JCEOI + Eue4+DmcNnSs2i2UaJxHMrNGGfU7b42a7vwP53F7045ffHPBGP4jb9q02/bStZzd + VHqfcgqkSRI7beBKjD2mfz82hF/wJSITTgCLs+NRpS6zKMFOFHUNo0IwQDAPBgNV + HRMBAf8EBTADAQH/MB0GA1UdDgQWBBS8uF/6hk5mPLH4qaWv9NVZaMmyTjAOBgNV + HQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIxAO7Pu9wzLyM0X7Q08uLIL+vL + qaxe3UFuzFTWjM16MLJHbzLf1i9IDFKz+Q4hXCSiJwIwClMBsqT49BPUxVsJnjGr + EbyEk6aOOVfY1p2yQL649zh3M4h8okLnwf+bYIb1YpeU + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEADCCAuigAwIBAgIQY+JhwFEQTe36qyRlUlF8ozANBgkqhkiG9w0BAQsFADCB + mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB + bWF6b24gUkRTIGFmLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUxOTE5MjQxNloYDzIwNjEwNTE5MjAyNDE2WjCBmDEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6 + b24gUkRTIGFmLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIye77j6ev40 + 8wRPyN2OdKFSUfI9jB20Or2RLO+RDoL43+USXdrze0Wv4HMRLqaen9BcmCfaKMp0 + E4SFo47bXK/O17r6G8eyq1sqnHE+v288mWtYH9lAlSamNFRF6YwA7zncmE/iKL8J + 0vePHMHP/B6svw8LULZCk+nZk3tgxQn2+r0B4FOz+RmpkoVddfqqUPMbKUxhM2wf + fO7F6bJaUXDNMBPhCn/3ayKCjYr49ErmnpYV2ZVs1i34S+LFq39J7kyv6zAgbHv9 + +/MtRMoRB1CjpqW0jIOZkHBdYcd1o9p1zFn591Do1wPkmMsWdjIYj+6e7UXcHvOB + 2+ScIRAcnwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQGtq2W + YSyMMxpdQ3IZvcGE+nyZqTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD + ggEBAEgoP3ixJsKSD5FN8dQ01RNHERl/IFbA7TRXfwC+L1yFocKnQh4Mp/msPRSV + +OeHIvemPW/wtZDJzLTOFJ6eTolGekHK1GRTQ6ZqsWiU2fmiOP8ks4oSpI+tQ9Lw + VrfZqTiEcS5wEIqyfUAZZfKDo7W1xp+dQWzfczSBuZJZwI5iaha7+ILM0r8Ckden + TVTapc5pLSoO15v0ziRuQ2bT3V3nwu/U0MRK44z+VWOJdSiKxdnOYDs8hFNnKhfe + klbTZF7kW7WbiNYB43OaAQBJ6BALZsIskEaqfeZT8FD71uN928TcEQyBDXdZpRN+ + iGQZDGhht0r0URGMDSs9waJtTfA= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECDCCAvCgAwIBAgIQEbIZbn8kcnd/sTnZkdoDkzANBgkqhkiG9w0BAQsFADCB + nDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTUwMwYDVQQDDCxB + bWF6b24gUkRTIGFwLXNvdXRoZWFzdC01IFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4G + A1UEBwwHU2VhdHRsZTAgFw0yNDA1MTUyMTUwMzdaGA8yMDY0MDUxNTIyNTAzN1ow + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtNSBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCK + c15oRFUw/MiZQ/qkfOlrcc/PC9TdxGjUqdZyQGqBWrFauIbsK7U0qTeTibt7t7cL + hBWmqb3eefU8e+JZwJ20/cFfWINEjp9xLKV5pzfcRH+BJF3Sa4iLeLSi8CEp5qvf + k70ADs2kye17q29G01NfCG9T2oMEEJQof1nKcfwjayjx7uyBPHtR0a2SC88QlSl9 + 9a009S0pUoISV3Zu/U+B6vUlBnGuIt+EsEFH0r19w/VRSO5mg9ylxh0/X5HXeBK5 + UxpNpXI9rPNd/AMTrv7FTyWsqkeSRS2lyT/8wyatApcCdPLyJDx7wZLY8/wARz7p + zi/uEKlhrrSDhDq2I7JFAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O + BBYEFAHKs1jyaNzThRo5XHN/dNJDtVNHMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG + 9w0BAQsFAAOCAQEAVAdR60a4czTpyu3JHj6oNVQUTt1D1jD/y1fZcc5a77fa2Qc6 + ZZEVBadpXAwkUQDbVRu/h6OrPhWKbQNLlTS1xzGuGeVbXSczvj37UB11WQfFN3M9 + Dpe5LTL0MCPO+elHzXrBhjhi9euCHXHDdvv4AZl7tfWuOrBdeBThXIehKniJmAjt + vq2mIHHThw2Wr+E65WerOVU+jepsG//1EkgrKfcGoS646jQXXKabW3cn0ymEV1/M + DhFbV05Jfvu969qcA3+TH1FaN/lAbwuSLFZ4HLFFjq7RVl/X//lyXl1q/coUdQXC + awfL88gOd/cYz0n5xm/S+gJUtOcz/dR6kV36NQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIF/jCCA+agAwIBAgIQXY/dmS+72lZPranO2JM9jjANBgkqhkiG9w0BAQwFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIGFwLWVhc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTI1MjEzNDUxWhgPMjEyMTA1MjUyMjM0NTFaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgYXAtZWFzdC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMyW9kBJjD/hx8e8 + b5E1sF42bp8TXsz1htSYE3Tl3T1Aq379DfEhB+xa/ASDZxt7/vwa81BkNo4M6HYq + okYIXeE7cu5SnSgjWXqcERhgPevtAwgmhdE3yREe8oz2DyOi2qKKZqah+1gpPaIQ + fK0uAqoeQlyHosye3KZZKkDHBatjBsQ5kf8lhuf7wVulEZVRHY2bP2X7N98PfbpL + QdH7mWXzDtJJ0LiwFwds47BrkgK1pkHx2p1mTo+HMkfX0P6Fq1atkVC2RHHtbB/X + iYyH7paaHBzviFrhr679zNqwXIOKlbf74w3mS11P76rFn9rS1BAH2Qm6eY5S/Fxe + HEKXm4kjPN63Zy0p3yE5EjPt54yPkvumOnT+RqDGJ2HCI9k8Ehcbve0ogfdRKNqQ + VHWYTy8V33ndQRHZlx/CuU1yN61TH4WSoMly1+q1ihTX9sApmlQ14B2pJi/9DnKW + cwECrPy1jAowC2UJ45RtC8UC05CbP9yrIy/7Noj8gQDiDOepm+6w1g6aNlWoiuQS + kyI6nzz1983GcnOHya73ga7otXo0Qfg9jPghlYiMomrgshlSLDHZG0Ib/3hb8cnR + 1OcN9FpzNmVK2Ll1SmTMLrIhuCkyNYX9O/bOknbcf706XeESxGduSkHEjIw/k1+2 + Atteoq5dT6cwjnJ9hyhiueVlVkiDAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFLUI+DD7RJs+0nRnjcwIVWzzYSsFMA4GA1UdDwEB/wQEAwIBhjAN + BgkqhkiG9w0BAQwFAAOCAgEAb1mcCHv4qMQetLGTBH9IxsB2YUUhr5dda0D2BcHr + UtDbfd0VQs4tux6h/6iKwHPx0Ew8fuuYj99WknG0ffgJfNc5/fMspxR/pc1jpdyU + 5zMQ+B9wi0lOZPO9uH7/pr+d2odcNEy8zAwqdv/ihsTwLmGP54is9fVbsgzNW1cm + HKAVL2t/Ope+3QnRiRilKCN1lzhav4HHdLlN401TcWRWKbEuxF/FgxSO2Hmx86pj + e726lweCTMmnq/cTsPOVY0WMjs0or3eHDVlyLgVeV5ldyN+ptg3Oit60T05SRa58 + AJPTaVKIcGQ/gKkKZConpu7GDofT67P/ox0YNY57LRbhsx9r5UY4ROgz7WMQ1yoS + Y+19xizm+mBm2PyjMUbfwZUyCxsdKMwVdOq5/UmTmdms+TR8+m1uBHPOTQ2vKR0s + Pd/THSzPuu+d3dbzRyDSLQbHFFneG760CUlD/ZmzFlQjJ89/HmAmz8IyENq+Sjhx + Jgzy+FjVZb8aRUoYLlnffpUpej1n87Ynlr1GrvC4GsRpNpOHlwuf6WD4W0qUTsC/ + C9JO+fBzUj/aWlJzNcLEW6pte1SB+EdkR2sZvWH+F88TxemeDrV0jKJw5R89CDf8 + ZQNfkxJYjhns+YeV0moYjqQdc7tq4i04uggEQEtVzEhRLU5PE83nlh/K2NZZm8Kj + dIA= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/zCCAuegAwIBAgIRAPVSMfFitmM5PhmbaOFoGfUwDQYJKoZIhvcNAQELBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyNTIyMzQ1N1oYDzIwNjEwNTI1MjMzNDU3WjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDu9H7TBeGoDzMr + dxN6H8COntJX4IR6dbyhnj5qMD4xl/IWvp50lt0VpmMd+z2PNZzx8RazeGC5IniV + 5nrLg0AKWRQ2A/lGGXbUrGXCSe09brMQCxWBSIYe1WZZ1iU1IJ/6Bp4D2YEHpXrW + bPkOq5x3YPcsoitgm1Xh8ygz6vb7PsvJvPbvRMnkDg5IqEThapPjmKb8ZJWyEFEE + QRrkCIRueB1EqQtJw0fvP4PKDlCJAKBEs/y049FoOqYpT3pRy0WKqPhWve+hScMd + 6obq8kxTFy1IHACjHc51nrGII5Bt76/MpTWhnJIJrCnq1/Uc3Qs8IVeb+sLaFC8K + DI69Sw6bAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE7PCopt + lyOgtXX0Y1lObBUxuKaCMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC + AQEAFj+bX8gLmMNefr5jRJfHjrL3iuZCjf7YEZgn89pS4z8408mjj9z6Q5D1H7yS + jNETVV8QaJip1qyhh5gRzRaArgGAYvi2/r0zPsy+Tgf7v1KGL5Lh8NT8iCEGGXwF + g3Ir+Nl3e+9XUp0eyyzBIjHtjLBm6yy8rGk9p6OtFDQnKF5OxwbAgip42CD75r/q + p421maEDDvvRFR4D+99JZxgAYDBGqRRceUoe16qDzbMvlz0A9paCZFclxeftAxv6 + QlR5rItMz/XdzpBJUpYhdzM0gCzAzdQuVO5tjJxmXhkSMcDP+8Q+Uv6FA9k2VpUV + E/O5jgpqUJJ2Hc/5rs9VkAPXeA== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrzCCAjWgAwIBAgIQW0yuFCle3uj4vWiGU0SaGzAKBggqhkjOPQQDAzCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGFmLXNvdXRoLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTE5MTkzNTE2WhgPMjEyMTA1MTkyMDM1MTZaMIGXMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS + RFMgYWYtc291dGgtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs + ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDPiKNZSaXs3Un/J/v+LTsFDANHpi7en + oL2qh0u0DoqNzEBTbBjvO23bLN3k599zh6CY3HKW0r2k1yaIdbWqt4upMCRCcUFi + I4iedAmubgzh56wJdoMZztjXZRwDthTkJKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUWbYkcrvVSnAWPR5PJhIzppcAnZIwDgYDVR0PAQH/BAQDAgGGMAoG + CCqGSM49BAMDA2gAMGUCMCESGqpat93CjrSEjE7z+Hbvz0psZTHwqaxuiH64GKUm + mYynIiwpKHyBrzjKBmeDoQIxANGrjIo6/b8Jl6sdIZQI18V0pAyLfLiZjlHVOnhM + MOTVgr82ZuPoEHTX78MxeMnYlw== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRAIbsx8XOl0sgTNiCN4O+18QwDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1ub3J0aGVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTI1MjE1NDU4WhgPMjA2MTA1MjUyMjU0NTha + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtbm9ydGhlYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + tROxwXWCgn5R9gI/2Ivjzaxc0g95ysBjoJsnhPdJEHQb7w3y2kWrVWU3Y9fOitgb + CEsnEC3PrhRnzNVW0fPsK6kbvOeCmjvY30rdbxbc8h+bjXfGmIOgAkmoULEr6Hc7 + G1Q/+tvv4lEwIs7bEaf+abSZxRJbZ0MBxhbHn7UHHDiMZYvzK+SV1MGCxx7JVhrm + xWu3GC1zZCsGDhB9YqY9eR6PmjbqA5wy8vqbC57dZZa1QVtWIQn3JaRXn+faIzHx + nLMN5CEWihsdmHBXhnRboXprE/OS4MFv1UrQF/XM/h5RBeCywpHePpC+Oe1T3LNC + iP8KzRFrjC1MX/WXJnmOVQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBS33XbXAUMs1znyZo4B0+B3D68WFTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBADuadd2EmlpueY2VlrIIPC30QkoA1EOSoCmZgN6124apkoY1 + HiV4r+QNPljN4WP8gmcARnNkS7ZeR4fvWi8xPh5AxQCpiaBMw4gcbTMCuKDV68Pw + P2dZCTMspvR3CDfM35oXCufdtFnxyU6PAyINUqF/wyTHguO3owRFPz64+sk3r2pT + WHmJjG9E7V+KOh0s6REgD17Gqn6C5ijLchSrPUHB0wOIkeLJZndHxN/76h7+zhMt + fFeNxPWHY2MfpcaLjz4UREzZPSB2U9k+y3pW1omCIcl6MQU9itGx/LpQE+H3ZeX2 + M2bdYd5L+ow+bdbGtsVKOuN+R9Dm17YpswF+vyQ= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + Em4Hy3A= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEBDCCAuygAwIBAgIQFn6AJ+uxaPDpNVx7174CpjANBgkqhkiG9w0BAQsFADCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIGlsLWNlbnRyYWwtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNV + BAcMB1NlYXR0bGUwIBcNMjIxMjAyMjAxNDA4WhgPMjA2MjEyMDIyMTE0MDhaMIGa + MQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5j + LjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMzAxBgNVBAMMKkFt + YXpvbiBSRFMgaWwtY2VudHJhbC0xIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2xGTSJ + fXorki/dkkTqdLyv4U1neeFYEyUCPN/HJ7ZloNwhj8RBrHYhZ4qtvUAvN+rs8fUm + L0wmaL69ye61S+CSfDzNwBDGwOzUm/cc1NEJOHCm8XA0unBNBvpJTjsFk2LQ+rz8 + oU0lVV4mjnfGektrTDeADonO1adJvUTYmF6v1wMnykSkp8AnW9EG/6nwcAJuAJ7d + BfaLThm6lfxPdsBNG81DLKi2me2TLQ4yl+vgRKJi2fJWwA77NaDqQuD5upRIcQwt + 5noJt2kFFmeiro98ZMMRaDTHAHhJfWkwkw5f2QNIww7T4r85IwbQCgJVRo4m4ZTC + W/1eiEccU2407mECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU + DNhVvGHzKXv0Yh6asK0apP9jJlUwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB + CwUAA4IBAQCoEVTUY/rF9Zrlpb1Y1hptEguw0i2pCLakcmv3YNj6thsubbGeGx8Z + RjUA/gPKirpoae2HU1y64WEu7akwr6pdTRtXXjbe9NReT6OW/0xAwceSXCOiStqS + cMsWWTGg6BA3uHqad5clqITjDZr1baQ8X8en4SXRBxXyhJXbOkB60HOQeFR9CNeh + pJdrWLeNYXwU0Z59juqdVMGwvDAYdugWUhW2rhafVUXszfRA5c8Izc+E31kq90aY + LmxFXUHUfG0eQOmxmg+Z/nG7yLUdHIFA3id8MRh22hye3KvRdQ7ZVGFni0hG2vQQ + Q01AvD/rhzyjg0czzJKLK9U/RttwdMaV + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + jGKc3k6UNxpg + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIF/jCCA+agAwIBAgIQaRHaEqqacXN20e8zZJtmDDANBgkqhkiG9w0BAQwFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTI1MjIzODM1WhgPMjEyMTA1MjUyMzM4MzVaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgdXMtZWFzdC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAInfBCaHuvj6Rb5c + L5Wmn1jv2PHtEGMHm+7Z8dYosdwouG8VG2A+BCYCZfij9lIGszrTXkY4O7vnXgru + JUNdxh0Q3M83p4X+bg+gODUs3jf+Z3Oeq7nTOk/2UYvQLcxP4FEXILxDInbQFcIx + yen1ESHggGrjEodgn6nbKQNRfIhjhW+TKYaewfsVWH7EF2pfj+cjbJ6njjgZ0/M9 + VZifJFBgat6XUTOf3jwHwkCBh7T6rDpgy19A61laImJCQhdTnHKvzTpxcxiLRh69 + ZObypR7W04OAUmFS88V7IotlPmCL8xf7kwxG+gQfvx31+A9IDMsiTqJ1Cc4fYEKg + bL+Vo+2Ii4W2esCTGVYmHm73drznfeKwL+kmIC/Bq+DrZ+veTqKFYwSkpHRyJCEe + U4Zym6POqQ/4LBSKwDUhWLJIlq99bjKX+hNTJykB+Lbcx0ScOP4IAZQoxmDxGWxN + S+lQj+Cx2pwU3S/7+OxlRndZAX/FKgk7xSMkg88HykUZaZ/ozIiqJqSnGpgXCtED + oQ4OJw5ozAr+/wudOawaMwUWQl5asD8fuy/hl5S1nv9XxIc842QJOtJFxhyeMIXt + LVECVw/dPekhMjS3Zo3wwRgYbnKG7YXXT5WMxJEnHu8+cYpMiRClzq2BEP6/MtI2 + AZQQUFu2yFjRGL2OZA6IYjxnXYiRAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFADCcQCPX2HmkqQcmuHfiQ2jjqnrMA4GA1UdDwEB/wQEAwIBhjAN + BgkqhkiG9w0BAQwFAAOCAgEASXkGQ2eUmudIKPeOIF7RBryCoPmMOsqP0+1qxF8l + pGkwmrgNDGpmd9s0ArfIVBTc1jmpgB3oiRW9c6n2OmwBKL4UPuQ8O3KwSP0iD2sZ + KMXoMEyphCEzW1I2GRvYDugL3Z9MWrnHkoaoH2l8YyTYvszTvdgxBPpM2x4pSkp+ + 76d4/eRpJ5mVuQ93nC+YG0wXCxSq63hX4kyZgPxgCdAA+qgFfKIGyNqUIqWgeyTP + n5OgKaboYk2141Rf2hGMD3/hsGm0rrJh7g3C0ZirPws3eeJfulvAOIy2IZzqHUSY + jkFzraz6LEH3IlArT3jUPvWKqvh2lJWnnp56aqxBR7qHH5voD49UpJWY1K0BjGnS + OHcurpp0Yt/BIs4VZeWdCZwI7JaSeDcPMaMDBvND3Ia5Fga0thgYQTG6dE+N5fgF + z+hRaujXO2nb0LmddVyvE8prYlWRMuYFv+Co8hcMdJ0lEZlfVNu0jbm9/GmwAZ+l + 9umeYO9yz/uC7edC8XJBglMAKUmVK9wNtOckUWAcCfnPWYLbYa/PqtXBYcxrso5j + iaS/A7iEW51uteHBGrViCy1afGG+hiUWwFlesli+Rq4dNstX3h6h2baWABaAxEVJ + y1RnTQSz6mROT1VmZSgSVO37rgIyY0Hf0872ogcTS+FfvXgBxCxsNWEbiQ/XXva4 + 0Ws= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtDCCAjqgAwIBAgIRAMyaTlVLN0ndGp4ffwKAfoMwCgYIKoZIzj0EAwMwgZkx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEyMDAGA1UEAwwpQW1h + em9uIFJEUyBtZS1jZW50cmFsLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjIwNTA3MDA0NDM3WhgPMjEyMjA1MDcwMTQ0MzdaMIGZMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMjAwBgNVBAMMKUFtYXpv + biBSRFMgbWUtY2VudHJhbC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE19nCV1nsI6CohSor13+B25cr + zg+IHdi9Y3L7ziQnHWI6yjBazvnKD+oC71aRRlR8b5YXsYGUQxWzPLHN7EGPcSGv + bzA9SLG1KQYCJaQ0m9Eg/iGrwKWOgylbhVw0bCxoo0IwQDAPBgNVHRMBAf8EBTAD + AQH/MB0GA1UdDgQWBBS4KsknsJXM9+QPEkBdZxUPaLr11zAOBgNVHQ8BAf8EBAMC + AYYwCgYIKoZIzj0EAwMDaAAwZQIxAJaRgrYIEfXQMZQQDxMTYS0azpyWSseQooXo + L3nYq4OHGBgYyQ9gVjvRYWU85PXbfgIwdi82DtANQFkCu+j+BU0JBY/uRKPEeYzo + JG92igKIcXPqCoxIJ7lJbbzmuf73gQu5 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGATCCA+mgAwIBAgIRAJwCobx0Os8F7ihbJngxrR8wDQYJKoZIhvcNAQEMBQAw + gZgxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTExMC8GA1UEAwwo + QW1hem9uIFJEUyBtZS1zb3V0aC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UE + BwwHU2VhdHRsZTAgFw0yMTA1MjAxNzE1MzNaGA8yMTIxMDUyMDE4MTUzM1owgZgx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTExMC8GA1UEAwwoQW1h + em9uIFJEUyBtZS1zb3V0aC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwH + U2VhdHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANukKwlm+ZaI + Y5MkWGbEVLApEyLmlrHLEg8PfiiEa9ts7jssQcin3bzEPdTqGr5jo91ONoZ3ccWq + xJgg1W3bLu5CAO2CqIOXTXHRyCO/u0Ch1FGgWB8xETPSi3UHt/Vn1ltdO6DYdbDU + mYgwzYrvLBdRCwxsb9o+BuYQHVFzUYonqk/y9ujz3gotzFq7r55UwDTA1ita3vb4 + eDKjIb4b1M4Wr81M23WHonpje+9qkkrAkdQcHrkgvSCV046xsq/6NctzwCUUNsgF + 7Q1a8ut5qJEYpz5ta8vI1rqFqAMBqCbFjRYlmAoTTpFPOmzAVxV+YoqTrW5A16su + /2SXlMYfJ/n/ad/QfBNPPAAQMpyOr2RCL/YiL/PFZPs7NxYjnZHNWxMLSPgFyI+/ + t2klnn5jR76KJK2qimmaXedB90EtFsMRUU1e4NxH9gDuyrihKPJ3aVnZ35mSipvR + /1KB8t8gtFXp/VQaz2sg8+uxPMKB81O37fL4zz6Mg5K8+aq3ejBiyHucpFGnsnVB + 3kQWeD36ONkybngmgWoyPceuSWm1hQ0Z7VRAQX+KlxxSaHmSaIk1XxZu9h9riQHx + fMuev6KXjRn/CjCoUTn+7eFrt0dT5GryQEIZP+nA0oq0LKxogigHNZlwAT4flrqb + JUfZJrqgoce5HjZSXl10APbtPjJi0fW9AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB + Af8wHQYDVR0OBBYEFEfV+LztI29OVDRm0tqClP3NrmEWMA4GA1UdDwEB/wQEAwIB + hjANBgkqhkiG9w0BAQwFAAOCAgEAvSNe+0wuk53KhWlRlRf2x/97H2Q76X3anzF0 + 5fOSVm022ldALzXMzqOfdnoKIhAu2oVKiHHKs7mMas+T6TL+Mkphx0CYEVxFE3PG + 061q3CqJU+wMm9W9xsB79oB2XG47r1fIEywZZ3GaRsatAbjcNOT8uBaATPQAfJFN + zjFe4XyN+rA4cFrYNvfHTeu5ftrYmvks7JlRaJgEGWsz+qXux7uvaEEVPqEumd2H + uYeaRNOZ2V23R009X5lbgBFx9tq5VDTnKhQiTQ2SeT0rc1W3Dz5ik6SbQQNP3nSR + 0Ywy7r/sZ3fcDyfFiqnrVY4Ympfvb4YW2PZ6OsQJbzH6xjdnTG2HtzEU30ngxdp1 + WUEF4zt6rjJCp7QBUqXgdlHvJqYu6949qtWjEPiFN9uSsRV2i1YDjJqN52dLjAPn + AipJKo8x1PHTwUzuITqnB9BdP+5TlTl8biJfkEf/+08eWDTLlDHr2VrZLOLompTh + bS5OrhDmqA2Q+O+EWrTIhMflwwlCpR9QYM/Xwvlbad9H0FUHbJsCVNaru3wGOgWo + tt3dNSK9Lqnv/Ej9K9v6CRr36in4ylJKivhJ5B9E7ABHg7EpBJ1xi7O5eNDkNoJG + +pFyphJq3AkBR2U4ni2tUaTAtSW2tks7IaiDV+UMtqZyGabT5ISQfWLLtLHSWn2F + Tspdjbg= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIRAJZFh4s9aZGzKaTMLrSb4acwDQYJKoZIhvcNAQELBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBCZXRhIHVzLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTE4MjEyODQxWhgPMjA2MTA1MTgyMjI4NDFa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgQmV0YSB1cy1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + 17i2yoU6diep+WrqxIn2CrDEO2NdJVwWTSckx4WMZlLpkQDoymSmkNHjq9ADIApD + A31Cx+843apL7wub8QkFZD0Tk7/ThdHWJOzcAM3ov98QBPQfOC1W5zYIIRP2F+vQ + TRETHQnLcW3rLv0NMk5oQvIKpJoC9ett6aeVrzu+4cU4DZVWYlJUoC/ljWzCluau + 8blfW0Vwin6OB7s0HCG5/wijQWJBU5SrP/KAIPeQi1GqG5efbqAXDr/ple0Ipwyo + Xjjl73LenGUgqpANlC9EAT4i7FkJcllLPeK3NcOHjuUG0AccLv1lGsHAxZLgjk/x + z9ZcnVV9UFWZiyJTKxeKPwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud + DgQWBBRWyMuZUo4gxCR3Luf9/bd2AqZ7CjAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggEBAIqN2DlIKlvDFPO0QUZQVFbsi/tLdYM98/vvzBpttlTGVMyD + gJuQeHVz+MnhGIwoCGOlGU3OOUoIlLAut0+WG74qYczn43oA2gbMd7HoD7oL/IGg + njorBwJVcuuLv2G//SqM3nxGcLRtkRnQ+lvqPxMz9+0fKFUn6QcIDuF0QSfthLs2 + WSiGEPKO9c9RSXdRQ4pXA7c3hXng8P4A2ZmdciPne5Nu4I4qLDGZYRrRLRkNTrOi + TyS6r2HNGUfgF7eOSeKt3NWL+mNChcYj71/Vycf5edeczpUgfnWy9WbPrK1svKyl + aAs2xg+X6O8qB+Mnj2dNBzm+lZIS3sIlm+nO9sg= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjSgAwIBAgIRAPAlEk8VJPmEzVRRaWvTh2AwCgYIKoZIzj0EAwMwgZYx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h + em9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTI1MjI0MTU1WhgPMjEyMTA1MjUyMzQxNTVaMIGWMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS + RFMgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx5xjrup8II4HOJw15NTnS3H5yMrQGlbj + EDA5MMGnE9DmHp5dACIxmPXPMe/99nO7wNdl7G71OYPCgEvWm0FhdvVUeTb3LVnV + BnaXt32Ek7/oxGk1T+Df03C+W0vmuJ+wo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G + A1UdDgQWBBTGXmqBWN/1tkSea4pNw0oHrjk2UDAOBgNVHQ8BAf8EBAMCAYYwCgYI + KoZIzj0EAwMDaAAwZQIxAIqqZWCSrIkZ7zsv/FygtAusW6yvlL935YAWYPVXU30m + jkMFLM+/RJ9GMvnO8jHfCgIwB+whlkcItzE9CRQ6CsMo/d5cEHDUu/QW6jSIh9BR + OGh9pTYPVkUbBiKPA7lVVhre + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + nWS0 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtDCCAjmgAwIBAgIQKKqVZvk6NsLET+uYv5myCzAKBggqhkjOPQQDAzCBmTEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTIwMAYDVQQDDClBbWF6 + b24gUkRTIGlsLWNlbnRyYWwtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwH + U2VhdHRsZTAgFw0yMjEyMDIyMDMyMjBaGA8yMTIyMTIwMjIxMzIyMFowgZkxCzAJ + BgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMw + EQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEyMDAGA1UEAwwpQW1hem9u + IFJEUyBpbC1jZW50cmFsLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASYwfvj8BmvLAP6UkNQ4X4dXBB/ + webBO7swW+8HnFN2DAu+Cn/lpcDpu+dys1JmkVX435lrCH3oZjol0kCDIM1lF4Cv + +78yoY1Jr/YMat22E4iz4AZd9q0NToS7+ZA0r2yjQjBAMA8GA1UdEwEB/wQFMAMB + Af8wHQYDVR0OBBYEFO/8Py16qPr7J2GWpvxlTMB+op7XMA4GA1UdDwEB/wQEAwIB + hjAKBggqhkjOPQQDAwNpADBmAjEAwk+rg788+u8JL6sdix7l57WTo8E/M+o3TO5x + uRuPdShrBFm4ArGR2PPs4zCQuKgqAjEAi0TA3PVqAxKpoz+Ps8/054p9WTgDfBFZ + i/lm2yTaPs0xjY6FNWoy7fsVw5oEKxOn + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCTCCA/GgAwIBAgIRAOY7gfcBZgR2tqfBzMbFQCUwDQYJKoZIhvcNAQEMBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1zb3V0aGVhc3QtNCBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjIwNTI1MTY1NDU5WhgPMjEyMjA1MjUxNzU0NTla + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtc291dGhlYXN0LTQgUm9vdCBDQSBSU0E0MDk2IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA + lfxER43FuLRdL08bddF0YhbCP+XXKj1A/TFMXmd2My8XDei8rPXFYyyjMig9+xZw + uAsIxLwz8uiA26CKA8bCZKg5VG2kTeOJAfvBJaLv1CZefs3Z4Uf1Sjvm6MF2yqEj + GoORfyfL9HiZFTDuF/hcjWoKYCfMuG6M/wO8IbdICrX3n+BiYQJu/pFO660Mg3h/ + 8YBBWYDbHoCiH/vkqqJugQ5BM3OI5nsElW51P1icEEqti4AZ7JmtSv9t7fIFBVyR + oaEyOgpp0sm193F/cDJQdssvjoOnaubsSYm1ep3awZAUyGN/X8MBrPY95d0hLhfH + Ehc5Icyg+hsosBljlAyksmt4hFQ9iBnWIz/ZTfGMck+6p3HVL9RDgvluez+rWv59 + 8q7omUGsiPApy5PDdwI/Wt/KtC34/2sjslIJfvgifdAtkRPkhff1WEwER00ADrN9 + eGGInaCpJfb1Rq8cV2n00jxg7DcEd65VR3dmIRb0bL+jWK62ni/WdEyomAOMfmGj + aWf78S/4rasHllWJ+QwnaUYY3u6N8Cgio0/ep4i34FxMXqMV3V0/qXdfhyabi/LM + wCxNo1Dwt+s6OtPJbwO92JL+829QAxydfmaMTeHBsgMPkG7RwAekeuatKGHNsc2Z + x2Q4C2wVvOGAhcHwxfM8JfZs3nDSZJndtVVnFlUY0UECAwEAAaNCMEAwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQUpnG7mWazy6k97/tb5iduRB3RXgQwDgYDVR0P + AQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQCDLqq1Wwa9Tkuv7vxBnIeVvvFF + ecTn+P+wJxl9Qa2ortzqTHZsBDyJO62d04AgBwiDXkJ9a+bthgG0H1J7Xee8xqv1 + xyX2yKj24ygHjspLotKP4eDMdDi5TYq+gdkbPmm9Q69B1+W6e049JVGXvWG8/7kU + igxeuCYwtCCdUPRLf6D8y+1XMGgVv3/DSOHWvTg3MJ1wJ3n3+eve3rjGdRYWZeJu + k21HLSZYzVrCtUsh2YAeLnUbSxVuT2Xr4JehYe9zW5HEQ8Je/OUfnCy9vzoN/ITw + osAH+EBJQey7RxEDqMwCaRefH0yeHFcnOll0OXg/urnQmwbEYzQ1uutJaBPsjU0J + Qf06sMxI7GiB5nPE+CnI2sM6A9AW9kvwexGXpNJiLxF8dvPQthpOKGcYu6BFvRmt + 6ctfXd9b7JJoVqMWuf5cCY6ihpk1e9JTlAqu4Eb/7JNyGiGCR40iSLvV28un9wiE + plrdYxwcNYq851BEu3r3AyYWw/UW1AKJ5tM+/Gtok+AphMC9ywT66o/Kfu44mOWm + L3nSLSWEcgfUVgrikpnyGbUnGtgCmHiMlUtNVexcE7OtCIZoVAlCGKNu7tyuJf10 + Qlk8oIIzfSIlcbHpOYoN79FkLoDNc2er4Gd+7w1oPQmdAB0jBJnA6t0OUBPKdDdE + Ufff2jrbfbzECn1ELg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + fejbXelUSJSzDIdY + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIGCTCCA/GgAwIBAgIRAN7Y9G9i4I+ZaslPobE7VL4wDQYJKoZIhvcNAQEMBQAw + gZwxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTE1MDMGA1UEAwws + QW1hem9uIFJEUyBhcC1ub3J0aGVhc3QtMiBSb290IENBIFJTQTQwOTYgRzExEDAO + BgNVBAcMB1NlYXR0bGUwIBcNMjEwNTIwMTYzMzIzWhgPMjEyMTA1MjAxNzMzMjNa + MIGcMQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywg + SW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExNTAzBgNVBAMM + LEFtYXpvbiBSRFMgYXAtbm9ydGhlYXN0LTIgUm9vdCBDQSBSU0E0MDk2IEcxMRAw + DgYDVQQHDAdTZWF0dGxlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA + 4BEPCiIfiK66Q/qa8k+eqf1Q3qsa6Xuu/fPkpuStXVBShhtXd3eqrM0iT4Xxs420 + Va0vSB3oZ7l86P9zYfa60n6PzRxdYFckYX330aI7L/oFIdaodB/C9szvROI0oLG+ + 6RwmIF2zcprH0cTby8MiM7G3v9ykpq27g4WhDC1if2j8giOQL3oHpUaByekZNIHF + dIllsI3RkXmR3xmmxoOxJM1B9MZi7e1CvuVtTGOnSGpNCQiqofehTGwxCN2wFSK8 + xysaWlw48G0VzZs7cbxoXMH9QbMpb4tpk0d+T8JfAPu6uWO9UwCLWWydf0CkmA/+ + D50/xd1t33X9P4FEaPSg5lYbHXzSLWn7oLbrN2UqMLaQrkoEBg/VGvzmfN0mbflw + +T87bJ/VEOVNlG+gepyCTf89qIQVWOjuYMox4sK0PjzZGsYEuYiq1+OUT3vk/e5K + ag1fCcq2Isy4/iwB2xcXrsQ6ljwdk1fc+EmOnjGKrhuOHJY3S+RFv4ToQBsVyYhC + XGaC3EkqIX0xaCpDimxYhFjWhpDXAjG/zJ+hRLDAMCMhl/LPGRk/D1kzSbPmdjpl + lEMK5695PeBvEBTQdBQdOiYgOU3vWU6tzwwHfiM2/wgvess/q0FDAHfJhppbgbb9 + 3vgsIUcsvoC5o29JvMsUxsDRvsAfEmMSDGkJoA/X6GECAwEAAaNCMEAwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQUgEWm1mZCbGD6ytbwk2UU1aLaOUUwDgYDVR0P + AQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQBb4+ABTGBGwxK1U/q4g8JDqTQM + 1Wh8Oz8yAk4XtPJMAmCctxbd81cRnSnePWw/hxViLVtkZ/GsemvXfqAQyOn1coN7 + QeYSw+ZOlu0j2jEJVynmgsR7nIRqE7QkCyZAU+d2FTJUfmee+IiBiGyFGgxz9n7A + JhBZ/eahBbiuoOik/APW2JWLh0xp0W0GznfJ8lAlaQTyDa8iDXmVtbJg9P9qzkvl + FgPXQttzEOyooF8Pb2LCZO4kUz+1sbU7tHdr2YE+SXxt6D3SBv+Yf0FlvyWLiqVk + GDEOlPPTDSjAWgKnqST8UJ0RDcZK/v1ixs7ayqQJU0GUQm1I7LGTErWXHMnCuHKe + UKYuiSZwmTcJ06NgdhcCnGZgPq13ryMDqxPeltQc3n5eO7f1cL9ERYLDLOzm6A9P + oQ3MfcVOsbHgGHZWaPSeNrQRN9xefqBXH0ZPasgcH9WJdsLlEjVUXoultaHOKx3b + UCCb+d3EfqF6pRT488ippOL6bk7zNubwhRa/+y4wjZtwe3kAX78ACJVcjPobH9jZ + ErySads5zdQeaoee5wRKdp3TOfvuCe4bwLRdhOLCHWzEcXzY3g/6+ppLvNom8o+h + Bh5X26G6KSfr9tqhQ3O9IcbARjnuPbvtJnoPY0gz3EHHGPhy0RNW8i2gl3nUp0ah + PtjwbKW0hYAhIttT0Q== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtzCCAj2gAwIBAgIQQRBQTs6Y3H1DDbpHGta3lzAKBggqhkjOPQQDAzCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC0zIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDYxMTAwMTI0M1oYDzIxMjEwNjExMDExMjQzWjCBmzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTQwMgYDVQQDDCtBbWF6 + b24gUkRTIGFwLXNvdXRoZWFzdC0zIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEs0942Xj4m/gKA+WA6F5h + AHYuek9eGpzTRoLJddM4rEV1T3eSueytMVKOSlS3Ub9IhyQrH2D8EHsLYk9ktnGR + pATk0kCYTqFbB7onNo070lmMJmGT/Q7NgwC8cySChFxbo0IwQDAPBgNVHRMBAf8E + BTADAQH/MB0GA1UdDgQWBBQ20iKBKiNkcbIZRu0y1uoF1yJTEzAOBgNVHQ8BAf8E + BAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwYv0wTSrpQTaPaarfLN8Xcqrqu3hzl07n + FrESIoRw6Cx77ZscFi2/MV6AFyjCV/TlAjEAhpwJ3tpzPXpThRML8DMJYZ3YgMh3 + CMuLqhPpla3cL0PhybrD27hJWl29C4el6aMO + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrDCCAjOgAwIBAgIQGcztRyV40pyMKbNeSN+vXTAKBggqhkjOPQQDAzCBljEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMS8wLQYDVQQDDCZBbWF6 + b24gUkRTIHVzLWVhc3QtMiBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTAgFw0yMTA1MjEyMzE1NTZaGA8yMTIxMDUyMjAwMTU1NlowgZYxCzAJBgNV + BAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYD + VQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1hem9uIFJE + UyB1cy1lYXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0bGUw + djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQfDcv+GGRESD9wT+I5YIPRsD3L+/jsiIis + Tr7t9RSbFl+gYpO7ZbDXvNbV5UGOC5lMJo/SnqFRTC6vL06NF7qOHfig3XO8QnQz + 6T5uhhrhnX2RSY3/10d2kTyHq3ZZg3+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD + VR0OBBYEFLDyD3PRyNXpvKHPYYxjHXWOgfPnMA4GA1UdDwEB/wQEAwIBhjAKBggq + hkjOPQQDAwNnADBkAjB20HQp6YL7CqYD82KaLGzgw305aUKw2aMrdkBR29J183jY + 6Ocj9+Wcif9xnRMS+7oCMAvrt03rbh4SU9BohpRUcQ2Pjkh7RoY0jDR4Xq4qzjNr + 5UFr3BXpFvACxXF51BksGQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjWgAwIBAgIQeKbS5zvtqDvRtwr5H48cAjAKBggqhkjOPQQDAzCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIG1lLXNvdXRoLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTIwMTcxOTU1WhgPMjEyMTA1MjAxODE5NTVaMIGXMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS + RFMgbWUtc291dGgtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs + ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABEKjgUaAPmUlRMEQdBC7BScAGosJ1zRV + LDd38qTBjzgmwBfQJ5ZfGIvyEK5unB09MB4e/3qqK5I/L6Qn5Px/n5g4dq0c7MQZ + u7G9GBYm90U3WRJBf7lQrPStXaRnS4A/O6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUNKcAbGEIn03/vkwd8g6jNyiRdD4wDgYDVR0PAQH/BAQDAgGGMAoG + CCqGSM49BAMDA2cAMGQCMHIeTrjenCSYuGC6txuBt/0ZwnM/ciO9kHGWVCoK8QLs + jGghb5/YSFGZbmQ6qpGlSAIwVOQgdFfTpEfe5i+Vs9frLJ4QKAfc27cTNYzRIM0I + E+AJgK4C4+DiyyMzOpiCfmvq + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + WT1QcNdw7ntUJP/w + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrzCCAjWgAwIBAgIQARky6+5PNFRkFVOp3Ob1CTAKBggqhkjOPQQDAzCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGV1LXNvdXRoLTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjIwNTIzMTg0MTI4WhgPMjEyMjA1MjMxOTQxMjdaMIGXMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS + RFMgZXUtc291dGgtMiBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs + ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABNVGL5oF7cfIBxKyWd2PVK/S5yQfaJY3 + QFHWvEdt6951n9JhiiPrHzfVHsxZp1CBjILRMzjgRbYWmc8qRoLkgGE7htGdwudJ + Fa/WuKzO574Prv4iZXUnVGTboC7JdvKbh6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUgDeIIEKynwUbNXApdIPnmRWieZwwDgYDVR0PAQH/BAQDAgGGMAoG + CCqGSM49BAMDA2gAMGUCMEOOJfucrST+FxuqJkMZyCM3gWGZaB+/w6+XUAJC6hFM + uSTY0F44/bERkA4XhH+YGAIxAIpJQBakCA1/mXjsTnQ+0El9ty+LODp8ibkn031c + 8DKDS7pR9UK7ZYdR6zFg3ZCjQw== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjOgAwIBAgIQJvkWUcYLbnxtuwnyjMmntDAKBggqhkjOPQQDAzCBljEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMS8wLQYDVQQDDCZBbWF6 + b24gUkRTIGV1LXdlc3QtMyBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTAgFw0yMTA1MjUyMjI2MTJaGA8yMTIxMDUyNTIzMjYxMlowgZYxCzAJBgNV + BAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYD + VQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1hem9uIFJE + UyBldS13ZXN0LTMgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0bGUw + djAQBgcqhkjOPQIBBgUrgQQAIgNiAARENn8uHCyjn1dFax4OeXxvbV861qsXFD9G + DshumTmFzWWHN/69WN/AOsxy9XN5S7Cgad4gQgeYYYgZ5taw+tFo/jQvCLY//uR5 + uihcLuLJ78opvRPvD9kbWZ6oXfBtFkWjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD + VR0OBBYEFKiK3LpoF+gDnqPldGSwChBPCYciMA4GA1UdDwEB/wQEAwIBhjAKBggq + hkjOPQQDAwNpADBmAjEA+7qfvRlnvF1Aosyp9HzxxCbN7VKu+QXXPhLEBWa5oeWW + UOcifunf/IVLC4/FGCsLAjEAte1AYp+iJyOHDB8UYkhBE/1sxnFaTiEPbvQBU0wZ + SuwWVLhu2wWDuSW+K7tTuL8p + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/zCCAuegAwIBAgIRAKeDpqX5WFCGNo94M4v69sUwDQYJKoZIhvcNAQELBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyBldS13ZXN0LTMgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyNTIyMTgzM1oYDzIwNjEwNTI1MjMxODMzWjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGV1LXdlc3QtMyBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcKOTEMTfzvs4H + WtJR8gI7GXN6xesulWtZPv21oT+fLGwJ+9Bv8ADCGDDrDxfeH/HxJmzG9hgVAzVn + 4g97Bn7q07tGZM5pVi96/aNp11velZT7spOJKfJDZTlGns6DPdHmx48whpdO+dOb + 6+eR0VwCIv+Vl1fWXgoACXYCoKjhxJs+R+fwY//0JJ1YG8yjZ+ghLCJmvlkOJmE1 + TCPUyIENaEONd6T+FHGLVYRRxC2cPO65Jc4yQjsXvvQypoGgx7FwD5voNJnFMdyY + 754JGPOOe/SZdepN7Tz7UEq8kn7NQSbhmCsgA/Hkjkchz96qN/YJ+H/okiQUTNB0 + eG9ogiVFAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFjayw9Y + MjbxfF14XAhMM2VPl0PfMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC + AQEAAtmx6d9+9CWlMoU0JCirtp4dSS41bBfb9Oor6GQ8WIr2LdfZLL6uES/ubJPE + 1Sh5Vu/Zon5/MbqLMVrfniv3UpQIof37jKXsjZJFE1JVD/qQfRzG8AlBkYgHNEiS + VtD4lFxERmaCkY1tjKB4Dbd5hfhdrDy29618ZjbSP7NwAfnwb96jobCmMKgxVGiH + UqsLSiEBZ33b2hI7PJ6iTJnYBWGuiDnsWzKRmheA4nxwbmcQSfjbrNwa93w3caL2 + v/4u54Kcasvcu3yFsUwJygt8z43jsGAemNZsS7GWESxVVlW93MJRn6M+MMakkl9L + tWaXdHZ+KUV7LhfYLb0ajvb40w== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEBDCCAuygAwIBAgIQJ5oxPEjefCsaESSwrxk68DANBgkqhkiG9w0BAQsFADCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIGV1LWNlbnRyYWwtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNV + BAcMB1NlYXR0bGUwIBcNMjIwNjA2MjExNzA1WhgPMjA2MjA2MDYyMjE3MDVaMIGa + MQswCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5j + LjETMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMzAxBgNVBAMMKkFt + YXpvbiBSRFMgZXUtY2VudHJhbC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UE + BwwHU2VhdHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTQt5eX + g+VP3BjO9VBkWJhE0GfLrU/QIk32I6WvrnejayTrlup9H1z4QWlXF7GNJrqScRMY + KhJHlcP05aPsx1lYco6pdFOf42ybXyWHHJdShj4A5glU81GTT+VrXGzHSarLmtua + eozkQgPpDsSlPt0RefyTyel7r3Cq+5K/4vyjCTcIqbfgaGwTU36ffjM1LaPCuE4O + nINMeD6YuImt2hU/mFl20FZ+IZQUIFZZU7pxGLqTRz/PWcH8tDDxnkYg7tNuXOeN + JbTpXrw7St50/E9ZQ0llGS+MxJD8jGRAa/oL4G/cwnV8P2OEPVVkgN9xDDQeieo0 + 3xkzolkDkmeKOnUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU + bwu8635iQGQMRanekesORM8Hkm4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB + CwUAA4IBAQAgN6LE9mUgjsj6xGCX1afYE69fnmCjjb0rC6eEe1mb/QZNcyw4XBIW + 6+zTXo4mjZ4ffoxb//R0/+vdTE7IvaLgfAZgFsLKJCtYDDstXZj8ujQnGR9Pig3R + W+LpNacvOOSJSawNQq0Xrlcu55AU4buyD5VjcICnfF1dqBMnGTnh27m/scd/ZMx/ + kapHZ/fMoK2mAgSX/NvUKF3UkhT85vSSM2BTtET33DzCPDQTZQYxFBa4rFRmFi4c + BLlmIReiCGyh3eJhuUUuYAbK6wLaRyPsyEcIOLMQmZe1+gAFm1+1/q5Ke9ugBmjf + PbTWjsi/lfZ5CdVAhc5lmZj/l5aKqwaS + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjSgAwIBAgIRAKKPTYKln9L4NTx9dpZGUjowCgYIKoZIzj0EAwMwgZYx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h + em9uIFJEUyBldS13ZXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTIxMjI1NTIxWhgPMjEyMTA1MjEyMzU1MjFaMIGWMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS + RFMgZXUtd2VzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE/owTReDvaRqdmbtTzXbyRmEpKCETNj6O + hZMKH0F8oU9Tmn8RU7kQQj6xUKEyjLPrFBN7c+26TvrVO1KmJAvbc8bVliiJZMbc + C0yV5PtJTalvlMZA1NnciZuhxaxrzlK1o0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G + A1UdDgQWBBT4i5HaoHtrs7Mi8auLhMbKM1XevDAOBgNVHQ8BAf8EBAMCAYYwCgYI + KoZIzj0EAwMDaAAwZQIxAK9A+8/lFdX4XJKgfP+ZLy5ySXC2E0Spoy12Gv2GdUEZ + p1G7c1KbWVlyb1d6subzkQIwKyH0Naf/3usWfftkmq8SzagicKz5cGcEUaULq4tO + GzA/AMpr63IDBAqkZbMDTCmH + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrzCCAjWgAwIBAgIQTgIvwTDuNWQo0Oe1sOPQEzAKBggqhkjOPQQDAzCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGV1LW5vcnRoLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTI0MjEwNjM4WhgPMjEyMTA1MjQyMjA2MzhaMIGXMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS + RFMgZXUtbm9ydGgtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs + ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJuzXLU8q6WwSKXBvx8BbdIi3mPhb7Xo + rNJBfuMW1XRj5BcKH1ZoGaDGw+BIIwyBJg8qNmCK8kqIb4cH8/Hbo3Y+xBJyoXq/ + cuk8aPrxiNoRsKWwiDHCsVxaK9L7GhHHAqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUYgcsdU4fm5xtuqLNppkfTHM2QMYwDgYDVR0PAQH/BAQDAgGGMAoG + CCqGSM49BAMDA2gAMGUCMQDz/Rm89+QJOWJecYAmYcBWCcETASyoK1kbr4vw7Hsg + 7Ew3LpLeq4IRmTyuiTMl0gMCMAa0QSjfAnxBKGhAnYxcNJSntUyyMpaXzur43ec0 + 3D8npJghwC4DuICtKEkQiI5cSg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + u3UBpZI= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtDCCAjmgAwIBAgIQenQbcP/Zbj9JxvZ+jXbRnTAKBggqhkjOPQQDAzCBmTEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTIwMAYDVQQDDClBbWF6 + b24gUkRTIGV1LWNlbnRyYWwtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwH + U2VhdHRsZTAgFw0yMTA1MjEyMjMzMjRaGA8yMTIxMDUyMTIzMzMyNFowgZkxCzAJ + BgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMw + EQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEyMDAGA1UEAwwpQW1hem9u + IFJEUyBldS1jZW50cmFsLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATlBHiEM9LoEb1Hdnd5j2VpCDOU + 5nGuFoBD8ROUCkFLFh5mHrHfPXwBc63heW9WrP3qnDEm+UZEUvW7ROvtWCTPZdLz + Z4XaqgAlSqeE2VfUyZOZzBSgUUJk7OlznXfkCMOjQjBAMA8GA1UdEwEB/wQFMAMB + Af8wHQYDVR0OBBYEFDT/ThjQZl42Nv/4Z/7JYaPNMly2MA4GA1UdDwEB/wQEAwIB + hjAKBggqhkjOPQQDAwNpADBmAjEAnZWmSgpEbmq+oiCa13l5aGmxSlfp9h12Orvw + Dq/W5cENJz891QD0ufOsic5oGq1JAjEAp5kSJj0MxJBTHQze1Aa9gG4sjHBxXn98 + 4MP1VGsQuhfndNHQb4V0Au7OWnOeiobq + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/zCCAuegAwIBAgIRAMgnyikWz46xY6yRgiYwZ3swDQYJKoZIhvcNAQELBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyBldS13ZXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyMDE2NDkxMloYDzIwNjEwNTIwMTc0OTEyWjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGV1LXdlc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCi8JYOc9cYSgZH + gYPxLk6Xcc7HqzamvsnjYU98Dcb98y6iDqS46Ra2Ne02MITtU5MDL+qjxb8WGDZV + RUA9ZS69tkTO3gldW8QdiSh3J6hVNJQW81F0M7ZWgV0gB3n76WCmfT4IWos0AXHM + 5v7M/M4tqVmCPViQnZb2kdVlM3/Xc9GInfSMCgNfwHPTXl+PXX+xCdNBePaP/A5C + 5S0oK3HiXaKGQAy3K7VnaQaYdiv32XUatlM4K2WS4AMKt+2cw3hTCjlmqKRHvYFQ + veWCXAuc+U5PQDJ9SuxB1buFJZhT4VP3JagOuZbh5NWpIbOTxlAJOb5pGEDuJTKi + 1gQQQVEFAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNXm+N87 + OFxK9Af/bjSxDCiulGUzMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC + AQEAkqIbkgZ45spvrgRQ6n9VKzDLvNg+WciLtmVrqyohwwJbj4pYvWwnKQCkVc7c + hUOSBmlSBa5REAPbH5o8bdt00FPRrD6BdXLXhaECKgjsHe1WW08nsequRKD8xVmc + 8bEX6sw/utBeBV3mB+3Zv7ejYAbDFM4vnRsWtO+XqgReOgrl+cwdA6SNQT9oW3e5 + rSQ+VaXgJtl9NhkiIysq9BeYigxqS/A13pHQp0COMwS8nz+kBPHhJTsajHCDc8F4 + HfLi6cgs9G0gaRhT8FCH66OdGSqn196sE7Y3bPFFFs/3U+vxvmQgoZC6jegQXAg5 + Prxd+VNXtNI/azitTysQPumH7A== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEBTCCAu2gAwIBAgIRAO8bekN7rUReuNPG8pSTKtEwDQYJKoZIhvcNAQELBQAw + gZoxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEzMDEGA1UEAwwq + QW1hem9uIFJEUyBldS1jZW50cmFsLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYD + VQQHDAdTZWF0dGxlMCAXDTIxMDUyMTIyMjM0N1oYDzIwNjEwNTIxMjMyMzQ3WjCB + mjELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTMwMQYDVQQDDCpB + bWF6b24gUkRTIGV1LWNlbnRyYWwtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNV + BAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTTYds + Tray+Q9VA5j5jTh5TunHKFQzn68ZbOzdqaoi/Rq4ohfC0xdLrxCpfqn2TGDHN6Zi + 2qGK1tWJZEd1H0trhzd9d1CtGK+3cjabUmz/TjSW/qBar7e9MA67/iJ74Gc+Ww43 + A0xPNIWcL4aLrHaLm7sHgAO2UCKsrBUpxErOAACERScVYwPAfu79xeFcX7DmcX+e + lIqY16pQAvK2RIzrekSYfLFxwFq2hnlgKHaVgZ3keKP+nmXcXmRSHQYUUr72oYNZ + HcNYl2+gxCc9ccPEHM7xncVEKmb5cWEWvVoaysgQ+osi5f5aQdzgC2X2g2daKbyA + XL/z5FM9GHpS5BJjAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE + FBDAiJ7Py9/A9etNa/ebOnx5l5MGMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B + AQsFAAOCAQEALMh/+81fFPdJV/RrJUeoUvFCGMp8iaANu97NpeJyKitNOv7RoeVP + WjivS0KcCqZaDBs+p6IZ0sLI5ZH098LDzzytcfZg0PsGqUAb8a0MiU/LfgDCI9Ee + jsOiwaFB8k0tfUJK32NPcIoQYApTMT2e26lPzYORSkfuntme2PTHUnuC7ikiQrZk + P+SZjWgRuMcp09JfRXyAYWIuix4Gy0eZ4rpRuaTK6mjAb1/LYoNK/iZ/gTeIqrNt + l70OWRsWW8jEmSyNTIubGK/gGGyfuZGSyqoRX6OKHESkP6SSulbIZHyJ5VZkgtXo + 2XvyRyJ7w5pFyoofrL3Wv0UF8yt/GDszmg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIF/zCCA+egAwIBAgIRAMDk/F+rrhdn42SfE+ghPC8wDQYJKoZIhvcNAQEMBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyBldS13ZXN0LTIgUm9vdCBDQSBSU0E0MDk2IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyMTIyNTEyMloYDzIxMjEwNTIxMjM1MTIyWjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGV1LXdlc3QtMiBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2twMALVg9vRVu + VNqsr6N8thmp3Dy8jEGTsm3GCQ+C5P2YcGlD/T/5icfWW84uF7Sx3ezcGlvsqFMf + Ukj9sQyqtz7qfFFugyy7pa/eH9f48kWFHLbQYm9GEgbYBIrWMp1cy3vyxuMCwQN4 + DCncqU+yNpy0CprQJEha3PzY+3yJOjDQtc3zr99lyECCFJTDUucxHzyQvX89eL74 + uh8la0lKH3v9wPpnEoftbrwmm5jHNFdzj7uXUHUJ41N7af7z7QUfghIRhlBDiKtx + 5lYZemPCXajTc3ryDKUZC/b+B6ViXZmAeMdmQoPE0jwyEp/uaUcdp+FlUQwCfsBk + ayPFEApTWgPiku2isjdeTVmEgL8bJTDUZ6FYFR7ZHcYAsDzcwHgIu3GGEMVRS3Uf + ILmioiyly9vcK4Sa01ondARmsi/I0s7pWpKflaekyv5boJKD/xqwz9lGejmJHelf + 8Od2TyqJScMpB7Q8c2ROxBwqwB72jMCEvYigB+Wnbb8RipliqNflIGx938FRCzKL + UQUBmNAznR/yRRL0wHf9UAE/8v9a09uZABeiznzOFAl/frHpgdAbC00LkFlnwwgX + g8YfEFlkp4fLx5B7LtoO6uVNFVimLxtwirpyKoj3G4M/kvSTux8bTw0heBCmWmKR + 57MS6k7ODzbv+Kpeht2hqVZCNFMxoQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/ + MB0GA1UdDgQWBBRuMnDhJjoj7DcKALj+HbxEqj3r6jAOBgNVHQ8BAf8EBAMCAYYw + DQYJKoZIhvcNAQEMBQADggIBALSnXfx72C3ldhBP5kY4Mo2DDaGQ8FGpTOOiD95d + 0rf7I9LrsBGVqu/Nir+kqqP80PB70+Jy9fHFFigXwcPBX3MpKGxK8Cel7kVf8t1B + 4YD6A6bqlzP+OUL0uGWfZpdpDxwMDI2Flt4NEldHgXWPjvN1VblEKs0+kPnKowyg + jhRMgBbD/y+8yg0fIcjXUDTAw/+INcp21gWaMukKQr/8HswqC1yoqW9in2ijQkpK + 2RB9vcQ0/gXR0oJUbZQx0jn0OH8Agt7yfMAnJAdnHO4M3gjvlJLzIC5/4aGrRXZl + JoZKfJ2fZRnrFMi0nhAYDeInoS+Rwx+QzaBk6fX5VPyCj8foZ0nmqvuYoydzD8W5 + mMlycgxFqS+DUmO+liWllQC4/MnVBlHGB1Cu3wTj5kgOvNs/k+FW3GXGzD3+rpv0 + QTLuwSbMr+MbEThxrSZRSXTCQzKfehyC+WZejgLb+8ylLJUA10e62o7H9PvCrwj+ + ZDVmN7qj6amzvndCP98sZfX7CFZPLfcBd4wVIjHsFjSNEwWHOiFyLPPG7cdolGKA + lOFvonvo4A1uRc13/zFeP0Xi5n5OZ2go8aOOeGYdI2vB2sgH9R2IASH/jHmr0gvY + 0dfBCcfXNgrS0toq0LX/y+5KkKOxh52vEYsJLdhqrveuZhQnsFEm/mFwjRXkyO7c + 2jpC + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + FEv9Bg== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICsDCCAjagAwIBAgIRAMgApnfGYPpK/fD0dbN2U4YwCgYIKoZIzj0EAwMwgZcx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwnQW1h + em9uIFJEUyBldS1zb3V0aC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMCAXDTIxMDUxOTE4MzgxMVoYDzIxMjEwNTE5MTkzODExWjCBlzELMAkG + A1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzAR + BgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6b24g + UkRTIGV1LXNvdXRoLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0 + bGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQfEWl6d4qSuIoECdZPp+39LaKsfsX7 + THs3/RrtT0+h/jl3bjZ7Qc68k16x+HGcHbaayHfqD0LPdzH/kKtNSfQKqemdxDQh + Z4pwkixJu8T1VpXZ5zzCvBXCl75UqgEFS92jQjBAMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFFPrSNtWS5JU+Tvi6ABV231XbjbEMA4GA1UdDwEB/wQEAwIBhjAK + BggqhkjOPQQDAwNoADBlAjEA+a7hF1IrNkBd2N/l7IQYAQw8chnRZDzh4wiGsZsC + 6A83maaKFWUKIb3qZYXFSi02AjAbp3wxH3myAmF8WekDHhKcC2zDvyOiKLkg9Y6v + ZVmyMR043dscQbcsVoacOYv198c= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICtDCCAjqgAwIBAgIRAPhVkIsQ51JFhD2kjFK5uAkwCgYIKoZIzj0EAwMwgZkx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEyMDAGA1UEAwwpQW1h + em9uIFJEUyBldS1jZW50cmFsLTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjIwNjA2MjEyOTE3WhgPMjEyMjA2MDYyMjI5MTdaMIGZMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMjAwBgNVBAMMKUFtYXpv + biBSRFMgZXUtY2VudHJhbC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEA5xnIEBtG5b2nmbj49UEwQza + yX0844fXjccYzZ8xCDUe9dS2XOUi0aZlGblgSe/3lwjg8fMcKXLObGGQfgIx1+5h + AIBjORis/dlyN5q/yH4U5sjS8tcR0GDGVHrsRUZCo0IwQDAPBgNVHRMBAf8EBTAD + AQH/MB0GA1UdDgQWBBRK+lSGutXf4DkTjR3WNfv4+KeNFTAOBgNVHQ8BAf8EBAMC + AYYwCgYIKoZIzj0EAwMDaAAwZQIxAJ4NxQ1Gerqr70ZrnUqc62Vl8NNqTzInamCG + Kce3FTsMWbS9qkgrjZkO9QqOcGIw/gIwSLrwUT+PKr9+H9eHyGvpq9/3AIYSnFkb + Cf3dyWPiLKoAtLFwjzB/CkJlsAS1c8dS + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIF/jCCA+agAwIBAgIQGZH12Q7x41qIh9vDu9ikTjANBgkqhkiG9w0BAQwFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIGV1LXdlc3QtMyBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTI1MjIyMjMzWhgPMjEyMTA1MjUyMzIyMzNaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgZXUtd2VzdC0zIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMqE47sHXWzdpuqj + JHb+6jM9tDbQLDFnYjDWpq4VpLPZhb7xPNh9gnYYTPKG4avG421EblAHqzy9D2pN + 1z90yKbIfUb/Sy2MhQbmZomsObhONEra06fJ0Dydyjswf1iYRp2kwpx5AgkVoNo7 + 3dlws73zFjD7ImKvUx2C7B75bhnw2pJWkFnGcswl8fZt9B5Yt95sFOKEz2MSJE91 + kZlHtya19OUxZ/cSGci4MlOySzqzbGwUqGxEIDlY8I39VMwXaYQ8uXUN4G780VcL + u46FeyRGxZGz2n3hMc805WAA1V5uir87vuirTvoSVREET97HVRGVVNJJ/FM6GXr1 + VKtptybbo81nefYJg9KBysxAa2Ao2x2ry/2ZxwhS6VZ6v1+90bpZA1BIYFEDXXn/ + dW07HSCFnYSlgPtSc+Muh15mdr94LspYeDqNIierK9i4tB6ep7llJAnq0BU91fM2 + JPeqyoTtc3m06QhLf68ccSxO4l8Hmq9kLSHO7UXgtdjfRVaffngopTNk8qK7bIb7 + LrgkqhiQw/PRCZjUdyXL153/fUcsj9nFNe25gM4vcFYwH6c5trd2tUl31NTi1MfG + Mgp3d2dqxQBIYANkEjtBDMy3SqQLIo9EymqmVP8xx2A/gCBgaxvMAsI6FSWRoC7+ + hqJ8XH4mFnXSHKtYMe6WPY+/XZgtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFIkXqTnllT/VJnI2NqipA4XV8rh1MA4GA1UdDwEB/wQEAwIBhjAN + BgkqhkiG9w0BAQwFAAOCAgEAKjSle8eenGeHgT8pltWCw/HzWyQruVKhfYIBfKJd + MhV4EnH5BK7LxBIvpXGsFUrb0ThzSw0fn0zoA9jBs3i/Sj6KyeZ9qUF6b8ycDXd+ + wHonmJiQ7nk7UuMefaYAfs06vosgl1rI7eBHC0itexIQmKh0aX+821l4GEgEoSMf + loMFTLXv2w36fPHHCsZ67ODldgcZbKNnpCTX0YrCwEYO3Pz/L398btiRcWGrewrK + jdxAAyietra8DRno1Zl87685tfqc6HsL9v8rVw58clAo9XAQvT+fmSOFw/PogRZ7 + OMHUat3gu/uQ1M5S64nkLLFsKu7jzudBuoNmcJysPlzIbqJ7vYc82OUGe9ucF3wi + 3tbKQ983hdJiTExVRBLX/fYjPsGbG3JtPTv89eg2tjWHlPhCDMMxyRKl6isu2RTq + 6VT489Z2zQrC33MYF8ZqO1NKjtyMAMIZwxVu4cGLkVsqFmEV2ScDHa5RadDyD3Ok + m+mqybhvEVm5tPgY6p0ILPMN3yvJsMSPSvuBXhO/X5ppNnpw9gnxpwbjQKNhkFaG + M5pkADZ14uRguOLM4VthSwUSEAr5VQYCFZhEwK+UOyJAGiB/nJz6IxL5XBNUXmRM + Hl8Xvz4riq48LMQbjcVQj0XvH941yPh+P8xOi00SGaQRaWp55Vyr4YKGbV0mEDz1 + r1o= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIF/zCCA+egAwIBAgIRAKwYju1QWxUZpn6D1gOtwgQwDQYJKoZIhvcNAQEMBQAw + gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ + bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn + QW1hem9uIFJEUyBldS13ZXN0LTEgUm9vdCBDQSBSU0E0MDk2IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyMDE2NTM1NFoYDzIxMjEwNTIwMTc1MzU0WjCBlzEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 + b24gUkRTIGV1LXdlc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCKdBP1U4lqWWkc + Cb25/BKRTsvNVnISiKocva8GAzJyKfcGRa85gmgu41U+Hz6+39K+XkRfM0YS4BvQ + F1XxWT0bNyypuvwCvmYShSTjN1TY0ltncDddahTajE/4MdSOZb/c98u0yt03cH+G + hVwRyT50h0v/UEol50VfwcVAEZEgcQQYhf1IFUFlIvKpmDOqLuFakOnc7c9akK+i + ivST+JO1tgowbnNkn2iLlSSgUWgb1gjaOsNfysagv1RXdlyPw3EyfwkFifAQvF2P + Q0ayYZfYS640cccv7efM1MSVyFHR9PrrDsF/zr2S2sGPbeHr7R/HwLl+S5J/l9N9 + y0rk6IHAWV4dEkOvgpnuJKURwA48iu1Hhi9e4moNS6eqoK2KmY3VFpuiyWcA73nH + GSmyaH+YuMrF7Fnuu7GEHZL/o6+F5cL3mj2SJJhL7sz0ryf5Cs5R4yN9BIEj/f49 + wh84pM6nexoI0Q4wiSFCxWiBpjSmOK6h7z6+2utaB5p20XDZHhxAlmlx4vMuWtjh + XckgRFxc+ZpVMU3cAHUpVEoO49e/+qKEpPzp8Xg4cToKw2+AfTk3cmyyXQfGwXMQ + ZUHNZ3w9ILMWihGCM2aGUsLcGDRennvNmnmin/SENsOQ8Ku0/a3teEzwV9cmmdYz + 5iYs1YtgPvKFobY6+T2RXXh+A5kprwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/ + MB0GA1UdDgQWBBSyUrsQVnKmA8z6/2Ech0rCvqpNmTAOBgNVHQ8BAf8EBAMCAYYw + DQYJKoZIhvcNAQEMBQADggIBAFlj3IFmgiFz5lvTzFTRizhVofhTJsGr14Yfkuc7 + UrXPuXOwJomd4uot2d/VIeGJpfnuS84qGdmQyGewGTJ9inatHsGZgHl9NHNWRwKZ + lTKTbBiq7aqgtUSFa06v202wpzU+1kadxJJePrbABxiXVfOmIW/a1a4hPNcT3syH + FIEg1+CGsp71UNjBuwg3JTKWna0sLSKcxLOSOvX1fzxK5djzVpEsvQMB4PSAzXca + vENgg2ErTwgTA+4s6rRtiBF9pAusN1QVuBahYP3ftrY6f3ycS4K65GnqscyfvKt5 + YgjtEKO3ZeeX8NpubMbzC+0Z6tVKfPFk/9TXuJtwvVeqow0YMrLLyRiYvK7EzJ97 + rrkxoKnHYQSZ+rH2tZ5SE392/rfk1PJL0cdHnkpDkUDO+8cKsFjjYKAQSNC52sKX + 74AVh6wMwxYwVZZJf2/2XxkjMWWhKNejsZhUkTISSmiLs+qPe3L67IM7GyKm9/m6 + R3r8x6NGjhTsKH64iYJg7AeKeax4b2e4hBb6GXFftyOs7unpEOIVkJJgM6gh3mwn + R7v4gwFbLKADKt1vHuerSZMiTuNTGhSfCeDM53XI/mjZl2HeuCKP1mCDLlaO+gZR + Q/G+E0sBKgEX4xTkAc3kgkuQGfExdGtnN2U2ehF80lBHB8+2y2E+xWWXih/ZyIcW + wOx+ + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + 89cEIGdbjsA= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEADCCAuigAwIBAgIQYjbPSg4+RNRD3zNxO1fuKDANBgkqhkiG9w0BAQsFADCB + mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB + bWF6b24gUkRTIGV1LW5vcnRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUyNDIwNTkyMVoYDzIwNjEwNTI0MjE1OTIxWjCBmDEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6 + b24gUkRTIGV1LW5vcnRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA179eQHxcV0YL + XMkqEmhSBazHhnRVd8yICbMq82PitE3BZcnv1Z5Zs/oOgNmMkOKae4tCXO/41JCX + wAgbs/eWWi+nnCfpQ/FqbLPg0h3dqzAgeszQyNl9IzTzX4Nd7JFRBVJXPIIKzlRf + +GmFsAhi3rYgDgO27pz3ciahVSN+CuACIRYnA0K0s9lhYdddmrW/SYeWyoB7jPa2 + LmWpAs7bDOgS4LlP2H3eFepBPgNufRytSQUVA8f58lsE5w25vNiUSnrdlvDrIU5n + Qwzc7NIZCx4qJpRbSKWrUtbyJriWfAkGU7i0IoainHLn0eHp9bWkwb9D+C/tMk1X + ERZw2PDGkwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSFmR7s + dAblusFN+xhf1ae0KUqhWTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD + ggEBAHsXOpjPMyH9lDhPM61zYdja1ebcMVgfUvsDvt+w0xKMKPhBzYDMs/cFOi1N + Q8LV79VNNfI2NuvFmGygcvTIR+4h0pqqZ+wjWl3Kk5jVxCrbHg3RBX02QLumKd/i + kwGcEtTUvTssn3SM8bgM0/1BDXgImZPC567ciLvWDo0s/Fe9dJJC3E0G7d/4s09n + OMdextcxFuWBZrBm/KK3QF0ByA8MG3//VXaGO9OIeeOJCpWn1G1PjT1UklYhkg61 + EbsTiZVA2DLd1BGzfU4o4M5mo68l0msse/ndR1nEY6IywwpgIFue7+rEleDh6b9d + PYkG1rHVw2I0XDG4o17aOn5E94I= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEADCCAuigAwIBAgIQC6W4HFghUkkgyQw14a6JljANBgkqhkiG9w0BAQsFADCB + mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB + bWF6b24gUkRTIGV1LXNvdXRoLTIgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIyMDUyMzE4MTYzMloYDzIwNjIwNTIzMTkxNjMyWjCBmDEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6 + b24gUkRTIGV1LXNvdXRoLTIgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiM/t4FV2R9Nx + UQG203UY83jInTa/6TMq0SPyg617FqYZxvz2kkx09x3dmxepUg9ttGMlPgjsRZM5 + LCFEi1FWk+hxHzt7vAdhHES5tdjwds3aIkgNEillmRDVrUsbrDwufLaa+MMDO2E1 + wQ/JYFXw16WBCCi2g1EtyQ2Xp+tZDX5IWOTnvhZpW8vVDptZ2AcJ5rMhfOYO3OsK + 5EF0GGA5ldzuezP+BkrBYGJ4wVKGxeaq9+5AT8iVZrypjwRkD7Y5CurywK3+aBwm + s9Q5Nd8t45JCOUzYp92rFKsCriD86n/JnEvgDfdP6Hvtm0/DkwXK40Wz2q0Zrd0k + mjP054NRPwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRR7yqd + SfKcX2Q8GzhcVucReIpewTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD + ggEBAEszBRDwXcZyNm07VcFwI1Im94oKwKccuKYeJEsizTBsVon8VpEiMwDs+yGu + 3p8kBhvkLwWybkD/vv6McH7T5b9jDX2DoOudqYnnaYeypsPH/00Vh3LvKagqzQza + orWLx+0tLo8xW4BtU+Wrn3JId8LvAhxyYXTn9bm+EwPcStp8xGLwu53OPD1RXYuy + uu+3ps/2piP7GVfou7H6PRaqbFHNfiGg6Y+WA0HGHiJzn8uLmrRJ5YRdIOOG9/xi + qTmAZloUNM7VNuurcMM2hWF494tQpsQ6ysg2qPjbBqzlGoOt3GfBTOZmqmwmqtam + K7juWM/mdMQAJ3SMlE5wI8nVdx4= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICrjCCAjSgAwIBAgIRAL9SdzVPcpq7GOpvdGoM80IwCgYIKoZIzj0EAwMwgZYx + CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu + MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h + em9uIFJEUyBldS13ZXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl + YXR0bGUwIBcNMjEwNTIwMTY1ODA3WhgPMjEyMTA1MjAxNzU4MDdaMIGWMQswCQYD + VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG + A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS + RFMgZXUtd2VzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJWDgXebvwjR+Ce+hxKOLbnsfN5W5dOlP + Zn8kwWnD+SLkU81Eac/BDJsXGrMk6jFD1vg16PEkoSevsuYWlC8xR6FmT6F6pmeh + fsMGOyJpfK4fyoEPhKeQoT23lFIc5Orjo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G + A1UdDgQWBBSVNAN1CHAz0eZ77qz2adeqjm31TzAOBgNVHQ8BAf8EBAMCAYYwCgYI + KoZIzj0EAwMDaAAwZQIxAMlQeHbcjor49jqmcJ9gRLWdEWpXG8thIf6zfYQ/OEAg + d7GDh4fR/OUk0VfjsBUN/gIwZB0bGdXvK38s6AAE/9IT051cz/wMe9GIrX1MnL1T + 1F5OqnXJdiwfZRRTHsRQ/L00 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + 1YfpdH2jp30= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIID/jCCAuagAwIBAgIQTDc+UgTRtYO7ZGTQ8UWKDDANBgkqhkiG9w0BAQsFADCB + lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB + bWF6b24gUkRTIGV1LXdlc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM + B1NlYXR0bGUwIBcNMjEwNTIxMjI0NjI0WhgPMjA2MTA1MjEyMzQ2MjRaMIGXMQsw + CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET + MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv + biBSRFMgZXUtd2VzdC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh + dHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM1oGtthQ1YiVIC2 + i4u4swMAGxAjc/BZp0yq0eP5ZQFaxnxs7zFAPabEWsrjeDzrRhdVO0h7zskrertP + gblGhfD20JfjvCHdP1RUhy/nzG+T+hn6Takan/GIgs8grlBMRHMgBYHW7tklhjaH + 3F7LujhceAHhhgp6IOrpb6YTaTTaJbF3GTmkqxSJ3l1LtEoWz8Al/nL/Ftzxrtez + Vs6ebpvd7sw37sxmXBWX2OlvUrPCTmladw9OrllGXtCFw4YyLe3zozBlZ3cHzQ0q + lINhpRcajTMfZrsiGCkQtoJT+AqVJPS2sHjqsEH8yiySW9Jbq4zyMbM1yqQ2vnnx + MJgoYMcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUaQG88UnV + JPTI+Pcti1P+q3H7pGYwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB + AQBAkgr75V0sEJimC6QRiTVWEuj2Khy7unjSfudbM6zumhXEU2/sUaVLiYy6cA/x + 3v0laDle6T07x9g64j5YastE/4jbzrGgIINFlY0JnaYmR3KZEjgi1s1fkRRf3llL + PJm9u4Q1mbwAMQK/ZjLuuRcL3uRIHJek18nRqT5h43GB26qXyvJqeYYpYfIjL9+/ + YiZAbSRRZG+Li23cmPWrbA1CJY121SB+WybCbysbOXzhD3Sl2KSZRwSw4p2HrFtV + 1Prk0dOBtZxCG9luf87ultuDZpfS0w6oNBAMXocgswk24ylcADkkFxBWW+7BETn1 + EpK+t1Lm37mU4sxtuha00XAi + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEADCCAuigAwIBAgIQcY44/8NUvBwr6LlHfRy7KjANBgkqhkiG9w0BAQsFADCB + mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu + Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB + bWF6b24gUkRTIGV1LXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH + DAdTZWF0dGxlMCAXDTIxMDUxOTE4MjcxOFoYDzIwNjEwNTE5MTkyNzE4WjCBmDEL + MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x + EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6 + b24gUkRTIGV1LXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT + ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0UaBeC+Usalu + EtXnV7+PnH+gi7/71tI/jkKVGKuhD2JDVvqLVoqbMHRh3+wGMvqKCjbHPcC2XMWv + 566fpAj4UZ9CLB5fVzss+QVNTl+FH2XhEzigopp+872ajsNzcZxrMkifxGb4i0U+ + t0Zi+UrbL5tsfP2JonKR1crOrbS6/DlzHBjIiJazGOQcMsJjNuTOItLbMohLpraA + /nApa3kOvI7Ufool1/34MG0+wL3UUA4YkZ6oBJVxjZvvs6tI7Lzz/SnhK2widGdc + snbLqBpHNIZQSorVoiwcFaRBGYX/uzYkiw44Yfa4cK2V/B5zgu1Fbr0gbI2am4eh + yVYyg4jPawIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS9gM1m + IIjyh9O5H/7Vj0R/akI7UzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD + ggEBAF0Sm9HC2AUyedBVnwgkVXMibnYChOzz7T+0Y+fOLXYAEXex2s8oqGeZdGYX + JHkjBn7JXu7LM+TpTbPbFFDoc1sgMguD/ls+8XsqAl1CssW+amryIL+jfcfbgQ+P + ICwEUD9hGdjBgJ5WcuS+qqxHsEIlFNci3HxcxfBa9VsWs5TjI7Vsl4meL5lf7ZyL + wDV7dHRuU+cImqG1MIvPRIlvPnT7EghrCYi2VCPhP2pM/UvShuwVnkz4MJ29ebIk + WR9kpblFxFdE92D5UUvMCjC2kmtgzNiErvTcwIvOO9YCbBHzRB1fFiWrXUHhJWq9 + IkaxR5icb/IpAV0A1lYZEWMVsfQ= + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + 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 + rM2p0kk= + -----END CERTIFICATE----- \ No newline at end of file diff --git a/.ibm/pipelines/resources/postgres-db/values-showcase-postgres.yaml b/.ibm/pipelines/resources/postgres-db/values-showcase-postgres.yaml new file mode 100644 index 0000000000..ea90c04566 --- /dev/null +++ b/.ibm/pipelines/resources/postgres-db/values-showcase-postgres.yaml @@ -0,0 +1,109 @@ +global: + dynamic: + includes: + - dynamic-plugins.default.yaml + plugins: [] +upstream: + nameOverride: backstage + commonLabels: + backstage.io/kubernetes-id: developer-hub + backstage: + image: + pullPolicy: Always + registry: quay.io + repository: janus-idp/backstage-showcase + tag: next + appConfig: + app: + baseUrl: 'https://{{- include "janus-idp.hostname" . }}' + backend: + auth: + externalAccess: + - options: + secret: '${BACKEND_SECRET}' + subject: legacy-default-config + type: legacy + baseUrl: 'https://{{- include "janus-idp.hostname" . }}' + cors: + origin: 'https://{{- include "janus-idp.hostname" . }}' + database: + connection: # configure Backstage DB connection parameters + host: ${POSTGRES_HOST} + port: ${POSTGRES_PORT} + user: ${POSTGRES_USER} + password: ${POSTGRES_PASSWORD} + auth: + environment: development + providers: + guest: + dangerouslyAllowOutsideDevelopment: true + extraEnvVars: + - name: BACKEND_SECRET + valueFrom: + secretKeyRef: + key: backend-secret + name: '{{ include "janus-idp.backend-secret-name" $ }}' + extraVolumeMounts: + - mountPath: /opt/app-root/src/dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/postgres-crt.pem + name: postgres-crt # inject certificate secret to Backstage cont. + subPath: postgres-crt.pem + extraVolumes: + - name: dynamic-plugins-root + persistentVolumeClaim: + claimName: '{{ printf "%s-dynamic-plugins-root" .Release.Name }}' + - configMap: + defaultMode: 420 + name: '{{ printf "%s-dynamic-plugins" .Release.Name }}' + optional: true + name: dynamic-plugins + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}' + - name: dynamic-plugins-registry-auth + secret: + defaultMode: 416 + optional: true + secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}' + - name: postgres-crt + secret: + secretName: postgres-crt + - emptyDir: {} + name: npmcacache + initContainers: + - name: install-dynamic-plugins + image: '{{ include "backstage.image" . }}' + command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + imagePullPolicy: Always + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/dynamic-plugins.yaml + name: dynamic-plugins + readOnly: true + subPath: dynamic-plugins.yaml + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + - mountPath: /opt/app-root/src/.config/containers + name: dynamic-plugins-registry-auth + readOnly: true + - mountPath: /opt/app-root/src/.npm/_cacache + name: npmcacache + workingDir: /opt/app-root/src + installDir: /opt/app-root/src + extraEnvVarsSecrets: + - postgres-cred + postgresql: + enabled: false + auth: + existingSecret: postgres-cred diff --git a/.ibm/pipelines/utils.sh b/.ibm/pipelines/utils.sh index 7e6ce01ef2..65f0632800 100755 --- a/.ibm/pipelines/utils.sh +++ b/.ibm/pipelines/utils.sh @@ -1,5 +1,7 @@ #!/bin/sh +set -x + retrieve_pod_logs() { local pod_name=$1; local container=$2; local namespace=$3 echo " Retrieving logs for container: $container" @@ -11,6 +13,7 @@ retrieve_pod_logs() { save_all_pod_logs(){ set +e local namespace=$1 + namespace=${namespace%-pr-*} # remove -pr- suffix if any. mkdir -p pod_logs # Get all pod names in the namespace @@ -23,7 +26,7 @@ save_all_pod_logs(){ for init_container in $init_containers; do retrieve_pod_logs $pod_name $init_container $namespace done - + containers=$(kubectl get pod $pod_name -n $namespace -o jsonpath='{.spec.containers[*].name}') for container in $containers; do retrieve_pod_logs $pod_name $container $namespace @@ -34,3 +37,660 @@ save_all_pod_logs(){ cp -a pod_logs/* "${ARTIFACT_DIR}/${namespace}/pod_logs" set -e } + +droute_send() { + temp_kubeconfig=$(mktemp) # Create temporary KUBECONFIG to open second `oc` session + ( # Open subshell + if [ -n "${PULL_NUMBER:-}" ]; then + set +e + fi + export KUBECONFIG="$temp_kubeconfig" + local droute_version="1.2.2" + local release_name=$1 + local project=$2 + local droute_project="droute" + METEDATA_OUTPUT="data_router_metadata_output.json" + + oc login --token="${RHDH_PR_OS_CLUSTER_TOKEN}" --server="${RHDH_PR_OS_CLUSTER_URL}" + oc whoami --show-server + local droute_pod_name=$(oc get pods -n droute --no-headers -o custom-columns=":metadata.name" | grep ubi9-cert-rsync) + local temp_droute=$(oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c "mktemp -d") + + JOB_BASE_URL="https://prow.ci.openshift.org/view/gs/test-platform-results" + if [ -n "${PULL_NUMBER:-}" ]; then + JOB_URL="${JOB_BASE_URL}/pr-logs/pull/${REPO_OWNER}_${REPO_NAME}/${PULL_NUMBER}/${JOB_NAME}/${BUILD_ID}" + ARTIFACTS_URL="https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/${REPO_OWNER}_${REPO_NAME}/${PULL_NUMBER}/${JOB_NAME}/${BUILD_ID}/artifacts/e2e-tests/${REPO_OWNER}-${REPO_NAME}/artifacts/${project}" + else + JOB_URL="${JOB_BASE_URL}/logs/${JOB_NAME}/${BUILD_ID}" + ARTIFACTS_URL="https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/logs/${JOB_NAME}/${BUILD_ID}/artifacts/${JOB_NAME##periodic-ci-janus-idp-backstage-showcase-main-}/${REPO_OWNER}-${REPO_NAME}/artifacts/${project}" + fi + + # Remove properties (only used for skipped test and invalidates the file if empty) + sed -i '//,/<\/properties>/d' "${ARTIFACT_DIR}/${project}/${JUNIT_RESULTS}" + # Replace attachments with link to OpenShift CI storage + sed -iE "s#\[\[ATTACHMENT|\(.*\)\]\]#${ARTIFACTS_URL}/\1#g" "${ARTIFACT_DIR}/${project}/${JUNIT_RESULTS}" + + jq \ + --arg hostname "$REPORTPORTAL_HOSTNAME" \ + --arg project "$DATA_ROUTER_PROJECT" \ + --arg name "$JOB_NAME" \ + --arg description "[View job run details](${JOB_URL})" \ + --arg key1 "job_type" \ + --arg value1 "$JOB_TYPE" \ + --arg key2 "pr" \ + --arg value2 "$GIT_PR_NUMBER" \ + --arg key3 "job_name" \ + --arg value3 "$JOB_NAME" \ + --arg key4 "tag_name" \ + --arg value4 "$TAG_NAME" \ + --arg auto_finalization_treshold $DATA_ROUTER_AUTO_FINALIZATION_TRESHOLD \ + '.targets.reportportal.config.hostname = $hostname | + .targets.reportportal.config.project = $project | + .targets.reportportal.processing.launch.name = $name | + .targets.reportportal.processing.launch.description = $description | + .targets.reportportal.processing.launch.attributes += [ + {"key": $key1, "value": $value1}, + {"key": $key2, "value": $value2}, + {"key": $key3, "value": $value3}, + {"key": $key4, "value": $value4} + ] | + .targets.reportportal.processing.tfa.auto_finalization_threshold = ($auto_finalization_treshold | tonumber) + ' data_router/data_router_metadata_template.json > "${ARTIFACT_DIR}/${project}/${METEDATA_OUTPUT}" + + oc rsync --include="${METEDATA_OUTPUT}" --include="${JUNIT_RESULTS}" --exclude="*" -n "${droute_project}" "${ARTIFACT_DIR}/${project}/" "${droute_project}/${droute_pod_name}:${temp_droute}/" + + # "Install" Data Router + oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c " + curl -fsSLk -o /tmp/droute-linux-amd64 'https://${DATA_ROUTER_NEXUS_HOSTNAME}/nexus/repository/dno-raw/droute-client/${droute_version}/droute-linux-amd64' \ + && chmod +x /tmp/droute-linux-amd64 \ + && /tmp/droute-linux-amd64 version" + + # Send test results through DataRouter and save the request ID. + DATA_ROUTER_REQUEST_ID=$(oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c " + /tmp/droute-linux-amd64 send --metadata ${temp_droute}/${METEDATA_OUTPUT} \ + --url '${DATA_ROUTER_URL}' \ + --username '${DATA_ROUTER_USERNAME}' \ + --password '${DATA_ROUTER_PASSWORD}' \ + --results '${temp_droute}/${JUNIT_RESULTS}' \ + --verbose" | grep "request:" | awk '{print $2}') + + if [[ "$JOB_NAME" == *periodic-* ]]; then + local max_attempts=30 + local wait_seconds=2 + set +e + for ((i = 1; i <= max_attempts; i++)); do + # Get DataRouter request information. + DATA_ROUTER_REQUEST_OUTPUT=$(oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c " + /tmp/droute-linux-amd64 request get \ + --url ${DATA_ROUTER_URL} \ + --username ${DATA_ROUTER_USERNAME} \ + --password ${DATA_ROUTER_PASSWORD} \ + ${DATA_ROUTER_REQUEST_ID}") + # Try to extract the ReportPortal launch URL from the request. This fails if it doesn't contain the launch URL. + REPORTPORTAL_LAUNCH_URL=$(echo "$DATA_ROUTER_REQUEST_OUTPUT" | yq e '.targets[0].events[] | select(.component == "reportportal-connector") | .message | fromjson | .[0].launch_url' -) + if [[ $? -eq 0 ]]; then + if [[ "$release_name" == *rbac* ]]; then + RUN_TYPE="rbac-nightly" + else + RUN_TYPE="nightly" + fi + if [[ ${PIPESTATUS[0]} -eq 0 ]]; then + RUN_STATUS_EMOJI=":done-circle-check:" + RUN_STATUS="passed" + else + RUN_STATUS_EMOJI=":failed:" + RUN_STATUS="failed" + fi + jq -n \ + --arg run_status "$RUN_STATUS" \ + --arg run_type "$RUN_TYPE" \ + --arg reportportal_launch_url "$REPORTPORTAL_LAUNCH_URL" \ + --arg job_name "$JOB_NAME" \ + --arg run_status_emoji "$RUN_STATUS_EMOJI" \ + '{ + "RUN_STATUS": $run_status, + "RUN_TYPE": $run_type, + "REPORTPORTAL_LAUNCH_URL": $reportportal_launch_url, + "JOB_NAME": $job_name, + "RUN_STATUS_EMOJI": $run_status_emoji + }' > /tmp/data_router_slack_message.json + curl -X POST -H 'Content-type: application/json' --data @/tmp/data_router_slack_message.json $SLACK_DATA_ROUTER_WEBHOOK_URL + return 0 + else + echo "Attempt ${i} of ${max_attempts}: ReportPortal launch URL not ready yet." + sleep "${wait_seconds}" + fi + done + set -e + fi + oc exec -n "${droute_project}" "${droute_pod_name}" -- /bin/bash -c "rm -rf ${temp_droute}/*" + if [ -n "${PULL_NUMBER:-}" ]; then + set -e + fi + ) # Close subshell + rm -f "$temp_kubeconfig" # Destroy temporary KUBECONFIG + oc whoami --show-server +} + +# Merge the base YAML value file with the differences file for Kubernetes +yq_merge_value_files() { + local base_file=$1 + local diff_file=$2 + local step_1_file="/tmp/step-without-plugins.yaml" + local step_2_file="/tmp/step-only-plugins.yaml" + local final_file=$3 + # Step 1: Merge files, excluding the .global.dynamic.plugins key + # Values from `diff_file` override those in `base_file` + yq eval-all ' + select(fileIndex == 0) * select(fileIndex == 1) | + del(.global.dynamic.plugins) + ' "${base_file}" "${diff_file}" > "${step_1_file}" + # Step 2: Merge files, combining the .global.dynamic.plugins key + # Values from `diff_file` take precedence; plugins are merged and deduplicated by the .package field + yq eval-all ' + select(fileIndex == 0) *+ select(fileIndex == 1) | + .global.dynamic.plugins |= (reverse | unique_by(.package) | reverse) + ' "${base_file}" "${diff_file}" > "${step_2_file}" + # Step 3: Combine results from the previous steps and remove null values + # Values from `step_2_file` override those in `step_1_file` + yq eval-all ' + select(fileIndex == 0) * select(fileIndex == 1) | del(.. | select(. == null)) + ' "${step_2_file}" "${step_1_file}" > "${final_file}" +} + +# Waits for a Kubernetes/OpenShift deployment to become ready within a specified timeout period +wait_for_deployment() { + local namespace=$1 + local resource_name=$2 + local timeout_minutes=${3:-5} # Default timeout: 5 minutes + local check_interval=${4:-10} # Default interval: 10 seconds + + # Validate required parameters + if [[ -z "$namespace" || -z "$resource_name" ]]; then + echo "Error: Missing required parameters" + echo "Usage: wait_for_deployment [timeout_minutes] [check_interval_seconds]" + echo "Example: wait_for_deployment my-namespace my-deployment 5 10" + return 1 + fi + + local max_attempts=$((timeout_minutes * 60 / check_interval)) + + echo "Waiting for resource '$resource_name' in namespace '$namespace' (timeout: ${timeout_minutes}m)..." + + for ((i=1; i<=max_attempts; i++)); do + # Get the first pod name matching the resource name + local pod_name=$(oc get pods -n "$namespace" | grep "$resource_name" | awk '{print $1}' | head -n 1) + + if [[ -n "$pod_name" ]]; then + # Check if pod's Ready condition is True + local is_ready=$(oc get pod "$pod_name" -n "$namespace" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') + # Verify pod is both Ready and Running + if [[ "$is_ready" == "True" ]] && \ + oc get pod "$pod_name" -n "$namespace" | grep -q "Running"; then + echo "Pod '$pod_name' is running and ready" + return 0 + else + echo "Pod '$pod_name' is not ready (Ready: $is_ready)" + fi + else + echo "No pods found matching '$resource_name' in namespace '$namespace'" + fi + + echo "Still waiting... (${i}/${max_attempts} checks)" + sleep "$check_interval" + done + + # Timeout occurred + echo "Timeout waiting for resource to be ready. Please check:" + echo "oc get pods -n $namespace | grep $resource_name" + return 1 +} + +# Creates an OpenShift Operator subscription +install_subscription(){ + name=$1 # Name of the subscription + namespace=$2 # Namespace to install the operator + package=$3 # Package name of the operator + channel=$4 # Channel to subscribe to + source_name=$5 # Name of the source catalog + # Apply the subscription manifest + oc apply -f - << EOD +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: $name + namespace: $namespace +spec: + channel: $channel + installPlanApproval: Automatic + name: $package + source: $source_name + sourceNamespace: openshift-marketplace +EOD +} + +# Installs the Crunchy Postgres Operator using predefined parameters +install_crunchy_postgres_operator(){ + install_subscription crunchy-postgres-operator openshift-operators crunchy-postgres-operator v5 certified-operators +} + +add_helm_repos() { + helm version + + local repos=( + "bitnami=https://charts.bitnami.com/bitnami" + "backstage=https://backstage.github.io/charts" + "${HELM_REPO_NAME}=${HELM_REPO_URL}" + ) + + for repo in "${repos[@]}"; do + local key="${repo%%=*}" + local value="${repo##*=}" + + if ! helm repo list | grep -q "^$key"; then + helm repo add "$key" "$value" + else + echo "Repository $key already exists - updating repository instead." + fi + done + + helm repo update +} + +uninstall_helmchart() { + local project=$1 + local release=$2 + if helm list -n "${project}" | grep -q "${release}"; then + echo "Chart already exists. Removing it before install." + helm uninstall "${release}" -n "${project}" + fi +} + +configure_namespace() { + local project=$1 + echo "Deleting and recreating namespace: $project" + delete_namespace $project + + if ! oc create namespace "${project}"; then + echo "Error: Failed to create namespace ${project}" >&2 + exit 1 + fi + if ! oc config set-context --current --namespace="${project}"; then + echo "Error: Failed to set context for namespace ${project}" >&2 + exit 1 + fi + + echo "Namespace ${project} is ready." +} + +delete_namespace() { + local project=$1 + if oc get namespace "$project" >/dev/null 2>&1; then + echo "Namespace ${project} exists. Attempting to delete..." + + # Remove blocking finalizers + remove_finalizers_from_resources "$project" + + # Attempt to delete the namespace + oc delete namespace "$project" --grace-period=0 --force || true + + # Check if namespace is still stuck in 'Terminating' and force removal if necessary + if oc get namespace "$project" -o jsonpath='{.status.phase}' | grep -q 'Terminating'; then + echo "Namespace ${project} is stuck in Terminating. Forcing deletion..." + force_delete_namespace "$project" + fi + fi +} + +configure_external_postgres_db() { + local project=$1 + oc apply -f "${DIR}/resources/postgres-db/postgres.yaml" --namespace="${NAME_SPACE_POSTGRES_DB}" + sleep 5 + + oc get secret postgress-external-db-cluster-cert -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath='{.data.ca\.crt}' | base64 --decode > postgres-ca + oc get secret postgress-external-db-cluster-cert -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath='{.data.tls\.crt}' | base64 --decode > postgres-tls-crt + oc get secret postgress-external-db-cluster-cert -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath='{.data.tls\.key}' | base64 --decode > postgres-tsl-key + + oc create secret generic postgress-external-db-cluster-cert \ + --from-file=ca.crt=postgres-ca \ + --from-file=tls.crt=postgres-tls-crt \ + --from-file=tls.key=postgres-tsl-key \ + --dry-run=client -o yaml | oc apply -f - --namespace="${project}" + + POSTGRES_PASSWORD=$(oc get secret/postgress-external-db-pguser-janus-idp -n "${NAME_SPACE_POSTGRES_DB}" -o jsonpath={.data.password}) + sed -i "s|POSTGRES_PASSWORD:.*|POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" + POSTGRES_HOST=$(echo -n "postgress-external-db-primary.$NAME_SPACE_POSTGRES_DB.svc.cluster.local" | base64 | tr -d '\n') + sed -i "s|POSTGRES_HOST:.*|POSTGRES_HOST: ${POSTGRES_HOST}|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" + oc apply -f "${DIR}/resources/postgres-db/postgres-cred.yaml" --namespace="${project}" +} + +set_github_app_3_credentials() { + GITHUB_APP_APP_ID=$GITHUB_APP_3_APP_ID + GITHUB_APP_CLIENT_ID=$GITHUB_APP_3_CLIENT_ID + GITHUB_APP_PRIVATE_KEY=$GITHUB_APP_3_PRIVATE_KEY + GITHUB_APP_CLIENT_SECRET=$GITHUB_APP_3_CLIENT_SECRET + + export GITHUB_APP_APP_ID + export GITHUB_APP_CLIENT_ID + export GITHUB_APP_PRIVATE_KEY + export GITHUB_APP_CLIENT_SECRET + echo "GitHub App 3 credentials set for current job." +} + +set_github_app_4_credentials() { + GITHUB_APP_APP_ID=$(cat /tmp/secrets/GITHUB_APP_4_APP_ID) + GITHUB_APP_CLIENT_ID=$(cat /tmp/secrets/GITHUB_APP_4_CLIENT_ID) + GITHUB_APP_PRIVATE_KEY=$(cat /tmp/secrets/GITHUB_APP_4_PRIVATE_KEY) + GITHUB_APP_CLIENT_SECRET=$(cat /tmp/secrets/GITHUB_APP_4_CLIENT_SECRET) + + export GITHUB_APP_APP_ID + export GITHUB_APP_CLIENT_ID + export GITHUB_APP_PRIVATE_KEY + export GITHUB_APP_CLIENT_SECRET + echo "GitHub App 4 credentials set for current job." +} + +apply_yaml_files() { + local dir=$1 + local project=$2 + echo "Applying YAML files to namespace ${project}" + + oc config set-context --current --namespace="${project}" + + local files=( + "$dir/resources/service_account/service-account-rhdh.yaml" + "$dir/resources/cluster_role_binding/cluster-role-binding-k8s.yaml" + "$dir/resources/cluster_role/cluster-role-k8s.yaml" + "$dir/resources/cluster_role/cluster-role-ocm.yaml" + "$dir/auth/secrets-rhdh-secrets.yaml" + ) + + for file in "${files[@]}"; do + sed -i "s/namespace:.*/namespace: ${project}/g" "$file" + done + + DH_TARGET_URL=$(echo -n "test-backstage-customization-provider-${project}.${K8S_CLUSTER_ROUTER_BASE}" | base64 -w 0) + + for key in GITHUB_APP_APP_ID GITHUB_APP_CLIENT_ID GITHUB_APP_PRIVATE_KEY GITHUB_APP_CLIENT_SECRET GITHUB_APP_JANUS_TEST_APP_ID GITHUB_APP_JANUS_TEST_CLIENT_ID GITHUB_APP_JANUS_TEST_CLIENT_SECRET GITHUB_APP_JANUS_TEST_PRIVATE_KEY GITHUB_APP_WEBHOOK_URL GITHUB_APP_WEBHOOK_SECRET KEYCLOAK_CLIENT_SECRET ACR_SECRET GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET K8S_CLUSTER_TOKEN_ENCODED OCM_CLUSTER_URL GITLAB_TOKEN DH_TARGET_URL; do + sed -i "s|${key}:.*|${key}: ${!key}|g" "$dir/auth/secrets-rhdh-secrets.yaml" + done + + oc apply -f "$dir/resources/service_account/service-account-rhdh.yaml" --namespace="${project}" + oc apply -f "$dir/auth/service-account-rhdh-secret.yaml" --namespace="${project}" + oc apply -f "$dir/auth/secrets-rhdh-secrets.yaml" --namespace="${project}" + + oc apply -f "$dir/resources/cluster_role/cluster-role-k8s.yaml" --namespace="${project}" + oc apply -f "$dir/resources/cluster_role_binding/cluster-role-binding-k8s.yaml" --namespace="${project}" + oc apply -f "$dir/resources/cluster_role/cluster-role-ocm.yaml" --namespace="${project}" + oc apply -f "$dir/resources/cluster_role_binding/cluster-role-binding-ocm.yaml" --namespace="${project}" + + escaped_url=$(printf '%s\n' "${ENCODED_API_SERVER_URL}" | sed 's/[\/&]/\\&/g') + sed -i "s/K8S_CLUSTER_API_SERVER_URL:.*/K8S_CLUSTER_API_SERVER_URL: ${escaped_url}/g" "$dir/auth/secrets-rhdh-secrets.yaml" \ + && echo "Updated K8S_CLUSTER_API_SERVER_URL in secrets file." \ + || echo "Failed to update K8S_CLUSTER_API_SERVER_URL." >&2 + + sed -i "s/K8S_CLUSTER_NAME:.*/K8S_CLUSTER_NAME: ${ENCODED_CLUSTER_NAME}/g" "$dir/auth/secrets-rhdh-secrets.yaml" + + token=$(oc get secret "${secret_name}" -n "${project}" -o=jsonpath='{.data.token}') + sed -i "s/OCM_CLUSTER_TOKEN: .*/OCM_CLUSTER_TOKEN: ${token}/" "$dir/auth/secrets-rhdh-secrets.yaml" + + # Select the configuration file based on the namespace or job + config_file=$(select_config_map_file) + # Apply the ConfigMap with the correct file + if [[ "${project}" == *showcase-k8s* ]]; then + create_app_config_map_k8s "$config_file" "$project" + else + create_app_config_map "$config_file" "$project" + fi + oc create configmap rbac-policy \ + --from-file="rbac-policy.csv"="$dir/resources/config_map/rbac-policy.csv" \ + --namespace="$project" \ + --dry-run=client -o yaml | oc apply -f - + + oc apply -f "$dir/auth/secrets-rhdh-secrets.yaml" --namespace="${project}" + +} + +deploy_test_backstage_provider() { + local project=$1 + echo "Deploying test-backstage-customization-provider in namespace ${project}" + + # Check if the buildconfig already exists + if ! oc get buildconfig test-backstage-customization-provider -n "${project}" >/dev/null 2>&1; then + echo "Creating new app for test-backstage-customization-provider" + oc new-app https://github.com/janus-qe/test-backstage-customization-provider --namespace="${project}" + else + echo "BuildConfig for test-backstage-customization-provider already exists in ${project}. Skipping new-app creation." + fi + + # Ensure the service exists + if ! oc get service test-backstage-customization-provider -n "${project}" >/dev/null 2>&1; then + echo "Exposing service for test-backstage-customization-provider" + oc expose svc/test-backstage-customization-provider --namespace="${project}" + else + echo "Service test-backstage-customization-provider is already exposed in ${project}." + fi +} + +create_app_config_map() { + local config_file=$1 + local project=$2 + + oc create configmap app-config-rhdh \ + --from-file="app-config-rhdh.yaml"="$config_file" \ + --namespace="$project" \ + --dry-run=client -o yaml | oc apply -f - +} + +select_config_map_file() { + if [[ "${project}" == *rbac* ]]; then + echo "$dir/resources/config_map/app-config-rhdh-rbac.yaml" + else + echo "$dir/resources/config_map/app-config-rhdh.yaml" + fi +} + +create_app_config_map_k8s() { + local config_file=$1 + local project=$2 + + echo "Creating app-config ConfigMap for AKS/GKE in namespace ${project}" + + yq 'del(.backend.cache)' "$config_file" \ + | oc create configmap app-config-rhdh \ + --from-file="app-config-rhdh.yaml"="/dev/stdin" \ + --namespace="${project}" \ + --dry-run=client -o yaml \ + | oc apply -f - +} + +run_tests() { + local release_name=$1 + local project=$2 + project=${project%-pr-*} # Remove -pr- suffix if any set for main branchs pr's. + cd "${DIR}/../../e2e-tests" + yarn install + yarn playwright install chromium + + Xvfb :99 & + export DISPLAY=:99 + + ( + set -e + echo "Using PR container image: ${TAG_NAME}" + yarn "$project" + ) 2>&1 | tee "/tmp/${LOGFILE}" + + local RESULT=${PIPESTATUS[0]} + + pkill Xvfb + + mkdir -p "${ARTIFACT_DIR}/${project}/test-results" + mkdir -p "${ARTIFACT_DIR}/${project}/attachments/screenshots" + cp -a /tmp/backstage-showcase/e2e-tests/test-results/* "${ARTIFACT_DIR}/${project}/test-results" + cp -a /tmp/backstage-showcase/e2e-tests/${JUNIT_RESULTS} "${ARTIFACT_DIR}/${project}/${JUNIT_RESULTS}" + + if [ -d "/tmp/backstage-showcase/e2e-tests/screenshots" ]; then + cp -a /tmp/backstage-showcase/e2e-tests/screenshots/* "${ARTIFACT_DIR}/${project}/attachments/screenshots/" + fi + + if [ -d "/tmp/backstage-showcase/e2e-tests/auth-providers-logs" ]; then + cp -a /tmp/backstage-showcase/e2e-tests/auth-providers-logs/* "${ARTIFACT_DIR}/${project}/" + fi + + ansi2html <"/tmp/${LOGFILE}" >"/tmp/${LOGFILE}.html" + cp -a "/tmp/${LOGFILE}.html" "${ARTIFACT_DIR}/${project}" + cp -a /tmp/backstage-showcase/e2e-tests/playwright-report/* "${ARTIFACT_DIR}/${project}" + + droute_send "${release_name}" "${project}" + + echo "${project} RESULT: ${RESULT}" + if [ "${RESULT}" -ne 0 ]; then + OVERALL_RESULT=1 + fi +} + +check_backstage_running() { + local release_name=$1 + local namespace=$2 + local url=$3 + + local max_attempts=30 + local wait_seconds=30 + + echo "Checking if Backstage is up and running at ${url}" + + for ((i = 1; i <= max_attempts; i++)); do + local http_status + http_status=$(curl --insecure -I -s -o /dev/null -w "%{http_code}" "${url}") + + if [ "${http_status}" -eq 200 ]; then + echo "Backstage is up and running!" + export BASE_URL="${url}" + echo "######## BASE URL ########" + echo "${BASE_URL}" + return 0 + else + echo "Attempt ${i} of ${max_attempts}: Backstage not yet available (HTTP Status: ${http_status})" + sleep "${wait_seconds}" + fi + done + + echo "Failed to reach Backstage at ${BASE_URL} after ${max_attempts} attempts." | tee -a "/tmp/${LOGFILE}" + cp -a "/tmp/${LOGFILE}" "${ARTIFACT_DIR}/${namespace}/" + return 1 +} + +install_tekton_pipelines() { + local dir=$1 + + if oc get pods -n "tekton-pipelines" | grep -q "tekton-pipelines"; then + echo "Tekton Pipelines are already installed." + else + echo "Tekton Pipelines is not installed. Installing..." + oc apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml + fi +} + +install_pipelines_operator() { + local dir=$1 + DISPLAY_NAME="Red Hat OpenShift Pipelines" + + if oc get csv -n "openshift-operators" | grep -q "${DISPLAY_NAME}"; then + echo "Red Hat OpenShift Pipelines operator is already installed." + else + echo "Red Hat OpenShift Pipelines operator is not installed. Installing..." + oc apply -f "${dir}/resources/pipeline-run/pipelines-operator.yaml" + fi +} + +initiate_deployments() { + + install_crunchy_postgres_operator + add_helm_repos + configure_namespace ${NAME_SPACE} + + # Deploy redis cache db. + oc apply -f "$DIR/resources/redis-cache/redis-deployment.yaml" --namespace="${NAME_SPACE}" + + cd "${DIR}" + apply_yaml_files "${DIR}" "${NAME_SPACE}" + echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE: ${NAME_SPACE}" + helm upgrade -i "${RELEASE_NAME}" -n "${NAME_SPACE}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "${DIR}/value_files/${HELM_CHART_VALUE_FILE_NAME}" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}" + + configure_namespace "${NAME_SPACE_POSTGRES_DB}" + configure_namespace "${NAME_SPACE_RBAC}" + configure_external_postgres_db "${NAME_SPACE_RBAC}" + + uninstall_helmchart "${NAME_SPACE_RBAC}" "${RELEASE_NAME_RBAC}" + apply_yaml_files "${DIR}" "${NAME_SPACE_RBAC}" + echo "Deploying image from repository: ${QUAY_REPO}, TAG_NAME: ${TAG_NAME}, in NAME_SPACE: ${RELEASE_NAME_RBAC}" + helm upgrade -i "${RELEASE_NAME_RBAC}" -n "${NAME_SPACE_RBAC}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "${DIR}/value_files/${HELM_CHART_RBAC_VALUE_FILE_NAME}" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}" +} + +initiate_rds_deployment() { + local release_name=$1 + local namespace=$2 + configure_namespace "${namespace}" + uninstall_helmchart "${namespace}" "${release_name}" + sed -i "s|POSTGRES_USER:.*|POSTGRES_USER: $RDS_USER|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" + sed -i "s|POSTGRES_PASSWORD:.*|POSTGRES_PASSWORD: $(echo -n $RDS_PASSWORD | base64 -w 0)|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" + sed -i "s|POSTGRES_HOST:.*|POSTGRES_HOST: $(echo -n $RDS_1_HOST | base64 -w 0)|g" "${DIR}/resources/postgres-db/postgres-cred.yaml" + oc apply -f "$DIR/resources/postgres-db/postgres-crt-rds.yaml" -n "${namespace}" + oc apply -f "$DIR/resources/postgres-db/postgres-cred.yaml" -n "${namespace}" + oc apply -f "$DIR/resources/postgres-db/dynamic-plugins-root-PVC.yaml" -n "${namespace}" + helm upgrade -i "${release_name}" -n "${namespace}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "$DIR/resources/postgres-db/values-showcase-postgres.yaml" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}" +} + +check_and_test() { + local release_name=$1 + local namespace=$2 + local url=$3 + if check_backstage_running "${release_name}" "${namespace}" "${url}"; then + echo "Display pods for verification..." + oc get pods -n "${namespace}" + run_tests "${release_name}" "${namespace}" + else + echo "Backstage is not running. Exiting..." + OVERALL_RESULT=1 + fi + save_all_pod_logs $namespace +} + +# Function to remove finalizers from specific resources in a namespace that are blocking deletion. +remove_finalizers_from_resources() { + local project=$1 + echo "Removing finalizers from resources in namespace ${project} that are blocking deletion." + + # Remove finalizers from stuck PipelineRuns and TaskRuns + for resource_type in "pipelineruns.tekton.dev" "taskruns.tekton.dev"; do + for resource in $(oc get "$resource_type" -n "$project" -o name); do + oc patch "$resource" -n "$project" --type='merge' -p '{"metadata":{"finalizers":[]}}' || true + echo "Removed finalizers from $resource in $project." + done + done + + # Check and remove specific finalizers stuck on 'chains.tekton.dev' resources + for chain_resource in $(oc get pipelineruns.tekton.dev,taskruns.tekton.dev -n "$project" -o name); do + oc patch "$chain_resource" -n "$project" --type='json' -p='[{"op": "remove", "path": "/metadata/finalizers"}]' || true + echo "Removed Tekton finalizers from $chain_resource in $project." + done +} + +# Function to forcibly delete a namespace stuck in 'Terminating' status +force_delete_namespace() { + local project=$1 + echo "Forcefully deleting namespace ${project}." + oc get namespace "$project" -o json | jq '.spec = {"finalizers":[]}' | oc replace --raw "/api/v1/namespaces/$project/finalize" -f - +} + +oc_login() { + export K8S_CLUSTER_URL=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_URL) + export K8S_CLUSTER_TOKEN=$(cat /tmp/secrets/RHDH_PR_OS_CLUSTER_TOKEN) + + oc login --token="${K8S_CLUSTER_TOKEN}" --server="${K8S_CLUSTER_URL}" + echo "OCP version: $(oc version)" + export K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//') +} + + diff --git a/.ibm/pipelines/value_files/diff-values_showcase-rbac_AKS.yaml b/.ibm/pipelines/value_files/diff-values_showcase-rbac_AKS.yaml new file mode 100644 index 0000000000..c545ab0a19 --- /dev/null +++ b/.ibm/pipelines/value_files/diff-values_showcase-rbac_AKS.yaml @@ -0,0 +1,117 @@ +# This file is for AKS installation only. +# It is applied by `helm upgrade` after the `values-showcase.yaml` is applied and only contains complementary differences for AKS. +# Note, that it overwrites the whole key that is present in this file. +# The only exception is global.dynamic.plugins, that gets merged with the base file. +route: + enabled: false +global: + dynamic: + plugins: [] +upstream: + backstage: + appConfig: + app: + # Please update to match host in case you don't want to configure hostname via `global.clusterRouterBase` or `global.host`. + baseUrl: 'https://{{- include "janus-idp.hostname" . }}' + backend: + baseUrl: 'https://{{- include "janus-idp.hostname" . }}' + cors: + origin: 'https://{{- include "janus-idp.hostname" . }}' + database: + connection: + host: null + port: null + password: ${POSTGRESQL_ADMIN_PASSWORD} + user: postgres + ssl: null + auth: + keys: + - secret: ${BACKEND_SECRET} + extraEnvVars: + - name: BACKEND_SECRET + valueFrom: + secretKeyRef: + key: backend-secret + name: '{{ include "janus-idp.backend-secret-name" $ }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{ .Release.Name }}-postgresql' + # disable telemetry in CI + - name: SEGMENT_TEST_MODE + value: 'true' + extraVolumeMounts: + # The initContainer below will install dynamic plugins in this volume mount. + - name: dynamic-plugins-root + mountPath: /opt/app-root/src/dynamic-plugins-root + - name: rbac-policy + mountPath: /opt/app-root/src/rbac + - name: rbac-conditions + mountPath: /opt/app-root/src/rbac-conditions + extraVolumes: + # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. + # To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html) + # could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). + - name: dynamic-plugins-root + emptyDir: {} + - name: rbac-policy + configMap: + defaultMode: 420 + name: rbac-policy + - name: rbac-conditions + emptyDir: {} + # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. + # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. + - name: dynamic-plugins + configMap: + defaultMode: 420 + name: dynamic-plugins + optional: true + # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) + # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + extraEnvVarsSecrets: + - rhdh-secrets + podSecurityContext: + fsGroup: 3000 + postgresql: + enabled: true + postgresqlDataDir: /var/lib/pgsql/data/userdata + image: + registry: quay.io + repository: fedora/postgresql-15 + tag: latest + auth: + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + existingSecret: null + primary: + securityContext: + enabled: false + podSecurityContext: + enabled: true + fsGroup: 3000 + containerSecurityContext: + enabled: false + persistence: + enabled: true + size: 1Gi + mountPath: /var/lib/pgsql/data + extraEnvVars: + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{ .Release.Name }}-postgresql' + volumePermissions: + enabled: true + ingress: + enabled: true + className: webapprouting.kubernetes.azure.com + host: '' \ No newline at end of file diff --git a/.ibm/pipelines/value_files/diff-values_showcase-rbac_GKE.yaml b/.ibm/pipelines/value_files/diff-values_showcase-rbac_GKE.yaml new file mode 100644 index 0000000000..911d04dcc6 --- /dev/null +++ b/.ibm/pipelines/value_files/diff-values_showcase-rbac_GKE.yaml @@ -0,0 +1,124 @@ +# This file is for GKE installation only. +# It is applied by `helm upgrade` after the `values-showcase.yaml` is applied and only contains complementary differences for GKE. +# Note, that it overwrites the whole key that is present in this file. +# e.g. global.dynamic.plugins key is completely overwritten by the content of this file. +route: + enabled: false +global: + dynamic: + plugins: [] +upstream: + backstage: + appConfig: + app: + # Please update to match host in case you don't want to configure hostname via `global.clusterRouterBase` or `global.host`. + baseUrl: 'https://{{- include "janus-idp.hostname" . }}' + backend: + baseUrl: 'https://{{- include "janus-idp.hostname" . }}' + cors: + origin: 'https://{{- include "janus-idp.hostname" . }}' + database: + connection: + host: null + port: null + password: ${POSTGRESQL_ADMIN_PASSWORD} + user: postgres + ssl: null + auth: + keys: + - secret: ${BACKEND_SECRET} + extraEnvVars: + - name: BACKEND_SECRET + valueFrom: + secretKeyRef: + key: backend-secret + name: '{{ include "janus-idp.backend-secret-name" $ }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{ .Release.Name }}-postgresql' + # disable telemetry in CI + - name: SEGMENT_TEST_MODE + value: 'true' + extraVolumeMounts: + # The initContainer below will install dynamic plugins in this volume mount. + - name: dynamic-plugins-root + mountPath: /opt/app-root/src/dynamic-plugins-root + - name: rbac-policy + mountPath: /opt/app-root/src/rbac + - name: rbac-conditions + mountPath: /opt/app-root/src/rbac-conditions + extraVolumes: + # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. + # To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html) + # could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). + - name: dynamic-plugins-root + emptyDir: {} + - name: rbac-policy + configMap: + defaultMode: 420 + name: rbac-policy + - name: rbac-conditions + emptyDir: {} + # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. + # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. + - name: dynamic-plugins + configMap: + defaultMode: 420 + name: dynamic-plugins + optional: true + # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) + # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + extraEnvVarsSecrets: + - rhdh-secrets + podSecurityContext: + fsGroup: 2000 + postgresql: + enabled: true + postgresqlDataDir: /var/lib/pgsql/data/userdata + image: + registry: quay.io + repository: fedora/postgresql-15 + tag: latest + auth: + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + existingSecret: null + primary: + securityContext: + enabled: false + podSecurityContext: + enabled: true + fsGroup: 3000 + containerSecurityContext: + enabled: false + persistence: + enabled: true + size: 1Gi + mountPath: /var/lib/pgsql/data + extraEnvVars: + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{ .Release.Name }}-postgresql' + volumePermissions: + enabled: true + service: + type: NodePort + ingress: + enabled: true + host: '' + annotations: + kubernetes.io/ingress.class: gce + kubernetes.io/ingress.global-static-ip-name: rhdh-static-ip + ingress.gcp.kubernetes.io/pre-shared-cert: "" + networking.gke.io/v1beta1.FrontendConfig: rhdh-gke-ingress-security-config + className: gce \ No newline at end of file diff --git a/.ibm/pipelines/value_files/diff-values_showcase_AKS.yaml b/.ibm/pipelines/value_files/diff-values_showcase_AKS.yaml new file mode 100644 index 0000000000..e6a18c8416 --- /dev/null +++ b/.ibm/pipelines/value_files/diff-values_showcase_AKS.yaml @@ -0,0 +1,28 @@ +# This file is for AKS installation only. +# It is applied by `helm upgrade` after the `values-showcase.yaml` is applied and only contains complementary differences for AKS. +# Note, that it overwrites the whole key that is present in this file. +# The only exception is global.dynamic.plugins, that gets merged with the base file. +route: + enabled: false +global: + dynamic: + plugins: + - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic + disabled: true +upstream: + backstage: + extraEnvVarsSecrets: + - rhdh-secrets + podSecurityContext: + fsGroup: 3000 + postgresql: + primary: + podSecurityContext: + enabled: true + fsGroup: 3000 + volumePermissions: + enabled: true + ingress: + enabled: true + className: webapprouting.kubernetes.azure.com + host: '' diff --git a/.ibm/pipelines/value_files/diff-values_showcase_GKE.yaml b/.ibm/pipelines/value_files/diff-values_showcase_GKE.yaml new file mode 100644 index 0000000000..defeaecd31 --- /dev/null +++ b/.ibm/pipelines/value_files/diff-values_showcase_GKE.yaml @@ -0,0 +1,34 @@ +# This file is for GKE installation only. +# It is applied by `helm upgrade` after the `values-showcase.yaml` is applied and only contains complementary differences for GKE. +# Note, that it overwrites the whole key that is present in this file. +# The only exception is global.dynamic.plugins, that gets merged with the base file. +route: + enabled: false +global: + dynamic: + plugins: + - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic + disabled: true +upstream: + backstage: + extraEnvVarsSecrets: + - rhdh-secrets + podSecurityContext: + fsGroup: 2000 + postgresql: + primary: + podSecurityContext: + enabled: true + fsGroup: 3000 + volumePermissions: + enabled: true + service: + type: NodePort + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: gce + kubernetes.io/ingress.global-static-ip-name: rhdh-static-ip + ingress.gcp.kubernetes.io/pre-shared-cert: "" + networking.gke.io/v1beta1.FrontendConfig: rhdh-gke-ingress-security-config + className: gce diff --git a/.ibm/pipelines/value_files/values_showcase-auth-provider-diff-rhbk.yaml b/.ibm/pipelines/value_files/values_showcase-auth-provider-diff-rhbk.yaml new file mode 100644 index 0000000000..b96d9a951b --- /dev/null +++ b/.ibm/pipelines/value_files/values_showcase-auth-provider-diff-rhbk.yaml @@ -0,0 +1,24 @@ +upstream: + backstage: + appConfig: + auth: + providers: + oidc: + production: + metadataUrl: ${RHBK_METADATA_URL} + clientId: ${RHBK_CLIENT_ID} + clientSecret: ${RHBK_CLIENT_SECRET} + prompt: auto + callbackUrl: ${RHBK_CALLBACK_URL} + catalog: + providers: + keycloakOrg: + default: + baseUrl: ${RHBK_URL} + loginRealm: ${AUTH_PROVIDERS_REALM_NAME} + realm: ${AUTH_PROVIDERS_REALM_NAME} + clientId: ${RHBK_CLIENT_ID} + clientSecret: ${RHBK_CLIENT_SECRET} + schedule: + frequency: { minutes: 1 } + timeout: { minutes: 1 } \ No newline at end of file diff --git a/.ibm/pipelines/value_files/values_showcase-auth-providers.yaml b/.ibm/pipelines/value_files/values_showcase-auth-providers.yaml new file mode 100644 index 0000000000..b032881d07 --- /dev/null +++ b/.ibm/pipelines/value_files/values_showcase-auth-providers.yaml @@ -0,0 +1,246 @@ +global: + dynamic: + includes: + - dynamic-plugins.default.yaml + plugins: + - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-keycloak-dynamic + disabled: true + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic + disabled: true + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-msgraph-dynamic + disabled: true + - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac + disabled: true +upstream: + backstage: + appConfig: + signInPage: oidc + auth: + environment: production + session: + secret: superSecretSecret + providers: + guest: + dangerouslyAllowOutsideDevelopment: true + microsoft: + development: + clientId: ${AUTH_PROVIDERS_AZURE_CLIENT_ID} + clientSecret: ${AUTH_PROVIDERS_AZURE_CLIENT_SECRET} + tenantId: ${AUTH_PROVIDERS_AZURE_TENANT_ID} + domainHint: ${AUTH_PROVIDERS_AZURE_TENANT_ID} + production: + clientId: ${AUTH_PROVIDERS_AZURE_CLIENT_ID} + clientSecret: ${AUTH_PROVIDERS_AZURE_CLIENT_SECRET} + tenantId: ${AUTH_PROVIDERS_AZURE_TENANT_ID} + domainHint: ${AUTH_PROVIDERS_AZURE_TENANT_ID} + github: + production: + clientSecret: ${AUTH_ORG_CLIENT_SECRET} + clientId: ${AUTH_ORG_CLIENT_ID} + oidc: + production: + metadataUrl: ${RHSSO76_METADATA_URL} + clientId: ${RHSSO76_CLIENT_ID} + clientSecret: ${RHSSO76_CLIENT_SECRET} + prompt: auto + callbackUrl: ${RHSSO76_CALLBACK_URL} + integrations: + github: + - host: github.com + apps: + - appId: ${AUTH_ORG_APP_ID} + clientId: ${AUTH_ORG_CLIENT_ID} + clientSecret: ${AUTH_ORG_CLIENT_SECRET} + privateKey: ${AUTH_ORG1_PRIVATE_KEY} + webhookSecret: ${AUTH_ORG_WEBHOOK_SECRET} + catalog: + locations: + - type: url + target: https://github.com/janus-qe/auth-providers/blob/main/location.yaml + rules: + - allow: [Component, Group, User, Resource, Location, Template] + providers: + githubOrg: + - id: github + githubUrl: https://github.com + orgs: ['${AUTH_PROVIDERS_GH_ORG_NAME}'] + schedule: + initialDelay: { seconds: 0 } + frequency: { minutes: 1 } + timeout: { minutes: 1 } + microsoftGraphOrg: + default: + target: https://graph.microsoft.com/v1.0 + authority: https://login.microsoftonline.com + tenantId: ${AUTH_PROVIDERS_AZURE_TENANT_ID} + clientId: ${AUTH_PROVIDERS_AZURE_CLIENT_ID} + clientSecret: ${AUTH_PROVIDERS_AZURE_CLIENT_SECRET} + user: + filter: accountEnabled eq true and userType eq 'member' and startswith(displayName,'QE') + group: + filter: > + securityEnabled eq true + and mailEnabled eq false + and startswith(displayName,'rhdh_test_group_') + schedule: + frequency: PT1M + timeout: PT1M + keycloakOrg: + default: + baseUrl: ${RHSSO76_URL} + loginRealm: ${AUTH_PROVIDERS_REALM_NAME} + realm: ${AUTH_PROVIDERS_REALM_NAME} + clientId: ${RHSSO76_CLIENT_ID} + clientSecret: ${RHSSO76_CLIENT_SECRET} + schedule: + frequency: { minutes: 1 } + timeout: { minutes: 1 } + permission: + enabled: true + rbac: + policyFileReload: true + policies-csv-file: './rbac/rbac-policy.csv' + admin: + users: + - name: user:default/qeadmin_rhdhtesting.onmicrosoft.com + - name: user:default/rhsso_admin + - name: user:default/rhdhqeauthadmin + backend: + auth: + externalAccess: + - type: static + options: + token: "somecicdtoken" + subject: e2e-tests-ci + extraEnvVarsSecrets: + - rhdh-secrets + image: + registry: quay.io + repository: rhdh/rhdh-hub-rhel9 + tag: 'next' + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 7007 + scheme: HTTP + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 2 + timeoutSeconds: 2 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 7007 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + extraEnvVars: + - name: BACKEND_SECRET + valueFrom: + secretKeyRef: + key: backend-secret + name: '{{ include "janus-idp.backend-secret-name" $ }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{ .Release.Name }}-postgresql' + # disable telemetry in CI + - name: SEGMENT_TEST_MODE + value: 'true' + - name: NODE_OPTIONS + value: '--no-node-snapshot' + args: + # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. + - '--config' + - dynamic-plugins-root/app-config.dynamic-plugins.yaml + extraVolumeMounts: + - mountPath: /opt/app-root/src/dynamic-plugins-root + name: dynamic-plugins-root + - name: rbac-policy + mountPath: /opt/app-root/src/rbac + extraVolumes: + - ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + name: dynamic-plugins-root + - name: rbac-policy + configMap: + defaultMode: 420 + name: rbac-policy + - configMap: + defaultMode: 420 + name: dynamic-plugins + optional: true + name: dynamic-plugins + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + initContainers: + - command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + image: '{{ include "backstage.image" . }}' + imagePullPolicy: Always + name: install-dynamic-plugins + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/dynamic-plugins.yaml + name: dynamic-plugins + readOnly: true + subPath: dynamic-plugins.yaml + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + workingDir: /opt/app-root/src + installDir: /opt/app-root/src + podAnnotations: + checksum/dynamic-plugins: >- + {{- include "common.tplvalues.render" ( dict "value" + .Values.global.dynamic "context" $) | sha256sum }} + postgresql: + enabled: true + postgresqlDataDir: /var/lib/pgsql/data/userdata + image: + registry: quay.io + repository: fedora/postgresql-15 + tag: latest + auth: + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + primary: + securityContext: + enabled: false + podSecurityContext: + enabled: false + containerSecurityContext: + enabled: false + persistence: + enabled: false + size: 1Gi + mountPath: /var/lib/pgsql/data + extraEnvVars: + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{ .Release.Name }}-postgresql' + ingress: + host: '{{ .Values.global.host }}' diff --git a/.ibm/pipelines/value_files/values_showcase-rbac.yaml b/.ibm/pipelines/value_files/values_showcase-rbac.yaml index 77b19cd306..59edfc5c28 100644 --- a/.ibm/pipelines/value_files/values_showcase-rbac.yaml +++ b/.ibm/pipelines/value_files/values_showcase-rbac.yaml @@ -12,117 +12,101 @@ global: # an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin # listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). plugins: - - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic - disabled: false - pluginConfig: - catalog: - providers: - github: - my-test-org: - organization: janus-qe - catalogPath: '/catalog-info.yaml' - schedule: - frequency: - minutes: 1 - timeout: - minutes: 1 - initialDelay: - seconds: 15 - - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-github-issues - disabled: false - - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-github-actions - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-quay - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-keycloak-backend-dynamic - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-tekton - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic - disabled: false - pluginConfig: - kubernetes: - clusterLocatorMethods: - - clusters: + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic + disabled: false + pluginConfig: + catalog: + providers: + github: + my-test-org: + organization: janus-qe + catalogPath: '/catalog-info.yaml' + schedule: + frequency: + minutes: 1 + timeout: + minutes: 1 + initialDelay: + seconds: 15 + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-github-issues + disabled: false + - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-github-actions + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-quay + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-keycloak-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-tekton + disabled: false + - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes + disabled: false + - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic + disabled: false + pluginConfig: + kubernetes: + clusterLocatorMethods: + - clusters: - authProvider: serviceAccount name: 'my-cluster' serviceAccountToken: ${K8S_SERVICE_ACCOUNT_TOKEN} url: ${K8S_CLUSTER_API_SERVER_URL} - type: config - customResources: - # Add for tekton - - apiVersion: 'v1beta1' - group: 'tekton.dev' - plural: 'pipelines' - - apiVersion: v1beta1 - group: tekton.dev - plural: pipelineruns - - apiVersion: v1beta1 - group: tekton.dev - plural: taskruns - # Add for topology plugin - - apiVersion: 'v1' - group: 'route.openshift.io' - plural: 'routes' - # Add to view topology code decorators - - group: 'org.eclipse.che' - apiVersion: 'v2' - plural: 'checlusters' - serviceLocatorMethod: - type: multiTenant - # Enable OCM plugins. - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm-backend-dynamic - disabled: false - pluginConfig: - catalog: - providers: - ocm: - default: - name: testCluster # Can be any arbitrary name supported by kubernetes - url: ${OCM_CLUSTER_URL} - serviceAccountToken: ${OCM_CLUSTER_TOKEN} - skipTLSVerify: true - owner: janus-authors - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm - disabled: false - # Enable Bulk import plugins. - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-bulk-import-backend-dynamic - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-bulk-import - disabled: false - # Enable tech-radar plugin. - - package: ./dynamic-plugins/dist/backstage-plugin-tech-radar - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-acr - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-rbac - disabled: false - - package: './dynamic-plugins/dist/janus-idp-backstage-plugin-analytics-provider-segment' - disabled: true - - - # this value will be overriden by 'helm install .... --set global.clusterRouterBase=value' - # -- Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled. - clusterRouterBase: apps.example.com - # -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig` - host: '' - # -- Enable service authentication within Backstage instance - auth: - # -- Backend service to service authentication - #
Ref: https://backstage.io/docs/auth/service-to-service-auth/ - backend: - # -- Enable backend service to service authentication, unless configured otherwise it generates a secret value - enabled: true - # -- Instead of generating a secret value, refer to existing secret - existingSecret: '' - # -- Instead of generating a secret value, use fo;lowing value - value: '' + type: config + customResources: + # Add for tekton + - apiVersion: 'v1beta1' + group: 'tekton.dev' + plural: 'pipelines' + - apiVersion: v1beta1 + group: tekton.dev + plural: pipelineruns + - apiVersion: v1beta1 + group: tekton.dev + plural: taskruns + # Add for topology plugin + - apiVersion: 'v1' + group: 'route.openshift.io' + plural: 'routes' + # Add to view topology code decorators + - group: 'org.eclipse.che' + apiVersion: 'v2' + plural: 'checlusters' + serviceLocatorMethod: + type: multiTenant + # Enable OCM plugins. + - package: ./dynamic-plugins/dist/backstage-community-plugin-ocm-backend-dynamic + disabled: false + pluginConfig: + catalog: + providers: + ocm: + default: + name: testCluster # Can be any arbitrary name supported by kubernetes + url: ${OCM_CLUSTER_URL} + serviceAccountToken: ${OCM_CLUSTER_TOKEN} + skipTLSVerify: true + owner: janus-authors + - package: ./dynamic-plugins/dist/backstage-community-plugin-ocm + disabled: false + # Enable Bulk import plugins. + - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic + disabled: false + - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import + disabled: false + - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page + disabled: true + # Enable tech-radar plugin. + - package: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic + disabled: true + - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment + disabled: true # -- Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) # @default -- Use Openshift compatible settings @@ -133,20 +117,10 @@ upstream: backstage: image: pullPolicy: Always - pullSecrets: - - rhdh-pull-secret # using test image from https://quay.io/repository/janus-idp/backstage-showcase registry: quay.io repository: janus-idp/backstage-showcase tag: next - command: [] - # FIXME (tumido): USE POSTGRES_PASSWORD and POSTGRES_USER instead of POSTGRES_ADMIN_PASSWORD - # This is a hack. In {fedora,rhel}/postgresql images, regular user is forbidden - # from creating DBs in runtime. A single DB can be created ahead of time via - # POSTGRESQL_DATABASE env variable (in this case via - # upstream.postgresql.primary.extraEnvVars value), but this doesn't allow us to - # create multiple DBs. Since Backstage requires by default 5 different DBs, we - # can't accommodate that properly. appConfig: app: # Please update to match host in case you don't want to configure hostname via `global.clusterRouterBase` or `global.host`. @@ -156,7 +130,7 @@ upstream: cors: origin: 'https://{{- include "janus-idp.hostname" . }}' database: - connection: # configure Backstage DB connection parameters + connection: # configure Backstage DB connection parameters host: ${POSTGRES_HOST} port: ${POSTGRES_PORT} user: ${POSTGRES_USER} @@ -172,26 +146,6 @@ upstream: auth: keys: - secret: ${BACKEND_SECRET} - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 7007 - scheme: HTTP - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 2 - timeoutSeconds: 2 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 7007 - scheme: HTTP - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 2 extraEnvVars: - name: BACKEND_SECRET valueFrom: @@ -201,16 +155,14 @@ upstream: # disable telemetry in CI - name: SEGMENT_TEST_MODE value: 'true' - args: - # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. - - '--config' - - dynamic-plugins-root/app-config.dynamic-plugins.yaml extraVolumeMounts: # The initContainer below will install dynamic plugins in this volume mount. - name: dynamic-plugins-root mountPath: /opt/app-root/src/dynamic-plugins-root - name: rbac-policy mountPath: /opt/app-root/src/rbac + - name: rbac-conditions + mountPath: /opt/app-root/src/rbac-conditions - mountPath: /opt/app-root/src/postgres-crt.pem name: postgress-external-db-cluster-cert subPath: tls.crt @@ -226,11 +178,6 @@ upstream: # could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). - name: dynamic-plugins-root emptyDir: {} - - name: rbac-policy - configMap: - defaultMode: 420 - name: rbac-policy - # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. - name: dynamic-plugins @@ -248,6 +195,12 @@ upstream: - name: postgress-external-db-cluster-cert secret: secretName: postgress-external-db-cluster-cert + - name: rbac-policy + configMap: + defaultMode: 420 + name: rbac-policy + - name: rbac-conditions + emptyDir: {} initContainers: - name: install-dynamic-plugins # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. @@ -255,9 +208,41 @@ upstream: # @default -- `quay.io/janus-idp/backstage-showcase:latest` image: '{{ include "backstage.image" . }}' command: - - python - - install-dynamic-plugins.py - - /dynamic-plugins-root + - sh + - '-c' + - | + cat > /rbac-conditions/conditional-policies.yaml <- - {{- include "common.tplvalues.render" ( dict "value" - .Values.global.dynamic "context" $) | sha256sum }} extraAppConfig: - configMapRef: app-config-rhdh filename: app-config-rhdh.yaml @@ -289,5 +274,3 @@ upstream: enabled: false auth: existingSecret: postgres-cred - ingress: - host: '{{ .Values.global.host }}' diff --git a/.ibm/pipelines/value_files/values_showcase.yaml b/.ibm/pipelines/value_files/values_showcase.yaml index 1c9c5535c9..d4ad325217 100644 --- a/.ibm/pipelines/value_files/values_showcase.yaml +++ b/.ibm/pipelines/value_files/values_showcase.yaml @@ -12,127 +12,110 @@ global: # an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin # listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). plugins: - - package: ./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-github-dynamic - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic - disabled: false - pluginConfig: - catalog: - providers: - github: - my-test-org: - organization: janus-qe - catalogPath: '/catalog-info.yaml' - schedule: - frequency: - minutes: 1 - timeout: - minutes: 1 - initialDelay: - seconds: 15 - - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-github-issues - disabled: false - - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-github-actions - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-quay - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-keycloak-backend-dynamic - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-tekton - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic - disabled: false - pluginConfig: - kubernetes: - clusterLocatorMethods: - - clusters: + - package: ./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-github-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic + disabled: false + pluginConfig: + catalog: + providers: + github: + my-test-org: + organization: janus-qe + catalogPath: '/catalog-info.yaml' + schedule: + frequency: + minutes: 1 + timeout: + minutes: 1 + initialDelay: + seconds: 15 + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-github-issues + disabled: false + - package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-github-actions + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-quay + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-keycloak-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-tekton + disabled: false + - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes + disabled: false + - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic + disabled: false + pluginConfig: + kubernetes: + clusterLocatorMethods: + - clusters: - authProvider: serviceAccount name: 'my-cluster' serviceAccountToken: ${K8S_CLUSTER_TOKEN_ENCODED} url: ${K8S_CLUSTER_API_SERVER_URL} - type: config - customResources: - # Add for tekton - - apiVersion: 'v1beta1' - group: 'tekton.dev' - plural: 'pipelines' - - apiVersion: v1beta1 - group: tekton.dev - plural: pipelineruns - - apiVersion: v1beta1 - group: tekton.dev - plural: taskruns - # Add for topology plugin - - apiVersion: 'v1' - group: 'route.openshift.io' - plural: 'routes' - serviceLocatorMethod: - type: multiTenant - # Enable OCM plugins. - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm-backend-dynamic - disabled: false - pluginConfig: - catalog: - providers: - ocm: - default: - name: testCluster # Can be any arbitrary name supported by kubernetes - url: ${OCM_CLUSTER_URL} - serviceAccountToken: ${OCM_CLUSTER_TOKEN} - skipTLSVerify: true - owner: janus-authors - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm - disabled: false - # Enable bulk import plugins. - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-bulk-import-backend-dynamic - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-bulk-import - disabled: false - # Enable tech-radar plugin. - - package: ./dynamic-plugins/dist/backstage-plugin-tech-radar - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-acr - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-rbac - disabled: true - - package: ./dynamic-plugins/dist/roadiehq-scaffolder-backend-module-http-request-dynamic - disabled: false - - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic - disabled: false - - package: ./dynamic-plugins/dist/immobiliarelabs-backstage-plugin-gitlab-backend-dynamic - disabled: false - - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-dynamic - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-topology - disabled: false - - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-aap-backend-dynamic - disabled: false - - # this value will be overriden by 'helm install .... --set global.clusterRouterBase=value' - # -- Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled. - clusterRouterBase: apps.example.com - # -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig` - host: '' - # -- Enable service authentication within Backstage instance - auth: - # -- Backend service to service authentication - #
Ref: https://backstage.io/docs/auth/service-to-service-auth/ - backend: - # -- Enable backend service to service authentication, unless configured otherwise it generates a secret value - enabled: true - # -- Instead of generating a secret value, refer to existing secret - existingSecret: '' - # -- Instead of generating a secret value, use fo;lowing value - value: '' + type: config + customResources: + # Add for tekton + - apiVersion: 'v1' + group: 'tekton.dev' + plural: 'pipelines' + - apiVersion: v1 + group: tekton.dev + plural: pipelineruns + - apiVersion: v1 + group: tekton.dev + plural: taskruns + # Add for topology plugin + - apiVersion: 'v1' + group: 'route.openshift.io' + plural: 'routes' + serviceLocatorMethod: + type: multiTenant + # Enable OCM plugins. + - package: ./dynamic-plugins/dist/backstage-community-plugin-ocm-backend-dynamic + disabled: false + pluginConfig: + catalog: + providers: + ocm: + default: + name: testCluster # Can be any arbitrary name supported by kubernetes + url: ${OCM_CLUSTER_URL} + serviceAccountToken: ${OCM_CLUSTER_TOKEN} + skipTLSVerify: true + owner: janus-authors + - package: ./dynamic-plugins/dist/backstage-community-plugin-ocm + disabled: false + # Enable bulk import plugins. + - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic + disabled: false + - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import + disabled: false + # Enable tech-radar plugins. + - package: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-acr + disabled: false + - package: ./dynamic-plugins/dist/roadiehq-scaffolder-backend-module-http-request-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic + disabled: false + - package: ./dynamic-plugins/dist/immobiliarelabs-backstage-plugin-gitlab-backend-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-dynamic + disabled: false + - package: ./dynamic-plugins/dist/backstage-community-plugin-topology + disabled: false + - package: '@pataknight/backstage-plugin-rhdh-qe-theme@0.5.5' + disabled: false + integrity: sha512-srTnFDYn3Ett6z33bX4nL2NQY8wqux8TkpgBQNsE8S73nMfsor/wAdmVgHL+xW7pxQ09DT4YTdaG3GkH+cyyNQ== # -- Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) -# @default -- Use Openshift compatible settings upstream: nameOverride: backstage commonLabels: @@ -140,55 +123,9 @@ upstream: backstage: image: pullPolicy: Always - pullSecrets: - - rhdh-pull-secret - # using test image from https://quay.io/repository/janus-idp/backstage-showcase registry: quay.io repository: janus-idp/backstage-showcase tag: next - command: [] - # FIXME (tumido): USE POSTGRES_PASSWORD and POSTGRES_USER instead of POSTGRES_ADMIN_PASSWORD - # This is a hack. In {fedora,rhel}/postgresql images, regular user is forbidden - # from creating DBs in runtime. A single DB can be created ahead of time via - # POSTGRESQL_DATABASE env variable (in this case via - # upstream.postgresql.primary.extraEnvVars value), but this doesn't allow us to - # create multiple DBs. Since Backstage requires by default 5 different DBs, we - # can't accommodate that properly. - appConfig: - app: - # Please update to match host in case you don't want to configure hostname via `global.clusterRouterBase` or `global.host`. - baseUrl: 'https://{{- include "janus-idp.hostname" . }}' - backend: - baseUrl: 'https://{{- include "janus-idp.hostname" . }}' - cors: - origin: 'https://{{- include "janus-idp.hostname" . }}' - database: - connection: - password: ${POSTGRESQL_ADMIN_PASSWORD} - user: postgres - auth: - keys: - - secret: ${BACKEND_SECRET} - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 7007 - scheme: HTTP - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 2 - timeoutSeconds: 2 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 7007 - scheme: HTTP - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 2 extraEnvVars: - name: BACKEND_SECRET valueFrom: @@ -205,105 +142,11 @@ upstream: value: 'true' - name: NODE_OPTIONS value: '--no-node-snapshot' - args: - # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. - - '--config' - - dynamic-plugins-root/app-config.dynamic-plugins.yaml - extraVolumeMounts: - # The initContainer below will install dynamic plugins in this volume mount. - - name: dynamic-plugins-root - mountPath: /opt/app-root/src/dynamic-plugins-root - - name: rbac-policy - mountPath: /opt/app-root/src/rbac - extraVolumes: - # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. - # To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html) - # could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). - - name: dynamic-plugins-root - emptyDir: {} - - name: rbac-policy - configMap: - defaultMode: 420 - name: rbac-policy - - # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. - # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. - - name: dynamic-plugins - configMap: - defaultMode: 420 - name: dynamic-plugins - optional: true - # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) - # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. - - name: dynamic-plugins-npmrc - secret: - defaultMode: 420 - optional: true - secretName: dynamic-plugins-npmrc - initContainers: - - name: install-dynamic-plugins - # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. - # It could be replaced by a custom image based on this one. - # @default -- `quay.io/janus-idp/backstage-showcase:latest` - image: '{{ include "backstage.image" . }}' - command: - - python - - install-dynamic-plugins.py - - /dynamic-plugins-root - env: - - name: NPM_CONFIG_USERCONFIG - value: /opt/app-root/src/.npmrc.dynamic-plugins - imagePullPolicy: Always - volumeMounts: - - mountPath: /dynamic-plugins-root - name: dynamic-plugins-root - - mountPath: /opt/app-root/src/dynamic-plugins.yaml - name: dynamic-plugins - readOnly: true - subPath: dynamic-plugins.yaml - - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins - name: dynamic-plugins-npmrc - readOnly: true - subPath: .npmrc - workingDir: /opt/app-root/src - installDir: /opt/app-root/src - podAnnotations: - checksum/dynamic-plugins: >- - {{- include "common.tplvalues.render" ( dict "value" - .Values.global.dynamic "context" $) | sha256sum }} extraAppConfig: - configMapRef: app-config-rhdh filename: app-config-rhdh.yaml extraEnvVarsSecrets: - rhdh-secrets - redis-secret - postgresql: - enabled: true - postgresqlDataDir: /var/lib/pgsql/data/userdata - image: - registry: quay.io - repository: fedora/postgresql-15 - tag: latest - auth: - secretKeys: - adminPasswordKey: postgres-password - userPasswordKey: password - primary: - securityContext: - enabled: false - podSecurityContext: - enabled: false - containerSecurityContext: - enabled: false - persistence: - enabled: true - size: 1Gi - mountPath: /var/lib/pgsql/data - extraEnvVars: - - name: POSTGRESQL_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - key: postgres-password - name: '{{ .Release.Name }}-postgresql' ingress: host: '{{ .Values.global.host }}' diff --git a/.nvmrc b/.nvmrc index 3516580bbb..d4b7699d36 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.17.0 +20.18.1 diff --git a/.rhdh/docker/Dockerfile b/.rhdh/docker/Dockerfile index 3c5361d2af..180ddd505c 100644 --- a/.rhdh/docker/Dockerfile +++ b/.rhdh/docker/Dockerfile @@ -1,5 +1,7 @@ +# THIS IS USED BY OSBS BUILDS <=1.3 +# FOR KONFLUX >=1.4, see ../../docker/Dockerfile # -# Copyright (c) 2023 Red Hat, Inc. +# Copyright (c) 2023-2024 Red Hat, Inc. # 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 @@ -20,7 +22,8 @@ # Stage 1 - Build nodejs skeleton #@follow_tag(registry.access.redhat.com/ubi9/nodejs-20:1) -FROM registry.access.redhat.com/ubi9/nodejs-20:1-54 AS build +# https://registry.access.redhat.com/ubi9/nodejs-20 +FROM registry.access.redhat.com/ubi9/nodejs-20:9.5-1731603589 AS build # hadolint ignore=DL3002 USER 0 @@ -37,24 +40,101 @@ ENV EXTERNAL_SOURCE_NESTED=$REMOTE_SOURCES/upstream1/app/distgit/containers/rhdh ENV CONTAINER_SOURCE=$REMOTE_SOURCES_DIR # Env vars -ENV YARN=$CONTAINER_SOURCE/.yarn/releases/yarn-1.22.19.cjs +ENV YARN=$CONTAINER_SOURCE/.yarn/releases/yarn-3.8.6.cjs WORKDIR $CONTAINER_SOURCE/ COPY $EXTERNAL_SOURCE_NESTED/.yarn ./.yarn COPY $EXTERNAL_SOURCE_NESTED/.yarnrc.yml ./ -RUN chmod +x "$YARN" + +# Add execute permissions to yarn; add yarn to path via symlink +RUN chmod +x "$YARN" && ln -s "$YARN" /usr/local/bin/yarn # Stage 2 - Install dependencies -COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/ ./dynamic-plugins/ -COPY $EXTERNAL_SOURCE_NESTED/package.json $EXTERNAL_SOURCE_NESTED/yarn.lock ./ -COPY $EXTERNAL_SOURCE_NESTED/patches/ ./patches/ -COPY $EXTERNAL_SOURCE_NESTED/packages/app/package.json ./packages/app/package.json -COPY $EXTERNAL_SOURCE_NESTED/packages/backend/package.json ./packages/backend/package.json +COPY $EXTERNAL_SOURCE_NESTED/yarn.lock ./ +# BEGIN COPY package.json files COPY $EXTERNAL_SOURCE_NESTED/plugins/scalprum-backend/package.json ./plugins/scalprum-backend/package.json +COPY $EXTERNAL_SOURCE_NESTED/plugins/licensed-users-info-backend/package.json ./plugins/licensed-users-info-backend/package.json COPY $EXTERNAL_SOURCE_NESTED/plugins/dynamic-plugins-info/package.json ./plugins/dynamic-plugins-info/package.json COPY $EXTERNAL_SOURCE_NESTED/plugins/dynamic-plugins-info-backend/package.json ./plugins/dynamic-plugins-info-backend/package.json -COPY $EXTERNAL_SOURCE_NESTED/plugins/auth-backend-module-oidc-provider/package.json ./plugins/auth-backend-module-oidc-provider/package.json -COPY $EXTERNAL_SOURCE_NESTED/plugins/licensed-users-info-backend/package.json ./plugins/licensed-users-info-backend/package.json +COPY $EXTERNAL_SOURCE_NESTED/packages/backend/package.json ./packages/backend/package.json +COPY $EXTERNAL_SOURCE_NESTED/packages/app/package.json ./packages/app/package.json +COPY $EXTERNAL_SOURCE_NESTED/package.json ./package.json +COPY $EXTERNAL_SOURCE_NESTED/e2e-tests/package.json ./e2e-tests/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/_utils/package.json ./dynamic-plugins/_utils/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-utils-dynamic/package.json ./dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-utils-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-http-request-dynamic/package.json ./dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-http-request-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-scaffolder-backend-argocd-dynamic/package.json ./dynamic-plugins/wrappers/roadiehq-scaffolder-backend-argocd-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-security-insights/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-security-insights/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-jira/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-jira/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-github-pull-requests/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-github-pull-requests/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-github-insights/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-github-insights/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-datadog/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-datadog/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-argo-cd/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-argo-cd/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-backstage-plugin-argo-cd-backend-dynamic/package.json ./dynamic-plugins/wrappers/roadiehq-backstage-plugin-argo-cd-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-dynamic-home-page/package.json ./dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-dynamic-home-page/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-bulk-import/package.json ./dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-bulk-import/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic/package.json ./dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/parfuemerie-douglas-scaffolder-backend-module-azure-repositories-dynamic/package.json ./dynamic-plugins/wrappers/parfuemerie-douglas-scaffolder-backend-module-azure-repositories-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/pagerduty-backstage-plugin/package.json ./dynamic-plugins/wrappers/pagerduty-backstage-plugin/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/pagerduty-backstage-plugin-backend-dynamic/package.json ./dynamic-plugins/wrappers/pagerduty-backstage-plugin-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/janus-idp-backstage-plugin-aap-backend-dynamic/package.json ./dynamic-plugins/wrappers/janus-idp-backstage-plugin-aap-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/immobiliarelabs-backstage-plugin-gitlab/package.json ./dynamic-plugins/wrappers/immobiliarelabs-backstage-plugin-gitlab/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/immobiliarelabs-backstage-plugin-gitlab-backend-dynamic/package.json ./dynamic-plugins/wrappers/immobiliarelabs-backstage-plugin-gitlab-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-techdocs/package.json ./dynamic-plugins/wrappers/backstage-plugin-techdocs/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-techdocs-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-techdocs-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-signals/package.json ./dynamic-plugins/wrappers/backstage-plugin-signals/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-signals-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-signals-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-gitlab-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-gitlab-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-github-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-github-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-gerrit-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-gerrit-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-bitbucket-server-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-bitbucket-server-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-bitbucket-cloud-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-bitbucket-cloud-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-azure-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-scaffolder-backend-module-azure-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-notifications/package.json ./dynamic-plugins/wrappers/backstage-plugin-notifications/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-notifications-backend-module-email-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-notifications-backend-module-email-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-notifications-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-notifications-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-kubernetes/package.json ./dynamic-plugins/wrappers/backstage-plugin-kubernetes/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-kubernetes-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-kubernetes-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-msgraph-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-msgraph-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-ldap-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-ldap-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-gitlab-org-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-gitlab-org-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-gitlab-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-gitlab-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-github-org-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-github-org-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-github-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-github-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-bitbucket-server-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-bitbucket-server-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-bitbucket-cloud-dynamic/package.json ./dynamic-plugins/wrappers/backstage-plugin-catalog-backend-module-bitbucket-cloud-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-topology/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-topology/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-tekton/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-tekton/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-tech-radar/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-tech-radar/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-tech-radar-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-tech-radar-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-sonarqube/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-sonarqube/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-sonarqube-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-sonarqube-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-sonarqube-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-sonarqube-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-servicenow-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-servicenow-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-regex-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-regex-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-quay-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-scaffolder-backend-module-quay-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-redhat-argocd/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-redhat-argocd/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-rbac/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-rbac/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-quay/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-quay/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-ocm/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-ocm/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-ocm-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-ocm-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-nexus-repository-manager/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-nexus-repository-manager/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-lighthouse/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-lighthouse/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-jfrog-artifactory/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-jfrog-artifactory/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-jenkins/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-jenkins/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-jenkins-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-jenkins-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-github-issues/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-github-issues/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-github-actions/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-github-actions/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-dynatrace/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-dynatrace/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-catalog-backend-module-pingidentity-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-catalog-backend-module-pingidentity-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-catalog-backend-module-keycloak-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-catalog-backend-module-keycloak-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-azure-devops/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-azure-devops/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-azure-devops-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-azure-devops-backend-dynamic/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-analytics-provider-segment/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-analytics-provider-segment/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-acr/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-acr/package.json +COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-3scale-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-3scale-backend-dynamic/package.json +# END COPY package.json files # Downstream only - debugging # COPY $REMOTE_SOURCES/ ./ @@ -82,38 +162,37 @@ COPY $REMOTE_SOURCES/upstream1/cachito.env \ # NOTE: this is overridden to "/remote-source/registry-ca.pem" below # hadolint ignore=SC1091,SC2046 RUN \ - # debug - # cat $CONTAINER_SOURCE/cachito.env; \ - # load envs - source "$CONTAINER_SOURCE/cachito.env"; \ - \ - # load cert - cert_path="$CONTAINER_SOURCE/registry-ca.pem"; \ - # debug - # ls -la "${cert_path}"; \ - npm config set cafile "${cert_path}"; "$YARN" config set cafile "${cert_path}" -g; \ - \ - # set longer timeouts - # npm config set fetch-retry-maxtimeout 6000000; \ - # npm config set fetch-retry-mintimeout 1000000; \ - "$YARN" config set network-timeout 600000 -g; \ - # set cachito as default registry - "$YARN" config set registry $(npm config get registry) -g; \ - \ - # debug - # ls -l /usr/; \ - # set up node dir with common.gypi and unsafe-perms=true - ln -s /usr/include/node/common.gypi /usr/common.gypi; "$YARN" config set nodedir /usr; "$YARN" config set unsafe-perm true; \ - \ - # add yarn to path via symlink - ln -s "$CONTAINER_SOURCE"/"$YARN" /usr/local/bin/yarn + # debug + # cat $CONTAINER_SOURCE/cachito.env; \ + # load envs + source "$CONTAINER_SOURCE/cachito.env"; \ + \ + # load cert + cert_path="$CONTAINER_SOURCE/registry-ca.pem"; \ + # debug + # ls -la "${cert_path}"; \ + npm config set cafile "${cert_path}"; "$YARN" config set cafile "${cert_path}" -g; \ + \ + # set longer timeouts + # npm config set fetch-retry-maxtimeout 6000000; \ + # npm config set fetch-retry-mintimeout 1000000; \ + # set cachito as default registry + "$YARN" config set registry $(npm config get registry) -g; \ + \ + # debug + # ls -l /usr/; \ + # set up node dir with common.gypi and unsafe-perms=true + ln -s /usr/include/node/common.gypi /usr/common.gypi; "$YARN" config set nodedir /usr; "$YARN" config set unsafe-perm true # Downstream only - debug # RUN echo $PATH; ls -la /usr/local/bin/yarn; whereis yarn;which yarn; yarn --version; \ - # cat "$CONTAINER_SOURCE"/.npmrc || true; \ - # "$YARN" config list --verbose; npm config list; npm config list -l +# cat "$CONTAINER_SOURCE"/.npmrc || true; \ +# "$YARN" config list --verbose; npm config list; npm config list -l + +# Increate timeout for yarn install +RUN "$YARN" config set httpTimeout 600000 -RUN "$YARN" install --frozen-lockfile --network-timeout 600000 +RUN "$YARN" install --immutable # Stage 3 - Build packages COPY $EXTERNAL_SOURCE_NESTED ./ @@ -129,30 +208,27 @@ COPY packages/app/src/build-metadata.json ./packages/app/src/ RUN \ # Downstream only - relabel upstream + append build time into packages/app/src/build-metadata.json now=$(date -u +%FT%TZ); sed -i packages/app/src/build-metadata.json -r \ - -e "s/\"Last Commit: (.+)\"/\"Upstream: \1\", \"Build Time: $now\"/" && \ + -e "s/\"Last Commit: (.+)\"/\"Upstream: \1\", \"Build Time: $now\"/" && \ cat packages/app/src/build-metadata.json; echo && \ "$YARN" build --filter=backend && \ - # Build dynamic plugins: yarn.lock files need to be present in order to transform to point to cachito URLs - "$YARN" --cwd ./dynamic-plugins/imports export-dynamic --no-install && \ # Downstream only - replace registry refs with cachito ones cachitoRegistry=$(npm config get registry); echo "cachito registry: $cachitoRegistry"; \ - for d in $(find . -name yarn.lock); do echo; echo "===== $d ====="; \ - sed -i "$d" -r -e "s#(https://registry.yarnpkg.com|https://registry.npmjs.org)#${cachitoRegistry}#g"; \ - grep resolved "$d" | head -1; echo "Total $(grep resolved $d | wc -l) resolution lines in $d"; \ - done; \ + for d in $(find . -name yarn.lock); do echo; echo "===== $d ====="; \ + sed -i "$d" -r -e "s#(https://registry.yarnpkg.com|https://registry.npmjs.org)#${cachitoRegistry}#g"; \ + grep resolved "$d" | head -1; echo "Total $(grep resolved $d | wc -l) resolution lines in $d"; \ + done; \ # Already imported the packages above; need to `yarn install` on the `dist-dynamic` sub-folder for backend plugins - "$YARN" --cwd ./dynamic-plugins/imports install-dynamic && \ - "$YARN" export-dynamic -- --filter=./dynamic-plugins/wrappers/* && \ + "$YARN" export-dynamic --filter=./dynamic-plugins/wrappers/* && \ "$YARN" copy-dynamic-plugins dist # Downstream only - debug # hadolint ignore=SC3010,DL4006 RUN echo "=== Check for yarn.lock files that don't use cachito registry ===>"; \ - for d in $(find . -name yarn.lock); do \ - found=$(grep -E "yarnpkg.com|npmjs.org" "$d" | head -1); \ - if [[ "$found" ]]; then echo;echo "$d : $found"; fi; \ - done; \ - echo "<=== Check for yarn.lock files that don't use cachito registry ===" + for d in $(find . -name yarn.lock); do \ + found=$(grep -E "yarnpkg.com|npmjs.org" "$d" | head -1); \ + if [[ "$found" ]]; then echo;echo "$d : $found"; fi; \ + done; \ + echo "<=== Check for yarn.lock files that don't use cachito registry ===" # Downstream only - clean up dynamic plugins sources: # Only keep the dist sub-folder in the dynamic-plugins folder @@ -166,7 +242,6 @@ ENV TARBALL_PATH=./packages/backend/dist RUN tar xzf "$TARBALL_PATH"/skeleton.tar.gz; tar xzf "$TARBALL_PATH"/bundle.tar.gz; \ rm -f "$TARBALL_PATH"/skeleton.tar.gz "$TARBALL_PATH"/bundle.tar.gz -COPY $EXTERNAL_SOURCE_NESTED/patches/ ./patches/ # Copy app-config files needed in runtime # Upstream only @@ -175,11 +250,17 @@ COPY $EXTERNAL_SOURCE_NESTED/patches/ ./patches/ # Install production dependencies # hadolint ignore=DL3059 -RUN "$YARN" install --frozen-lockfile --production --network-timeout 600000 +RUN "$YARN" workspaces focus --all --production && \ + # delete all the nested .npmrc files and set default values + find . -type f -name .npmrc -exec rm -Rf {} \; && \ + # reset npm config to the default registry and absolute path to .pem file + npm config set registry=https://registry.npmjs.org/ && \ + npm config set cafile /opt/app-root/src/registry-ca.pem # Stage 5 - Build the runner image #@follow_tag(registry.access.redhat.com/ubi9/nodejs-20-minimal:1) -FROM registry.access.redhat.com/ubi9/nodejs-20-minimal:1-57 AS runner +# https://registry.access.redhat.com/ubi9/nodejs-20-minimal +FROM registry.access.redhat.com/ubi9/nodejs-20-minimal:9.5-1730525319 AS runner USER 0 # Downstream sources @@ -219,14 +300,13 @@ COPY --from=build --chown=1001:1001 "$REMOTE_SOURCES_DIR"/ ./ # Downstream only - copy embedded dynamic plugins from "$REMOTE_SOURCES_DIR" COPY --from=build "$REMOTE_SOURCES_DIR"/dynamic-plugins/dist/ ./dynamic-plugins/dist/ -# include patch files in final container just for reference -COPY $EXTERNAL_SOURCE_NESTED/patches/ ./patches/ +# RHIDP-4220 - make Konflux preflight and EC checks happy - [check-container] Create a directory named /licenses and include all relevant licensing +COPY $EXTERNAL_SOURCE/LICENSE /licenses/ # Copy script to gather dynamic plugins; copy embedded dynamic plugins to root folder; fix permissions COPY docker/install-dynamic-plugins.py docker/install-dynamic-plugins.sh ./ RUN chmod -R a+r ./dynamic-plugins/ ./install-dynamic-plugins.py; \ - chmod -R a+rx ./install-dynamic-plugins.sh; \ - rm -fr dynamic-plugins-root && cp -R dynamic-plugins/dist/ dynamic-plugins-root + chmod -R a+rx ./install-dynamic-plugins.sh; # Downstream only - fix for https://issues.redhat.com/browse/RHIDP-728 RUN mkdir /opt/app-root/src/.npm @@ -247,20 +327,30 @@ ENV CHOKIDAR_USEPOLLING='1' CHOKIDAR_INTERVAL='10000' ENV NPM_CONFIG_ignore-scripts='true' # gGVM6sYRK0D0ndVX22BOtS7NRcxPej8t is key for dev environment -# Use production key in stable 1.yy.x branch; use dev key in main for CI/next builds +# Use production key in stable release-1.yy branch; use dev key in main for CI/next builds ENV SEGMENT_WRITE_KEY=gGVM6sYRK0D0ndVX22BOtS7NRcxPej8t ENV SEGMENT_TEST_MODE=false -# RHIDP-2217: corporate proxy support (configured using 'global-agent') +# RHIDP-2217: corporate proxy support (configured using 'global-agent' for 'node-fetch' calls and 'undici' for 'fetch' calls) # This is to avoid having to define several environment variables for the same purpose, # i.e, GLOBAL_AGENT_HTTP(S)_PROXY (for 'global-agent') and the conventional HTTP(S)_PROXY (honored by other libraries like Axios). # By setting GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE to an empty value, # 'global-agent' will use the same HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables. ENV GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE='' +# RHDHBUGS-106,RHIDP-4646: requests to the loopback interface should bypass the corporate proxy if set. +# Note that NO_PROXY will take effect only if the 'HTTP(S)_PROXY' environment variables are set. +# Users can still override this when running the image. +ENV NO_PROXY='localhost,127.0.0.1' + # The `--no-node-snapshot` node option enables the usage of the backstage scaffolder on nodejs 20 # https://github.com/backstage/backstage/issues/20661 -ENTRYPOINT ["node", "packages/backend", "--no-node-snapshot", "--config", "app-config.yaml", "--config", "app-config.example.yaml", "--config", "app-config.example.production.yaml"] +# Copy instrumentation needed for surfacing metrics +COPY --chown=1001:1001 $EXTERNAL_SOURCE_NESTED/packages/backend/src/instrumentation.js ./ +# Remove write and execute permissions +RUN chmod a=r ./instrumentation.js + +ENTRYPOINT ["node", "--require", "./instrumentation.js", "packages/backend", "--no-node-snapshot", "--config", "app-config.yaml", "--config", "app-config.example.yaml", "--config", "app-config.example.production.yaml"] # append Brew metadata here diff --git a/.sonarcloud.properties b/.sonarcloud.properties index 5bc44f69b6..1683112c39 100644 --- a/.sonarcloud.properties +++ b/.sonarcloud.properties @@ -1,2 +1,9 @@ +# everything in this repo falls under source analysis +sonar.sources = . +# exclude all tests and fixtures from source analysis +sonar.exclusions = e2e-tests/**/*, **/*.test.*, **/__fixtures__/*, +# apply test scope analysis to e2e tests and unit tests +sonar.tests = e2e-tests/**/*, **/*.test.* + # comma delimited path of files to exclude from copy/paste duplicate checking -sonar.cpd.exclusions=packages/app/src/components/DynamicRoot/DynamicRoot.test.tsx,packages/app/src/components/admin/AdminTabs.test.tsx,packages/app/src/components/catalog/EntityPage/defaultTabs.tsx,plugins/dynamic-plugins-info/src/components/InternalPluginsMap.tsx +sonar.cpd.exclusions=packages/app/src/components/DynamicRoot/DynamicRoot.test.tsx,packages/app/src/components/admin/AdminTabs.test.tsx,packages/app/src/components/catalog/EntityPage/defaultTabs.tsx,plugins/dynamic-plugins-info/src/components/InternalPluginsMap.tsx,e2e-tests/playwright/e2e/audit-log/LogUtils.ts diff --git a/.yarn/patches/@backstage-backend-dynamic-feature-service-npm-0.4.4.patch b/.yarn/patches/@backstage-backend-dynamic-feature-service-npm-0.4.4.patch new file mode 100644 index 0000000000..c7583053ef --- /dev/null +++ b/.yarn/patches/@backstage-backend-dynamic-feature-service-npm-0.4.4.patch @@ -0,0 +1,76 @@ +diff --git a/dist/features/features.cjs.js b/dist/features/features.cjs.js +index debb6ce817c7aa0111a3cbc20edeee815ad59759..cea4f6fde4c4c57793db5f9732d6810bdd517256 100644 +--- a/dist/features/features.cjs.js ++++ b/dist/features/features.cjs.js +@@ -1,11 +1,11 @@ + 'use strict'; + + var backendPluginApi = require('@backstage/backend-plugin-api'); ++var pluginManager = require('../manager/plugin-manager.cjs.js'); ++var pluginScanner = require('../scanner/plugin-scanner.cjs.js'); + var schemas = require('../schemas/schemas.cjs.js'); + var frontend = require('../schemas/frontend.cjs.js'); + var rootLogger = require('../schemas/rootLogger.cjs.js'); +-var pluginManager = require('../manager/plugin-manager.cjs.js'); +-var pluginScanner = require('../scanner/plugin-scanner.cjs.js'); + + const dynamicPluginsFeatureLoaderWithOptions = (options) => backendPluginApi.createBackendFeatureLoader({ + deps: { +@@ -13,13 +13,17 @@ const dynamicPluginsFeatureLoaderWithOptions = (options) => backendPluginApi.cre + }, + *loader({ config }) { + const dynamicPluginsEnabled = config.has(pluginScanner.configKey); ++ let rootLoggerOptions = {}; ++ if (options?.logger) { ++ rootLoggerOptions = options.logger(config); ++ } + yield* [ + schemas.dynamicPluginsSchemasServiceFactory(options), + pluginManager.dynamicPluginsServiceFactory(options) + ]; + if (dynamicPluginsEnabled) { + yield* [ +- rootLogger.dynamicPluginsRootLoggerServiceFactory(options), ++ rootLogger.dynamicPluginsRootLoggerServiceFactory(rootLoggerOptions), + frontend.dynamicPluginsFrontendSchemas, + pluginManager.dynamicPluginsFeatureDiscoveryLoader + ]; +diff --git a/dist/features/features.cjs.js.map b/dist/features/features.cjs.js.map +index 4c36851870462037a9c505eb5b20a7085499c734..9db90b1fd34484a06aaaa1137322f22f4a9e82c2 100644 +--- a/dist/features/features.cjs.js.map ++++ b/dist/features/features.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"features.cjs.js","sources":["../../src/features/features.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendFeatureLoader,\n} from '@backstage/backend-plugin-api';\nimport {\n DynamicPluginsSchemasOptions,\n dynamicPluginsFrontendSchemas,\n dynamicPluginsRootLoggerServiceFactory,\n dynamicPluginsSchemasServiceFactory,\n} from '../schemas';\nimport {\n DynamicPluginsFactoryOptions,\n dynamicPluginsFeatureDiscoveryLoader,\n dynamicPluginsServiceFactory,\n} from '../manager';\nimport { DynamicPluginsRootLoggerFactoryOptions } from '../schemas';\nimport { configKey } from '../scanner/plugin-scanner';\n\n/**\n * @public\n */\nexport type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions &\n DynamicPluginsSchemasOptions &\n DynamicPluginsRootLoggerFactoryOptions;\n\nconst dynamicPluginsFeatureLoaderWithOptions = (\n options?: DynamicPluginsFeatureLoaderOptions,\n) =>\n createBackendFeatureLoader({\n deps: {\n config: coreServices.rootConfig,\n },\n *loader({ config }) {\n const dynamicPluginsEnabled = config.has(configKey);\n\n yield* [\n dynamicPluginsSchemasServiceFactory(options),\n dynamicPluginsServiceFactory(options),\n ];\n if (dynamicPluginsEnabled) {\n yield* [\n dynamicPluginsRootLoggerServiceFactory(options),\n dynamicPluginsFrontendSchemas,\n dynamicPluginsFeatureDiscoveryLoader,\n ];\n }\n },\n });\n\n/**\n * A backend feature loader that fully enable backend dynamic plugins.\n * More precisely it:\n * - adds the dynamic plugins root service (typically depended upon by plugins),\n * - adds additional required features to allow supporting dynamic plugins config schemas\n * in the frontend application and the backend root logger,\n * - uses the dynamic plugins service to discover and expose dynamic plugins as features.\n *\n * @public\n *\n * @example\n * Using the `dynamicPluginsFeatureLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureLoader);\n * //...\n * backend.start();\n * ```\n *\n * @example\n * Passing options to the `dynamicPluginsFeatureLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';\n * import { myCustomModuleLoader } from './myCustomModuleLoader';\n * import { myCustomSchemaLocator } from './myCustomSchemaLocator';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureLoader({\n * moduleLoader: myCustomModuleLoader,\n * schemaLocator: myCustomSchemaLocator,\n *\n * }));\n * //...\n * backend.start();\n * ```\n */\nexport const dynamicPluginsFeatureLoader = Object.assign(\n dynamicPluginsFeatureLoaderWithOptions,\n dynamicPluginsFeatureLoaderWithOptions(),\n);\n"],"names":["createBackendFeatureLoader","coreServices","configKey","dynamicPluginsSchemasServiceFactory","dynamicPluginsServiceFactory","dynamicPluginsRootLoggerServiceFactory","dynamicPluginsFrontendSchemas","dynamicPluginsFeatureDiscoveryLoader"],"mappings":";;;;;;;;;AAyCA,MAAM,sCAAA,GAAyC,CAC7C,OAAA,KAEAA,2CAA2B,CAAA;AAAA,EACzB,IAAM,EAAA;AAAA,IACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,GACvB;AAAA,EACA,CAAC,MAAA,CAAO,EAAE,MAAA,EAAU,EAAA;AAClB,IAAM,MAAA,qBAAA,GAAwB,MAAO,CAAA,GAAA,CAAIC,uBAAS,CAAA,CAAA;AAElD,IAAO,OAAA;AAAA,MACLC,4CAAoC,OAAO,CAAA;AAAA,MAC3CC,2CAA6B,OAAO,CAAA;AAAA,KACtC,CAAA;AACA,IAAA,IAAI,qBAAuB,EAAA;AACzB,MAAO,OAAA;AAAA,QACLC,kDAAuC,OAAO,CAAA;AAAA,QAC9CC,sCAAA;AAAA,QACAC,kDAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,GACF;AACF,CAAC,CAAA,CAAA;AA4CI,MAAM,8BAA8B,MAAO,CAAA,MAAA;AAAA,EAChD,sCAAA;AAAA,EACA,sCAAuC,EAAA;AACzC;;;;"} +\ No newline at end of file ++{"version":3,"file":"features.cjs.js","sources":["../../src/features/features.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendFeatureLoader,\n} from '@backstage/backend-plugin-api';\nimport type { Config } from '@backstage/config';\nimport {\n DynamicPluginsFactoryOptions,\n dynamicPluginsFeatureDiscoveryLoader,\n dynamicPluginsServiceFactory,\n} from '../manager';\nimport { configKey } from '../scanner/plugin-scanner';\nimport {\n DynamicPluginsRootLoggerFactoryOptions,\n DynamicPluginsSchemasOptions,\n dynamicPluginsFrontendSchemas,\n dynamicPluginsRootLoggerServiceFactory,\n dynamicPluginsSchemasServiceFactory,\n} from '../schemas';\n\n/**\n * @public\n */\nexport type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions &\n DynamicPluginsSchemasOptions & {\n logger?: (config?: Config) => DynamicPluginsRootLoggerFactoryOptions;\n };\n\nconst dynamicPluginsFeatureLoaderWithOptions = (\n options?: DynamicPluginsFeatureLoaderOptions,\n) =>\n createBackendFeatureLoader({\n deps: {\n config: coreServices.rootConfig,\n },\n *loader({ config }) {\n const dynamicPluginsEnabled = config.has(configKey);\n\n let rootLoggerOptions: DynamicPluginsRootLoggerFactoryOptions = {};\n if (options?.logger) {\n rootLoggerOptions = options.logger(config);\n }\n\n yield* [\n dynamicPluginsSchemasServiceFactory(options),\n dynamicPluginsServiceFactory(options),\n ];\n if (dynamicPluginsEnabled) {\n yield* [\n dynamicPluginsRootLoggerServiceFactory(rootLoggerOptions),\n dynamicPluginsFrontendSchemas,\n dynamicPluginsFeatureDiscoveryLoader,\n ];\n }\n },\n });\n\n/**\n * A backend feature loader that fully enable backend dynamic plugins.\n * More precisely it:\n * - adds the dynamic plugins root service (typically depended upon by plugins),\n * - adds additional required features to allow supporting dynamic plugins config schemas\n * in the frontend application and the backend root logger,\n * - uses the dynamic plugins service to discover and expose dynamic plugins as features.\n *\n * @public\n *\n * @example\n * Using the `dynamicPluginsFeatureLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureLoader);\n * //...\n * backend.start();\n * ```\n *\n * @example\n * Passing options to the `dynamicPluginsFeatureLoader` loader in a backend instance:\n * ```ts\n * //...\n * import { createBackend } from '@backstage/backend-defaults';\n * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';\n * import { myCustomModuleLoader } from './myCustomModuleLoader';\n * import { myCustomSchemaLocator } from './myCustomSchemaLocator';\n * import { myConfiguredLoggerOptions } from './myConfiguredLoggerOptions';\n *\n * const backend = createBackend();\n * backend.add(dynamicPluginsFeatureLoader({\n * moduleLoader: myCustomModuleLoader,\n * schemaLocator: myCustomSchemaLocator,\n * logger: (config) => myConfiguredLoggerOptions(config),\n * }));\n * //...\n * backend.start();\n * ```\n */\nexport const dynamicPluginsFeatureLoader = Object.assign(\n dynamicPluginsFeatureLoaderWithOptions,\n dynamicPluginsFeatureLoaderWithOptions(),\n);\n"],"names":["createBackendFeatureLoader","coreServices","configKey","dynamicPluginsSchemasServiceFactory","dynamicPluginsServiceFactory","dynamicPluginsRootLoggerServiceFactory","dynamicPluginsFrontendSchemas","dynamicPluginsFeatureDiscoveryLoader"],"mappings":";;;;;;;;;AA2CA,MAAM,sCAAA,GAAyC,CAC7C,OAAA,KAEAA,2CAA2B,CAAA;AAAA,EACzB,IAAM,EAAA;AAAA,IACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,GACvB;AAAA,EACA,CAAC,MAAA,CAAO,EAAE,MAAA,EAAU,EAAA;AAClB,IAAM,MAAA,qBAAA,GAAwB,MAAO,CAAA,GAAA,CAAIC,uBAAS,CAAA,CAAA;AAElD,IAAA,IAAI,oBAA4D,EAAC,CAAA;AACjE,IAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,MAAoB,iBAAA,GAAA,OAAA,CAAQ,OAAO,MAAM,CAAA,CAAA;AAAA,KAC3C;AAEA,IAAO,OAAA;AAAA,MACLC,4CAAoC,OAAO,CAAA;AAAA,MAC3CC,2CAA6B,OAAO,CAAA;AAAA,KACtC,CAAA;AACA,IAAA,IAAI,qBAAuB,EAAA;AACzB,MAAO,OAAA;AAAA,QACLC,kDAAuC,iBAAiB,CAAA;AAAA,QACxDC,sCAAA;AAAA,QACAC,kDAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,GACF;AACF,CAAC,CAAA,CAAA;AA6CI,MAAM,8BAA8B,MAAO,CAAA,MAAA;AAAA,EAChD,sCAAA;AAAA,EACA,sCAAuC,EAAA;AACzC;;;;"} +\ No newline at end of file +diff --git a/dist/index.d.ts b/dist/index.d.ts +index 212ed98b995d33e38f428a108805a6a791bd948f..3baf7cda73cfc095254f6818b37edc46bf7d2c1d 100644 +--- a/dist/index.d.ts ++++ b/dist/index.d.ts +@@ -276,7 +276,9 @@ declare const dynamicPluginsRootLoggerServiceFactory: ((options?: DynamicPlugins + /** + * @public + */ +-type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions & DynamicPluginsSchemasOptions & DynamicPluginsRootLoggerFactoryOptions; ++type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions & DynamicPluginsSchemasOptions & { ++ logger?: (config?: Config) => DynamicPluginsRootLoggerFactoryOptions; ++}; + /** + * A backend feature loader that fully enable backend dynamic plugins. + * More precisely it: +@@ -308,12 +310,13 @@ type DynamicPluginsFeatureLoaderOptions = DynamicPluginsFactoryOptions & Dynamic + * import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service'; + * import { myCustomModuleLoader } from './myCustomModuleLoader'; + * import { myCustomSchemaLocator } from './myCustomSchemaLocator'; ++ * import { myConfiguredLoggerOptions } from './myConfiguredLoggerOptions'; + * + * const backend = createBackend(); + * backend.add(dynamicPluginsFeatureLoader({ + * moduleLoader: myCustomModuleLoader, + * schemaLocator: myCustomSchemaLocator, +- * ++ * logger: (config) => myConfiguredLoggerOptions(config), + * })); + * //... + * backend.start(); diff --git a/.yarn/patches/@backstage-plugin-auth-backend-module-oidc-provider-npm-0.3.1.patch b/.yarn/patches/@backstage-plugin-auth-backend-module-oidc-provider-npm-0.3.1.patch new file mode 100644 index 0000000000..9280ee97c8 --- /dev/null +++ b/.yarn/patches/@backstage-plugin-auth-backend-module-oidc-provider-npm-0.3.1.patch @@ -0,0 +1,104 @@ +diff --git a/config.d.ts b/config.d.ts +index d59c40697ab250330eb71483692def8785142e07..17b26a6eb580921e8a50b3ef87316e6cdb89b7a4 100644 +--- a/config.d.ts ++++ b/config.d.ts +@@ -34,10 +34,11 @@ export interface Config { + signIn?: { + resolvers: Array< + | { +- resolver: 'emailLocalPartMatchingUserEntityName'; +- allowedDomains?: string[]; +- } ++ resolver: 'emailLocalPartMatchingUserEntityName'; ++ allowedDomains?: string[]; ++ } + | { resolver: 'emailMatchingUserEntityProfileEmail' } ++ | { resolver: 'preferredUsernameMatchingUserEntityName' } + >; + }; + }; +diff --git a/dist/authenticator.cjs.js.map b/dist/authenticator.cjs.js.map +index f5838857e575c085b99bec2b558b8d3818b89c9d..92e72750e7e99f74d8aacf56dc8c42a601b97a1c 100644 +--- a/dist/authenticator.cjs.js.map ++++ b/dist/authenticator.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"authenticator.cjs.js","sources":["../src/authenticator.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport crypto from 'crypto';\nimport {\n custom,\n CustomHttpOptionsProvider,\n Issuer,\n ClientAuthMethod,\n TokenSet,\n UserinfoResponse,\n Strategy as OidcStrategy,\n} from 'openid-client';\nimport {\n createOAuthAuthenticator,\n OAuthAuthenticatorResult,\n PassportDoneCallback,\n PassportHelpers,\n PassportOAuthAuthenticatorHelper,\n PassportOAuthPrivateInfo,\n} from '@backstage/plugin-auth-node';\n\nconst HTTP_OPTION_TIMEOUT = 10000;\nconst httpOptionsProvider: CustomHttpOptionsProvider = (_url, options) => {\n return {\n ...options,\n timeout: HTTP_OPTION_TIMEOUT,\n };\n};\n\n/**\n * authentication result for the OIDC which includes the token set and user\n * profile response\n * @public\n */\nexport type OidcAuthResult = {\n tokenset: TokenSet;\n userinfo: UserinfoResponse;\n};\n\n/** @public */\nexport const oidcAuthenticator = createOAuthAuthenticator({\n defaultProfileTransform: async (\n input: OAuthAuthenticatorResult,\n ) => ({\n profile: {\n email: input.fullProfile.userinfo.email,\n picture: input.fullProfile.userinfo.picture,\n displayName: input.fullProfile.userinfo.name,\n },\n }),\n scopes: {\n persist: true,\n required: ['openid', 'profile', 'email'],\n },\n initialize({ callbackUrl, config }) {\n const clientId = config.getString('clientId');\n const clientSecret = config.getString('clientSecret');\n const metadataUrl = config.getString('metadataUrl');\n const customCallbackUrl = config.getOptionalString('callbackUrl');\n const tokenEndpointAuthMethod = config.getOptionalString(\n 'tokenEndpointAuthMethod',\n ) as ClientAuthMethod;\n const tokenSignedResponseAlg = config.getOptionalString(\n 'tokenSignedResponseAlg',\n );\n const initializedPrompt = config.getOptionalString('prompt');\n\n if (config.has('scope')) {\n throw new Error(\n 'The oidc provider no longer supports the \"scope\" configuration option. Please use the \"additionalScopes\" option instead.',\n );\n }\n\n Issuer[custom.http_options] = httpOptionsProvider;\n const promise = Issuer.discover(metadataUrl).then(issuer => {\n issuer[custom.http_options] = httpOptionsProvider;\n issuer.Client[custom.http_options] = httpOptionsProvider;\n\n const client = new issuer.Client({\n access_type: 'offline', // this option must be passed to provider to receive a refresh token\n client_id: clientId,\n client_secret: clientSecret,\n redirect_uris: [customCallbackUrl || callbackUrl],\n response_types: ['code'],\n token_endpoint_auth_method:\n tokenEndpointAuthMethod || 'client_secret_basic',\n id_token_signed_response_alg: tokenSignedResponseAlg || 'RS256',\n });\n client[custom.http_options] = httpOptionsProvider;\n\n const strategy = new OidcStrategy(\n {\n client,\n passReqToCallback: false,\n },\n (\n tokenset: TokenSet,\n userinfo: UserinfoResponse,\n done: PassportDoneCallback,\n ) => {\n if (typeof done !== 'function') {\n throw new Error(\n 'OIDC IdP must provide a userinfo_endpoint in the metadata response',\n );\n }\n\n done(\n undefined,\n { tokenset, userinfo },\n { refreshToken: tokenset.refresh_token },\n );\n },\n );\n\n const helper = PassportOAuthAuthenticatorHelper.from(strategy);\n return { helper, client, strategy };\n });\n\n return { initializedPrompt, promise };\n },\n\n async start(input, ctx) {\n const { initializedPrompt, promise } = ctx;\n const { helper, strategy } = await promise;\n const options: Record = {\n scope: input.scope,\n state: input.state,\n nonce: crypto.randomBytes(16).toString('base64'),\n };\n const prompt = initializedPrompt || 'none';\n if (prompt !== 'auto') {\n options.prompt = prompt;\n }\n\n return new Promise((resolve, reject) => {\n strategy.error = reject;\n\n return helper\n .start(input, {\n ...options,\n })\n .then(resolve);\n });\n },\n\n async authenticate(\n input,\n ctx,\n ): Promise> {\n const { strategy } = await ctx.promise;\n const { result, privateInfo } =\n await PassportHelpers.executeFrameHandlerStrategy<\n OidcAuthResult,\n PassportOAuthPrivateInfo\n >(input.req, strategy);\n\n return {\n fullProfile: result,\n session: {\n accessToken: result.tokenset.access_token!,\n tokenType: result.tokenset.token_type ?? 'bearer',\n scope: result.tokenset.scope!,\n expiresInSeconds: result.tokenset.expires_in,\n idToken: result.tokenset.id_token,\n refreshToken: privateInfo.refreshToken,\n },\n };\n },\n\n async refresh(input, ctx) {\n const { client } = await ctx.promise;\n const tokenset = await client.refresh(input.refreshToken);\n if (!tokenset.access_token) {\n throw new Error('Refresh failed');\n }\n const userinfo = await client.userinfo(tokenset.access_token);\n\n return new Promise((resolve, reject) => {\n if (!tokenset.access_token) {\n reject(new Error('Refresh Failed'));\n }\n resolve({\n fullProfile: { userinfo, tokenset },\n session: {\n accessToken: tokenset.access_token!,\n tokenType: tokenset.token_type ?? 'bearer',\n scope: tokenset.scope!,\n expiresInSeconds: tokenset.expires_in,\n idToken: tokenset.id_token,\n refreshToken: tokenset.refresh_token,\n },\n });\n });\n },\n\n async logout(input, ctx) {\n const { client } = await ctx.promise;\n const issuer = client.issuer;\n /**\n * https://github.com/panva/node-openid-client/blob/main/lib/client.js#L1398\n * client.revoke will check revocation_endpoint and if undefined throw error。\n *\n * if oidc server do not provide revocation_endpoint,we should not call revoke function\n */\n\n if (input.refreshToken && issuer.revocation_endpoint) {\n await client.revoke(input.refreshToken);\n }\n },\n});\n"],"names":["createOAuthAuthenticator","Issuer","custom","OidcStrategy","PassportOAuthAuthenticatorHelper","crypto","PassportHelpers"],"mappings":"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"} +\ No newline at end of file ++{"version":3,"file":"authenticator.cjs.js","sources":["../src/authenticator.ts"],"sourcesContent":["/*\r\n * Copyright 2023 The Backstage Authors\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\nimport crypto from 'crypto';\r\nimport {\r\n custom,\r\n CustomHttpOptionsProvider,\r\n Issuer,\r\n ClientAuthMethod,\r\n TokenSet,\r\n UserinfoResponse,\r\n Strategy as OidcStrategy,\r\n} from 'openid-client';\r\nimport {\r\n createOAuthAuthenticator,\r\n OAuthAuthenticatorResult,\r\n PassportDoneCallback,\r\n PassportHelpers,\r\n PassportOAuthAuthenticatorHelper,\r\n PassportOAuthPrivateInfo,\r\n} from '@backstage/plugin-auth-node';\r\n\r\nconst HTTP_OPTION_TIMEOUT = 10000;\r\nconst httpOptionsProvider: CustomHttpOptionsProvider = (_url, options) => {\r\n return {\r\n ...options,\r\n timeout: HTTP_OPTION_TIMEOUT,\r\n };\r\n};\r\n\r\n/**\r\n * authentication result for the OIDC which includes the token set and user\r\n * profile response\r\n * @public\r\n */\r\nexport type OidcAuthResult = {\r\n tokenset: TokenSet;\r\n userinfo: UserinfoResponse;\r\n};\r\n\r\n/** @public */\r\nexport const oidcAuthenticator = createOAuthAuthenticator({\r\n defaultProfileTransform: async (\r\n input: OAuthAuthenticatorResult,\r\n ) => ({\r\n profile: {\r\n email: input.fullProfile.userinfo.email,\r\n picture: input.fullProfile.userinfo.picture,\r\n displayName: input.fullProfile.userinfo.name,\r\n },\r\n }),\r\n scopes: {\r\n persist: true,\r\n required: ['openid', 'profile', 'email'],\r\n },\r\n initialize({ callbackUrl, config }) {\r\n const clientId = config.getString('clientId');\r\n const clientSecret = config.getString('clientSecret');\r\n const metadataUrl = config.getString('metadataUrl');\r\n const customCallbackUrl = config.getOptionalString('callbackUrl');\r\n const tokenEndpointAuthMethod = config.getOptionalString(\r\n 'tokenEndpointAuthMethod',\r\n ) as ClientAuthMethod;\r\n const tokenSignedResponseAlg = config.getOptionalString(\r\n 'tokenSignedResponseAlg',\r\n );\r\n const initializedPrompt = config.getOptionalString('prompt');\r\n\r\n if (config.has('scope')) {\r\n throw new Error(\r\n 'The oidc provider no longer supports the \"scope\" configuration option. Please use the \"additionalScopes\" option instead.',\r\n );\r\n }\r\n\r\n Issuer[custom.http_options] = httpOptionsProvider;\r\n const promise = Issuer.discover(metadataUrl).then(issuer => {\r\n issuer[custom.http_options] = httpOptionsProvider;\r\n issuer.Client[custom.http_options] = httpOptionsProvider;\r\n\r\n const client = new issuer.Client({\r\n access_type: 'offline', // this option must be passed to provider to receive a refresh token\r\n client_id: clientId,\r\n client_secret: clientSecret,\r\n redirect_uris: [customCallbackUrl || callbackUrl],\r\n response_types: ['code'],\r\n token_endpoint_auth_method:\r\n tokenEndpointAuthMethod || 'client_secret_basic',\r\n id_token_signed_response_alg: tokenSignedResponseAlg || 'RS256',\r\n });\r\n client[custom.http_options] = httpOptionsProvider;\r\n\r\n const strategy = new OidcStrategy(\r\n {\r\n client,\r\n passReqToCallback: false,\r\n },\r\n (\r\n tokenset: TokenSet,\r\n userinfo: UserinfoResponse,\r\n done: PassportDoneCallback,\r\n ) => {\r\n if (typeof done !== 'function') {\r\n throw new Error(\r\n 'OIDC IdP must provide a userinfo_endpoint in the metadata response',\r\n );\r\n }\r\n\r\n done(\r\n undefined,\r\n { tokenset, userinfo },\r\n { refreshToken: tokenset.refresh_token },\r\n );\r\n },\r\n );\r\n\r\n const helper = PassportOAuthAuthenticatorHelper.from(strategy);\r\n return { helper, client, strategy };\r\n });\r\n\r\n return { initializedPrompt, promise };\r\n },\r\n\r\n async start(input, ctx) {\r\n const { initializedPrompt, promise } = ctx;\r\n const { helper, strategy } = await promise;\r\n const options: Record = {\r\n scope: input.scope,\r\n state: input.state,\r\n nonce: crypto.randomBytes(16).toString('base64'),\r\n };\r\n const prompt = initializedPrompt || 'none';\r\n if (prompt !== 'auto') {\r\n options.prompt = prompt;\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n strategy.error = reject;\r\n\r\n return helper\r\n .start(input, {\r\n ...options,\r\n })\r\n .then(resolve);\r\n });\r\n },\r\n\r\n async authenticate(\r\n input,\r\n ctx,\r\n ): Promise> {\r\n const { strategy } = await ctx.promise;\r\n const { result, privateInfo } =\r\n await PassportHelpers.executeFrameHandlerStrategy<\r\n OidcAuthResult,\r\n PassportOAuthPrivateInfo\r\n >(input.req, strategy);\r\n\r\n return {\r\n fullProfile: result,\r\n session: {\r\n accessToken: result.tokenset.access_token!,\r\n tokenType: result.tokenset.token_type ?? 'bearer',\r\n scope: result.tokenset.scope!,\r\n expiresInSeconds: result.tokenset.expires_in,\r\n idToken: result.tokenset.id_token,\r\n refreshToken: privateInfo.refreshToken,\r\n },\r\n };\r\n },\r\n\r\n async refresh(input, ctx) {\r\n const { client } = await ctx.promise;\r\n const tokenset = await client.refresh(input.refreshToken);\r\n if (!tokenset.access_token) {\r\n throw new Error('Refresh failed');\r\n }\r\n const userinfo = await client.userinfo(tokenset.access_token);\r\n\r\n return new Promise((resolve, reject) => {\r\n if (!tokenset.access_token) {\r\n reject(new Error('Refresh Failed'));\r\n }\r\n resolve({\r\n fullProfile: { userinfo, tokenset },\r\n session: {\r\n accessToken: tokenset.access_token!,\r\n tokenType: tokenset.token_type ?? 'bearer',\r\n scope: tokenset.scope!,\r\n expiresInSeconds: tokenset.expires_in,\r\n idToken: tokenset.id_token,\r\n refreshToken: tokenset.refresh_token,\r\n },\r\n });\r\n });\r\n },\r\n\r\n async logout(input, ctx) {\r\n const { client } = await ctx.promise;\r\n const issuer = client.issuer;\r\n /**\r\n * https://github.com/panva/node-openid-client/blob/main/lib/client.js#L1398\r\n * client.revoke will check revocation_endpoint and if undefined throw error。\r\n *\r\n * if oidc server do not provide revocation_endpoint,we should not call revoke function\r\n */\r\n\r\n if (input.refreshToken && issuer.revocation_endpoint) {\r\n await client.revoke(input.refreshToken);\r\n }\r\n },\r\n});\r\n"],"names":["createOAuthAuthenticator","Issuer","custom","OidcStrategy","PassportOAuthAuthenticatorHelper","crypto","PassportHelpers"],"mappings":"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"} +\ No newline at end of file +diff --git a/dist/index.d.ts b/dist/index.d.ts +index bd2eb330b124be25d60f9dd2bb325a5cf02c1761..b8be7582ab706e90f787ee8349306e70d18ede75 100644 +--- a/dist/index.d.ts ++++ b/dist/index.d.ts +@@ -1,5 +1,5 @@ + import * as _backstage_plugin_auth_node from '@backstage/plugin-auth-node'; +-import { PassportOAuthAuthenticatorHelper } from '@backstage/plugin-auth-node'; ++import { PassportOAuthAuthenticatorHelper, OAuthAuthenticatorResult } from '@backstage/plugin-auth-node'; + import * as openid_client from 'openid-client'; + import { TokenSet, UserinfoResponse, Strategy } from 'openid-client'; + import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api'; +@@ -44,6 +44,11 @@ declare namespace oidcSignInResolvers { + * as email of the entity. + */ + const emailMatchingUserEntityProfileEmail: _backstage_plugin_auth_node.SignInResolverFactory; ++ /** ++ * A oidc resolver that looks up the user using their preferred username ++ * as the entity name ++ */ ++ const preferredUsernameMatchingUserEntityName: _backstage_plugin_auth_node.SignInResolverFactory, unknown>; + } + + export { type OidcAuthResult, authModuleOidcProvider as default, oidcAuthenticator, oidcSignInResolvers }; +diff --git a/dist/module.cjs.js b/dist/module.cjs.js +index f9dc2ae601a240550c1f975ddd55b94796ae081f..18c95c0b1b8cee1c3afcfcb035397d587cbcf6b6 100644 +--- a/dist/module.cjs.js ++++ b/dist/module.cjs.js +@@ -19,8 +19,7 @@ const authModuleOidcProvider = backendPluginApi.createBackendModule({ + factory: pluginAuthNode.createOAuthProviderFactory({ + authenticator: authenticator.oidcAuthenticator, + signInResolverFactories: { +- ...resolvers.oidcSignInResolvers, +- ...pluginAuthNode.commonSignInResolvers ++ ...resolvers.oidcSignInResolvers + } + }) + }); +diff --git a/dist/module.cjs.js.map b/dist/module.cjs.js.map +index 1f62b0c3a73d65d0618e2a14c5b9e0244d921955..e225d9f66b84b63d0c676e3fa424efe884d5e4f7 100644 +--- a/dist/module.cjs.js.map ++++ b/dist/module.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createBackendModule } from '@backstage/backend-plugin-api';\nimport {\n authProvidersExtensionPoint,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { oidcAuthenticator } from './authenticator';\nimport { oidcSignInResolvers } from './resolvers';\n\n/** @public */\nexport const authModuleOidcProvider = createBackendModule({\n pluginId: 'auth',\n moduleId: 'oidc-provider',\n register(reg) {\n reg.registerInit({\n deps: {\n providers: authProvidersExtensionPoint,\n },\n async init({ providers }) {\n providers.registerProvider({\n providerId: 'oidc',\n factory: createOAuthProviderFactory({\n authenticator: oidcAuthenticator,\n signInResolverFactories: {\n ...oidcSignInResolvers,\n ...commonSignInResolvers,\n },\n }),\n });\n },\n });\n },\n});\n"],"names":["createBackendModule","authProvidersExtensionPoint","createOAuthProviderFactory","oidcAuthenticator","oidcSignInResolvers","commonSignInResolvers"],"mappings":";;;;;;;AAyBO,MAAM,yBAAyBA,oCAAoB,CAAA;AAAA,EACxD,QAAU,EAAA,MAAA;AAAA,EACV,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,SAAW,EAAAC,0CAAA;AAAA,OACb;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,SAAA,EAAa,EAAA;AACxB,QAAA,SAAA,CAAU,gBAAiB,CAAA;AAAA,UACzB,UAAY,EAAA,MAAA;AAAA,UACZ,SAASC,yCAA2B,CAAA;AAAA,YAClC,aAAe,EAAAC,+BAAA;AAAA,YACf,uBAAyB,EAAA;AAAA,cACvB,GAAGC,6BAAA;AAAA,cACH,GAAGC,oCAAA;AAAA,aACL;AAAA,WACD,CAAA;AAAA,SACF,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"} +\ No newline at end of file ++{"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["/*\r\n * Copyright 2023 The Backstage Authors\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\nimport { createBackendModule } from '@backstage/backend-plugin-api';\r\nimport {\r\n authProvidersExtensionPoint,\r\n createOAuthProviderFactory\r\n} from '@backstage/plugin-auth-node';\r\nimport { oidcAuthenticator } from './authenticator';\r\nimport { oidcSignInResolvers } from './resolvers';\r\n\r\n/** @public */\r\nexport const authModuleOidcProvider = createBackendModule({\r\n pluginId: 'auth',\r\n moduleId: 'oidc-provider',\r\n register(reg) {\r\n reg.registerInit({\r\n deps: {\r\n providers: authProvidersExtensionPoint,\r\n },\r\n async init({ providers }) {\r\n providers.registerProvider({\r\n providerId: 'oidc',\r\n factory: createOAuthProviderFactory({\r\n authenticator: oidcAuthenticator,\r\n signInResolverFactories: {\r\n ...oidcSignInResolvers,\r\n },\r\n }),\r\n });\r\n },\r\n });\r\n },\r\n});\r\n"],"names":["createBackendModule","authProvidersExtensionPoint","createOAuthProviderFactory","oidcAuthenticator","oidcSignInResolvers"],"mappings":";;;;;;;AAwBO,MAAM,yBAAyBA,oCAAoB,CAAA;AAAA,EACxD,QAAU,EAAA,MAAA;AAAA,EACV,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,SAAW,EAAAC,0CAAA;AAAA,OACb;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,SAAA,EAAa,EAAA;AACxB,QAAA,SAAA,CAAU,gBAAiB,CAAA;AAAA,UACzB,UAAY,EAAA,MAAA;AAAA,UACZ,SAASC,yCAA2B,CAAA;AAAA,YAClC,aAAe,EAAAC,+BAAA;AAAA,YACf,uBAAyB,EAAA;AAAA,cACvB,GAAGC,6BAAA;AAAA,aACL;AAAA,WACD,CAAA;AAAA,SACF,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"} +\ No newline at end of file +diff --git a/dist/resolvers.cjs.js b/dist/resolvers.cjs.js +index 380a9624cb461b3782fc319d7722dc1da1c442d7..dc3ebe39b74807c3b0a94835030a89640d7ce976 100644 +--- a/dist/resolvers.cjs.js ++++ b/dist/resolvers.cjs.js +@@ -6,5 +6,16 @@ exports.oidcSignInResolvers = void 0; + ((oidcSignInResolvers2) => { + oidcSignInResolvers2.emailLocalPartMatchingUserEntityName = pluginAuthNode.commonSignInResolvers.emailLocalPartMatchingUserEntityName; + oidcSignInResolvers2.emailMatchingUserEntityProfileEmail = pluginAuthNode.commonSignInResolvers.emailMatchingUserEntityProfileEmail; ++ oidcSignInResolvers2.preferredUsernameMatchingUserEntityName = pluginAuthNode.createSignInResolverFactory({ ++ create() { ++ return async (info, ctx) => { ++ const userId = info.result.fullProfile.userinfo.preferred_username; ++ if (!userId) { ++ throw new Error(`OIDC user profile does not contain a username`); ++ } ++ return ctx.signInWithCatalogUser({ entityRef: { name: userId } }); ++ }; ++ } ++ }); + })(exports.oidcSignInResolvers || (exports.oidcSignInResolvers = {})); + //# sourceMappingURL=resolvers.cjs.js.map +diff --git a/dist/resolvers.cjs.js.map b/dist/resolvers.cjs.js.map +index b345faec13e95559fa23cb3fefb8d657b04a48ff..e631e22279a30f7efe136db9d0ae170bce1b329a 100644 +--- a/dist/resolvers.cjs.js.map ++++ b/dist/resolvers.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"resolvers.cjs.js","sources":["../src/resolvers.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { commonSignInResolvers } from '@backstage/plugin-auth-node';\n\n/**\n * Available sign-in resolvers for the Oidc auth provider.\n *\n * @public\n */\nexport namespace oidcSignInResolvers {\n /**\n * A oidc resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\n export const emailLocalPartMatchingUserEntityName =\n commonSignInResolvers.emailLocalPartMatchingUserEntityName;\n\n /**\n * A oidc resolver that looks up the user using their email address\n * as email of the entity.\n */\n export const emailMatchingUserEntityProfileEmail =\n commonSignInResolvers.emailMatchingUserEntityProfileEmail;\n}\n"],"names":["oidcSignInResolvers","commonSignInResolvers"],"mappings":";;;;AAuBiBA,qCAAA;AAAA,CAAV,CAAUA,oBAAV,KAAA;AAKE,EAAMA,oBAAAA,CAAA,uCACXC,oCAAsB,CAAA,oCAAA,CAAA;AAMjB,EAAMD,oBAAAA,CAAA,sCACXC,oCAAsB,CAAA,mCAAA,CAAA;AAAA,CAbT,EAAAD,2BAAA,KAAAA,2BAAA,GAAA,EAAA,CAAA,CAAA;;"} +\ No newline at end of file ++{"version":3,"file":"resolvers.cjs.js","sources":["../src/resolvers.ts"],"sourcesContent":["/*\r\n * Copyright 2023 The Backstage Authors\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\nimport {\r\n AuthResolverContext,\r\n OAuthAuthenticatorResult,\r\n SignInInfo,\r\n commonSignInResolvers,\r\n createSignInResolverFactory,\r\n} from '@backstage/plugin-auth-node';\r\nimport { OidcAuthResult } from './authenticator';\r\n\r\n/**\r\n * Available sign-in resolvers for the Oidc auth provider.\r\n *\r\n * @public\r\n */\r\nexport namespace oidcSignInResolvers {\r\n /**\r\n * A oidc resolver that looks up the user using the local part of\r\n * their email address as the entity name.\r\n */\r\n export const emailLocalPartMatchingUserEntityName =\r\n commonSignInResolvers.emailLocalPartMatchingUserEntityName;\r\n\r\n /**\r\n * A oidc resolver that looks up the user using their email address\r\n * as email of the entity.\r\n */\r\n export const emailMatchingUserEntityProfileEmail =\r\n commonSignInResolvers.emailMatchingUserEntityProfileEmail;\r\n\r\n /**\r\n* A oidc resolver that looks up the user using their preferred username\r\n* as the entity name\r\n*/\r\n export const preferredUsernameMatchingUserEntityName =\r\n createSignInResolverFactory({\r\n create() {\r\n return async (\r\n info: SignInInfo>,\r\n ctx: AuthResolverContext,\r\n ) => {\r\n const userId = info.result.fullProfile.userinfo.preferred_username;\r\n\r\n if (!userId) {\r\n throw new Error(`OIDC user profile does not contain a username`);\r\n }\r\n return ctx.signInWithCatalogUser({ entityRef: { name: userId } });\r\n };\r\n },\r\n });\r\n}\r\n\r\n"],"names":["oidcSignInResolvers","commonSignInResolvers","createSignInResolverFactory"],"mappings":";;;;AA8BiBA,qCAAA;AAAA,CAAV,CAAUA,oBAAV,KAAA;AAKE,EAAMA,oBAAAA,CAAA,uCACXC,oCAAsB,CAAA,oCAAA,CAAA;AAMjB,EAAMD,oBAAAA,CAAA,sCACXC,oCAAsB,CAAA,mCAAA,CAAA;AAMjB,EAAMD,oBAAAA,CAAA,0CACXE,0CAA4B,CAAA;AAAA,IAC1B,MAAS,GAAA;AACP,MAAO,OAAA,OACL,MACA,GACG,KAAA;AACH,QAAA,MAAM,MAAS,GAAA,IAAA,CAAK,MAAO,CAAA,WAAA,CAAY,QAAS,CAAA,kBAAA,CAAA;AAEhD,QAAA,IAAI,CAAC,MAAQ,EAAA;AACX,UAAM,MAAA,IAAI,MAAM,CAA+C,6CAAA,CAAA,CAAA,CAAA;AAAA,SACjE;AACA,QAAO,OAAA,GAAA,CAAI,sBAAsB,EAAE,SAAA,EAAW,EAAE,IAAM,EAAA,MAAA,IAAU,CAAA,CAAA;AAAA,OAClE,CAAA;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AAAA,CAlCY,EAAAF,2BAAA,KAAAA,2BAAA,GAAA,EAAA,CAAA,CAAA;;"} +\ No newline at end of file diff --git a/.yarn/patches/@backstage-plugin-catalog-backend-npm-1.27.1.patch b/.yarn/patches/@backstage-plugin-catalog-backend-npm-1.27.1.patch new file mode 100644 index 0000000000..9f71ddb915 --- /dev/null +++ b/.yarn/patches/@backstage-plugin-catalog-backend-npm-1.27.1.patch @@ -0,0 +1,1225 @@ +diff --git a/dist/service/createRouter.cjs.js b/dist/service/createRouter.cjs.js +index 87c8651bca6953c2eb65181a8657f32b2250a017..b3c556992c5f4c14b5ae54c1cc81d46346829abb 100644 +--- a/dist/service/createRouter.cjs.js ++++ b/dist/service/createRouter.cjs.js +@@ -17,6 +17,7 @@ var util = require('./util.cjs.js'); + var openapi_generated = require('../schema/openapi.generated.cjs.js'); + var parseEntityPaginationParams = require('./request/parseEntityPaginationParams.cjs.js'); + var AuthorizedValidationService = require('./AuthorizedValidationService.cjs.js'); ++var backstagePluginAuditLogNode = require('@janus-idp/backstage-plugin-audit-log-node'); + + function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } + +@@ -43,6 +44,11 @@ async function createRouter(options) { + auth, + httpAuth + } = options; ++ const auditLogger = new backstagePluginAuditLogNode.DefaultAuditLogger({ ++ logger, ++ authService: auth, ++ httpAuthService: httpAuth ++ }); + const readonlyEnabled = config.getOptionalBoolean("catalog.readonly") || false; + if (readonlyEnabled) { + logger.info("Catalog is running in readonly mode"); +@@ -50,12 +56,61 @@ async function createRouter(options) { + if (refreshService) { + router.post("/refresh", async (req, res) => { + const { authorizationToken, ...restBody } = req.body; +- const credentials = authorizationToken ? await auth.authenticate(authorizationToken) : await httpAuth.credentials(req); +- await refreshService.refresh({ +- ...restBody, +- credentials +- }); +- res.status(200).end(); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityRefresh", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ metadata: { ++ entityRef: restBody.entityRef ++ }, ++ request: req, ++ message: `Refresh attempt for ${restBody.entityRef} initiated by ${actorId}` ++ }); ++ const credentials = authorizationToken ? await auth.authenticate(authorizationToken) : await httpAuth.credentials(req); ++ await refreshService.refresh({ ++ ...restBody, ++ credentials ++ }); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityRefresh", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ metadata: { ++ entityRef: restBody.entityRef ++ }, ++ response: { ++ status: 200 ++ }, ++ request: req, ++ message: `Refresh attempt for ${restBody.entityRef} triggered by ${actorId}` ++ }); ++ res.status(200).end(); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityRefresh", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ metadata: { ++ entityRef: restBody.entityRef ++ }, ++ request: req, ++ message: `Refresh attempt for ${restBody.entityRef} by ${actorId} failed` ++ }); ++ throw err; ++ } + }); + } + if (permissionIntegrationRouter) { +@@ -63,217 +118,965 @@ async function createRouter(options) { + } + if (entitiesCatalog) { + router.get("/entities", async (req, res) => { +- const { entities, pageInfo } = await entitiesCatalog.entities({ +- filter: parseEntityFilterParams.parseEntityFilterParams(req.query), +- fields: parseEntityTransformParams.parseEntityTransformParams(req.query), +- order: parseEntityOrderParams.parseEntityOrderParams(req.query), +- pagination: parseEntityPaginationParams.parseEntityPaginationParams(req.query), +- credentials: await httpAuth.credentials(req) +- }); +- if (pageInfo.hasNextPage) { +- const url = new URL(`http://ignored${req.url}`); +- url.searchParams.delete("offset"); +- url.searchParams.set("after", pageInfo.endCursor); +- res.setHeader("link", `<${url.pathname}${url.search}>; rel="next"`); ++ const actorId = await auditLogger.getActorId( ++ req ++ ); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetch", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ message: `Entity fetch attempt initiated by ${actorId}` ++ }); ++ const { entities, pageInfo } = await entitiesCatalog.entities({ ++ filter: parseEntityFilterParams.parseEntityFilterParams(req.query), ++ fields: parseEntityTransformParams.parseEntityTransformParams(req.query), ++ order: parseEntityOrderParams.parseEntityOrderParams(req.query), ++ pagination: parseEntityPaginationParams.parseEntityPaginationParams(req.query), ++ credentials: await httpAuth.credentials(req) ++ }); ++ if (pageInfo.hasNextPage) { ++ const url = new URL(`http://ignored${req.url}`); ++ url.searchParams.delete("offset"); ++ url.searchParams.set("after", pageInfo.endCursor); ++ res.setHeader("link", `<${url.pathname}${url.search}>; rel="next"`); ++ } ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetch", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ // Let's not log out the entities since this can make the log very big due to it not being paged? ++ response: { ++ status: 200 ++ }, ++ message: `Entity fetch attempt by ${actorId} succeeded` ++ }); ++ res.json(entities); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetch", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Entity fetch attempt by ${actorId} failed` ++ }); ++ throw err; + } +- res.json(entities); + }).get("/entities/by-query", async (req, res) => { +- const { items, pageInfo, totalItems } = await entitiesCatalog.queryEntities({ +- limit: req.query.limit, +- offset: req.query.offset, +- ...parseQueryEntitiesParams.parseQueryEntitiesParams(req.query), +- credentials: await httpAuth.credentials(req) +- }); +- res.json({ +- items, +- totalItems, +- pageInfo: { +- ...pageInfo.nextCursor && { +- nextCursor: util.encodeCursor(pageInfo.nextCursor) +- }, +- ...pageInfo.prevCursor && { +- prevCursor: util.encodeCursor(pageInfo.prevCursor) ++ const actorId = await auditLogger.getActorId( ++ req ++ ); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "QueriedCatalogEntityFetch", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ message: `Queried entity fetch attempt initiated by ${actorId}` ++ }); ++ const { items, pageInfo, totalItems } = await entitiesCatalog.queryEntities({ ++ limit: req.query.limit, ++ ...parseQueryEntitiesParams.parseQueryEntitiesParams(req.query), ++ credentials: await httpAuth.credentials(req) ++ }); ++ res.json({ ++ items, ++ totalItems, ++ pageInfo: { ++ ...pageInfo.nextCursor && { ++ nextCursor: util.encodeCursor(pageInfo.nextCursor) ++ }, ++ ...pageInfo.prevCursor && { ++ prevCursor: util.encodeCursor(pageInfo.prevCursor) ++ } + } +- } +- }); ++ }); ++ await auditLogger.auditLog({ ++ eventName: "QueriedCatalogEntityFetch", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ metadata: { ++ totalEntities: totalItems, ++ pageInfo: { ++ ...pageInfo.nextCursor && { ++ nextCursor: util.encodeCursor(pageInfo.nextCursor) ++ }, ++ ...pageInfo.prevCursor && { ++ prevCursor: util.encodeCursor(pageInfo.prevCursor) ++ } ++ } ++ }, ++ // Let's not log out the entities since this can make the log very big ++ response: { ++ status: 200 ++ }, ++ message: `Queried entity fetch attempt by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "QueriedCatalogEntityFetch", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Queried entity fetch attempt by ${actorId} failed` ++ }); ++ throw err; ++ } + }).get("/entities/by-uid/:uid", async (req, res) => { + const { uid } = req.params; +- const { entities } = await entitiesCatalog.entities({ +- filter: basicEntityFilter.basicEntityFilter({ "metadata.uid": uid }), +- credentials: await httpAuth.credentials(req) +- }); +- if (!entities.length) { +- throw new errors.NotFoundError(`No entity with uid ${uid}`); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetchByUid", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ metadata: { ++ uid ++ }, ++ message: `Fetch attempt for entity with uid ${uid} initiated by ${actorId}` ++ }); ++ const { entities } = await entitiesCatalog.entities({ ++ filter: basicEntityFilter.basicEntityFilter({ "metadata.uid": uid }), ++ credentials: await httpAuth.credentials(req) ++ }); ++ if (!entities.length) { ++ throw new errors.NotFoundError(`No entity with uid ${uid}`); ++ } ++ res.status(200).json(entities[0]); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetchByUid", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ metadata: { ++ uid, ++ entityRef: catalogModel.stringifyEntityRef(entities[0]) ++ }, ++ response: { ++ status: 200 ++ }, ++ message: `Fetch attempt for entity with uid ${uid} by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetchByUid", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ metadata: { ++ uid ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Fetch attempt for entity with uid ${uid} by ${actorId} failed` ++ }); ++ throw err; + } +- res.status(200).json(entities[0]); + }).delete("/entities/by-uid/:uid", async (req, res) => { + const { uid } = req.params; +- await entitiesCatalog.removeEntityByUid(uid, { +- credentials: await httpAuth.credentials(req) +- }); +- res.status(204).end(); ++ const actorId = await auditLogger.getActorId(req); ++ let entityRef; ++ try { ++ const { entities } = await entitiesCatalog.entities({ ++ filter: basicEntityFilter.basicEntityFilter({ "metadata.uid": uid }), ++ credentials: await httpAuth.credentials(req) ++ }); ++ if (entities.length) { ++ entityRef = catalogModel.stringifyEntityRef(entities[0]); ++ } ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityDeletion", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ metadata: { ++ uid, ++ entityRef ++ }, ++ message: `Deletion attempt for entity with uid ${uid} initiated by ${actorId}` ++ }); ++ await entitiesCatalog.removeEntityByUid(uid, { ++ credentials: await httpAuth.credentials(req) ++ }); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityDeletion", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ metadata: { ++ uid, ++ entityRef ++ }, ++ response: { ++ status: 204 ++ }, ++ message: `Deletion attempt for entity with uid ${uid} by ${actorId} succeeded` ++ }); ++ res.status(204).end(); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityDeletion", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Deletion attempt for entity with uid ${uid} by ${actorId} failed` ++ }); ++ throw err; ++ } + }).get("/entities/by-name/:kind/:namespace/:name", async (req, res) => { + const { kind, namespace, name } = req.params; +- const { entities } = await entitiesCatalog.entities({ +- filter: basicEntityFilter.basicEntityFilter({ +- kind, +- "metadata.namespace": namespace, +- "metadata.name": name +- }), +- credentials: await httpAuth.credentials(req) +- }); +- if (!entities.length) { +- throw new errors.NotFoundError( +- `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'` +- ); ++ const entityRef = catalogModel.stringifyEntityRef({ kind, namespace, name }); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetchByName", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ metadata: { ++ entityRef ++ }, ++ message: `Fetch attempt for entity with entityRef ${entityRef} initiated by ${actorId}` ++ }); ++ const { entities } = await entitiesCatalog.entities({ ++ filter: basicEntityFilter.basicEntityFilter({ ++ kind, ++ "metadata.namespace": namespace, ++ "metadata.name": name ++ }), ++ credentials: await httpAuth.credentials(req) ++ }); ++ if (!entities.length) { ++ throw new errors.NotFoundError( ++ `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'` ++ ); ++ } ++ res.status(200).json(entities[0]); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetchByName", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ metadata: { ++ entityRef ++ }, ++ response: { ++ status: 200 ++ }, ++ message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFetchByName", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ metadata: { ++ entityRef ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} failed` ++ }); ++ throw err; + } +- res.status(200).json(entities[0]); + }).get( + "/entities/by-name/:kind/:namespace/:name/ancestry", + async (req, res) => { + const { kind, namespace, name } = req.params; + const entityRef = catalogModel.stringifyEntityRef({ kind, namespace, name }); +- const response = await entitiesCatalog.entityAncestry(entityRef, { ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityAncestryFetch", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ metadata: { ++ entityRef ++ }, ++ message: `Fetch attempt for entity ancestor of entity ${entityRef} initiated by ${actorId}` ++ }); ++ const response = await entitiesCatalog.entityAncestry(entityRef, { ++ credentials: await httpAuth.credentials(req) ++ }); ++ res.status(200).json(response); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityAncestryFetch", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ metadata: { ++ rootEntityRef: response.rootEntityRef, ++ ancestry: response.items.map((ancestryLink) => { ++ return { ++ entityRef: catalogModel.stringifyEntityRef(ancestryLink.entity), ++ parentEntityRefs: ancestryLink.parentEntityRefs ++ }; ++ }) ++ }, ++ response: { ++ status: 200 ++ }, ++ message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityAncestryFetch", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ metadata: { ++ entityRef ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} failed` ++ }); ++ throw err; ++ } ++ } ++ ).post("/entities/by-refs", async (req, res) => { ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityBatchFetch", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ message: `Batch entity fetch attempt initiated by ${actorId}` ++ }); ++ const request = entitiesBatchRequest.entitiesBatchRequest(req); ++ const response = await entitiesCatalog.entitiesBatch({ ++ entityRefs: request.entityRefs, ++ filter: parseEntityFilterParams.parseEntityFilterParams(req.query), ++ fields: parseEntityTransformParams.parseEntityTransformParams(req.query, request.fields), + credentials: await httpAuth.credentials(req) + }); + res.status(200).json(response); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityBatchFetch", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ metadata: { ++ ...request ++ }, ++ response: { ++ status: 200 ++ }, ++ message: `Batch entity fetch attempt by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityBatchFetch", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Batch entity fetch attempt by ${actorId} failed` ++ }); ++ throw err; + } +- ).post("/entities/by-refs", async (req, res) => { +- const request = entitiesBatchRequest.entitiesBatchRequest(req); +- const response = await entitiesCatalog.entitiesBatch({ +- entityRefs: request.entityRefs, +- filter: parseEntityFilterParams.parseEntityFilterParams(req.query), +- fields: parseEntityTransformParams.parseEntityTransformParams(req.query, request.fields), +- credentials: await httpAuth.credentials(req) +- }); +- res.status(200).json(response); + }).get("/entity-facets", async (req, res) => { +- const response = await entitiesCatalog.facets({ +- filter: parseEntityFilterParams.parseEntityFilterParams(req.query), +- facets: parseEntityFacetParams.parseEntityFacetParams(req.query), +- credentials: await httpAuth.credentials(req) +- }); +- res.status(200).json(response); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFacetFetch", ++ actorId, ++ status: "succeeded", ++ stage: "initiation", ++ request: req, ++ message: `Entity facet fetch attempt initiated by ${actorId}` ++ }); ++ const response = await entitiesCatalog.facets({ ++ filter: parseEntityFilterParams.parseEntityFilterParams(req.query), ++ facets: parseEntityFacetParams.parseEntityFacetParams(req.query), ++ credentials: await httpAuth.credentials(req) ++ }); ++ res.status(200).json(response); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFacetFetch", ++ actorId, ++ status: "succeeded", ++ stage: "completion", ++ request: req, ++ response: { status: 200 }, ++ message: `Entity facet fetch attempt by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityFacetFetch", ++ actorId, ++ status: "failed", ++ stage: "completion", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Entity facet fetch attempt by ${actorId} failed` ++ }); ++ throw err; ++ } + }); + } + if (locationService) { + router.post("/locations", async (req, res) => { ++ const credentials = await httpAuth.credentials(req); ++ const actorId = await auditLogger.getActorId(req); + const location = await util.validateRequestBody(req, util.locationInput); + const dryRun = yn__default.default(req.query.dryRun, { default: false }); +- if (!dryRun) { +- util.disallowReadonlyMode(readonlyEnabled); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationCreation", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ metadata: { ++ location, ++ isDryRun: dryRun ++ }, ++ request: req, ++ message: `Creation attempt of location entity for ${location.target} initiated by ${actorId}` ++ }); ++ if (!dryRun) { ++ util.disallowReadonlyMode(readonlyEnabled); ++ } ++ const output = await locationService.createLocation( ++ location, ++ dryRun, ++ { ++ credentials ++ } ++ ); ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationCreation", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ metadata: { ++ location: output.location, ++ isDryRun: dryRun ++ }, ++ request: req, ++ response: { ++ status: 201 ++ }, ++ message: `Creation of location entity for ${location.target} initiated by ${actorId} succeeded` ++ }); ++ res.status(201).json(output); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationCreation", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ actorId, ++ metadata: { ++ location, ++ isDryRun: dryRun ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ request: req, ++ message: `Creation of location entity for ${location.target} initiated by ${actorId} failed` ++ }); ++ throw err; + } +- const output = await locationService.createLocation(location, dryRun, { +- credentials: await httpAuth.credentials(req) +- }); +- res.status(201).json(output); + }).get("/locations", async (req, res) => { +- const locations = await locationService.listLocations({ +- credentials: await httpAuth.credentials(req) +- }); +- res.status(200).json(locations.map((l) => ({ data: l }))); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetch", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ request: req, ++ message: `Fetch attempt of locations initiated by ${actorId}` ++ }); ++ const locations = await locationService.listLocations({ ++ credentials: await httpAuth.credentials(req) ++ }); ++ res.status(200).json(locations.map((l) => ({ data: l }))); ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetch", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ request: req, ++ response: { ++ status: 200 ++ }, ++ message: `Fetch attempt of locations by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetch", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ actorId, ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Fetch attempt of locations by ${actorId} failed` ++ }); ++ throw err; ++ } + }).get("/locations/:id", async (req, res) => { + const { id } = req.params; +- const output = await locationService.getLocation(id, { +- credentials: await httpAuth.credentials(req) +- }); +- res.status(200).json(output); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetchById", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ metadata: { ++ id ++ }, ++ request: req, ++ message: `Fetch attempt of location with id: ${id} initiated by ${actorId}` ++ }); ++ const output = await locationService.getLocation(id, { ++ credentials: await httpAuth.credentials(req) ++ }); ++ res.status(200).json(output); ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetchById", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ metadata: { ++ id ++ }, ++ response: { ++ status: 200, ++ body: output ++ }, ++ request: req, ++ message: `Fetch attempt of location with id: ${id} by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetchById", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ actorId, ++ metadata: { ++ id ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ request: req, ++ message: `Fetch attempt of location with id: ${id} by ${actorId} failed` ++ }); ++ throw err; ++ } + }).delete("/locations/:id", async (req, res) => { +- util.disallowReadonlyMode(readonlyEnabled); ++ const actorId = await auditLogger.getActorId(req); + const { id } = req.params; +- await locationService.deleteLocation(id, { +- credentials: await httpAuth.credentials(req) +- }); +- res.status(204).end(); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationDeletion", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ metadata: { ++ id ++ }, ++ request: req, ++ message: `Deletion attempt of location with id: ${id} initiated by ${actorId}` ++ }); ++ util.disallowReadonlyMode(readonlyEnabled); ++ const location = await locationService.getLocation(id, { ++ credentials: await httpAuth.credentials(req) ++ }); ++ await locationService.deleteLocation(id, { ++ credentials: await httpAuth.credentials(req) ++ }); ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationDeletion", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ metadata: { ++ location ++ }, ++ response: { ++ status: 204 ++ }, ++ request: req, ++ message: `Deletion attempt of location with id: ${id} by ${actorId} succeeded` ++ }); ++ res.status(204).end(); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationDeletion", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ actorId, ++ metadata: { ++ id ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ request: req, ++ message: `Deletion attempt of location with id: ${id} by ${actorId} failed` ++ }); ++ throw err; ++ } + }).get("/locations/by-entity/:kind/:namespace/:name", async (req, res) => { + const { kind, namespace, name } = req.params; +- const output = await locationService.getLocationByEntity( +- { kind, namespace, name }, +- { credentials: await httpAuth.credentials(req) } +- ); +- res.status(200).json(output); ++ const actorId = await auditLogger.getActorId(req); ++ const locationRef = `${kind}:${namespace}/${name}`; ++ try { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetchByEntityRef", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ metadata: { ++ locationRef ++ }, ++ request: req, ++ message: `Fetch attempt for location ${locationRef} initiated by ${actorId}` ++ }); ++ const output = await locationService.getLocationByEntity( ++ { kind, namespace, name }, ++ { credentials: await httpAuth.credentials(req) } ++ ); ++ res.status(200).json(output); ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetchByEntityRef", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ metadata: { ++ locationRef ++ }, ++ response: { ++ status: 200, ++ body: output ++ }, ++ request: req, ++ message: `Fetch attempt for location ${locationRef} by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationFetchByEntityRef", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ actorId, ++ metadata: { ++ locationRef ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ request: req, ++ message: `Fetch attempt for location ${locationRef} by ${actorId} failed` ++ }); ++ throw err; ++ } + }); + } + if (locationAnalyzer) { + router.post("/analyze-location", async (req, res) => { +- const body = await util.validateRequestBody( +- req, +- zod.z.object({ +- location: util.locationInput, +- catalogFilename: zod.z.string().optional() +- }) +- ); +- const schema = zod.z.object({ +- location: util.locationInput, +- catalogFilename: zod.z.string().optional() +- }); +- const credentials = await httpAuth.credentials(req); +- const parsedBody = schema.parse(body); ++ const actorId = await auditLogger.getActorId(req); + try { +- const output = await locationAnalyzer.analyzeLocation( +- parsedBody, +- credentials ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationAnalyze", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ request: req, ++ message: `Analyze location for location initiated by ${actorId}` ++ }); ++ const body = await util.validateRequestBody( ++ req, ++ zod.z.object({ ++ location: util.locationInput, ++ catalogFilename: zod.z.string().optional() ++ }) + ); +- res.status(200).json(output); +- } catch (err) { +- if ( +- // Catch errors from parse-url library. +- err.name === "Error" && "subject_url" in err +- ) { +- throw new errors.InputError("The given location.target is not a URL"); ++ const schema = zod.z.object({ ++ location: util.locationInput, ++ catalogFilename: zod.z.string().optional() ++ }); ++ const credentials = await httpAuth.credentials(req); ++ const parsedBody = schema.parse(body); ++ try { ++ const output = await locationAnalyzer.analyzeLocation( ++ parsedBody, ++ credentials ++ ); ++ res.status(200).json(output); ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationAnalyze", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ request: req, ++ response: { ++ status: 200, ++ body: output ++ }, ++ message: `Analyze location for location by ${actorId} succeeded` ++ }); ++ } catch (err) { ++ if ( ++ // Catch errors from parse-url library. ++ err.name === "Error" && "subject_url" in err ++ ) { ++ throw new errors.InputError("The given location.target is not a URL"); ++ } ++ throw err; + } ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogLocationAnalyze", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ actorId, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ request: req, ++ message: `Analyze location for location by ${actorId} failed` ++ }); + throw err; + } + }); + } + if (orchestrator) { + router.post("/validate-entity", async (req, res) => { +- const bodySchema = zod.z.object({ +- entity: zod.z.unknown(), +- location: zod.z.string() +- }); +- let body; +- let entity; +- let location; ++ const actorId = await auditLogger.getActorId(req); + try { +- body = await util.validateRequestBody(req, bodySchema); +- entity = util$1.validateEntityEnvelope(body.entity); +- location = catalogModel.parseLocationRef(body.location); +- if (location.type !== "url") +- throw new TypeError( +- `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path` +- ); +- } catch (err) { +- return res.status(400).json({ +- errors: [errors.serializeError(err)] ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityValidate", ++ status: "succeeded", ++ stage: "initiation", ++ actorId, ++ request: req, ++ message: `Entity validation for entity initiated by ${actorId}` + }); +- } +- const credentials = await httpAuth.credentials(req); +- const authorizedValidationService = new AuthorizedValidationService.AuthorizedValidationService( +- orchestrator, +- permissionsService +- ); +- const processingResult = await authorizedValidationService.process( +- { +- entity: { +- ...entity, +- metadata: { +- ...entity.metadata, +- annotations: { +- [catalogModel.ANNOTATION_LOCATION]: body.location, +- [catalogModel.ANNOTATION_ORIGIN_LOCATION]: body.location, +- ...entity.metadata.annotations ++ const bodySchema = zod.z.object({ ++ entity: zod.z.unknown(), ++ location: zod.z.string() ++ }); ++ let body; ++ let entity; ++ let location; ++ try { ++ body = await util.validateRequestBody(req, bodySchema); ++ entity = util$1.validateEntityEnvelope(body.entity); ++ location = catalogModel.parseLocationRef(body.location); ++ if (location.type !== "url") ++ throw new TypeError( ++ `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path` ++ ); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityValidate", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ actorId, ++ request: req, ++ message: `Entity validation for entity initiated by ${actorId} failed` ++ }); ++ return res.status(400).json({ ++ errors: [errors.serializeError(err)] ++ }); ++ } ++ const credentials = await httpAuth.credentials(req); ++ const authorizedValidationService = new AuthorizedValidationService.AuthorizedValidationService( ++ orchestrator, ++ permissionsService ++ ); ++ const processingResult = await authorizedValidationService.process( ++ { ++ entity: { ++ ...entity, ++ metadata: { ++ ...entity.metadata, ++ annotations: { ++ [catalogModel.ANNOTATION_LOCATION]: body.location, ++ [catalogModel.ANNOTATION_ORIGIN_LOCATION]: body.location, ++ ...entity.metadata.annotations ++ } + } + } +- } +- }, +- credentials +- ); +- if (!processingResult.ok) +- res.status(400).json({ +- errors: processingResult.errors.map((e) => errors.serializeError(e)) ++ }, ++ credentials ++ ); ++ if (!processingResult.ok) { ++ const errors$1 = processingResult.errors.map((e) => errors.serializeError(e)); ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityValidate", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ errors: errors$1, ++ response: { ++ status: 400 ++ }, ++ actorId, ++ request: req, ++ message: `Entity validation for entity initiated by ${actorId} failed` ++ }); ++ return res.status(400).json({ ++ errors: errors$1 ++ }); ++ } ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityValidate", ++ status: "succeeded", ++ stage: "completion", ++ actorId, ++ response: { ++ status: 200 ++ }, ++ request: req, ++ message: `Entity validation for entity by ${actorId} succeeded` + }); +- return res.status(200).end(); ++ return res.status(200).end(); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "CatalogEntityValidate", ++ status: "failed", ++ stage: "completion", ++ level: "error", ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ actorId, ++ request: req, ++ message: `Entity validation for entity initiated by ${actorId} failed` ++ }); ++ throw err; ++ } + }); + } + router.use(backendCommon.errorHandler()); +diff --git a/dist/service/createRouter.cjs.js.map b/dist/service/createRouter.cjs.js.map +index d99c14b522abceb4b397ecb4aede3b53a5f51e04..d4313425f9e28b91aabf58c2434a267879e08d6d 100644 +--- a/dist/service/createRouter.cjs.js.map ++++ b/dist/service/createRouter.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"createRouter.cjs.js","sources":["../../src/service/createRouter.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError, serializeError } from '@backstage/errors';\nimport express from 'express';\nimport yn from 'yn';\nimport { z } from 'zod';\nimport { EntitiesCatalog } from '../catalog/types';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { validateEntityEnvelope } from '../processing/util';\nimport {\n basicEntityFilter,\n entitiesBatchRequest,\n parseEntityFilterParams,\n parseEntityTransformParams,\n parseQueryEntitiesParams,\n} from './request';\nimport { parseEntityFacetParams } from './request/parseEntityFacetParams';\nimport { parseEntityOrderParams } from './request/parseEntityOrderParams';\nimport { LocationService, RefreshService } from './types';\nimport {\n disallowReadonlyMode,\n encodeCursor,\n locationInput,\n validateRequestBody,\n} from './util';\nimport { createOpenApiRouter } from '../schema/openapi.generated';\nimport { parseEntityPaginationParams } from './request/parseEntityPaginationParams';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n SchedulerService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { LocationAnalyzer } from '@backstage/plugin-catalog-node';\nimport { AuthorizedValidationService } from './AuthorizedValidationService';\n\n/**\n * Options used by {@link createRouter}.\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport interface RouterOptions {\n entitiesCatalog?: EntitiesCatalog;\n locationAnalyzer?: LocationAnalyzer;\n locationService: LocationService;\n orchestrator?: CatalogProcessingOrchestrator;\n refreshService?: RefreshService;\n scheduler?: SchedulerService;\n logger: LoggerService;\n config: Config;\n permissionIntegrationRouter?: express.Router;\n auth: AuthService;\n httpAuth: HttpAuthService;\n permissionsService: PermissionsService;\n}\n\n/**\n * Creates a catalog router.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = await createOpenApiRouter({\n validatorOptions: {\n // We want the spec to be up to date with the expected value, but the return type needs\n // to be controlled by the router implementation not the request validator.\n ignorePaths: /^\\/validate-entity\\/?$/,\n },\n });\n const {\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n config,\n logger,\n permissionIntegrationRouter,\n permissionsService,\n auth,\n httpAuth,\n } = options;\n\n const readonlyEnabled =\n config.getOptionalBoolean('catalog.readonly') || false;\n if (readonlyEnabled) {\n logger.info('Catalog is running in readonly mode');\n }\n\n if (refreshService) {\n router.post('/refresh', async (req, res) => {\n const { authorizationToken, ...restBody } = req.body;\n\n const credentials = authorizationToken\n ? await auth.authenticate(authorizationToken)\n : await httpAuth.credentials(req);\n\n await refreshService.refresh({\n ...restBody,\n credentials,\n });\n res.status(200).end();\n });\n }\n\n if (permissionIntegrationRouter) {\n router.use(permissionIntegrationRouter);\n }\n\n if (entitiesCatalog) {\n router\n .get('/entities', async (req, res) => {\n const { entities, pageInfo } = await entitiesCatalog.entities({\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query),\n order: parseEntityOrderParams(req.query),\n pagination: parseEntityPaginationParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n // Add a Link header to the next page\n if (pageInfo.hasNextPage) {\n const url = new URL(`http://ignored${req.url}`);\n url.searchParams.delete('offset');\n url.searchParams.set('after', pageInfo.endCursor);\n res.setHeader('link', `<${url.pathname}${url.search}>; rel=\"next\"`);\n }\n\n // TODO(freben): encode the pageInfo in the response\n res.json(entities);\n })\n .get('/entities/by-query', async (req, res) => {\n const { items, pageInfo, totalItems } =\n await entitiesCatalog.queryEntities({\n limit: req.query.limit,\n offset: req.query.offset,\n ...parseQueryEntitiesParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n res.json({\n items,\n totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n });\n })\n .get('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(`No entity with uid ${uid}`);\n }\n res.status(200).json(entities[0]);\n })\n .delete('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n await entitiesCatalog.removeEntityByUid(uid, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(204).end();\n })\n .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({\n kind: kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(\n `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`,\n );\n }\n res.status(200).json(entities[0]);\n })\n .get(\n '/entities/by-name/:kind/:namespace/:name/ancestry',\n async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const response = await entitiesCatalog.entityAncestry(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n },\n )\n .post('/entities/by-refs', async (req, res) => {\n const request = entitiesBatchRequest(req);\n const response = await entitiesCatalog.entitiesBatch({\n entityRefs: request.entityRefs,\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query, request.fields),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n })\n .get('/entity-facets', async (req, res) => {\n const response = await entitiesCatalog.facets({\n filter: parseEntityFilterParams(req.query),\n facets: parseEntityFacetParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n });\n }\n\n if (locationService) {\n router\n .post('/locations', async (req, res) => {\n const location = await validateRequestBody(req, locationInput);\n const dryRun = yn(req.query.dryRun, { default: false });\n\n // when in dryRun addLocation is effectively a read operation so we don't\n // need to disallow readonly\n if (!dryRun) {\n disallowReadonlyMode(readonlyEnabled);\n }\n\n const output = await locationService.createLocation(location, dryRun, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(201).json(output);\n })\n .get('/locations', async (req, res) => {\n const locations = await locationService.listLocations({\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(locations.map(l => ({ data: l })));\n })\n\n .get('/locations/:id', async (req, res) => {\n const { id } = req.params;\n const output = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(output);\n })\n .delete('/locations/:id', async (req, res) => {\n disallowReadonlyMode(readonlyEnabled);\n\n const { id } = req.params;\n await locationService.deleteLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(204).end();\n })\n .get('/locations/by-entity/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const output = await locationService.getLocationByEntity(\n { kind, namespace, name },\n { credentials: await httpAuth.credentials(req) },\n );\n res.status(200).json(output);\n });\n }\n\n if (locationAnalyzer) {\n router.post('/analyze-location', async (req, res) => {\n const body = await validateRequestBody(\n req,\n z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n }),\n );\n const schema = z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n });\n const credentials = await httpAuth.credentials(req);\n const parsedBody = schema.parse(body);\n try {\n const output = await locationAnalyzer.analyzeLocation(\n parsedBody,\n credentials,\n );\n res.status(200).json(output);\n } catch (err) {\n if (\n // Catch errors from parse-url library.\n err.name === 'Error' &&\n 'subject_url' in err\n ) {\n throw new InputError('The given location.target is not a URL');\n }\n throw err;\n }\n });\n }\n\n if (orchestrator) {\n router.post('/validate-entity', async (req, res) => {\n const bodySchema = z.object({\n entity: z.unknown(),\n location: z.string(),\n });\n\n let body: z.infer;\n let entity: Entity;\n let location: { type: string; target: string };\n try {\n body = await validateRequestBody(req, bodySchema);\n entity = validateEntityEnvelope(body.entity);\n location = parseLocationRef(body.location);\n if (location.type !== 'url')\n throw new TypeError(\n `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path`,\n );\n } catch (err) {\n return res.status(400).json({\n errors: [serializeError(err)],\n });\n }\n\n const credentials = await httpAuth.credentials(req);\n const authorizedValidationService = new AuthorizedValidationService(\n orchestrator,\n permissionsService,\n );\n const processingResult = await authorizedValidationService.process(\n {\n entity: {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n [ANNOTATION_LOCATION]: body.location,\n [ANNOTATION_ORIGIN_LOCATION]: body.location,\n ...entity.metadata.annotations,\n },\n },\n },\n },\n credentials,\n );\n\n if (!processingResult.ok)\n res.status(400).json({\n errors: processingResult.errors.map(e => serializeError(e)),\n });\n return res.status(200).end();\n });\n }\n\n router.use(errorHandler());\n return router;\n}\n"],"names":["createOpenApiRouter","parseEntityFilterParams","parseEntityTransformParams","parseEntityOrderParams","parseEntityPaginationParams","parseQueryEntitiesParams","encodeCursor","basicEntityFilter","NotFoundError","stringifyEntityRef","entitiesBatchRequest","parseEntityFacetParams","validateRequestBody","locationInput","yn","disallowReadonlyMode","z","InputError","validateEntityEnvelope","parseLocationRef","serializeError","AuthorizedValidationService","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","errorHandler"],"mappings":"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"} +\ No newline at end of file ++{"version":3,"file":"createRouter.cjs.js","sources":["../../src/service/createRouter.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError, serializeError } from '@backstage/errors';\nimport express from 'express';\nimport yn from 'yn';\nimport { z } from 'zod';\nimport { EntitiesCatalog } from '../catalog/types';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { validateEntityEnvelope } from '../processing/util';\nimport {\n basicEntityFilter,\n entitiesBatchRequest,\n parseEntityFilterParams,\n parseEntityTransformParams,\n parseQueryEntitiesParams,\n} from './request';\nimport { parseEntityFacetParams } from './request/parseEntityFacetParams';\nimport { parseEntityOrderParams } from './request/parseEntityOrderParams';\nimport { LocationService, RefreshService } from './types';\nimport {\n disallowReadonlyMode,\n encodeCursor,\n locationInput,\n validateRequestBody,\n} from './util';\nimport { createOpenApiRouter } from '../schema/openapi.generated';\nimport { parseEntityPaginationParams } from './request/parseEntityPaginationParams';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n SchedulerService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { LocationAnalyzer } from '@backstage/plugin-catalog-node';\nimport { AuthorizedValidationService } from './AuthorizedValidationService';\n\nimport { DefaultAuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\n/**\n * Options used by {@link createRouter}.\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport interface RouterOptions {\n entitiesCatalog?: EntitiesCatalog;\n locationAnalyzer?: LocationAnalyzer;\n locationService: LocationService;\n orchestrator?: CatalogProcessingOrchestrator;\n refreshService?: RefreshService;\n scheduler?: SchedulerService;\n logger: LoggerService;\n config: Config;\n permissionIntegrationRouter?: express.Router;\n auth: AuthService;\n httpAuth: HttpAuthService;\n permissionsService: PermissionsService;\n}\n\n/**\n * Creates a catalog router.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = await createOpenApiRouter({\n validatorOptions: {\n // We want the spec to be up to date with the expected value, but the return type needs\n // to be controlled by the router implementation not the request validator.\n ignorePaths: /^\\/validate-entity\\/?$/,\n },\n });\n const {\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n config,\n logger,\n permissionIntegrationRouter,\n permissionsService,\n auth,\n httpAuth,\n } = options;\n\n const auditLogger = new DefaultAuditLogger({\n logger,\n authService: auth,\n httpAuthService: httpAuth,\n });\n const readonlyEnabled =\n config.getOptionalBoolean('catalog.readonly') || false;\n if (readonlyEnabled) {\n logger.info('Catalog is running in readonly mode');\n }\n\n if (refreshService) {\n // TODO: Potentially find a way to track the ancestor that gets refreshed to refresh this entity (as well as the child of that ancestor?)\n router.post('/refresh', async (req, res) => {\n const { authorizationToken, ...restBody } = req.body;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityRefresh',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n metadata: {\n entityRef: restBody.entityRef,\n },\n request: req,\n message: `Refresh attempt for ${restBody.entityRef} initiated by ${actorId}`,\n });\n\n const credentials = authorizationToken\n ? await auth.authenticate(authorizationToken)\n : await httpAuth.credentials(req);\n\n await refreshService.refresh({\n ...restBody,\n credentials,\n });\n await auditLogger.auditLog({\n eventName: 'CatalogEntityRefresh',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n metadata: {\n entityRef: restBody.entityRef,\n },\n response: {\n status: 200,\n },\n request: req,\n message: `Refresh attempt for ${restBody.entityRef} triggered by ${actorId}`,\n });\n res.status(200).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityRefresh',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n metadata: {\n entityRef: restBody.entityRef,\n },\n request: req,\n message: `Refresh attempt for ${restBody.entityRef} by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (permissionIntegrationRouter) {\n router.use(permissionIntegrationRouter);\n }\n\n if (entitiesCatalog) {\n router\n .get('/entities', async (req, res) => {\n const actorId = await auditLogger.getActorId(\n req as unknown as express.Request,\n );\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req as unknown as express.Request,\n message: `Entity fetch attempt initiated by ${actorId}`,\n });\n const { entities, pageInfo } = await entitiesCatalog.entities({\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query),\n order: parseEntityOrderParams(req.query),\n pagination: parseEntityPaginationParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n // Add a Link header to the next page\n if (pageInfo.hasNextPage) {\n const url = new URL(`http://ignored${req.url}`);\n url.searchParams.delete('offset');\n url.searchParams.set('after', pageInfo.endCursor);\n res.setHeader('link', `<${url.pathname}${url.search}>; rel=\"next\"`);\n }\n\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req as unknown as express.Request,\n // Let's not log out the entities since this can make the log very big due to it not being paged?\n response: {\n status: 200,\n },\n message: `Entity fetch attempt by ${actorId} succeeded`,\n });\n\n // TODO(freben): encode the pageInfo in the response\n res.json(entities);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetch',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req as unknown as express.Request,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Entity fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entities/by-query', async (req, res) => {\n const actorId = await auditLogger.getActorId(\n req as unknown as express.Request,\n );\n try {\n await auditLogger.auditLog({\n eventName: 'QueriedCatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req as unknown as express.Request,\n message: `Queried entity fetch attempt initiated by ${actorId}`,\n });\n const { items, pageInfo, totalItems } =\n await entitiesCatalog.queryEntities({\n limit: req.query.limit,\n ...parseQueryEntitiesParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n res.json({\n items,\n totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n });\n await auditLogger.auditLog({\n eventName: 'QueriedCatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req as unknown as express.Request,\n metadata: {\n totalEntities: totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n },\n // Let's not log out the entities since this can make the log very big\n response: {\n status: 200,\n },\n message: `Queried entity fetch attempt by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'QueriedCatalogEntityFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req as unknown as express.Request,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Queried entity fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByUid',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n uid: uid,\n },\n message: `Fetch attempt for entity with uid ${uid} initiated by ${actorId}`,\n });\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(`No entity with uid ${uid}`);\n }\n res.status(200).json(entities[0]);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByUid',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n uid: uid,\n entityRef: stringifyEntityRef(entities[0]),\n },\n response: {\n status: 200,\n },\n message: `Fetch attempt for entity with uid ${uid} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByUid',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n metadata: {\n uid: uid,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt for entity with uid ${uid} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .delete('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n const actorId = await auditLogger.getActorId(req);\n let entityRef: string | undefined;\n try {\n // Get the entityRef of the UID so users can more easily identity the entity\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n if (entities.length) {\n entityRef = stringifyEntityRef(entities[0]);\n }\n await auditLogger.auditLog({\n eventName: 'CatalogEntityDeletion',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n uid: uid,\n entityRef: entityRef,\n },\n message: `Deletion attempt for entity with uid ${uid} initiated by ${actorId}`,\n });\n await entitiesCatalog.removeEntityByUid(uid, {\n credentials: await httpAuth.credentials(req),\n });\n await auditLogger.auditLog({\n eventName: 'CatalogEntityDeletion',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n uid: uid,\n entityRef: entityRef,\n },\n response: {\n status: 204,\n },\n message: `Deletion attempt for entity with uid ${uid} by ${actorId} succeeded`,\n });\n res.status(204).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityDeletion',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Deletion attempt for entity with uid ${uid} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByName',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n message: `Fetch attempt for entity with entityRef ${entityRef} initiated by ${actorId}`,\n });\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({\n kind: kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(\n `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`,\n );\n }\n res.status(200).json(entities[0]);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByName',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n response: {\n status: 200,\n },\n message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByName',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get(\n '/entities/by-name/:kind/:namespace/:name/ancestry',\n async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityAncestryFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n message: `Fetch attempt for entity ancestor of entity ${entityRef} initiated by ${actorId}`,\n });\n const response = await entitiesCatalog.entityAncestry(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityAncestryFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n rootEntityRef: response.rootEntityRef,\n ancestry: response.items.map(ancestryLink => {\n return {\n entityRef: stringifyEntityRef(ancestryLink.entity),\n parentEntityRefs: ancestryLink.parentEntityRefs,\n };\n }),\n },\n response: {\n status: 200,\n },\n message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityAncestryFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} failed`,\n });\n throw err;\n }\n },\n )\n .post('/entities/by-refs', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityBatchFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n message: `Batch entity fetch attempt initiated by ${actorId}`,\n });\n const request = entitiesBatchRequest(req);\n const response = await entitiesCatalog.entitiesBatch({\n entityRefs: request.entityRefs,\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query, request.fields),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityBatchFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n ...request,\n },\n response: {\n status: 200,\n },\n message: `Batch entity fetch attempt by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityBatchFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Batch entity fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entity-facets', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFacetFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n message: `Entity facet fetch attempt initiated by ${actorId}`,\n });\n const response = await entitiesCatalog.facets({\n filter: parseEntityFilterParams(req.query),\n facets: parseEntityFacetParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFacetFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n response: { status: 200 },\n message: `Entity facet fetch attempt by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFacetFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Entity facet fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (locationService) {\n router\n .post('/locations', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n const actorId = await auditLogger.getActorId(req);\n const location = await validateRequestBody(req, locationInput);\n const dryRun = yn(req.query.dryRun, { default: false });\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationCreation',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n location: location,\n isDryRun: dryRun,\n },\n request: req,\n message: `Creation attempt of location entity for ${location.target} initiated by ${actorId}`,\n });\n\n // when in dryRun addLocation is effectively a read operation so we don't\n // need to disallow readonly\n if (!dryRun) {\n disallowReadonlyMode(readonlyEnabled);\n }\n\n const output = await locationService.createLocation(\n location,\n dryRun,\n {\n credentials,\n },\n );\n await auditLogger.auditLog({\n eventName: 'CatalogLocationCreation',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n location: output.location,\n isDryRun: dryRun,\n },\n request: req,\n response: {\n status: 201,\n },\n message: `Creation of location entity for ${location.target} initiated by ${actorId} succeeded`,\n });\n res.status(201).json(output);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationCreation',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n location: location,\n isDryRun: dryRun,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Creation of location entity for ${location.target} initiated by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/locations', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetch',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n request: req,\n message: `Fetch attempt of locations initiated by ${actorId}`,\n });\n const locations = await locationService.listLocations({\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(locations.map(l => ({ data: l })));\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetch',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n request: req,\n response: {\n status: 200,\n },\n message: `Fetch attempt of locations by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetch',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt of locations by ${actorId} failed`,\n });\n throw err;\n }\n })\n\n .get('/locations/:id', async (req, res) => {\n const { id } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchById',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n id: id,\n },\n request: req,\n message: `Fetch attempt of location with id: ${id} initiated by ${actorId}`,\n });\n const output = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(output);\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchById',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n id: id,\n },\n response: {\n status: 200,\n body: output,\n },\n request: req,\n message: `Fetch attempt of location with id: ${id} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchById',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n id: id,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Fetch attempt of location with id: ${id} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .delete('/locations/:id', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n const { id } = req.params;\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationDeletion',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n id: id,\n },\n request: req,\n message: `Deletion attempt of location with id: ${id} initiated by ${actorId}`,\n });\n disallowReadonlyMode(readonlyEnabled);\n // Grabbing the information of the location begin deleted\n const location = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n await locationService.deleteLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n await auditLogger.auditLog({\n eventName: 'CatalogLocationDeletion',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n location,\n },\n response: {\n status: 204,\n },\n request: req,\n message: `Deletion attempt of location with id: ${id} by ${actorId} succeeded`,\n });\n res.status(204).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationDeletion',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n id: id,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Deletion attempt of location with id: ${id} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/locations/by-entity/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const actorId = await auditLogger.getActorId(req);\n const locationRef = `${kind}:${namespace}/${name}`;\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchByEntityRef',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n locationRef: locationRef,\n },\n request: req,\n message: `Fetch attempt for location ${locationRef} initiated by ${actorId}`,\n });\n\n const output = await locationService.getLocationByEntity(\n { kind, namespace, name },\n { credentials: await httpAuth.credentials(req) },\n );\n res.status(200).json(output);\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchByEntityRef',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n locationRef: locationRef,\n },\n response: {\n status: 200,\n body: output,\n },\n request: req,\n message: `Fetch attempt for location ${locationRef} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchByEntityRef',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n locationRef: locationRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Fetch attempt for location ${locationRef} by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (locationAnalyzer) {\n router.post('/analyze-location', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationAnalyze',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n request: req,\n message: `Analyze location for location initiated by ${actorId}`,\n });\n const body = await validateRequestBody(\n req,\n z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n }),\n );\n const schema = z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n });\n const credentials = await httpAuth.credentials(req);\n const parsedBody = schema.parse(body);\n try {\n const output = await locationAnalyzer.analyzeLocation(\n parsedBody,\n credentials,\n );\n res.status(200).json(output);\n await auditLogger.auditLog({\n eventName: 'CatalogLocationAnalyze',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n request: req,\n response: {\n status: 200,\n body: output,\n },\n message: `Analyze location for location by ${actorId} succeeded`,\n });\n } catch (err) {\n if (\n // Catch errors from parse-url library.\n err.name === 'Error' &&\n 'subject_url' in err\n ) {\n throw new InputError('The given location.target is not a URL');\n }\n throw err;\n }\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationAnalyze',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Analyze location for location by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (orchestrator) {\n router.post('/validate-entity', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId}`,\n });\n const bodySchema = z.object({\n entity: z.unknown(),\n location: z.string(),\n });\n\n let body: z.infer;\n let entity: Entity;\n let location: { type: string; target: string };\n try {\n body = await validateRequestBody(req, bodySchema);\n entity = validateEntityEnvelope(body.entity);\n location = parseLocationRef(body.location);\n if (location.type !== 'url')\n throw new TypeError(\n `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path`,\n );\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId} failed`,\n });\n return res.status(400).json({\n errors: [serializeError(err)],\n });\n }\n\n const credentials = await httpAuth.credentials(req);\n const authorizedValidationService = new AuthorizedValidationService(\n orchestrator,\n permissionsService,\n );\n\n const processingResult = await authorizedValidationService.process(\n {\n entity: {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n [ANNOTATION_LOCATION]: body.location,\n [ANNOTATION_ORIGIN_LOCATION]: body.location,\n ...entity.metadata.annotations,\n },\n },\n },\n },\n credentials,\n );\n\n if (!processingResult.ok) {\n const errors = processingResult.errors.map(e => serializeError(e));\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: errors,\n response: {\n status: 400,\n },\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId} failed`,\n });\n return res.status(400).json({\n errors,\n });\n }\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n response: {\n status: 200,\n },\n request: req,\n message: `Entity validation for entity by ${actorId} succeeded`,\n });\n return res.status(200).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n router.use(errorHandler());\n return router;\n}\n"],"names":["createOpenApiRouter","DefaultAuditLogger","parseEntityFilterParams","parseEntityTransformParams","parseEntityOrderParams","parseEntityPaginationParams","parseQueryEntitiesParams","encodeCursor","basicEntityFilter","NotFoundError","stringifyEntityRef","entitiesBatchRequest","parseEntityFacetParams","validateRequestBody","locationInput","yn","disallowReadonlyMode","z","InputError","validateEntityEnvelope","parseLocationRef","serializeError","AuthorizedValidationService","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","errors","errorHandler"],"mappings":"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"} +\ No newline at end of file diff --git a/.yarn/patches/@backstage-plugin-scaffolder-backend-npm-1.26.2.patch b/.yarn/patches/@backstage-plugin-scaffolder-backend-npm-1.26.2.patch new file mode 100644 index 0000000000..bd3bd966fc --- /dev/null +++ b/.yarn/patches/@backstage-plugin-scaffolder-backend-npm-1.26.2.patch @@ -0,0 +1,1800 @@ +diff --git a/dist/index.d.ts b/dist/index.d.ts +index ff0521a12ae6a15ebf1df629f5971dca68257dfa..dbcb8ad1d6de2958fed9a33d7a678c3473b9007d 100644 +--- a/dist/index.d.ts ++++ b/dist/index.d.ts +@@ -23,6 +23,7 @@ import * as _backstage_plugin_scaffolder_common from '@backstage/plugin-scaffold + import { TaskSpec, TaskRecovery, TemplateEntityStepV1beta3, TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; + import { Logger } from 'winston'; + import { WorkspaceProvider, AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; ++import { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node'; + import { PermissionEvaluator, PermissionRuleParams } from '@backstage/plugin-permission-common'; + import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, RESOURCE_TYPE_SCAFFOLDER_ACTION } from '@backstage/plugin-scaffolder-common/alpha'; + import express from 'express'; +@@ -378,7 +379,7 @@ declare const createPublishGitlabMergeRequestAction: (options: { + sourcePath?: string | undefined; + targetPath?: string | undefined; + token?: string | undefined; +- commitAction?: "auto" | "update" | "delete" | "create" | "skip" | undefined; ++ commitAction?: "create" | "update" | "delete" | "skip" | "auto" | undefined; + projectid?: string | undefined; + removeSourceBranch?: boolean | undefined; + assignee?: string | undefined; +@@ -711,11 +712,13 @@ declare class TaskManager implements TaskContext$1 { + private readonly signal; + private readonly logger; + private readonly workspaceService; ++ private readonly auditLogger; + private readonly auth?; + private isDone; + private heartbeatTimeoutId?; +- static create(task: CurrentClaimedTask, storage: TaskStore, abortSignal: AbortSignal, logger: Logger, auth?: AuthService, config?: Config, additionalWorkspaceProviders?: Record): TaskManager; ++ static create(task: CurrentClaimedTask, storage: TaskStore, abortSignal: AbortSignal, logger: Logger, auditLogger: AuditLogger, auth?: AuthService, config?: Config, additionalWorkspaceProviders?: Record): TaskManager; + private constructor(); ++ get taskId(): string; + get spec(): _backstage_plugin_scaffolder_common.TaskSpecV1beta3; + get cancelSignal(): AbortSignal; + get secrets(): TaskSecrets$1 | undefined; +@@ -790,6 +793,7 @@ type CreateWorkerOptions = { + integrations: ScmIntegrations; + workingDirectory: string; + logger: Logger; ++ auditLogger: AuditLogger; + additionalTemplateFilters?: Record; + /** + * The number of tasks that can be executed at the same time by the worker +@@ -817,6 +821,7 @@ declare class TaskWorker { + private taskQueue; + private logger; + private stopWorkers; ++ private auditLogger; + private constructor(); + static create(options: CreateWorkerOptions): Promise; + recoverTasks(): Promise; +diff --git a/dist/scaffolder/dryrun/createDryRunner.cjs.js b/dist/scaffolder/dryrun/createDryRunner.cjs.js +index b62685bf4f732cfd5a59448e4806d0886f0f1871..95b283f30d842b47adeeb0f5e0de3635367bd128 100644 +--- a/dist/scaffolder/dryrun/createDryRunner.cjs.js ++++ b/dist/scaffolder/dryrun/createDryRunner.cjs.js +@@ -39,6 +39,7 @@ function createDryRunner(options) { + await pluginScaffolderNode.deserializeDirectoryContents(contentsPath, input.directoryContents); + const abortSignal = new AbortController().signal; + const result = await workflowRunner.execute({ ++ taskId: dryRunId, + spec: { + ...input.spec, + steps: [ +diff --git a/dist/scaffolder/dryrun/createDryRunner.cjs.js.map b/dist/scaffolder/dryrun/createDryRunner.cjs.js.map +index 961ae8d0ca5d4be82c4b52e109b6aa79d59a0467..6d02340804373b8c08d6f7198e8e71c016b1ac79 100644 +--- a/dist/scaffolder/dryrun/createDryRunner.cjs.js.map ++++ b/dist/scaffolder/dryrun/createDryRunner.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"createDryRunner.cjs.js","sources":["../../../src/scaffolder/dryrun/createDryRunner.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject } from '@backstage/types';\nimport { v4 as uuid } from 'uuid';\nimport { pathToFileURL } from 'url';\nimport { Logger } from 'winston';\nimport {\n createTemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n deserializeDirectoryContents,\n SerializedFile,\n serializeDirectoryContents,\n} from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\nimport { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';\nimport { DecoratedActionsRegistry } from './DecoratedActionsRegistry';\nimport fs from 'fs-extra';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n BackstageCredentials,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport type { UserEntity } from '@backstage/catalog-model';\n\ninterface DryRunInput {\n spec: TaskSpec;\n secrets?: TaskSecrets;\n directoryContents: SerializedFile[];\n credentials: BackstageCredentials;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n}\n\ninterface DryRunResult {\n log: Array<{ body: JsonObject }>;\n directoryContents: SerializedFile[];\n output: JsonObject;\n}\n\n/** @internal */\nexport type TemplateTesterCreateOptions = {\n logger: Logger;\n integrations: ScmIntegrations;\n actionRegistry: TemplateActionRegistry;\n workingDirectory: string;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * Executes a dry-run of the provided template.\n *\n * The provided content will be extracted into a temporary directory\n * which is then use as the base for any relative file fetch paths.\n *\n * @internal\n */\nexport function createDryRunner(options: TemplateTesterCreateOptions) {\n return async function dryRun(input: DryRunInput): Promise {\n let contentPromise;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n ...options,\n actionRegistry: new DecoratedActionsRegistry(options.actionRegistry, [\n createTemplateAction({\n id: 'dry-run:extract',\n supportsDryRun: true,\n async handler(ctx) {\n contentPromise = serializeDirectoryContents(ctx.workspacePath);\n await contentPromise.catch(() => {});\n },\n }),\n ]),\n });\n\n const dryRunId = uuid();\n const log = new Array<{ body: JsonObject }>();\n const contentsPath = resolveSafeChildPath(\n options.workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n\n try {\n await deserializeDirectoryContents(contentsPath, input.directoryContents);\n\n const abortSignal = new AbortController().signal;\n\n const result = await workflowRunner.execute({\n spec: {\n ...input.spec,\n steps: [\n ...input.spec.steps,\n {\n id: dryRunId,\n name: 'dry-run:extract',\n action: 'dry-run:extract',\n },\n ],\n templateInfo: {\n entityRef: 'template:default/dry-run',\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n },\n },\n secrets: input.secrets,\n getInitiatorCredentials: () => Promise.resolve(input.credentials),\n // No need to update this at the end of the run, so just hard-code it\n done: false,\n isDryRun: true,\n getWorkspaceName: async () => `dry-run-${dryRunId}`,\n cancelSignal: abortSignal,\n async emitLog(message: string, logMetadata?: JsonObject) {\n if (logMetadata?.stepId === dryRunId) {\n return;\n }\n log.push({\n body: {\n ...logMetadata,\n message,\n },\n });\n },\n complete: async () => {\n throw new Error('Not implemented');\n },\n });\n\n if (!contentPromise) {\n throw new Error('Content extraction step was skipped');\n }\n const directoryContents = await contentPromise;\n\n return {\n log,\n directoryContents,\n output: result.output,\n };\n } finally {\n await fs.remove(contentsPath);\n }\n };\n}\n"],"names":["NunjucksWorkflowRunner","DecoratedActionsRegistry","createTemplateAction","serializeDirectoryContents","uuid","resolveSafeChildPath","deserializeDirectoryContents","pathToFileURL","fs"],"mappings":"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"} +\ No newline at end of file ++{"version":3,"file":"createDryRunner.cjs.js","sources":["../../../src/scaffolder/dryrun/createDryRunner.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject } from '@backstage/types';\nimport { v4 as uuid } from 'uuid';\nimport { pathToFileURL } from 'url';\nimport { Logger } from 'winston';\nimport {\n createTemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n deserializeDirectoryContents,\n SerializedFile,\n serializeDirectoryContents,\n} from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\nimport { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';\nimport { DecoratedActionsRegistry } from './DecoratedActionsRegistry';\nimport fs from 'fs-extra';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n BackstageCredentials,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport type { UserEntity } from '@backstage/catalog-model';\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\ninterface DryRunInput {\n spec: TaskSpec;\n secrets?: TaskSecrets;\n directoryContents: SerializedFile[];\n credentials: BackstageCredentials;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n}\n\ninterface DryRunResult {\n log: Array<{ body: JsonObject }>;\n directoryContents: SerializedFile[];\n output: JsonObject;\n}\n\n/** @internal */\nexport type TemplateTesterCreateOptions = {\n logger: Logger;\n auditLogger: AuditLogger;\n integrations: ScmIntegrations;\n actionRegistry: TemplateActionRegistry;\n workingDirectory: string;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * Executes a dry-run of the provided template.\n *\n * The provided content will be extracted into a temporary directory\n * which is then use as the base for any relative file fetch paths.\n *\n * @internal\n */\nexport function createDryRunner(options: TemplateTesterCreateOptions) {\n return async function dryRun(input: DryRunInput): Promise {\n let contentPromise;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n ...options,\n actionRegistry: new DecoratedActionsRegistry(options.actionRegistry, [\n createTemplateAction({\n id: 'dry-run:extract',\n supportsDryRun: true,\n async handler(ctx) {\n contentPromise = serializeDirectoryContents(ctx.workspacePath);\n await contentPromise.catch(() => {});\n },\n }),\n ]),\n });\n\n const dryRunId = uuid();\n const log = new Array<{ body: JsonObject }>();\n const contentsPath = resolveSafeChildPath(\n options.workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n\n try {\n await deserializeDirectoryContents(contentsPath, input.directoryContents);\n\n const abortSignal = new AbortController().signal;\n\n const result = await workflowRunner.execute({\n taskId: dryRunId,\n spec: {\n ...input.spec,\n steps: [\n ...input.spec.steps,\n {\n id: dryRunId,\n name: 'dry-run:extract',\n action: 'dry-run:extract',\n },\n ],\n templateInfo: {\n entityRef: 'template:default/dry-run',\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n },\n },\n secrets: input.secrets,\n getInitiatorCredentials: () => Promise.resolve(input.credentials),\n // No need to update this at the end of the run, so just hard-code it\n done: false,\n isDryRun: true,\n getWorkspaceName: async () => `dry-run-${dryRunId}`,\n cancelSignal: abortSignal,\n async emitLog(message: string, logMetadata?: JsonObject) {\n if (logMetadata?.stepId === dryRunId) {\n return;\n }\n log.push({\n body: {\n ...logMetadata,\n message,\n },\n });\n },\n complete: async () => {\n throw new Error('Not implemented');\n },\n });\n\n if (!contentPromise) {\n throw new Error('Content extraction step was skipped');\n }\n const directoryContents = await contentPromise;\n\n return {\n log,\n directoryContents,\n output: result.output,\n };\n } finally {\n await fs.remove(contentsPath);\n }\n };\n}\n"],"names":["NunjucksWorkflowRunner","DecoratedActionsRegistry","createTemplateAction","serializeDirectoryContents","uuid","resolveSafeChildPath","deserializeDirectoryContents","pathToFileURL","fs"],"mappings":"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"} +\ No newline at end of file +diff --git a/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js b/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js +index eed6830ca6e3f3dd18cd0bad3dcaf1b3f36bd1ac..0b3eca651b23f6de6384412d62d57c4929fb0166 100644 +--- a/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js ++++ b/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js +@@ -79,9 +79,10 @@ class NunjucksWorkflowRunner { + this.defaultTemplateFilters = filters.createDefaultFilters({ + integrations: this.options.integrations + }); ++ this.tracker = scaffoldingTracker(this.options.auditLogger); + } + defaultTemplateFilters; +- tracker = scaffoldingTracker(); ++ tracker; + isSingleTemplateString(input) { + const { parser, nodes } = nunjucks__default.default; + const parsed = parser.parse( +@@ -133,34 +134,63 @@ class NunjucksWorkflowRunner { + async executeStep(task, step, context, renderTemplate, taskTrack, workspacePath, decision) { + const stepTrack = await this.tracker.stepStart(task, step); + if (task.cancelSignal.aborted) { +- throw new Error(`Step ${step.name} has been cancelled.`); ++ throw new Error( ++ `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.` ++ ); + } + try { +- if (step.if === false || typeof step.if === "string" && !helper.isTruthy(this.render(step.if, context, renderTemplate))) { +- await stepTrack.skipFalsy(); +- return; +- } + const action = this.options.actionRegistry.get(step.action); + const { taskLogger, streamLogger } = createStepLogger({ + task, + step, + rootLogger: this.options.logger + }); ++ const redactedSecrets = Object.fromEntries( ++ Object.entries(task.secrets ?? {}).map((secret) => [secret[0], "***"]) ++ ); ++ const stepInputs = (step.input && this.render( ++ step.input, ++ { ++ ...context, ++ secrets: redactedSecrets ++ }, ++ renderTemplate ++ )) ?? {}; ++ const commonStepAuditMetadata = { ++ templateRef: task.spec.templateInfo?.entityRef || "", ++ taskId: task.taskId, ++ stepId: step.id, ++ stepName: step.name, ++ stepAction: step.action, ++ stepInputs, ++ stepConditional: step.if, ++ stepEach: step.each, ++ isDryRun: task.isDryRun || false ++ }; ++ if (step.if === false || typeof step.if === "string" && !helper.isTruthy(this.render(step.if, context, renderTemplate))) { ++ await stepTrack.skipFalsy(); ++ await this.options.auditLogger.auditLog({ ++ eventName: "ScaffolderTaskStepSkip", ++ actorId: "scaffolder-backend", ++ stage: "completion", ++ status: "succeeded", ++ metadata: commonStepAuditMetadata, ++ message: `Skipped step ${step.name} (id: ${step.id}) of task ${task.taskId}` ++ }); ++ return; ++ } ++ await this.options.auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderTaskStepExecution", ++ stage: "initiation", ++ status: "succeeded", ++ metadata: commonStepAuditMetadata, ++ message: `Started ${step.name} (id: ${step.id}) of task ${task.taskId} triggering the ${step.action} action` ++ }); + if (task.isDryRun) { +- const redactedSecrets = Object.fromEntries( +- Object.entries(task.secrets ?? {}).map((secret) => [secret[0], "***"]) +- ); +- const debugInput = (step.input && this.render( +- step.input, +- { +- ...context, +- secrets: redactedSecrets +- }, +- renderTemplate +- )) ?? {}; + taskLogger.info( + `Running ${action.id} in dry-run mode with inputs (secrets redacted): ${JSON.stringify( +- debugInput, ++ stepInputs, + void 0, + 2 + )}` +@@ -221,6 +251,7 @@ class NunjucksWorkflowRunner { + const tmpDirs = new Array(); + const stepOutput = {}; + const prevTaskState = await task.getTaskState?.(); ++ let iterationCount = 0; + for (const iteration of iterations) { + if (iteration.each) { + taskLogger.info( +@@ -230,6 +261,22 @@ class NunjucksWorkflowRunner { + 0 + )}` + ); ++ await this.options.auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderTaskStepIteration", ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ ...commonStepAuditMetadata, ++ stepInputs: void 0, ++ stepAction: `${step.action}[${iteration.each.key}]`, ++ stepIterationInputs: iteration.input, ++ stepIterationCount: ++iterationCount, ++ stepIterationValue: iteration.each.value, ++ totalIterations: iterations.length ++ }, ++ message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} started` ++ }); + } + await action.handler({ + input: iteration.input, +@@ -289,18 +336,38 @@ class NunjucksWorkflowRunner { + signal: task.cancelSignal, + getInitiatorCredentials: () => task.getInitiatorCredentials() + }); ++ if (iteration.each) { ++ await this.options.auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderTaskStepIteration", ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ ...commonStepAuditMetadata, ++ stepInputs: void 0, ++ stepAction: `${step.action}[${iteration.each.key}]`, ++ stepIterationCount: iterationCount, ++ stepIterationValue: iteration.each.value, ++ stepIterationInputs: iteration.input, ++ totalIterations: iterations.length ++ }, ++ message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded` ++ }); ++ } + } + for (const tmpDir of tmpDirs) { + await fs__default.default.remove(tmpDir); + } + context.steps[step.id] = { output: stepOutput }; + if (task.cancelSignal.aborted) { +- throw new Error(`Step ${step.name} has been cancelled.`); ++ throw new Error( ++ `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.` ++ ); + } + await stepTrack.markSuccessful(); + } catch (err) { + await taskTrack.markFailed(step, err); +- await stepTrack.markFailed(); ++ await stepTrack.markFailed(err); + throw err; + } finally { + await task.serializeWorkspace?.({ path: workspacePath }); +@@ -357,7 +424,7 @@ class NunjucksWorkflowRunner { + } + } + } +-function scaffoldingTracker() { ++function scaffoldingTracker(auditLogger) { + const promTaskCount = metrics.createCounterMetric({ + name: "scaffolder_task_count", + help: "Count of task runs", +@@ -492,6 +559,21 @@ function scaffoldingTracker() { + stepDuration.record(endTime(), { + result: "ok" + }); ++ await auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderTaskStepExecution", ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ templateRef: template, ++ taskId: task.taskId, ++ stepId: step.id, ++ stepName: step.name, ++ stepAction: step.action, ++ isDryRun: task.isDryRun || false ++ }, ++ message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded` ++ }); + } + async function markCancelled() { + promtStepCount.inc({ +@@ -505,7 +587,7 @@ function scaffoldingTracker() { + result: "cancelled" + }); + } +- async function markFailed() { ++ async function markFailed(err) { + promtStepCount.inc({ + template, + step: step.name, +@@ -516,6 +598,29 @@ function scaffoldingTracker() { + stepDuration.record(endTime(), { + result: "failed" + }); ++ await auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderTaskStepExecution", ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ templateRef: template, ++ taskId: task.taskId, ++ stepId: step.id, ++ stepName: step.name, ++ stepAction: step.action, ++ isDryRun: task.isDryRun || false ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} failed` ++ }); + } + async function skipFalsy() { + await task.emitLog( +diff --git a/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map b/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map +index 427b1b440f43e0f5773f93dc44358838162b34f0..ba4def6722d29e51ad274a03a8725fb53f22f33b 100644 +--- a/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map ++++ b/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"NunjucksWorkflowRunner.cjs.js","sources":["../../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\nimport * as winston from 'winston';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport nunjucks from 'nunjucks';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { generateExampleOutput, isTruthy } from './helper';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport { TemplateActionRegistry } from '../actions';\nimport { metrics } from '@opentelemetry/api';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\n\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { createDefaultFilters } from '../../lib/templating/filters';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: winston.Logger;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n};\n\ntype CheckpointState =\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: winston.Logger;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(task.secrets ?? {}));\n\n // This stream logger should be deprecated. We're going to replace it with\n // just using the logger directly, as all those logs get written to step logs\n // using the stepLogStream above.\n // Initially this stream used to be the only way to write to the client logs, but that\n // has changed over time, there's not really a need for this anymore.\n // You can just create a simple wrapper like the below in your action to write to the main logger.\n // This way we also get recactions for free.\n const streamLogger = new PassThrough();\n streamLogger.on('data', async data => {\n const message = data.toString().trim();\n if (message?.length > 1) {\n taskLogger.info(message);\n }\n });\n\n return { taskLogger, streamLogger };\n};\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record;\n\n constructor(private readonly options: NunjucksWorkflowRunnerOptions) {\n this.defaultTemplateFilters = createDefaultFilters({\n integrations: this.options.integrations,\n });\n }\n\n private readonly tracker = scaffoldingTracker();\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n try {\n if (\n step.if === false ||\n (typeof step.if === 'string' &&\n !isTruthy(this.render(step.if, context, renderTemplate)))\n ) {\n await stepTrack.skipFalsy();\n return;\n }\n const action: TemplateAction =\n this.options.actionRegistry.get(step.action);\n const { taskLogger, streamLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n });\n\n if (task.isDryRun) {\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n const debugInput =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n debugInput,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n const iterations = (\n step.each\n ? Object.entries(this.render(step.each, context, renderTemplate)).map(\n ([key, value]) => ({\n each: { key, value },\n }),\n )\n : [{}]\n ).map(i => ({\n ...i,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(\n step.input,\n { ...context, secrets: task.secrets ?? {}, ...i },\n renderTemplate,\n )\n : {},\n }));\n for (const iteration of iterations) {\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n\n for (const iteration of iterations) {\n if (iteration.each) {\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? v.toString() : v),\n 0,\n )}`,\n );\n }\n await action.handler({\n input: iteration.input,\n secrets: task.secrets ?? {},\n // TODO(blam): move to LoggerService and away from Winston\n logger: loggerToWinstonLogger(taskLogger),\n logStream: streamLogger,\n workspacePath,\n async checkpoint(\n keySuffix: string,\n fn: () => Promise,\n ) {\n const key = `v1.task.checkpoint.${step.id}.${keySuffix}`;\n try {\n let prevValue: U | undefined;\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as {\n [key: string]: CheckpointState;\n }\n )?.[key];\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as U;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value,\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n });\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed();\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n steps: {},\n user: task.spec.user,\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n for (const step of task.spec.steps) {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n await taskTrack.markSuccessful();\n await task.cleanWorkspace?.();\n\n return { output };\n } finally {\n if (workspacePath) {\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promTaskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const promTaskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const promtStepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const promStepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n const meter = metrics.getMeter('default');\n const taskCount = meter.createCounter('scaffolder.task.count', {\n description: 'Count of task runs',\n });\n\n const taskDuration = meter.createHistogram('scaffolder.task.duration', {\n description: 'Duration of a task run',\n unit: 'seconds',\n });\n\n const stepCount = meter.createCounter('scaffolder.step.count', {\n description: 'Count of step runs',\n });\n\n const stepDuration = meter.createHistogram('scaffolder.step.duration', {\n description: 'Duration of a step runs',\n unit: 'seconds',\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const startTime = process.hrtime();\n const taskTimer = promTaskDuration.startTimer({\n template,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n promTaskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n\n taskCount.add(1, { template, user, result: 'ok' });\n taskDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n\n taskCount.add(1, { template, user, result: 'failed' });\n taskDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n\n taskCount.add(1, { template, user, result: 'cancelled' });\n taskDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const startTime = process.hrtime();\n const stepTimer = promStepDuration.startTimer({\n template,\n step: step.name,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n\n stepCount.add(1, { template, step: step.name, result: 'ok' });\n stepDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markCancelled() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n\n stepCount.add(1, { template, step: step.name, result: 'cancelled' });\n stepDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n async function markFailed() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n\n stepCount.add(1, { template, step: step.name, result: 'failed' });\n stepDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n\n stepCount.add(1, { template, step: step.name, result: 'skipped' });\n stepDuration.record(endTime(), {\n result: 'skipped',\n });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n"],"names":["WinstonLogger","winston","BackstageLoggerTransport","PassThrough","createConditionAuthorizer","scaffolderActionRules","createDefaultFilters","nunjucks","templated","isTruthy","generateExampleOutput","validateJsonSchema","errors","InputError","NotAllowedError","loggerToWinstonLogger","stringifyError","fs","path","SecureTemplater","actionExecutePermission","AuthorizeResult","createCounterMetric","createHistogramMetric","metrics"],"mappings":"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"} +\ No newline at end of file ++{"version":3,"file":"NunjucksWorkflowRunner.cjs.js","sources":["../../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\nimport * as winston from 'winston';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport nunjucks from 'nunjucks';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { generateExampleOutput, isTruthy } from './helper';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport { TemplateActionRegistry } from '../actions';\nimport { metrics } from '@opentelemetry/api';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\n\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { createDefaultFilters } from '../../lib/templating/filters';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: winston.Logger;\n auditLogger: AuditLogger;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n};\n\ntype CheckpointState =\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: winston.Logger;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(task.secrets ?? {}));\n\n // This stream logger should be deprecated. We're going to replace it with\n // just using the logger directly, as all those logs get written to step logs\n // using the stepLogStream above.\n // Initially this stream used to be the only way to write to the client logs, but that\n // has changed over time, there's not really a need for this anymore.\n // You can just create a simple wrapper like the below in your action to write to the main logger.\n // This way we also get redactions for free.\n const streamLogger = new PassThrough();\n streamLogger.on('data', async data => {\n const message = data.toString().trim();\n if (message?.length > 1) {\n taskLogger.info(message);\n }\n });\n\n return { taskLogger, streamLogger };\n};\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record;\n private readonly tracker;\n\n constructor(private readonly options: NunjucksWorkflowRunnerOptions) {\n this.defaultTemplateFilters = createDefaultFilters({\n integrations: this.options.integrations,\n });\n this.tracker = scaffoldingTracker(this.options.auditLogger);\n }\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n try {\n const action: TemplateAction =\n this.options.actionRegistry.get(step.action);\n const { taskLogger, streamLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n });\n\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n const stepInputs =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n const commonStepAuditMetadata = {\n templateRef: task.spec.templateInfo?.entityRef || '',\n taskId: task.taskId,\n stepId: step.id,\n stepName: step.name,\n stepAction: step.action,\n stepInputs: stepInputs,\n stepConditional: step.if,\n stepEach: step.each,\n isDryRun: task.isDryRun || false,\n };\n if (\n step.if === false ||\n (typeof step.if === 'string' &&\n !isTruthy(this.render(step.if, context, renderTemplate)))\n ) {\n await stepTrack.skipFalsy();\n await this.options.auditLogger.auditLog({\n eventName: 'ScaffolderTaskStepSkip',\n actorId: 'scaffolder-backend',\n stage: 'completion',\n status: 'succeeded',\n metadata: commonStepAuditMetadata,\n message: `Skipped step ${step.name} (id: ${step.id}) of task ${task.taskId}`,\n });\n return;\n }\n\n await this.options.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepExecution',\n stage: 'initiation',\n status: 'succeeded',\n metadata: commonStepAuditMetadata,\n message: `Started ${step.name} (id: ${step.id}) of task ${task.taskId} triggering the ${step.action} action`,\n });\n\n if (task.isDryRun) {\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n stepInputs,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n const iterations = (\n step.each\n ? Object.entries(this.render(step.each, context, renderTemplate)).map(\n ([key, value]) => ({\n each: { key, value },\n }),\n )\n : [{}]\n ).map(i => ({\n ...i,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(\n step.input,\n { ...context, secrets: task.secrets ?? {}, ...i },\n renderTemplate,\n )\n : {},\n }));\n for (const iteration of iterations) {\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n let iterationCount: number = 0;\n for (const iteration of iterations) {\n if (iteration.each) {\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? v.toString() : v),\n 0,\n )}`,\n );\n\n await this.options.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepIteration',\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n ...commonStepAuditMetadata,\n stepInputs: undefined,\n stepAction: `${step.action}[${iteration.each.key}]`,\n stepIterationInputs: iteration.input,\n stepIterationCount: ++iterationCount,\n stepIterationValue: iteration.each.value,\n totalIterations: iterations.length,\n },\n message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} started`,\n });\n }\n\n await action.handler({\n input: iteration.input,\n secrets: task.secrets ?? {},\n // TODO(blam): move to LoggerService and away from Winston\n logger: loggerToWinstonLogger(taskLogger),\n logStream: streamLogger,\n workspacePath,\n async checkpoint(\n keySuffix: string,\n fn: () => Promise,\n ) {\n const key = `v1.task.checkpoint.${step.id}.${keySuffix}`;\n try {\n let prevValue: U | undefined;\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as {\n [key: string]: CheckpointState;\n }\n )?.[key];\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as U;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value,\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n });\n if (iteration.each) {\n await this.options.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepIteration',\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n ...commonStepAuditMetadata,\n stepInputs: undefined,\n stepAction: `${step.action}[${iteration.each.key}]`,\n stepIterationCount: iterationCount,\n stepIterationValue: iteration.each.value,\n stepIterationInputs: iteration.input,\n totalIterations: iterations.length,\n },\n message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded`,\n });\n }\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed(err);\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n steps: {},\n user: task.spec.user,\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n for (const step of task.spec.steps) {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n await taskTrack.markSuccessful();\n await task.cleanWorkspace?.();\n\n return { output };\n } finally {\n if (workspacePath) {\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker(auditLogger: AuditLogger) {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promTaskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const promTaskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const promtStepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const promStepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n const meter = metrics.getMeter('default');\n const taskCount = meter.createCounter('scaffolder.task.count', {\n description: 'Count of task runs',\n });\n\n const taskDuration = meter.createHistogram('scaffolder.task.duration', {\n description: 'Duration of a task run',\n unit: 'seconds',\n });\n\n const stepCount = meter.createCounter('scaffolder.step.count', {\n description: 'Count of step runs',\n });\n\n const stepDuration = meter.createHistogram('scaffolder.step.duration', {\n description: 'Duration of a step runs',\n unit: 'seconds',\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const startTime = process.hrtime();\n const taskTimer = promTaskDuration.startTimer({\n template,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n promTaskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n\n taskCount.add(1, { template, user, result: 'ok' });\n taskDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n\n taskCount.add(1, { template, user, result: 'failed' });\n taskDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n\n taskCount.add(1, { template, user, result: 'cancelled' });\n taskDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const startTime = process.hrtime();\n const stepTimer = promStepDuration.startTimer({\n template,\n step: step.name,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n\n stepCount.add(1, { template, step: step.name, result: 'ok' });\n stepDuration.record(endTime(), {\n result: 'ok',\n });\n await auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepExecution',\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n templateRef: template,\n taskId: task.taskId,\n stepId: step.id,\n stepName: step.name,\n stepAction: step.action,\n isDryRun: task.isDryRun || false,\n },\n message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded`,\n });\n }\n\n async function markCancelled() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n\n stepCount.add(1, { template, step: step.name, result: 'cancelled' });\n stepDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n async function markFailed(err: Error) {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n\n stepCount.add(1, { template, step: step.name, result: 'failed' });\n stepDuration.record(endTime(), {\n result: 'failed',\n });\n\n await auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepExecution',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n templateRef: template,\n taskId: task.taskId,\n stepId: step.id,\n stepName: step.name,\n stepAction: step.action,\n isDryRun: task.isDryRun || false,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} failed`,\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n\n stepCount.add(1, { template, step: step.name, result: 'skipped' });\n stepDuration.record(endTime(), {\n result: 'skipped',\n });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n"],"names":["WinstonLogger","winston","BackstageLoggerTransport","PassThrough","createConditionAuthorizer","scaffolderActionRules","createDefaultFilters","nunjucks","templated","isTruthy","generateExampleOutput","validateJsonSchema","errors","InputError","NotAllowedError","loggerToWinstonLogger","stringifyError","fs","path","SecureTemplater","actionExecutePermission","AuthorizeResult","createCounterMetric","createHistogramMetric","metrics"],"mappings":"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"} +\ No newline at end of file +diff --git a/dist/scaffolder/tasks/StorageTaskBroker.cjs.js b/dist/scaffolder/tasks/StorageTaskBroker.cjs.js +index 7de5b00ad9e1fb519397d91f1989451eb3f89709..c70a5dd1be2443c7dd1ab62c67c1ebde98a20c1b 100644 +--- a/dist/scaffolder/tasks/StorageTaskBroker.cjs.js ++++ b/dist/scaffolder/tasks/StorageTaskBroker.cjs.js +@@ -10,17 +10,18 @@ var ObservableImpl__default = /*#__PURE__*/_interopDefaultCompat(ObservableImpl) + + class TaskManager { + // Runs heartbeat internally +- constructor(task, storage, signal, logger, workspaceService, auth) { ++ constructor(task, storage, signal, logger, workspaceService, auditLogger, auth) { + this.task = task; + this.storage = storage; + this.signal = signal; + this.logger = logger; + this.workspaceService = workspaceService; ++ this.auditLogger = auditLogger; + this.auth = auth; + } + isDone = false; + heartbeatTimeoutId; +- static create(task, storage, abortSignal, logger, auth, config, additionalWorkspaceProviders) { ++ static create(task, storage, abortSignal, logger, auditLogger, auth, config, additionalWorkspaceProviders) { + const workspaceService = WorkspaceService.DefaultWorkspaceService.create( + task, + storage, +@@ -33,11 +34,15 @@ class TaskManager { + abortSignal, + logger, + workspaceService, ++ auditLogger, + auth + ); + agent.startTimeout(); + return agent; + } ++ get taskId() { ++ return this.task.taskId; ++ } + get spec() { + return this.task.spec; + } +@@ -99,6 +104,34 @@ class TaskManager { + if (this.heartbeatTimeoutId) { + clearTimeout(this.heartbeatTimeoutId); + } ++ const commonAuditFields = { ++ eventName: "ScaffolderTaskExecution", ++ actorId: "scaffolder-backend", ++ stage: "completion", ++ metadata: { ++ taskId: this.task.taskId, ++ taskParameters: this.task.spec.parameters ++ } ++ }; ++ if (result === "failed") { ++ await this.auditLogger?.auditLog({ ++ ...commonAuditFields, ++ status: "failed", ++ level: "error", ++ errors: [metadata?.error], ++ message: `Scaffolding task with taskId: ${this.task.taskId} failed` ++ }); ++ } else { ++ await this.auditLogger?.auditLog({ ++ ...commonAuditFields, ++ status: "succeeded", ++ metadata: { ++ ...commonAuditFields.metadata, ++ ...metadata ++ }, ++ message: `Scaffolding task with taskId: ${this.task.taskId} completed successfully` ++ }); ++ } + } + startTimeout() { + this.heartbeatTimeoutId = setTimeout(async () => { +@@ -136,9 +169,10 @@ function defer() { + return { promise, resolve }; + } + class StorageTaskBroker { +- constructor(storage, logger, config, auth, additionalWorkspaceProviders) { ++ constructor(storage, logger, auditLogger, config, auth, additionalWorkspaceProviders) { + this.storage = storage; + this.logger = logger; ++ this.auditLogger = auditLogger; + this.config = config; + this.auth = auth; + this.additionalWorkspaceProviders = additionalWorkspaceProviders; +@@ -175,9 +209,7 @@ class StorageTaskBroker { + }); + } + async recoverTasks() { +- const enabled = (this.config && this.config.getOptionalBoolean( +- "scaffolder.EXPERIMENTAL_recoverTasks" +- )) ?? false; ++ const enabled = this.config?.getOptionalBoolean("scaffolder.EXPERIMENTAL_recoverTasks") ?? false; + if (enabled) { + const defaultTimeout = { seconds: 30 }; + const timeout = helper.readDuration( +@@ -213,6 +245,7 @@ class StorageTaskBroker { + this.storage, + abortController.signal, + this.logger, ++ this.auditLogger, + this.auth, + this.config, + this.additionalWorkspaceProviders +@@ -275,6 +308,16 @@ class StorageTaskBroker { + await Promise.all( + tasks.map(async (task) => { + try { ++ this.auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderStaleTaskCancellation", ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId: task.taskId ++ }, ++ message: `Attempting to cancel Stale scaffolding task ${task.taskId} because the task worker lost connection to the task broker` ++ }); + await this.storage.completeTask({ + taskId: task.taskId, + status: "failed", +@@ -282,8 +325,35 @@ class StorageTaskBroker { + message: "The task was cancelled because the task worker lost connection to the task broker" + } + }); ++ this.auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderStaleTaskCancellation", ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ taskId: task.taskId ++ }, ++ message: `Stale scaffolding task ${task.taskId} successfully cancelled` ++ }); + } catch (error) { +- this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`); ++ this.auditLogger.auditLog({ ++ actorId: "scaffolder-backend", ++ eventName: "ScaffolderStaleTaskCancellation", ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ taskId: task.taskId ++ }, ++ errors: [ ++ { ++ name: error.name, ++ message: error.message, ++ stack: error.stack ++ } ++ ], ++ message: `Failed to cancel stale scaffolding task ${task.taskId}` ++ }); + } + }) + ); +diff --git a/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map b/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map +index 2d5bdf995e048b0274465b48cb2e3e4e2bc99980..f43c5fa2454b31f16e0d0ec936739d20c570ee15 100644 +--- a/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map ++++ b/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"StorageTaskBroker.cjs.js","sources":["../../../src/scaffolder/tasks/StorageTaskBroker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Logger } from 'winston';\nimport ObservableImpl from 'zen-observable';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { readDuration } from './helper';\nimport {\n AuthService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\ntype TaskState = {\n checkpoints: {\n [key: string]:\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n };\n};\n/**\n * TaskManager\n *\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: Logger,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: Logger,\n private readonly workspaceService: WorkspaceService,\n private readonly auth?: AuthService,\n ) {}\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(\n options:\n | {\n key: string;\n status: 'success';\n value: JsonValue;\n }\n | {\n key: string;\n status: 'failed';\n reason: string;\n },\n ): Promise {\n const { key, ...value } = options;\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n /**\n * The workspace of the task.\n */\n workspace?: Promise;\n}\n\nfunction defer() {\n let resolve = () => {};\n const promise = new Promise(_resolve => {\n resolve = _resolve;\n });\n return { promise, resolve };\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: Logger,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n ) {}\n\n async list(options?: {\n createdBy?: string;\n status?: TaskStatus;\n filters?: {\n createdBy?: string | string[];\n status?: TaskStatus | TaskStatus[];\n };\n pagination?: {\n limit?: number;\n offset?: number;\n };\n order?: { order: 'asc' | 'desc'; field: string }[];\n }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list(options ?? {});\n }\n\n private deferredDispatch = defer();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise {\n const enabled =\n (this.config &&\n this.config.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_recoverTasks',\n )) ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n const task = await this.storage.getTask(taskId);\n const isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n while (!cancelled) {\n const result = await this.storage.listEvents({\n isTaskRecoverable,\n taskId,\n after,\n });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n try {\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n } catch (error) {\n this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch.promise;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = defer();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n\n async retry?(taskId: string): Promise {\n await this.storage.retryTask?.({ taskId });\n this.signalDispatch();\n }\n}\n"],"names":["DefaultWorkspaceService","readDuration","ObservableImpl"],"mappings":";;;;;;;;;;AA0DO,MAAM,WAAmC,CAAA;AAAA;AAAA,EAkCtC,YACW,IACA,EAAA,OAAA,EACA,MACA,EAAA,MAAA,EACA,kBACA,IACjB,EAAA;AANiB,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AAAA,GAChB;AAAA,EAxCK,MAAS,GAAA,KAAA,CAAA;AAAA,EAET,kBAAA,CAAA;AAAA,EAER,OAAO,OACL,IACA,EAAA,OAAA,EACA,aACA,MACA,EAAA,IAAA,EACA,QACA,4BACA,EAAA;AACA,IAAA,MAAM,mBAAmBA,wCAAwB,CAAA,MAAA;AAAA,MAC/C,IAAA;AAAA,MACA,OAAA;AAAA,MACA,4BAAA;AAAA,MACA,MAAA;AAAA,KACF,CAAA;AAEA,IAAA,MAAM,QAAQ,IAAI,WAAA;AAAA,MAChB,IAAA;AAAA,MACA,OAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,gBAAA;AAAA,MACA,IAAA;AAAA,KACF,CAAA;AACA,IAAA,KAAA,CAAM,YAAa,EAAA,CAAA;AACnB,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAAA,EAYA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,KAAK,IAAK,CAAA,IAAA,CAAA;AAAA,GACnB;AAAA,EAEA,IAAI,YAAe,GAAA;AACjB,IAAA,OAAO,IAAK,CAAA,MAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,OAAU,GAAA;AACZ,IAAA,OAAO,KAAK,IAAK,CAAA,OAAA,CAAA;AAAA,GACnB;AAAA,EAEA,IAAI,SAAY,GAAA;AACd,IAAA,OAAO,KAAK,IAAK,CAAA,SAAA,CAAA;AAAA,GACnB;AAAA,EAEA,MAAM,gBAAmB,GAAA;AACvB,IAAA,OAAO,KAAK,IAAK,CAAA,MAAA,CAAA;AAAA,GACnB;AAAA,EAEA,MAAM,mBAAoB,OAGR,EAAA;AAChB,IAAM,MAAA,IAAA,CAAK,gBAAiB,CAAA,kBAAA,CAAmB,OAAO,CAAA,CAAA;AAAA,GACxD;AAAA,EAEA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,IAAK,CAAA,MAAA,CAAA;AAAA,GACd;AAAA,EAEA,MAAM,OAAQ,CAAA,OAAA,EAAiB,WAAyC,EAAA;AACtE,IAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,MAC9B,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,IAAM,EAAA,EAAE,OAAS,EAAA,GAAG,WAAY,EAAA;AAAA,KACjC,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,YAKJ,GAAA;AACA,IAAO,OAAA,IAAA,CAAK,QAAQ,YAAe,GAAA,EAAE,QAAQ,IAAK,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,GACjE;AAAA,EAEA,MAAM,iBACJ,OAWe,EAAA;AACf,IAAA,MAAM,EAAE,GAAA,EAAK,GAAG,KAAA,EAAU,GAAA,OAAA,CAAA;AAC1B,IAAI,IAAA,IAAA,CAAK,KAAK,KAAO,EAAA;AACnB,MAAC,IAAK,CAAA,IAAA,CAAK,KAAoB,CAAA,WAAA,CAAY,GAAG,CAAI,GAAA,KAAA,CAAA;AAAA,KAC7C,MAAA;AACL,MAAK,IAAA,CAAA,IAAA,CAAK,QAAQ,EAAE,WAAA,EAAa,EAAE,CAAC,GAAG,GAAG,KAAA,EAAQ,EAAA,CAAA;AAAA,KACpD;AACA,IAAM,MAAA,IAAA,CAAK,QAAQ,aAAgB,GAAA;AAAA,MACjC,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,KAAA,EAAO,KAAK,IAAK,CAAA,KAAA;AAAA,KAClB,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,mBAAoB,OAA0C,EAAA;AAClE,IAAM,MAAA,IAAA,CAAK,gBAAiB,CAAA,kBAAA,CAAmB,OAAO,CAAA,CAAA;AAAA,GACxD;AAAA,EAEA,MAAM,cAAiC,GAAA;AACrC,IAAM,MAAA,IAAA,CAAK,iBAAiB,cAAe,EAAA,CAAA;AAAA,GAC7C;AAAA,EAEA,MAAM,QACJ,CAAA,MAAA,EACA,QACe,EAAA;AACf,IAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,MAC9B,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,MAAA,EAAQ,MAAW,KAAA,QAAA,GAAW,QAAW,GAAA,WAAA;AAAA,MACzC,SAAW,EAAA;AAAA,QACT,OAAA,EAAS,8BAA8B,MAAM,CAAA,CAAA;AAAA,QAC7C,GAAG,QAAA;AAAA,OACL;AAAA,KACD,CAAA,CAAA;AACD,IAAA,IAAA,CAAK,MAAS,GAAA,IAAA,CAAA;AACd,IAAA,IAAI,KAAK,kBAAoB,EAAA;AAC3B,MAAA,YAAA,CAAa,KAAK,kBAAkB,CAAA,CAAA;AAAA,KACtC;AAAA,GACF;AAAA,EAEQ,YAAe,GAAA;AACrB,IAAK,IAAA,CAAA,kBAAA,GAAqB,WAAW,YAAY;AAC/C,MAAI,IAAA;AACF,QAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,aAAc,CAAA,IAAA,CAAK,KAAK,MAAM,CAAA,CAAA;AACjD,QAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,eACX,KAAO,EAAA;AACd,QAAA,IAAA,CAAK,MAAS,GAAA,IAAA,CAAA;AAEd,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,UACV,CAAA,mBAAA,EAAsB,IAAK,CAAA,IAAA,CAAK,MAAM,CAAA,OAAA,CAAA;AAAA,UACtC,KAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,OACC,GAAI,CAAA,CAAA;AAAA,GACT;AAAA,EAEA,MAAM,uBAAyD,GAAA;AAC7D,IAAM,MAAA,OAAA,GAAU,KAAK,IAAK,CAAA,OAAA,CAAA;AAE1B,IAAI,IAAA,OAAA,IAAW,QAAQ,sBAAwB,EAAA;AAC7C,MAAO,OAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,sBAAsB,CAAA,CAAA;AAAA,KAClD;AACA,IAAI,IAAA,CAAC,KAAK,IAAM,EAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,oIAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAO,OAAA,IAAA,CAAK,KAAK,kBAAmB,EAAA,CAAA;AAAA,GACtC;AACF,CAAA;AAkCA,SAAS,KAAQ,GAAA;AACf,EAAA,IAAI,UAAU,MAAM;AAAA,GAAC,CAAA;AACrB,EAAM,MAAA,OAAA,GAAU,IAAI,OAAA,CAAc,CAAY,QAAA,KAAA;AAC5C,IAAU,OAAA,GAAA,QAAA,CAAA;AAAA,GACX,CAAA,CAAA;AACD,EAAO,OAAA,EAAE,SAAS,OAAQ,EAAA,CAAA;AAC5B,CAAA;AAEO,MAAM,iBAAwC,CAAA;AAAA,EACnD,WACmB,CAAA,OAAA,EACA,MACA,EAAA,MAAA,EACA,MACA,4BAIjB,EAAA;AARiB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,4BAAA,GAAA,4BAAA,CAAA;AAAA,GAIhB;AAAA,EAEH,MAAM,KAAK,OAYmD,EAAA;AAC5D,IAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA;AACtB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,yGAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAA,OAAO,MAAM,IAAK,CAAA,OAAA,CAAQ,IAAK,CAAA,OAAA,IAAW,EAAE,CAAA,CAAA;AAAA,GAC9C;AAAA,EAEQ,mBAAmB,KAAM,EAAA,CAAA;AAAA,EAEjC,MAAc,mBACZ,CAAA,MAAA,EACA,eACA,EAAA;AACA,IAAA,IAAI,iBAAoB,GAAA,KAAA,CAAA;AACxB,IAAM,MAAA,YAAA,GAAe,KAAK,MAAO,CAAA,EAAE,QAAQ,KAAO,EAAA,KAAA,CAAA,EAAW,CAAA,CAAE,SAAU,CAAA;AAAA,MACvE,OAAO,CAAK,CAAA,KAAA;AACV,QAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AAAA,OAC3B;AAAA,MACA,IAAM,EAAA,CAAC,EAAE,MAAA,EAAa,KAAA;AACpB,QAAA,KAAA,MAAW,SAAS,MAAQ,EAAA;AAC1B,UAAI,IAAA,KAAA,CAAM,SAAS,WAAa,EAAA;AAC9B,YAAA,eAAA,CAAgB,KAAM,EAAA,CAAA;AACtB,YAAoB,iBAAA,GAAA,IAAA,CAAA;AAAA,WACtB;AAEA,UAAA,IAAI,KAAM,CAAA,IAAA,KAAS,YAAgB,IAAA,CAAC,MAAM,iBAAmB,EAAA;AAC3D,YAAoB,iBAAA,GAAA,IAAA,CAAA;AAAA,WACtB;AAAA,SACF;AACA,QAAA,IAAI,iBAAmB,EAAA;AACrB,UAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AAAA,SAC3B;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAa,YAA8B,GAAA;AACzC,IAAA,MAAM,OACH,GAAA,CAAA,IAAA,CAAK,MACJ,IAAA,IAAA,CAAK,MAAO,CAAA,kBAAA;AAAA,MACV,sCAAA;AAAA,KAEJ,KAAA,KAAA,CAAA;AAEF,IAAA,IAAI,OAAS,EAAA;AACX,MAAM,MAAA,cAAA,GAAiB,EAAE,OAAA,EAAS,EAAG,EAAA,CAAA;AACrC,MAAA,MAAM,OAAU,GAAAC,mBAAA;AAAA,QACd,IAAK,CAAA,MAAA;AAAA,QACL,6CAAA;AAAA,QACA,cAAA;AAAA,OACF,CAAA;AACA,MAAA,MAAM,EAAE,GAAK,EAAA,gBAAA,KAAsB,MAAM,IAAA,CAAK,QAAQ,YAAe,GAAA;AAAA,QACnE,OAAA;AAAA,OACD,CAAA,IAAM,EAAE,GAAA,EAAK,EAAG,EAAA,CAAA;AACjB,MAAI,IAAA,gBAAA,CAAiB,SAAS,CAAG,EAAA;AAC/B,QAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AAAA,OACtB;AAAA,KACF;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAA8B,GAAA;AAClC,IAAS,WAAA;AACP,MAAA,MAAM,WAAc,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAU,EAAA,CAAA;AACjD,MAAA,IAAI,WAAa,EAAA;AACf,QAAM,MAAA,eAAA,GAAkB,IAAI,eAAgB,EAAA,CAAA;AAC5C,QAAA,MAAM,IAAK,CAAA,mBAAA,CAAoB,WAAY,CAAA,EAAA,EAAI,eAAe,CAAA,CAAA;AAC9D,QAAA,OAAO,WAAY,CAAA,MAAA;AAAA,UACjB;AAAA,YACE,QAAQ,WAAY,CAAA,EAAA;AAAA,YACpB,MAAM,WAAY,CAAA,IAAA;AAAA,YAClB,SAAS,WAAY,CAAA,OAAA;AAAA,YACrB,WAAW,WAAY,CAAA,SAAA;AAAA,YACvB,OAAO,WAAY,CAAA,KAAA;AAAA,WACrB;AAAA,UACA,IAAK,CAAA,OAAA;AAAA,UACL,eAAgB,CAAA,MAAA;AAAA,UAChB,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA,IAAA;AAAA,UACL,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA,4BAAA;AAAA,SACP,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,KAAK,eAAgB,EAAA,CAAA;AAAA,KAC7B;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,OAC6B,EAAA;AAC7B,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,WAAW,OAAO,CAAA,CAAA;AACrD,IAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AACpB,IAAO,OAAA;AAAA,MACL,QAAQ,OAAQ,CAAA,MAAA;AAAA,KAClB,CAAA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,MAAyC,EAAA;AACjD,IAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AAAA,GACpC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAG2C,EAAA;AAChD,IAAO,OAAA,IAAIC,gCAAe,CAAY,QAAA,KAAA;AACpC,MAAM,MAAA,EAAE,QAAW,GAAA,OAAA,CAAA;AAEnB,MAAA,IAAI,QAAQ,OAAQ,CAAA,KAAA,CAAA;AACpB,MAAA,IAAI,SAAY,GAAA,KAAA,CAAA;AAEhB,MAAA,CAAC,YAAY;AACX,QAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA,CAAA;AAC9C,QAAA,MAAM,iBACJ,GAAA,IAAA,CAAK,IAAK,CAAA,qBAAA,EAAuB,qBACjC,KAAA,WAAA,CAAA;AAEF,QAAA,OAAO,CAAC,SAAW,EAAA;AACjB,UAAA,MAAM,MAAS,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,UAAW,CAAA;AAAA,YAC3C,iBAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA;AAAA,WACD,CAAA,CAAA;AACD,UAAM,MAAA,EAAE,QAAW,GAAA,MAAA,CAAA;AACnB,UAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,YAAA,KAAA,GAAQ,MAAO,CAAA,MAAA,CAAO,MAAS,GAAA,CAAC,CAAE,CAAA,EAAA,CAAA;AAClC,YAAA,QAAA,CAAS,KAAK,MAAM,CAAA,CAAA;AAAA,WACtB;AAEA,UAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAI,CAAC,CAAA,CAAA;AAAA,SACxD;AAAA,OACC,GAAA,CAAA;AAEH,MAAA,OAAO,MAAM;AACX,QAAY,SAAA,GAAA,IAAA,CAAA;AAAA,OACd,CAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,OAA8C,EAAA;AAC9D,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAK,CAAA,OAAA,CAAQ,eAAe,OAAO,CAAA,CAAA;AAC3D,IAAA,MAAM,OAAQ,CAAA,GAAA;AAAA,MACZ,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AACtB,QAAI,IAAA;AACF,UAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,YAC9B,QAAQ,IAAK,CAAA,MAAA;AAAA,YACb,MAAQ,EAAA,QAAA;AAAA,YACR,SAAW,EAAA;AAAA,cACT,OACE,EAAA,mFAAA;AAAA,aACJ;AAAA,WACD,CAAA,CAAA;AAAA,iBACM,KAAO,EAAA;AACd,UAAA,IAAA,CAAK,OAAO,IAAK,CAAA,CAAA,uBAAA,EAA0B,KAAK,MAAM,CAAA,GAAA,EAAM,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,SACrE;AAAA,OACD,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AAAA,EAEQ,eAAkB,GAAA;AACxB,IAAA,OAAO,KAAK,gBAAiB,CAAA,OAAA,CAAA;AAAA,GAC/B;AAAA,EAEQ,cAAiB,GAAA;AACvB,IAAA,IAAA,CAAK,iBAAiB,OAAQ,EAAA,CAAA;AAC9B,IAAA,IAAA,CAAK,mBAAmB,KAAM,EAAA,CAAA;AAAA,GAChC;AAAA,EAEA,MAAM,OAAO,MAAgB,EAAA;AAC3B,IAAM,MAAA,EAAE,QAAW,GAAA,MAAM,KAAK,OAAQ,CAAA,UAAA,CAAW,EAAE,MAAA,EAAQ,CAAA,CAAA;AAC3D,IAAM,MAAA,aAAA,GACJ,MAAO,CAAA,MAAA,GAAS,CACZ,GAAA,MAAA,CACG,OAAO,CAAC,EAAE,IAAK,EAAA,KAAM,IAAM,EAAA,MAAM,EACjC,MAAO,CAAA,CAAC,IAAM,EAAA,IAAA,KAAU,IAAK,CAAA,EAAA,GAAK,IAAK,CAAA,EAAA,GAAK,IAAO,GAAA,IAAK,CAAE,CAAA,IAAA,CAC1D,MACH,GAAA,CAAA,CAAA;AAEN,IAAM,MAAA,IAAA,CAAK,QAAQ,UAAa,GAAA;AAAA,MAC9B,MAAA;AAAA,MACA,IAAM,EAAA;AAAA,QACJ,OAAA,EAAS,QAAQ,aAAa,CAAA,oBAAA,CAAA;AAAA,QAC9B,MAAQ,EAAA,aAAA;AAAA,QACR,MAAQ,EAAA,WAAA;AAAA,OACV;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,MAAO,MAA+B,EAAA;AAC1C,IAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAY,GAAA,EAAE,QAAQ,CAAA,CAAA;AACzC,IAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AAAA,GACtB;AACF;;;;;"} +\ No newline at end of file ++{"version":3,"file":"StorageTaskBroker.cjs.js","sources":["../../../src/scaffolder/tasks/StorageTaskBroker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Logger } from 'winston';\nimport ObservableImpl from 'zen-observable';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { readDuration } from './helper';\nimport {\n AuthService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\ntype TaskState = {\n checkpoints: {\n [key: string]:\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n };\n};\n/**\n * TaskManager\n *\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: Logger,\n auditLogger: AuditLogger,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auditLogger,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: Logger,\n private readonly workspaceService: WorkspaceService,\n private readonly auditLogger: AuditLogger,\n private readonly auth?: AuthService,\n ) {}\n\n get taskId() {\n return this.task.taskId;\n }\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(\n options:\n | {\n key: string;\n status: 'success';\n value: JsonValue;\n }\n | {\n key: string;\n status: 'failed';\n reason: string;\n },\n ): Promise {\n const { key, ...value } = options;\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n const commonAuditFields = {\n eventName: 'ScaffolderTaskExecution',\n actorId: 'scaffolder-backend',\n stage: 'completion',\n metadata: {\n taskId: this.task.taskId,\n taskParameters: this.task.spec.parameters,\n },\n };\n if (result === 'failed') {\n await this.auditLogger?.auditLog({\n ...commonAuditFields,\n status: 'failed',\n level: 'error',\n errors: [metadata?.error],\n message: `Scaffolding task with taskId: ${this.task.taskId} failed`,\n });\n } else {\n await this.auditLogger?.auditLog({\n ...commonAuditFields,\n status: 'succeeded',\n metadata: {\n ...commonAuditFields.metadata,\n ...metadata,\n },\n message: `Scaffolding task with taskId: ${this.task.taskId} completed successfully`,\n });\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n /**\n * The workspace of the task.\n */\n workspace?: Promise;\n}\n\nfunction defer() {\n let resolve = () => {};\n const promise = new Promise(_resolve => {\n resolve = _resolve;\n });\n return { promise, resolve };\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: Logger,\n private readonly auditLogger: AuditLogger,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n ) {}\n\n async list(options?: {\n createdBy?: string;\n status?: TaskStatus;\n filters?: {\n createdBy?: string | string[];\n status?: TaskStatus | TaskStatus[];\n };\n pagination?: {\n limit?: number;\n offset?: number;\n };\n order?: { order: 'asc' | 'desc'; field: string }[];\n }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list(options ?? {});\n }\n\n private deferredDispatch = defer();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise {\n const enabled =\n this.config?.getOptionalBoolean('scaffolder.EXPERIMENTAL_recoverTasks') ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auditLogger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n const task = await this.storage.getTask(taskId);\n const isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n while (!cancelled) {\n const result = await this.storage.listEvents({\n isTaskRecoverable,\n taskId,\n after,\n });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n try {\n this.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderStaleTaskCancellation',\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId: task.taskId,\n },\n message: `Attempting to cancel Stale scaffolding task ${task.taskId} because the task worker lost connection to the task broker`,\n });\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n this.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderStaleTaskCancellation',\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId: task.taskId,\n },\n message: `Stale scaffolding task ${task.taskId} successfully cancelled`,\n });\n } catch (error) {\n this.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderStaleTaskCancellation',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId: task.taskId,\n },\n errors: [\n {\n name: error.name,\n message: error.message,\n stack: error.stack,\n },\n ],\n message: `Failed to cancel stale scaffolding task ${task.taskId}`,\n });\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch.promise;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = defer();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n\n async retry?(taskId: string): Promise {\n await this.storage.retryTask?.({ taskId });\n this.signalDispatch();\n }\n}\n"],"names":["DefaultWorkspaceService","readDuration","ObservableImpl"],"mappings":"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"} +\ No newline at end of file +diff --git a/dist/scaffolder/tasks/TaskWorker.cjs.js b/dist/scaffolder/tasks/TaskWorker.cjs.js +index 3c432ad8854984e61df2265a4a044cb6ed4307c2..f959924862b85f14074962c6f0b0302b0a5dec20 100644 +--- a/dist/scaffolder/tasks/TaskWorker.cjs.js ++++ b/dist/scaffolder/tasks/TaskWorker.cjs.js +@@ -13,6 +13,7 @@ class TaskWorker { + this.options = options; + this.stopWorkers = false; + this.logger = options.logger; ++ this.auditLogger = options.auditLogger; + this.taskQueue = new PQueue__default.default({ + concurrency: options.concurrentTasksLimit + }); +@@ -20,6 +21,7 @@ class TaskWorker { + taskQueue; + logger; + stopWorkers; ++ auditLogger; + static async create(options) { + const { + taskBroker, +@@ -31,12 +33,14 @@ class TaskWorker { + concurrentTasksLimit = 10, + // from 1 to Infinity + additionalTemplateGlobals, +- permissions ++ permissions, ++ auditLogger + } = options; + const workflowRunner = new NunjucksWorkflowRunner.NunjucksWorkflowRunner({ + actionRegistry, + integrations, + logger, ++ auditLogger, + workingDirectory, + additionalTemplateFilters, + additionalTemplateGlobals, +@@ -46,7 +50,8 @@ class TaskWorker { + taskBroker, + runners: { workflowRunner }, + concurrentTasksLimit, +- permissions ++ permissions, ++ auditLogger + }); + } + async recoverTasks() { +@@ -88,6 +93,18 @@ class TaskWorker { + } + async runOneTask(task) { + try { ++ await this.auditLogger?.auditLog({ ++ eventName: "ScaffolderTaskExecution", ++ actorId: "scaffolder-backend", ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId: task.taskId, ++ taskParameters: task.spec.parameters, ++ templateRef: task.spec.templateInfo?.entityRef ++ }, ++ message: `Scaffolding task with taskId: ${task.taskId} initiated` ++ }); + if (task.spec.apiVersion !== "scaffolder.backstage.io/v1beta3") { + throw new Error( + `Unsupported Template apiVersion ${task.spec.apiVersion}` +diff --git a/dist/scaffolder/tasks/TaskWorker.cjs.js.map b/dist/scaffolder/tasks/TaskWorker.cjs.js.map +index f34e0d282f02ad2291a23fd71f864d4740678c2a..20ee2a529cd976e163ad3845eda8785bb90f35fe 100644 +--- a/dist/scaffolder/tasks/TaskWorker.cjs.js.map ++++ b/dist/scaffolder/tasks/TaskWorker.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../src/scaffolder/tasks/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WorkflowRunner } from './types';\nimport {\n TaskContext,\n TaskBroker,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport PQueue from 'p-queue';\nimport { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';\nimport { Logger } from 'winston';\nimport { TemplateActionRegistry } from '../actions';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { assertError, stringifyError } from '@backstage/errors';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\n\n/**\n * TaskWorkerOptions\n *\n * @public\n */\nexport type TaskWorkerOptions = {\n taskBroker: TaskBroker;\n runners: {\n workflowRunner: WorkflowRunner;\n };\n concurrentTasksLimit: number;\n permissions?: PermissionEvaluator;\n logger?: Logger;\n};\n\n/**\n * CreateWorkerOptions\n *\n * @public\n */\nexport type CreateWorkerOptions = {\n taskBroker: TaskBroker;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n workingDirectory: string;\n logger: Logger;\n additionalTemplateFilters?: Record;\n /**\n * The number of tasks that can be executed at the same time by the worker\n * @defaultValue 10\n * @example\n * ```\n * {\n * concurrentTasksLimit: 1,\n * // OR\n * concurrentTasksLimit: Infinity\n * }\n * ```\n */\n concurrentTasksLimit?: number;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * TaskWorker\n *\n * @public\n */\nexport class TaskWorker {\n private taskQueue: PQueue;\n private logger: Logger | undefined;\n private stopWorkers: boolean;\n\n private constructor(private readonly options: TaskWorkerOptions) {\n this.stopWorkers = false;\n this.logger = options.logger;\n this.taskQueue = new PQueue({\n concurrency: options.concurrentTasksLimit,\n });\n }\n\n static async create(options: CreateWorkerOptions): Promise {\n const {\n taskBroker,\n logger,\n actionRegistry,\n integrations,\n workingDirectory,\n additionalTemplateFilters,\n concurrentTasksLimit = 10, // from 1 to Infinity\n additionalTemplateGlobals,\n permissions,\n } = options;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n return new TaskWorker({\n taskBroker: taskBroker,\n runners: { workflowRunner },\n concurrentTasksLimit,\n permissions,\n });\n }\n\n async recoverTasks() {\n try {\n await this.options.taskBroker.recoverTasks?.();\n } catch (err) {\n this.logger?.error(stringifyError(err));\n }\n }\n\n start() {\n (async () => {\n while (!this.stopWorkers) {\n await new Promise(resolve => setTimeout(resolve, 10000));\n await this.recoverTasks();\n }\n })();\n (async () => {\n while (!this.stopWorkers) {\n await this.onReadyToClaimTask();\n if (!this.stopWorkers) {\n const task = await this.options.taskBroker.claim();\n void this.taskQueue.add(() => this.runOneTask(task));\n }\n }\n })();\n }\n\n stop() {\n this.stopWorkers = true;\n }\n\n protected onReadyToClaimTask(): Promise {\n if (this.taskQueue.pending < this.options.concurrentTasksLimit) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n // \"next\" event emits when a task completes\n // https://github.com/sindresorhus/p-queue#next\n this.taskQueue.once('next', () => {\n resolve();\n });\n });\n }\n\n async runOneTask(task: TaskContext) {\n try {\n if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {\n throw new Error(\n `Unsupported Template apiVersion ${task.spec.apiVersion}`,\n );\n }\n\n const { output } = await this.options.runners.workflowRunner.execute(\n task,\n );\n\n await task.complete('completed', { output });\n } catch (error) {\n assertError(error);\n await task.complete('failed', {\n error: { name: error.name, message: error.message },\n });\n }\n }\n}\n"],"names":["PQueue","NunjucksWorkflowRunner","stringifyError","assertError"],"mappings":";;;;;;;;;;AAgFO,MAAM,UAAW,CAAA;AAAA,EAKd,YAA6B,OAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AACnC,IAAA,IAAA,CAAK,WAAc,GAAA,KAAA,CAAA;AACnB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAK,IAAA,CAAA,SAAA,GAAY,IAAIA,uBAAO,CAAA;AAAA,MAC1B,aAAa,OAAQ,CAAA,oBAAA;AAAA,KACtB,CAAA,CAAA;AAAA,GACH;AAAA,EAVQ,SAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EACA,WAAA,CAAA;AAAA,EAUR,aAAa,OAAO,OAAmD,EAAA;AACrE,IAAM,MAAA;AAAA,MACJ,UAAA;AAAA,MACA,MAAA;AAAA,MACA,cAAA;AAAA,MACA,YAAA;AAAA,MACA,gBAAA;AAAA,MACA,yBAAA;AAAA,MACA,oBAAuB,GAAA,EAAA;AAAA;AAAA,MACvB,yBAAA;AAAA,MACA,WAAA;AAAA,KACE,GAAA,OAAA,CAAA;AAEJ,IAAM,MAAA,cAAA,GAAiB,IAAIC,6CAAuB,CAAA;AAAA,MAChD,cAAA;AAAA,MACA,YAAA;AAAA,MACA,MAAA;AAAA,MACA,gBAAA;AAAA,MACA,yBAAA;AAAA,MACA,yBAAA;AAAA,MACA,WAAA;AAAA,KACD,CAAA,CAAA;AAED,IAAA,OAAO,IAAI,UAAW,CAAA;AAAA,MACpB,UAAA;AAAA,MACA,OAAA,EAAS,EAAE,cAAe,EAAA;AAAA,MAC1B,oBAAA;AAAA,MACA,WAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,YAAe,GAAA;AACnB,IAAI,IAAA;AACF,MAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,UAAA,CAAW,YAAe,IAAA,CAAA;AAAA,aACtC,GAAK,EAAA;AACZ,MAAA,IAAA,CAAK,MAAQ,EAAA,KAAA,CAAMC,qBAAe,CAAA,GAAG,CAAC,CAAA,CAAA;AAAA,KACxC;AAAA,GACF;AAAA,EAEA,KAAQ,GAAA;AACN,IAAA,CAAC,YAAY;AACX,MAAO,OAAA,CAAC,KAAK,WAAa,EAAA;AACxB,QAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAK,CAAC,CAAA,CAAA;AACvD,QAAA,MAAM,KAAK,YAAa,EAAA,CAAA;AAAA,OAC1B;AAAA,KACC,GAAA,CAAA;AACH,IAAA,CAAC,YAAY;AACX,MAAO,OAAA,CAAC,KAAK,WAAa,EAAA;AACxB,QAAA,MAAM,KAAK,kBAAmB,EAAA,CAAA;AAC9B,QAAI,IAAA,CAAC,KAAK,WAAa,EAAA;AACrB,UAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,WAAW,KAAM,EAAA,CAAA;AACjD,UAAA,KAAK,KAAK,SAAU,CAAA,GAAA,CAAI,MAAM,IAAK,CAAA,UAAA,CAAW,IAAI,CAAC,CAAA,CAAA;AAAA,SACrD;AAAA,OACF;AAAA,KACC,GAAA,CAAA;AAAA,GACL;AAAA,EAEA,IAAO,GAAA;AACL,IAAA,IAAA,CAAK,WAAc,GAAA,IAAA,CAAA;AAAA,GACrB;AAAA,EAEU,kBAAoC,GAAA;AAC5C,IAAA,IAAI,IAAK,CAAA,SAAA,CAAU,OAAU,GAAA,IAAA,CAAK,QAAQ,oBAAsB,EAAA;AAC9D,MAAA,OAAO,QAAQ,OAAQ,EAAA,CAAA;AAAA,KACzB;AACA,IAAO,OAAA,IAAI,QAAQ,CAAW,OAAA,KAAA;AAG5B,MAAK,IAAA,CAAA,SAAA,CAAU,IAAK,CAAA,MAAA,EAAQ,MAAM;AAChC,QAAQ,OAAA,EAAA,CAAA;AAAA,OACT,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,WAAW,IAAmB,EAAA;AAClC,IAAI,IAAA;AACF,MAAI,IAAA,IAAA,CAAK,IAAK,CAAA,UAAA,KAAe,iCAAmC,EAAA;AAC9D,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,gCAAA,EAAmC,IAAK,CAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,SACzD,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,EAAE,MAAO,EAAA,GAAI,MAAM,IAAK,CAAA,OAAA,CAAQ,QAAQ,cAAe,CAAA,OAAA;AAAA,QAC3D,IAAA;AAAA,OACF,CAAA;AAEA,MAAA,MAAM,IAAK,CAAA,QAAA,CAAS,WAAa,EAAA,EAAE,QAAQ,CAAA,CAAA;AAAA,aACpC,KAAO,EAAA;AACd,MAAAC,kBAAA,CAAY,KAAK,CAAA,CAAA;AACjB,MAAM,MAAA,IAAA,CAAK,SAAS,QAAU,EAAA;AAAA,QAC5B,OAAO,EAAE,IAAA,EAAM,MAAM,IAAM,EAAA,OAAA,EAAS,MAAM,OAAQ,EAAA;AAAA,OACnD,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AACF;;;;"} +\ No newline at end of file ++{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../src/scaffolder/tasks/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WorkflowRunner } from './types';\nimport {\n TaskContext,\n TaskBroker,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport PQueue from 'p-queue';\nimport { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';\nimport { Logger } from 'winston';\nimport { TemplateActionRegistry } from '../actions';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { assertError, stringifyError } from '@backstage/errors';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\n/**\n * TaskWorkerOptions\n *\n * @public\n */\nexport type TaskWorkerOptions = {\n taskBroker: TaskBroker;\n runners: {\n workflowRunner: WorkflowRunner;\n };\n concurrentTasksLimit: number;\n permissions?: PermissionEvaluator;\n logger?: Logger;\n auditLogger?: AuditLogger;\n};\n\n/**\n * CreateWorkerOptions\n *\n * @public\n */\nexport type CreateWorkerOptions = {\n taskBroker: TaskBroker;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n workingDirectory: string;\n logger: Logger;\n auditLogger: AuditLogger;\n additionalTemplateFilters?: Record;\n /**\n * The number of tasks that can be executed at the same time by the worker\n * @defaultValue 10\n * @example\n * ```\n * {\n * concurrentTasksLimit: 1,\n * // OR\n * concurrentTasksLimit: Infinity\n * }\n * ```\n */\n concurrentTasksLimit?: number;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * TaskWorker\n *\n * @public\n */\nexport class TaskWorker {\n private taskQueue: PQueue;\n private logger: Logger | undefined;\n private stopWorkers: boolean;\n private auditLogger: AuditLogger | undefined;\n\n private constructor(private readonly options: TaskWorkerOptions) {\n this.stopWorkers = false;\n this.logger = options.logger;\n this.auditLogger = options.auditLogger;\n this.taskQueue = new PQueue({\n concurrency: options.concurrentTasksLimit,\n });\n }\n\n static async create(options: CreateWorkerOptions): Promise {\n const {\n taskBroker,\n logger,\n actionRegistry,\n integrations,\n workingDirectory,\n additionalTemplateFilters,\n concurrentTasksLimit = 10, // from 1 to Infinity\n additionalTemplateGlobals,\n permissions,\n auditLogger,\n } = options;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n actionRegistry,\n integrations,\n logger,\n auditLogger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n return new TaskWorker({\n taskBroker: taskBroker,\n runners: { workflowRunner },\n concurrentTasksLimit,\n permissions,\n auditLogger,\n });\n }\n\n async recoverTasks() {\n try {\n await this.options.taskBroker.recoverTasks?.();\n } catch (err) {\n this.logger?.error(stringifyError(err));\n }\n }\n\n start() {\n (async () => {\n while (!this.stopWorkers) {\n await new Promise(resolve => setTimeout(resolve, 10000));\n await this.recoverTasks();\n }\n })();\n (async () => {\n while (!this.stopWorkers) {\n await this.onReadyToClaimTask();\n if (!this.stopWorkers) {\n const task = await this.options.taskBroker.claim();\n void this.taskQueue.add(() => this.runOneTask(task));\n }\n }\n })();\n }\n\n stop() {\n this.stopWorkers = true;\n }\n\n protected onReadyToClaimTask(): Promise {\n if (this.taskQueue.pending < this.options.concurrentTasksLimit) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n // \"next\" event emits when a task completes\n // https://github.com/sindresorhus/p-queue#next\n this.taskQueue.once('next', () => {\n resolve();\n });\n });\n }\n\n async runOneTask(task: TaskContext) {\n try {\n await this.auditLogger?.auditLog({\n eventName: 'ScaffolderTaskExecution',\n actorId: 'scaffolder-backend',\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId: task.taskId,\n taskParameters: task.spec.parameters,\n templateRef: task.spec.templateInfo?.entityRef,\n },\n message: `Scaffolding task with taskId: ${task.taskId} initiated`,\n });\n if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {\n throw new Error(\n `Unsupported Template apiVersion ${task.spec.apiVersion}`,\n );\n }\n const { output } = await this.options.runners.workflowRunner.execute(\n task,\n );\n await task.complete('completed', { output });\n } catch (error) {\n assertError(error);\n await task.complete('failed', {\n error: { name: error.name, message: error.message },\n });\n }\n }\n}\n"],"names":["PQueue","NunjucksWorkflowRunner","stringifyError","assertError"],"mappings":"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"} +\ No newline at end of file +diff --git a/dist/service/router.cjs.js b/dist/service/router.cjs.js +index 7ecf2b0d18bbbd9f2fc5a571af6d999c0068d37b..6c0a2ecfa0f896b44b3bb7681b680aafba60cdc3 100644 +--- a/dist/service/router.cjs.js ++++ b/dist/service/router.cjs.js +@@ -50,6 +50,8 @@ var helpers = require('./helpers.cjs.js'); + var pluginPermissionNode = require('@backstage/plugin-permission-node'); + var rules = require('./rules.cjs.js'); + var checkPermissions = require('../util/checkPermissions.cjs.js'); ++var lodash = require('lodash'); ++var backstagePluginAuditLogNode = require('@janus-idp/backstage-plugin-audit-log-node'); + + function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } + +@@ -142,6 +144,11 @@ async function createRouter(options) { + }); + const concurrentTasksLimit = options.concurrentTasksLimit ?? options.config.getOptionalNumber("scaffolder.concurrentTasksLimit"); + const logger = parentLogger.child({ plugin: "scaffolder" }); ++ const auditLogger = new backstagePluginAuditLogNode.DefaultAuditLogger({ ++ logger, ++ authService: auth, ++ httpAuthService: httpAuth ++ }); + const workingDirectory = await helpers.getWorkingDirectory(config, logger); + const integrations = integration.ScmIntegrations.fromConfig(config); + let taskBroker; +@@ -150,6 +157,7 @@ async function createRouter(options) { + taskBroker = new StorageTaskBroker.StorageTaskBroker( + databaseTaskStore, + logger, ++ auditLogger, + config, + auth, + additionalWorkspaceProviders +@@ -196,7 +204,8 @@ async function createRouter(options) { + additionalTemplateFilters, + additionalTemplateGlobals, + concurrentTasksLimit, +- permissions ++ permissions, ++ auditLogger + }); + workers.push(worker); + } +@@ -225,6 +234,7 @@ async function createRouter(options) { + actionRegistry, + integrations, + logger, ++ auditLogger, + workingDirectory, + additionalTemplateFilters, + additionalTemplateGlobals, +@@ -262,40 +272,134 @@ async function createRouter(options) { + router.get( + "/v2/templates/:namespace/:kind/:name/parameter-schema", + async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- const { token } = await auth.getPluginRequestToken({ +- onBehalfOf: credentials, +- targetPluginId: "catalog" ++ const requestedTemplateRef = `${req.params.kind}:${req.params.namespace}/${req.params.name}`; ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ const credentials = await httpAuth.credentials(req); ++ const { token } = await auth.getPluginRequestToken({ ++ onBehalfOf: credentials, ++ targetPluginId: "catalog" ++ }); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderParameterSchemaFetch", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ templateRef: requestedTemplateRef ++ }, ++ request: req, ++ message: `${actorId} requested the parameter schema for ${requestedTemplateRef}` ++ }); ++ const template = await authorizeTemplate( ++ req.params, ++ token, ++ credentials ++ ); ++ const parameters = [template.spec.parameters ?? []].flat(); ++ const presentation = template.spec.presentation; ++ const templateRef = `${template.kind}:${template.metadata.namespace || "default"}/${template.metadata.name}`; ++ const responseBody = { ++ title: template.metadata.title ?? template.metadata.name, ++ ...presentation ? { presentation } : {}, ++ description: template.metadata.description, ++ "ui:options": template.metadata["ui:options"], ++ steps: parameters.map((schema) => ({ ++ title: schema.title ?? "Please enter the following information", ++ description: schema.description, ++ schema ++ })) ++ }; ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderParameterSchemaFetch", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ templateRef ++ }, ++ request: req, ++ response: { ++ status: 200, ++ body: responseBody ++ }, ++ message: `${actorId} successfully requested the parameter schema for ${templateRef}` ++ }); ++ res.json(responseBody); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderParameterSchemaFetch", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ metadata: { ++ templateRef: requestedTemplateRef ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `${actorId} failed to request the parameter schema for ${requestedTemplateRef}` ++ }); ++ throw err; ++ } ++ } ++ ).get("/v2/actions", async (req, res) => { ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderInstalledActionsFetch", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ request: req, ++ message: `${actorId} requested the list of installed actions` + }); +- const template = await authorizeTemplate( +- req.params, +- token, +- credentials +- ); +- const parameters = [template.spec.parameters ?? []].flat(); +- const presentation = template.spec.presentation; +- res.json({ +- title: template.metadata.title ?? template.metadata.name, +- ...presentation ? { presentation } : {}, +- description: template.metadata.description, +- "ui:options": template.metadata["ui:options"], +- steps: parameters.map((schema) => ({ +- title: schema.title ?? "Please enter the following information", +- description: schema.description, +- schema +- })) ++ const actionsList = actionRegistry.list().map((action) => { ++ return { ++ id: action.id, ++ description: action.description, ++ examples: action.examples, ++ schema: action.schema ++ }; ++ }); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderInstalledActionsFetch", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ request: req, ++ response: { ++ status: 200, ++ body: actionsList ++ }, ++ message: `${actorId} successfully requested the list of installed actions` + }); ++ res.json(actionsList); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderInstalledActionsFetch", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `${actorId} failed to request for the list of installed actions` ++ }); ++ throw err; + } +- ).get("/v2/actions", async (_req, res) => { +- const actionsList = actionRegistry.list().map((action) => { +- return { +- id: action.id, +- description: action.description, +- examples: action.examples, +- schema: action.schema +- }; +- }); +- res.json(actionsList); + }).post("/v2/tasks", async (req, res) => { + const templateRef = req.body.templateRef; + const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, { +@@ -313,280 +417,762 @@ async function createRouter(options) { + }); + const userEntityRef = auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0; + const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0; +- let auditLog = `Scaffolding task for ${templateRef}`; +- if (userEntityRef) { +- auditLog += ` created by ${userEntityRef}`; +- } +- logger.info(auditLog); + const values = req.body.values; +- const template = await authorizeTemplate( +- { kind, namespace, name }, +- token, +- credentials +- ); +- for (const parameters of [template.spec.parameters ?? []].flat()) { +- const result2 = jsonschema.validate(values, parameters); +- if (!result2.valid) { +- res.status(400).json({ errors: result2.errors }); +- return; ++ const redactedRequest = lodash.cloneDeep(req); ++ Object.defineProperty(redactedRequest, "ip", { ++ get: () => { ++ return req.ip; + } ++ }); ++ if (req.body.secrets) { ++ const redactedBody = { ++ ...req.body, ++ secrets: Object.keys(req.body.secrets).reduce((acc, key) => { ++ return { ++ ...acc, ++ [key]: "***" ++ }; ++ }, {}) ++ }; ++ redactedRequest.body = redactedBody; + } +- const baseUrl = helpers.getEntityBaseUrl(template); +- const taskSpec = { +- apiVersion: template.apiVersion, +- steps: template.spec.steps.map((step, index) => ({ +- ...step, +- id: step.id ?? `step-${index + 1}`, +- name: step.name ?? step.action +- })), +- EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery, +- output: template.spec.output ?? {}, +- parameters: values, +- user: { +- entity: userEntity, +- ref: userEntityRef +- }, +- templateInfo: { +- entityRef: catalogModel.stringifyEntityRef({ kind, name, namespace }), +- baseUrl, +- entity: { +- metadata: template.metadata ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCreation", ++ stage: "initiation", ++ status: "succeeded", ++ actorId: userEntityRef, ++ request: redactedRequest, ++ metadata: { ++ templateRef ++ }, ++ message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} initiated` ++ }); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskCreatePermission], ++ permissionService: permissions ++ }); ++ const template = await authorizeTemplate( ++ { kind, namespace, name }, ++ token, ++ credentials ++ ); ++ for (const parameters of [template.spec.parameters ?? []].flat()) { ++ const result2 = jsonschema.validate(values, parameters); ++ if (!result2.valid) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCreation", ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ actorId: userEntityRef, ++ request: redactedRequest, ++ metadata: { ++ templateRef ++ }, ++ response: { ++ status: 400, ++ body: { errors: result2.errors } ++ }, ++ errors: result2.errors, ++ message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed` ++ }); ++ return res.status(400).json({ errors: result2.errors }); + } + } +- }; +- const secrets = { +- ...req.body.secrets, +- backstageToken: token, +- __initiatorCredentials: JSON.stringify({ +- ...credentials, +- // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly +- token: credentials.token +- }) +- }; +- const result = await taskBroker.dispatch({ +- spec: taskSpec, +- createdBy: userEntityRef, +- secrets +- }); +- res.status(201).json({ id: result.taskId }); +- }).get("/v2/tasks", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskReadPermission], +- permissionService: permissions +- }); +- if (!taskBroker.list) { +- throw new Error( +- "TaskBroker does not support listing tasks, please implement the list method on the TaskBroker." +- ); ++ const baseUrl = helpers.getEntityBaseUrl(template); ++ const taskSpec = { ++ apiVersion: template.apiVersion, ++ steps: template.spec.steps.map((step, index) => ({ ++ ...step, ++ id: step.id ?? `step-${index + 1}`, ++ name: step.name ?? step.action ++ })), ++ EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery, ++ output: template.spec.output ?? {}, ++ parameters: values, ++ user: { ++ entity: userEntity, ++ ref: userEntityRef ++ }, ++ templateInfo: { ++ entityRef: catalogModel.stringifyEntityRef({ kind, name, namespace }), ++ baseUrl, ++ entity: { ++ metadata: template.metadata ++ } ++ } ++ }; ++ const secrets = { ++ ...req.body.secrets, ++ backstageToken: token, ++ __initiatorCredentials: JSON.stringify({ ++ ...credentials, ++ // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly ++ token: credentials.token ++ }) ++ }; ++ const result = await taskBroker.dispatch({ ++ spec: taskSpec, ++ createdBy: userEntityRef, ++ secrets ++ }); ++ let auditLog = `Scaffolding task for ${templateRef}`; ++ if (userEntityRef) { ++ auditLog += ` created by ${userEntityRef}`; ++ } ++ logger.info(auditLog); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCreation", ++ stage: "completion", ++ status: "succeeded", ++ actorId: userEntityRef, ++ request: redactedRequest, ++ metadata: { ++ taskId: result.taskId, ++ templateRef ++ }, ++ response: { ++ status: 201, ++ body: { id: result.taskId } ++ }, ++ message: `Scaffolding task for ${templateRef} with taskId: ${result.taskId} successfully created by ${userEntityRef}` ++ }); ++ return res.status(201).json({ id: result.taskId }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCreation", ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ actorId: userEntityRef, ++ request: redactedRequest, ++ metadata: { ++ templateRef ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed` ++ }); ++ throw err; + } +- const createdBy = helpers.parseStringsParam(req.query.createdBy, "createdBy"); +- const status = helpers.parseStringsParam(req.query.status, "status"); +- const order = helpers.parseStringsParam(req.query.order, "order")?.map((item) => { +- const match = item.match(/^(asc|desc):(.+)$/); +- if (!match) { +- throw new errors.InputError( +- `Invalid order parameter "${item}", expected ":"` ++ }).get("/v2/tasks", async (req, res) => { ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskListFetch", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ request: req, ++ message: `${actorId} requested for the list of scaffolder tasks` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskReadPermission], ++ permissionService: permissions ++ }); ++ if (!taskBroker.list) { ++ throw new Error( ++ "TaskBroker does not support listing tasks, please implement the list method on the TaskBroker." + ); + } +- return { +- order: match[1], +- field: match[2] +- }; +- }); +- const limit = helpers.parseNumberParam(req.query.limit, "limit"); +- const offset = helpers.parseNumberParam(req.query.offset, "offset"); +- const tasks = await taskBroker.list({ +- filters: { +- createdBy, +- status: status ? status : void 0 +- }, +- order, +- pagination: { +- limit: limit ? limit[0] : void 0, +- offset: offset ? offset[0] : void 0 +- } +- }); +- res.status(200).json(tasks); ++ const createdBy = helpers.parseStringsParam(req.query.createdBy, "createdBy"); ++ const status = helpers.parseStringsParam(req.query.status, "status"); ++ const order = helpers.parseStringsParam(req.query.order, "order")?.map((item) => { ++ const match = item.match(/^(asc|desc):(.+)$/); ++ if (!match) { ++ throw new errors.InputError( ++ `Invalid order parameter "${item}", expected ":"` ++ ); ++ } ++ return { ++ order: match[1], ++ field: match[2] ++ }; ++ }); ++ const limit = helpers.parseNumberParam(req.query.limit, "limit"); ++ const offset = helpers.parseNumberParam(req.query.offset, "offset"); ++ const tasks = await taskBroker.list({ ++ filters: { ++ createdBy, ++ status: status ? status : void 0 ++ }, ++ order, ++ pagination: { ++ limit: limit ? limit[0] : void 0, ++ offset: offset ? offset[0] : void 0 ++ } ++ }); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskListFetch", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ request: req, ++ response: { ++ status: 200, ++ body: tasks ++ }, ++ message: `${actorId} successfully requested for the list of scaffolder tasks` ++ }); ++ res.status(200).json(tasks); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskListFetch", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `${actorId} request for the list of scaffolder tasks failed` ++ }); ++ throw err; ++ } + }).get("/v2/tasks/:taskId", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskReadPermission], +- permissionService: permissions +- }); + const { taskId } = req.params; +- const task = await taskBroker.get(taskId); +- if (!task) { +- throw new errors.NotFoundError(`Task with id ${taskId} does not exist`); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskFetch", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ message: `${actorId} requested for scaffolder task ${taskId}` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskReadPermission], ++ permissionService: permissions ++ }); ++ const task = await taskBroker.get(taskId); ++ if (!task) { ++ throw new errors.NotFoundError(`Task with id ${taskId} does not exist`); ++ } ++ delete task.secrets; ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskFetch", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ request: req, ++ response: { ++ status: 200, ++ body: task ++ }, ++ message: `${actorId} successfully requested for scaffolder tasks ${taskId}` ++ }); ++ res.status(200).json(task); ++ } catch (err) { ++ let status = 500; ++ if (err.name === "NotFoundError") { ++ status = 404; ++ } ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskFetch", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ response: { ++ status ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `${actorId} request for scaffolder tasks ${taskId} failed` ++ }); ++ throw err; + } +- delete task.secrets; +- res.status(200).json(task); + }).post("/v2/tasks/:taskId/cancel", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskCancelPermission, alpha.taskReadPermission], +- permissionService: permissions +- }); + const { taskId } = req.params; +- await taskBroker.cancel?.(taskId); +- res.status(200).json({ status: "cancelled" }); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCancellation", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ message: `Cancellation request for Scaffolding task with taskId: ${taskId} from ${actorId} received` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskCancelPermission], ++ permissionService: permissions ++ }); ++ await taskBroker.cancel?.(taskId); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCancellation", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ response: { ++ status: 200, ++ body: { status: "cancelled" } ++ }, ++ message: `Scaffolding task with taskId: ${taskId} successfully cancelled by ${actorId}` ++ }); ++ res.status(200).json({ status: "cancelled" }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskCancellation", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `${actorId}'s cancel request for task ${taskId} failed` ++ }); ++ throw err; ++ } + }).post("/v2/tasks/:taskId/retry", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskCreatePermission, alpha.taskReadPermission], +- permissionService: permissions +- }); + const { taskId } = req.params; +- await taskBroker.retry?.(taskId); +- res.status(201).json({ id: taskId }); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskRetry", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ message: `Retry request for Scaffolding task with taskId: ${taskId} from ${actorId} received` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskCreatePermission, alpha.taskReadPermission], ++ permissionService: permissions ++ }); ++ await taskBroker.retry?.(taskId); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskRetry", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ response: { ++ status: 201, ++ body: { id: taskId } ++ }, ++ message: `Scaffolding task with taskId: ${taskId} successfully retried by ${actorId}` ++ }); ++ res.status(201).json({ id: taskId }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskRetry", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `${actorId}'s retry request for task ${taskId} failed` ++ }); ++ throw err; ++ } + }).get("/v2/tasks/:taskId/eventstream", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskReadPermission], +- permissionService: permissions +- }); + const { taskId } = req.params; +- const after = req.query.after !== void 0 ? Number(req.query.after) : void 0; +- logger.debug(`Event stream observing taskId '${taskId}' opened`); +- res.writeHead(200, { +- Connection: "keep-alive", +- "Cache-Control": "no-cache", +- "Content-Type": "text/event-stream" +- }); +- const subscription = taskBroker.event$({ taskId, after }).subscribe({ +- error: (error) => { +- logger.error( +- `Received error from event stream when observing taskId '${taskId}', ${error}` +- ); +- res.end(); +- }, +- next: ({ events }) => { +- let shouldUnsubscribe = false; +- for (const event of events) { +- res.write( +- `event: ${event.type} ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ const after = req.query.after !== void 0 ? Number(req.query.after) : void 0; ++ logger.debug(`Event stream observing taskId '${taskId}' opened`); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskStream", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ message: `Event stream for scaffolding task with taskId: ${taskId} was opened by ${actorId}` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskReadPermission], ++ permissionService: permissions ++ }); ++ res.writeHead(200, { ++ Connection: "keep-alive", ++ "Cache-Control": "no-cache", ++ "Content-Type": "text/event-stream" ++ }); ++ const subscription = taskBroker.event$({ taskId, after }).subscribe({ ++ error: async (error) => { ++ logger.error( ++ `Received error from event stream when observing taskId '${taskId}', ${error}` ++ ); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskStream", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ errors: [ ++ { ++ name: error.name, ++ message: error.message, ++ stack: error.stack, ++ cause: error.cause ++ } ++ ], ++ message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}` ++ }); ++ res.end(); ++ }, ++ next: ({ events }) => { ++ let shouldUnsubscribe = false; ++ for (const event of events) { ++ res.write( ++ `event: ${event.type} + data: ${JSON.stringify(event)} + + ` +- ); +- if (event.type === "completion" && !event.isTaskRecoverable) { +- shouldUnsubscribe = true; ++ ); ++ if (event.type === "completion") { ++ shouldUnsubscribe = true; ++ } ++ } ++ res.flush?.(); ++ if (shouldUnsubscribe) { ++ subscription.unsubscribe(); ++ res.end(); + } + } +- res.flush?.(); +- if (shouldUnsubscribe) { +- subscription.unsubscribe(); +- res.end(); +- } +- } +- }); +- req.on("close", () => { +- subscription.unsubscribe(); +- logger.debug(`Event stream observing taskId '${taskId}' closed`); +- }); ++ }); ++ req.on("close", async () => { ++ subscription.unsubscribe(); ++ logger.debug(`Event stream observing taskId '${taskId}' closed`); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskStream", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ message: `Event stream observing scaffolding task with taskId: ${taskId} was closed by ${actorId}` ++ }); ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskStream", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}` ++ }); ++ throw err; ++ } + }).get("/v2/tasks/:taskId/events", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskReadPermission], +- permissionService: permissions +- }); + const { taskId } = req.params; +- const after = Number(req.query.after) || void 0; +- const timeout = setTimeout(() => { +- res.json([]); +- }, 3e4); +- const subscription = taskBroker.event$({ taskId, after }).subscribe({ +- error: (error) => { +- logger.error( +- `Received error from event stream when observing taskId '${taskId}', ${error}` +- ); +- }, +- next: ({ events }) => { +- clearTimeout(timeout); ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ const after = Number(req.query.after) || void 0; ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskEventFetch", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} initiated by ${actorId}` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskReadPermission], ++ permissionService: permissions ++ }); ++ const timeout = setTimeout(() => { ++ res.json([]); ++ }, 3e4); ++ const subscription = taskBroker.event$({ taskId, after }).subscribe({ ++ error: async (error) => { ++ logger.error( ++ `Received error from event stream when observing taskId '${taskId}', ${error}` ++ ); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskEventFetch", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ errors: [ ++ { ++ name: error.name, ++ message: error.message, ++ stack: error.stack ++ } ++ ], ++ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed` ++ }); ++ }, ++ next: async ({ events }) => { ++ clearTimeout(timeout); ++ subscription.unsubscribe(); ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskEventFetch", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ response: { ++ status: 200, ++ body: events ++ }, ++ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} by ${actorId} succeeded` ++ }); ++ res.json(events); ++ } ++ }); ++ req.on("close", () => { + subscription.unsubscribe(); +- res.json(events); +- } +- }); +- req.on("close", () => { +- subscription.unsubscribe(); +- clearTimeout(timeout); +- }); +- }).post("/v2/dry-run", async (req, res) => { +- const credentials = await httpAuth.credentials(req); +- await checkPermissions.checkPermission({ +- credentials, +- permissions: [alpha.taskCreatePermission], +- permissionService: permissions +- }); +- const bodySchema = zod.z.object({ +- template: zod.z.unknown(), +- values: zod.z.record(zod.z.unknown()), +- secrets: zod.z.record(zod.z.string()).optional(), +- directoryContents: zod.z.array( +- zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() }) +- ) +- }); +- const body = await bodySchema.parseAsync(req.body).catch((e) => { +- throw new errors.InputError(`Malformed request: ${e}`); +- }); +- const template = body.template; +- if (!await pluginScaffolderCommon.templateEntityV1beta3Validator.check(template)) { +- throw new errors.InputError("Input template is not a template"); ++ clearTimeout(timeout); ++ }); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskEventFetch", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ taskId ++ }, ++ request: req, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed` ++ }); ++ throw err; + } +- const { token } = await auth.getPluginRequestToken({ +- onBehalfOf: credentials, +- targetPluginId: "catalog" +- }); +- const userEntityRef = auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0; +- const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0; +- for (const parameters of [template.spec.parameters ?? []].flat()) { +- const result2 = jsonschema.validate(body.values, parameters); +- if (!result2.valid) { +- res.status(400).json({ errors: result2.errors }); +- return; ++ }).post("/v2/dry-run", async (req, res) => { ++ const actorId = await auditLogger.getActorId(req); ++ try { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskDryRun", ++ actorId, ++ stage: "initiation", ++ status: "succeeded", ++ metadata: { ++ isDryRun: true ++ }, ++ request: req, ++ message: `Dry Run scaffolder task initiated by ${actorId}` ++ }); ++ const credentials = await httpAuth.credentials(req); ++ await checkPermissions.checkPermission({ ++ credentials, ++ permissions: [alpha.taskCreatePermission], ++ permissionService: permissions ++ }); ++ const bodySchema = zod.z.object({ ++ template: zod.z.unknown(), ++ values: zod.z.record(zod.z.unknown()), ++ secrets: zod.z.record(zod.z.string()).optional(), ++ directoryContents: zod.z.array( ++ zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() }) ++ ) ++ }); ++ const body = await bodySchema.parseAsync(req.body).catch((e) => { ++ throw new errors.InputError(`Malformed request: ${e}`); ++ }); ++ const template = body.template; ++ if (!await pluginScaffolderCommon.templateEntityV1beta3Validator.check(template)) { ++ throw new errors.InputError("Input template is not a template"); + } +- } +- const steps = template.spec.steps.map((step, index) => ({ +- ...step, +- id: step.id ?? `step-${index + 1}`, +- name: step.name ?? step.action +- })); +- const result = await dryRunner({ +- spec: { +- apiVersion: template.apiVersion, +- steps, +- output: template.spec.output ?? {}, +- parameters: body.values, +- user: { +- entity: userEntity, +- ref: userEntityRef ++ const templateRef = `${template.kind}:${template.metadata.namespace || "default"}/${template.metadata.name}`; ++ const { token } = await auth.getPluginRequestToken({ ++ onBehalfOf: credentials, ++ targetPluginId: "catalog" ++ }); ++ const userEntityRef = auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0; ++ const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0; ++ for (const parameters of [template.spec.parameters ?? []].flat()) { ++ const result2 = jsonschema.validate(body.values, parameters); ++ if (!result2.valid) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskDryRun", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ metadata: { ++ templateRef, ++ parameters: template.spec.parameters, ++ isDryRun: true ++ }, ++ errors: result2.errors, ++ request: req, ++ response: { ++ status: 400, ++ body: { errors: result2.errors } ++ }, ++ message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} failed` ++ }); ++ return res.status(400).json({ errors: result2.errors }); + } +- }, +- directoryContents: (body.directoryContents ?? []).map((file) => ({ +- path: file.path, +- content: Buffer.from(file.base64Content, "base64") +- })), +- secrets: { +- ...body.secrets, +- ...token && { backstageToken: token } +- }, +- credentials +- }); +- res.status(200).json({ +- ...result, +- steps, +- directoryContents: result.directoryContents.map((file) => ({ +- path: file.path, +- executable: file.executable, +- base64Content: file.content.toString("base64") +- })) +- }); ++ } ++ const steps = template.spec.steps.map((step, index) => ({ ++ ...step, ++ id: step.id ?? `step-${index + 1}`, ++ name: step.name ?? step.action ++ })); ++ const result = await dryRunner({ ++ spec: { ++ apiVersion: template.apiVersion, ++ steps, ++ output: template.spec.output ?? {}, ++ parameters: body.values, ++ user: { ++ entity: userEntity, ++ ref: userEntityRef ++ } ++ }, ++ directoryContents: (body.directoryContents ?? []).map((file) => ({ ++ path: file.path, ++ content: Buffer.from(file.base64Content, "base64") ++ })), ++ secrets: { ++ ...body.secrets, ++ ...token && { backstageToken: token } ++ }, ++ credentials ++ }); ++ const dryRunResults = { ++ ...result, ++ steps, ++ directoryContents: result.directoryContents.map((file) => ({ ++ path: file.path, ++ executable: file.executable, ++ base64Content: file.content.toString("base64") ++ })) ++ }; ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskDryRun", ++ actorId, ++ stage: "completion", ++ status: "succeeded", ++ metadata: { ++ templateRef, ++ parameters: template.spec.parameters, ++ isDryRun: true ++ }, ++ request: req, ++ response: { ++ status: 200, ++ body: dryRunResults ++ }, ++ message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} completed successfully` ++ }); ++ return res.status(200).json(dryRunResults); ++ } catch (err) { ++ await auditLogger.auditLog({ ++ eventName: "ScaffolderTaskDryRun", ++ actorId, ++ stage: "completion", ++ status: "failed", ++ level: "error", ++ request: req, ++ metadata: { ++ isDryRun: true ++ }, ++ errors: [ ++ { ++ name: err.name, ++ message: err.message, ++ stack: err.stack ++ } ++ ], ++ message: `Scaffolder Task Dry Run requested by ${actorId} failed` ++ }); ++ throw err; ++ } + }).post("/v2/autocomplete/:provider/:resource", async (req, res) => { + const { token, context } = req.body; + const { provider, resource } = req.params; +diff --git a/dist/service/router.cjs.js.map b/dist/service/router.cjs.js.map +index f564bdd67f041c9fe90e04ed0b30018b070559e8..8f096c5e96512a6bf05d86c15fc8a4cd7da95cdc 100644 +--- a/dist/service/router.cjs.js.map ++++ b/dist/service/router.cjs.js.map +@@ -1 +1 @@ +-{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n} from '@backstage/backend-common';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n CompoundEntityRef,\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { InputError, NotFoundError, stringifyError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { HumanDuration, JsonObject, JsonValue } from '@backstage/types';\nimport {\n TaskSpec,\n TemplateEntityStepV1beta3,\n TemplateEntityV1beta3,\n templateEntityV1beta3Validator,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n scaffolderActionPermissions,\n scaffolderTaskPermissions,\n scaffolderTemplatePermissions,\n taskCancelPermission,\n taskCreatePermission,\n taskReadPermission,\n templateParameterReadPermission,\n templateStepReadPermission,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { validate } from 'jsonschema';\nimport { Logger } from 'winston';\nimport { z } from 'zod';\nimport {\n TaskBroker,\n TaskStatus,\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n createBuiltinActions,\n DatabaseTaskStore,\n TaskWorker,\n TemplateActionRegistry,\n} from '../scaffolder';\nimport { createDryRunner } from '../scaffolder/dryrun';\nimport { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker';\nimport {\n findTemplate,\n getEntityBaseUrl,\n getWorkingDirectory,\n parseNumberParam,\n parseStringsParam,\n} from './helpers';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport {\n createConditionAuthorizer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { scaffolderActionRules, scaffolderTemplateRules } from './rules';\nimport { Duration } from 'luxon';\nimport {\n AuthService,\n BackstageCredentials,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LifecycleService,\n PermissionsService,\n SchedulerService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport {\n IdentityApi,\n IdentityApiGetIdentityRequest,\n} from '@backstage/plugin-auth-node';\nimport { InternalTaskSecrets } from '../scaffolder/tasks/types';\nimport { checkPermission } from '../util/checkPermissions';\nimport {\n AutocompleteHandler,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\n\n/**\n *\n * @public\n */\nexport type TemplatePermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n TParams\n>;\nfunction isTemplatePermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is TemplatePermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TEMPLATE;\n}\n\n/**\n *\n * @public\n */\nexport type ActionPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION,\n TParams\n>;\nfunction isActionPermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is ActionPermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_ACTION;\n}\n\n/**\n * RouterOptions\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n reader: UrlReaderService;\n lifecycle?: LifecycleService;\n database: DatabaseService;\n catalogClient: CatalogApi;\n scheduler?: SchedulerService;\n actions?: TemplateAction[];\n /**\n * @deprecated taskWorkers is deprecated in favor of concurrentTasksLimit option with a single TaskWorker\n * @defaultValue 1\n */\n taskWorkers?: number;\n /**\n * Sets the number of concurrent tasks that can be run at any given time on the TaskWorker\n * @defaultValue 10\n */\n concurrentTasksLimit?: number;\n taskBroker?: TaskBroker;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n additionalWorkspaceProviders?: Record;\n permissions?: PermissionsService;\n permissionRules?: Array<\n TemplatePermissionRuleInput | ActionPermissionRuleInput\n >;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n identity?: IdentityApi;\n discovery?: DiscoveryService;\n\n autocompleteHandlers?: Record;\n}\n\nfunction isSupportedTemplate(entity: TemplateEntityV1beta3) {\n return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';\n}\n\n/*\n * @deprecated This function remains as the DefaultIdentityClient behaves slightly differently to the pre-existing\n * scaffolder behaviour. Specifically if the token fails to parse, the DefaultIdentityClient will raise an error.\n * The scaffolder did not raise an error in this case. As such we chose to allow it to behave as it did previously\n * until someone explicitly passes an IdentityApi. When we have reasonable confidence that most backstage deployments\n * are using the IdentityApi, we can remove this function.\n */\nfunction buildDefaultIdentityClient(options: RouterOptions): IdentityApi {\n return {\n getIdentity: async ({ request }: IdentityApiGetIdentityRequest) => {\n const header = request.headers.authorization;\n const { logger } = options;\n\n if (!header) {\n return undefined;\n }\n\n try {\n const token = header.match(/^Bearer\\s(\\S+\\.\\S+\\.\\S+)$/i)?.[1];\n if (!token) {\n throw new TypeError('Expected Bearer with JWT');\n }\n\n const [_header, rawPayload, _signature] = token.split('.');\n const payload: JsonValue = JSON.parse(\n Buffer.from(rawPayload, 'base64').toString(),\n );\n\n if (\n typeof payload !== 'object' ||\n payload === null ||\n Array.isArray(payload)\n ) {\n throw new TypeError('Malformed JWT payload');\n }\n\n const sub = payload.sub;\n if (typeof sub !== 'string') {\n throw new TypeError('Expected string sub claim');\n }\n\n if (sub === 'backstage-server') {\n return undefined;\n }\n\n // Check that it's a valid ref, otherwise this will throw.\n parseEntityRef(sub);\n\n return {\n identity: {\n userEntityRef: sub,\n ownershipEntityRefs: [],\n type: 'user',\n },\n token,\n };\n } catch (e) {\n logger.error(`Invalid authorization header: ${stringifyError(e)}`);\n return undefined;\n }\n },\n };\n}\n\nconst readDuration = (\n config: Config,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n\n/**\n * A method to create a router for the scaffolder backend plugin.\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = Router();\n // Be generous in upload size to support a wide range of templates in dry-run mode.\n router.use(express.json({ limit: '10MB' }));\n\n const {\n logger: parentLogger,\n config,\n reader,\n database,\n catalogClient,\n actions,\n taskWorkers,\n scheduler,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n additionalWorkspaceProviders,\n permissions,\n permissionRules,\n discovery = HostDiscovery.fromConfig(config),\n identity = buildDefaultIdentityClient(options),\n autocompleteHandlers = {},\n } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...options,\n identity,\n discovery,\n });\n\n const concurrentTasksLimit =\n options.concurrentTasksLimit ??\n options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');\n\n const logger = parentLogger.child({ plugin: 'scaffolder' });\n\n const workingDirectory = await getWorkingDirectory(config, logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n let taskBroker: TaskBroker;\n if (!options.taskBroker) {\n const databaseTaskStore = await DatabaseTaskStore.create({ database });\n taskBroker = new StorageTaskBroker(\n databaseTaskStore,\n logger,\n config,\n auth,\n additionalWorkspaceProviders,\n );\n\n if (scheduler && databaseTaskStore.listStaleTasks) {\n await scheduler.scheduleTask({\n id: 'close_stale_tasks',\n frequency: readDuration(\n config,\n 'scaffolder.taskTimeoutJanitorFrequency',\n {\n minutes: 5,\n },\n ),\n timeout: { minutes: 15 },\n fn: async () => {\n const { tasks } = await databaseTaskStore.listStaleTasks({\n timeoutS: Duration.fromObject(\n readDuration(config, 'scaffolder.taskTimeout', {\n hours: 24,\n }),\n ).as('seconds'),\n });\n\n for (const task of tasks) {\n await databaseTaskStore.shutdownTask(task);\n logger.info(`Successfully closed stale task ${task.taskId}`);\n }\n },\n });\n }\n } else {\n taskBroker = options.taskBroker;\n }\n\n const actionRegistry = new TemplateActionRegistry();\n\n const workers: TaskWorker[] = [];\n if (concurrentTasksLimit !== 0) {\n for (let i = 0; i < (taskWorkers || 1); i++) {\n const worker = await TaskWorker.create({\n taskBroker,\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n concurrentTasksLimit,\n permissions,\n });\n workers.push(worker);\n }\n }\n\n const actionsToRegister = Array.isArray(actions)\n ? actions\n : createBuiltinActions({\n integrations,\n catalogClient,\n reader,\n config,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n });\n\n actionsToRegister.forEach(action => actionRegistry.register(action));\n\n const launchWorkers = () => workers.forEach(worker => worker.start());\n\n const shutdownWorkers = () => {\n workers.forEach(worker => worker.stop());\n };\n\n if (options.lifecycle) {\n options.lifecycle.addStartupHook(launchWorkers);\n options.lifecycle.addShutdownHook(shutdownWorkers);\n } else {\n launchWorkers();\n }\n\n const dryRunner = createDryRunner({\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n const templateRules: TemplatePermissionRuleInput[] = Object.values(\n scaffolderTemplateRules,\n );\n const actionRules: ActionPermissionRuleInput[] = Object.values(\n scaffolderActionRules,\n );\n\n if (permissionRules) {\n templateRules.push(\n ...permissionRules.filter(isTemplatePermissionRuleInput),\n );\n actionRules.push(...permissionRules.filter(isActionPermissionRuleInput));\n }\n\n const isAuthorized = createConditionAuthorizer(Object.values(templateRules));\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resources: [\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n permissions: scaffolderTemplatePermissions,\n rules: templateRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n permissions: scaffolderActionPermissions,\n rules: actionRules,\n },\n ],\n permissions: scaffolderTaskPermissions,\n });\n\n router.use(permissionIntegrationRouter);\n\n router\n .get(\n '/v2/templates/:namespace/:kind/:name/parameter-schema',\n async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const template = await authorizeTemplate(\n req.params,\n token,\n credentials,\n );\n\n const parameters = [template.spec.parameters ?? []].flat();\n\n const presentation = template.spec.presentation;\n\n res.json({\n title: template.metadata.title ?? template.metadata.name,\n ...(presentation ? { presentation } : {}),\n description: template.metadata.description,\n 'ui:options': template.metadata['ui:options'],\n steps: parameters.map(schema => ({\n title: schema.title ?? 'Please enter the following information',\n description: schema.description,\n schema,\n })),\n });\n },\n )\n .get('/v2/actions', async (_req, res) => {\n const actionsList = actionRegistry.list().map(action => {\n return {\n id: action.id,\n description: action.description,\n examples: action.examples,\n schema: action.schema,\n };\n });\n res.json(actionsList);\n })\n .post('/v2/tasks', async (req, res) => {\n const templateRef: string = req.body.templateRef;\n const { kind, namespace, name } = parseEntityRef(templateRef, {\n defaultKind: 'template',\n });\n\n const credentials = await httpAuth.credentials(req);\n\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n\n let auditLog = `Scaffolding task for ${templateRef}`;\n if (userEntityRef) {\n auditLog += ` created by ${userEntityRef}`;\n }\n logger.info(auditLog);\n\n const values = req.body.values;\n\n const template = await authorizeTemplate(\n { kind, namespace, name },\n token,\n credentials,\n );\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(values, parameters);\n\n if (!result.valid) {\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const baseUrl = getEntityBaseUrl(template);\n\n const taskSpec: TaskSpec = {\n apiVersion: template.apiVersion,\n steps: template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n })),\n EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery,\n output: template.spec.output ?? {},\n parameters: values,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n templateInfo: {\n entityRef: stringifyEntityRef({ kind, name, namespace }),\n baseUrl,\n entity: {\n metadata: template.metadata,\n },\n },\n };\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: token,\n __initiatorCredentials: JSON.stringify({\n ...credentials,\n // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly\n token: (credentials as any).token,\n }),\n };\n\n const result = await taskBroker.dispatch({\n spec: taskSpec,\n createdBy: userEntityRef,\n secrets,\n });\n\n res.status(201).json({ id: result.taskId });\n })\n .get('/v2/tasks', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n if (!taskBroker.list) {\n throw new Error(\n 'TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.',\n );\n }\n\n const createdBy = parseStringsParam(req.query.createdBy, 'createdBy');\n const status = parseStringsParam(req.query.status, 'status');\n\n const order = parseStringsParam(req.query.order, 'order')?.map(item => {\n const match = item.match(/^(asc|desc):(.+)$/);\n if (!match) {\n throw new InputError(\n `Invalid order parameter \"${item}\", expected \":\"`,\n );\n }\n\n return {\n order: match[1] as 'asc' | 'desc',\n field: match[2],\n };\n });\n\n const limit = parseNumberParam(req.query.limit, 'limit');\n const offset = parseNumberParam(req.query.offset, 'offset');\n\n const tasks = await taskBroker.list({\n filters: {\n createdBy,\n status: status ? (status as TaskStatus[]) : undefined,\n },\n order,\n pagination: {\n limit: limit ? limit[0] : undefined,\n offset: offset ? offset[0] : undefined,\n },\n });\n\n res.status(200).json(tasks);\n })\n .get('/v2/tasks/:taskId', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n const task = await taskBroker.get(taskId);\n if (!task) {\n throw new NotFoundError(`Task with id ${taskId} does not exist`);\n }\n // Do not disclose secrets\n delete task.secrets;\n res.status(200).json(task);\n })\n .post('/v2/tasks/:taskId/cancel', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n // Requires both read and cancel permissions\n await checkPermission({\n credentials,\n permissions: [taskCancelPermission, taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n await taskBroker.cancel?.(taskId);\n res.status(200).json({ status: 'cancelled' });\n })\n .post('/v2/tasks/:taskId/retry', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n // Requires both read and cancel permissions\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission, taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n await taskBroker.retry?.(taskId);\n res.status(201).json({ id: taskId });\n })\n .get('/v2/tasks/:taskId/eventstream', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n const after =\n req.query.after !== undefined ? Number(req.query.after) : undefined;\n\n logger.debug(`Event stream observing taskId '${taskId}' opened`);\n\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // After client opens connection send all events as string\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n res.end();\n },\n next: ({ events }) => {\n let shouldUnsubscribe = false;\n for (const event of events) {\n res.write(\n `event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n );\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n // res.flush() is only available with the compression middleware\n res.flush?.();\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n res.end();\n }\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n logger.debug(`Event stream observing taskId '${taskId}' closed`);\n });\n })\n .get('/v2/tasks/:taskId/events', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n const after = Number(req.query.after) || undefined;\n\n // cancel the request after 30 seconds. this aligns with the recommendations of RFC 6202.\n const timeout = setTimeout(() => {\n res.json([]);\n }, 30_000);\n\n // Get all known events after an id (always includes the completion event) and return the first callback\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n },\n next: ({ events }) => {\n clearTimeout(timeout);\n subscription.unsubscribe();\n res.json(events);\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n clearTimeout(timeout);\n });\n })\n .post('/v2/dry-run', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const bodySchema = z.object({\n template: z.unknown(),\n values: z.record(z.unknown()),\n secrets: z.record(z.string()).optional(),\n directoryContents: z.array(\n z.object({ path: z.string(), base64Content: z.string() }),\n ),\n });\n const body = await bodySchema.parseAsync(req.body).catch(e => {\n throw new InputError(`Malformed request: ${e}`);\n });\n\n const template = body.template as TemplateEntityV1beta3;\n if (!(await templateEntityV1beta3Validator.check(template))) {\n throw new InputError('Input template is not a template');\n }\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(body.values, parameters);\n if (!result.valid) {\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const steps = template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n }));\n\n const result = await dryRunner({\n spec: {\n apiVersion: template.apiVersion,\n steps,\n output: template.spec.output ?? {},\n parameters: body.values as JsonObject,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n },\n directoryContents: (body.directoryContents ?? []).map(file => ({\n path: file.path,\n content: Buffer.from(file.base64Content, 'base64'),\n })),\n secrets: {\n ...body.secrets,\n ...(token && { backstageToken: token }),\n },\n credentials,\n });\n\n res.status(200).json({\n ...result,\n steps,\n directoryContents: result.directoryContents.map(file => ({\n path: file.path,\n executable: file.executable,\n base64Content: file.content.toString('base64'),\n })),\n });\n })\n .post('/v2/autocomplete/:provider/:resource', async (req, res) => {\n const { token, context } = req.body;\n const { provider, resource } = req.params;\n\n if (!token) throw new InputError('Missing token query parameter');\n\n if (!autocompleteHandlers[provider]) {\n throw new InputError(`Unsupported provider: ${provider}`);\n }\n\n const { results } = await autocompleteHandlers[provider]({\n resource,\n token,\n context,\n });\n\n res.status(200).json({ results });\n });\n\n const app = express();\n app.set('logger', logger);\n app.use('/', router);\n\n async function authorizeTemplate(\n entityRef: CompoundEntityRef,\n token: string | undefined,\n credentials: BackstageCredentials,\n ) {\n const template = await findTemplate({\n catalogApi: catalogClient,\n entityRef,\n token,\n });\n\n if (!isSupportedTemplate(template)) {\n throw new InputError(\n `Unsupported apiVersion field in schema entity, ${\n (template as Entity).apiVersion\n }`,\n );\n }\n\n if (!permissions) {\n return template;\n }\n\n const [parameterDecision, stepDecision] =\n await permissions.authorizeConditional(\n [\n { permission: templateParameterReadPermission },\n { permission: templateStepReadPermission },\n ],\n { credentials },\n );\n\n // Authorize parameters\n if (Array.isArray(template.spec.parameters)) {\n template.spec.parameters = template.spec.parameters.filter(step =>\n isAuthorized(parameterDecision, step),\n );\n } else if (\n template.spec.parameters &&\n !isAuthorized(parameterDecision, template.spec.parameters)\n ) {\n template.spec.parameters = undefined;\n }\n\n // Authorize steps\n template.spec.steps = template.spec.steps.filter(step =>\n isAuthorized(stepDecision, step),\n );\n\n return template;\n }\n\n return app;\n}\n"],"names":["RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","RESOURCE_TYPE_SCAFFOLDER_ACTION","parseEntityRef","stringifyError","config","readDurationFromConfig","Router","express","HostDiscovery","createLegacyAuthAdapters","getWorkingDirectory","ScmIntegrations","DatabaseTaskStore","StorageTaskBroker","Duration","TemplateActionRegistry","TaskWorker","createBuiltinActions","createDryRunner","scaffolderTemplateRules","scaffolderActionRules","createConditionAuthorizer","createPermissionIntegrationRouter","scaffolderTemplatePermissions","scaffolderActionPermissions","scaffolderTaskPermissions","checkPermission","taskCreatePermission","result","validate","getEntityBaseUrl","stringifyEntityRef","taskReadPermission","parseStringsParam","InputError","parseNumberParam","NotFoundError","taskCancelPermission","z","templateEntityV1beta3Validator","findTemplate","templateParameterReadPermission","templateStepReadPermission"],"mappings":"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"} +\ No newline at end of file ++{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n} from '@backstage/backend-common';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n CompoundEntityRef,\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { InputError, NotFoundError, stringifyError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { HumanDuration, JsonObject, JsonValue } from '@backstage/types';\nimport {\n TaskSpec,\n TemplateEntityStepV1beta3,\n TemplateEntityV1beta3,\n templateEntityV1beta3Validator,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n scaffolderActionPermissions,\n scaffolderTaskPermissions,\n scaffolderTemplatePermissions,\n taskCancelPermission,\n taskCreatePermission,\n taskReadPermission,\n templateParameterReadPermission,\n templateStepReadPermission,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { validate } from 'jsonschema';\nimport { Logger } from 'winston';\nimport { z } from 'zod';\nimport {\n TaskBroker,\n TaskStatus,\n TemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n createBuiltinActions,\n DatabaseTaskStore,\n TaskWorker,\n TemplateActionRegistry,\n} from '../scaffolder';\nimport { createDryRunner } from '../scaffolder/dryrun';\nimport { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker';\nimport {\n findTemplate,\n getEntityBaseUrl,\n getWorkingDirectory,\n parseNumberParam,\n parseStringsParam,\n} from './helpers';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport {\n createConditionAuthorizer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { scaffolderActionRules, scaffolderTemplateRules } from './rules';\nimport { Duration } from 'luxon';\nimport {\n AuthService,\n BackstageCredentials,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LifecycleService,\n PermissionsService,\n SchedulerService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport {\n IdentityApi,\n IdentityApiGetIdentityRequest,\n} from '@backstage/plugin-auth-node';\nimport { InternalTaskSecrets } from '../scaffolder/tasks/types';\nimport { checkPermission } from '../util/checkPermissions';\nimport {\n AutocompleteHandler,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { cloneDeep } from 'lodash';\n\nimport { DefaultAuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\n/**\n *\n * @public\n */\nexport type TemplatePermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n TParams\n>;\nfunction isTemplatePermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is TemplatePermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TEMPLATE;\n}\n\n/**\n *\n * @public\n */\nexport type ActionPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION,\n TParams\n>;\nfunction isActionPermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is ActionPermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_ACTION;\n}\n\n/**\n * RouterOptions\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n reader: UrlReaderService;\n lifecycle?: LifecycleService;\n database: DatabaseService;\n catalogClient: CatalogApi;\n scheduler?: SchedulerService;\n actions?: TemplateAction[];\n /**\n * @deprecated taskWorkers is deprecated in favor of concurrentTasksLimit option with a single TaskWorker\n * @defaultValue 1\n */\n taskWorkers?: number;\n /**\n * Sets the number of concurrent tasks that can be run at any given time on the TaskWorker\n * @defaultValue 10\n */\n concurrentTasksLimit?: number;\n taskBroker?: TaskBroker;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n additionalWorkspaceProviders?: Record;\n permissions?: PermissionsService;\n permissionRules?: Array<\n TemplatePermissionRuleInput | ActionPermissionRuleInput\n >;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n identity?: IdentityApi;\n discovery?: DiscoveryService;\n\n autocompleteHandlers?: Record;\n}\n\nfunction isSupportedTemplate(entity: TemplateEntityV1beta3) {\n return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';\n}\n\n/*\n * @deprecated This function remains as the DefaultIdentityClient behaves slightly differently to the pre-existing\n * scaffolder behaviour. Specifically if the token fails to parse, the DefaultIdentityClient will raise an error.\n * The scaffolder did not raise an error in this case. As such we chose to allow it to behave as it did previously\n * until someone explicitly passes an IdentityApi. When we have reasonable confidence that most backstage deployments\n * are using the IdentityApi, we can remove this function.\n */\nfunction buildDefaultIdentityClient(options: RouterOptions): IdentityApi {\n return {\n getIdentity: async ({ request }: IdentityApiGetIdentityRequest) => {\n const header = request.headers.authorization;\n const { logger } = options;\n\n if (!header) {\n return undefined;\n }\n\n try {\n const token = header.match(/^Bearer\\s(\\S+\\.\\S+\\.\\S+)$/i)?.[1];\n if (!token) {\n throw new TypeError('Expected Bearer with JWT');\n }\n\n const [_header, rawPayload, _signature] = token.split('.');\n const payload: JsonValue = JSON.parse(\n Buffer.from(rawPayload, 'base64').toString(),\n );\n\n if (\n typeof payload !== 'object' ||\n payload === null ||\n Array.isArray(payload)\n ) {\n throw new TypeError('Malformed JWT payload');\n }\n\n const sub = payload.sub;\n if (typeof sub !== 'string') {\n throw new TypeError('Expected string sub claim');\n }\n\n if (sub === 'backstage-server') {\n return undefined;\n }\n\n // Check that it's a valid ref, otherwise this will throw.\n parseEntityRef(sub);\n\n return {\n identity: {\n userEntityRef: sub,\n ownershipEntityRefs: [],\n type: 'user',\n },\n token,\n };\n } catch (e) {\n logger.error(`Invalid authorization header: ${stringifyError(e)}`);\n return undefined;\n }\n },\n };\n}\n\nconst readDuration = (\n config: Config,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n\n/**\n * A method to create a router for the scaffolder backend plugin.\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = Router();\n // Be generous in upload size to support a wide range of templates in dry-run mode.\n router.use(express.json({ limit: '10MB' }));\n\n const {\n logger: parentLogger,\n config,\n reader,\n database,\n catalogClient,\n actions,\n taskWorkers,\n scheduler,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n additionalWorkspaceProviders,\n permissions,\n permissionRules,\n discovery = HostDiscovery.fromConfig(config),\n identity = buildDefaultIdentityClient(options),\n autocompleteHandlers = {},\n } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...options,\n identity,\n discovery,\n });\n\n const concurrentTasksLimit =\n options.concurrentTasksLimit ??\n options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');\n\n const logger = parentLogger.child({ plugin: 'scaffolder' });\n const auditLogger = new DefaultAuditLogger({\n logger,\n authService: auth,\n httpAuthService: httpAuth,\n });\n\n const workingDirectory = await getWorkingDirectory(config, logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n let taskBroker: TaskBroker;\n if (!options.taskBroker) {\n const databaseTaskStore = await DatabaseTaskStore.create({ database });\n taskBroker = new StorageTaskBroker(\n databaseTaskStore,\n logger,\n auditLogger,\n config,\n auth,\n additionalWorkspaceProviders,\n );\n\n if (scheduler && databaseTaskStore.listStaleTasks) {\n await scheduler.scheduleTask({\n id: 'close_stale_tasks',\n frequency: readDuration(\n config,\n 'scaffolder.taskTimeoutJanitorFrequency',\n {\n minutes: 5,\n },\n ),\n timeout: { minutes: 15 },\n fn: async () => {\n const { tasks } = await databaseTaskStore.listStaleTasks({\n timeoutS: Duration.fromObject(\n readDuration(config, 'scaffolder.taskTimeout', {\n hours: 24,\n }),\n ).as('seconds'),\n });\n\n for (const task of tasks) {\n await databaseTaskStore.shutdownTask(task);\n logger.info(`Successfully closed stale task ${task.taskId}`);\n }\n },\n });\n }\n } else {\n taskBroker = options.taskBroker;\n }\n\n const actionRegistry = new TemplateActionRegistry();\n\n const workers: TaskWorker[] = [];\n if (concurrentTasksLimit !== 0) {\n for (let i = 0; i < (taskWorkers || 1); i++) {\n const worker = await TaskWorker.create({\n taskBroker,\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n concurrentTasksLimit,\n permissions,\n auditLogger,\n });\n workers.push(worker);\n }\n }\n\n const actionsToRegister = Array.isArray(actions)\n ? actions\n : createBuiltinActions({\n integrations,\n catalogClient,\n reader,\n config,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n });\n\n actionsToRegister.forEach(action => actionRegistry.register(action));\n\n const launchWorkers = () => workers.forEach(worker => worker.start());\n\n const shutdownWorkers = () => {\n workers.forEach(worker => worker.stop());\n };\n\n if (options.lifecycle) {\n options.lifecycle.addStartupHook(launchWorkers);\n options.lifecycle.addShutdownHook(shutdownWorkers);\n } else {\n launchWorkers();\n }\n\n const dryRunner = createDryRunner({\n actionRegistry,\n integrations,\n logger,\n auditLogger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n const templateRules: TemplatePermissionRuleInput[] = Object.values(\n scaffolderTemplateRules,\n );\n const actionRules: ActionPermissionRuleInput[] = Object.values(\n scaffolderActionRules,\n );\n\n if (permissionRules) {\n templateRules.push(\n ...permissionRules.filter(isTemplatePermissionRuleInput),\n );\n actionRules.push(...permissionRules.filter(isActionPermissionRuleInput));\n }\n\n const isAuthorized = createConditionAuthorizer(Object.values(templateRules));\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resources: [\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n permissions: scaffolderTemplatePermissions,\n rules: templateRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n permissions: scaffolderActionPermissions,\n rules: actionRules,\n },\n ],\n permissions: scaffolderTaskPermissions,\n });\n\n router.use(permissionIntegrationRouter);\n\n router\n .get(\n '/v2/templates/:namespace/:kind/:name/parameter-schema',\n async (req, res) => {\n const requestedTemplateRef = `${req.params.kind}:${req.params.namespace}/${req.params.name}`;\n const actorId = await auditLogger.getActorId(req);\n try {\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n await auditLogger.auditLog({\n eventName: 'ScaffolderParameterSchemaFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n templateRef: requestedTemplateRef,\n },\n request: req,\n message: `${actorId} requested the parameter schema for ${requestedTemplateRef}`,\n });\n const template = await authorizeTemplate(\n req.params,\n token,\n credentials,\n );\n\n const parameters = [template.spec.parameters ?? []].flat();\n\n const presentation = template.spec.presentation;\n const templateRef = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n const responseBody = {\n title: template.metadata.title ?? template.metadata.name,\n ...(presentation ? { presentation } : {}),\n description: template.metadata.description,\n 'ui:options': template.metadata['ui:options'],\n steps: parameters.map(schema => ({\n title: schema.title ?? 'Please enter the following information',\n description: schema.description,\n schema,\n })),\n };\n await auditLogger.auditLog({\n eventName: 'ScaffolderParameterSchemaFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n templateRef: templateRef,\n },\n request: req,\n response: {\n status: 200,\n body: responseBody,\n },\n message: `${actorId} successfully requested the parameter schema for ${templateRef}`,\n });\n\n res.json(responseBody);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderParameterSchemaFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n metadata: {\n templateRef: requestedTemplateRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} failed to request the parameter schema for ${requestedTemplateRef}`,\n });\n throw err;\n }\n },\n )\n .get('/v2/actions', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderInstalledActionsFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n request: req,\n message: `${actorId} requested the list of installed actions`,\n });\n const actionsList = actionRegistry.list().map(action => {\n return {\n id: action.id,\n description: action.description,\n examples: action.examples,\n schema: action.schema,\n };\n });\n await auditLogger.auditLog({\n eventName: 'ScaffolderInstalledActionsFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n request: req,\n response: {\n status: 200,\n body: actionsList,\n },\n message: `${actorId} successfully requested the list of installed actions`,\n });\n res.json(actionsList);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderInstalledActionsFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} failed to request for the list of installed actions`,\n });\n throw err;\n }\n })\n .post('/v2/tasks', async (req, res) => {\n const templateRef: string = req.body.templateRef;\n const { kind, namespace, name } = parseEntityRef(templateRef, {\n defaultKind: 'template',\n });\n const credentials = await httpAuth.credentials(req);\n\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n const values = req.body.values;\n const redactedRequest = cloneDeep(req);\n\n // Workaround ensure that redactedRequest.ip accesses the original req.ip with the correct context, preventing 'Illegal invocation' errors\n Object.defineProperty(redactedRequest, 'ip', {\n get: () => {\n return req.ip;\n },\n });\n if (req.body.secrets) {\n const redactedBody = {\n ...req.body,\n secrets: Object.keys(req.body.secrets).reduce((acc, key) => {\n return {\n ...acc,\n [key]: '***',\n };\n }, {} as TaskSecrets),\n };\n redactedRequest.body = redactedBody;\n }\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'initiation',\n status: 'succeeded',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n templateRef: templateRef,\n },\n\n message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} initiated`,\n });\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n const template = await authorizeTemplate(\n { kind, namespace, name },\n token,\n credentials,\n );\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(values, parameters);\n if (!result.valid) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n templateRef: templateRef,\n },\n response: {\n status: 400,\n body: { errors: result.errors },\n },\n errors: result.errors,\n message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed`,\n });\n return res.status(400).json({ errors: result.errors });\n }\n }\n\n const baseUrl = getEntityBaseUrl(template);\n\n const taskSpec: TaskSpec = {\n apiVersion: template.apiVersion,\n steps: template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n })),\n EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery,\n output: template.spec.output ?? {},\n parameters: values,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n templateInfo: {\n entityRef: stringifyEntityRef({ kind, name, namespace }),\n baseUrl,\n entity: {\n metadata: template.metadata,\n },\n },\n };\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: token,\n __initiatorCredentials: JSON.stringify({\n ...credentials,\n // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly\n token: (credentials as any).token,\n }),\n };\n\n const result = await taskBroker.dispatch({\n spec: taskSpec,\n createdBy: userEntityRef,\n secrets,\n });\n\n let auditLog = `Scaffolding task for ${templateRef}`;\n if (userEntityRef) {\n auditLog += ` created by ${userEntityRef}`;\n }\n\n logger.info(auditLog);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'completion',\n status: 'succeeded',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n taskId: result.taskId,\n templateRef: templateRef,\n },\n response: {\n status: 201,\n body: { id: result.taskId },\n },\n message: `Scaffolding task for ${templateRef} with taskId: ${result.taskId} successfully created by ${userEntityRef}`,\n });\n return res.status(201).json({ id: result.taskId });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n templateRef: templateRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed`,\n });\n throw err;\n }\n })\n .get('/v2/tasks', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskListFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n request: req,\n message: `${actorId} requested for the list of scaffolder tasks`,\n });\n const credentials = await httpAuth.credentials(req);\n\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n if (!taskBroker.list) {\n throw new Error(\n 'TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.',\n );\n }\n\n const createdBy = parseStringsParam(req.query.createdBy, 'createdBy');\n const status = parseStringsParam(req.query.status, 'status');\n\n const order = parseStringsParam(req.query.order, 'order')?.map(item => {\n const match = item.match(/^(asc|desc):(.+)$/);\n if (!match) {\n throw new InputError(\n `Invalid order parameter \"${item}\", expected \":\"`,\n );\n }\n\n return {\n order: match[1] as 'asc' | 'desc',\n field: match[2],\n };\n });\n\n const limit = parseNumberParam(req.query.limit, 'limit');\n const offset = parseNumberParam(req.query.offset, 'offset');\n\n const tasks = await taskBroker.list({\n filters: {\n createdBy,\n status: status ? (status as TaskStatus[]) : undefined,\n },\n order,\n pagination: {\n limit: limit ? limit[0] : undefined,\n offset: offset ? offset[0] : undefined,\n },\n });\n\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskListFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n request: req,\n response: {\n status: 200,\n body: tasks,\n },\n message: `${actorId} successfully requested for the list of scaffolder tasks`,\n });\n res.status(200).json(tasks);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskListFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} request for the list of scaffolder tasks failed`,\n });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId: taskId,\n },\n request: req,\n message: `${actorId} requested for scaffolder task ${taskId}`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const task = await taskBroker.get(taskId);\n if (!task) {\n throw new NotFoundError(`Task with id ${taskId} does not exist`);\n }\n // Do not disclose secrets\n delete task.secrets;\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n request: req,\n response: {\n status: 200,\n body: task,\n },\n message: `${actorId} successfully requested for scaffolder tasks ${taskId}`,\n });\n res.status(200).json(task);\n } catch (err) {\n let status = 500;\n if (err.name === 'NotFoundError') {\n status = 404;\n }\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n response: {\n status: status,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} request for scaffolder tasks ${taskId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/cancel', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCancellation',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Cancellation request for Scaffolding task with taskId: ${taskId} from ${actorId} received`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCancelPermission],\n permissionService: permissions,\n });\n await taskBroker.cancel?.(taskId);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCancellation',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n response: {\n status: 200,\n body: { status: 'cancelled' },\n },\n message: `Scaffolding task with taskId: ${taskId} successfully cancelled by ${actorId}`,\n });\n res.status(200).json({ status: 'cancelled' });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCancellation',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId}'s cancel request for task ${taskId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/retry', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskRetry',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Retry request for Scaffolding task with taskId: ${taskId} from ${actorId} received`,\n });\n const credentials = await httpAuth.credentials(req);\n // Requires both read and cancel permissions\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission, taskReadPermission],\n permissionService: permissions,\n });\n await taskBroker.retry?.(taskId);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskRetry',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n response: {\n status: 201,\n body: { id: taskId },\n },\n message: `Scaffolding task with taskId: ${taskId} successfully retried by ${actorId}`,\n });\n res.status(201).json({ id: taskId });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskRetry',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId}'s retry request for task ${taskId} failed`,\n });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/eventstream', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n const after =\n req.query.after !== undefined ? Number(req.query.after) : undefined;\n\n logger.debug(`Event stream observing taskId '${taskId}' opened`);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Event stream for scaffolding task with taskId: ${taskId} was opened by ${actorId}`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // After client opens connection send all events as string\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: error.name,\n message: error.message,\n stack: error.stack,\n cause: error.cause,\n },\n ],\n message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}`,\n });\n res.end();\n },\n next: ({ events }) => {\n let shouldUnsubscribe = false;\n for (const event of events) {\n res.write(\n `event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n );\n if (event.type === 'completion') {\n shouldUnsubscribe = true;\n }\n }\n // res.flush() is only available with the compression middleware\n res.flush?.();\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n res.end();\n }\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', async () => {\n subscription.unsubscribe();\n logger.debug(`Event stream observing taskId '${taskId}' closed`);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Event stream observing scaffolding task with taskId: ${taskId} was closed by ${actorId}`,\n });\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}`,\n });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/events', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n const after = Number(req.query.after) || undefined;\n\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} initiated by ${actorId}`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n // cancel the request after 30 seconds. this aligns with the recommendations of RFC 6202.\n const timeout = setTimeout(() => {\n res.json([]);\n }, 30_000);\n\n // Get all known events after an id (always includes the completion event) and return the first callback\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: error.name,\n message: error.message,\n stack: error.stack,\n },\n ],\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed`,\n });\n },\n next: async ({ events }) => {\n clearTimeout(timeout);\n subscription.unsubscribe();\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n response: {\n status: 200,\n body: events,\n },\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} by ${actorId} succeeded`,\n });\n res.json(events);\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n clearTimeout(timeout);\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/dry-run', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n isDryRun: true,\n },\n request: req,\n message: `Dry Run scaffolder task initiated by ${actorId}`,\n });\n const credentials = await httpAuth.credentials(req);\n\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n const bodySchema = z.object({\n template: z.unknown(),\n values: z.record(z.unknown()),\n secrets: z.record(z.string()).optional(),\n directoryContents: z.array(\n z.object({ path: z.string(), base64Content: z.string() }),\n ),\n });\n const body = await bodySchema.parseAsync(req.body).catch(e => {\n throw new InputError(`Malformed request: ${e}`);\n });\n\n const template = body.template as TemplateEntityV1beta3;\n if (!(await templateEntityV1beta3Validator.check(template))) {\n throw new InputError('Input template is not a template');\n }\n const templateRef: string = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(body.values, parameters);\n if (!result.valid) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n isDryRun: true,\n },\n errors: result.errors,\n request: req,\n response: {\n status: 400,\n body: { errors: result.errors },\n },\n message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} failed`,\n });\n return res.status(400).json({ errors: result.errors });\n }\n }\n\n const steps = template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n }));\n\n const result = await dryRunner({\n spec: {\n apiVersion: template.apiVersion,\n steps,\n output: template.spec.output ?? {},\n parameters: body.values as JsonObject,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n },\n directoryContents: (body.directoryContents ?? []).map(file => ({\n path: file.path,\n content: Buffer.from(file.base64Content, 'base64'),\n })),\n secrets: {\n ...body.secrets,\n ...(token && { backstageToken: token }),\n },\n credentials,\n });\n\n const dryRunResults = {\n ...result,\n steps,\n directoryContents: result.directoryContents.map(file => ({\n path: file.path,\n executable: file.executable,\n base64Content: file.content.toString('base64'),\n })),\n };\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n isDryRun: true,\n },\n request: req,\n response: {\n status: 200,\n body: dryRunResults,\n },\n message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} completed successfully`,\n });\n return res.status(200).json(dryRunResults);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n metadata: {\n isDryRun: true,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Scaffolder Task Dry Run requested by ${actorId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/autocomplete/:provider/:resource', async (req, res) => {\n const { token, context } = req.body;\n const { provider, resource } = req.params;\n\n if (!token) throw new InputError('Missing token query parameter');\n\n if (!autocompleteHandlers[provider]) {\n throw new InputError(`Unsupported provider: ${provider}`);\n }\n\n const { results } = await autocompleteHandlers[provider]({\n resource,\n token,\n context,\n });\n\n res.status(200).json({ results });\n });\n\n const app = express();\n app.set('logger', logger);\n app.use('/', router);\n\n async function authorizeTemplate(\n entityRef: CompoundEntityRef,\n token: string | undefined,\n credentials: BackstageCredentials,\n ) {\n const template = await findTemplate({\n catalogApi: catalogClient,\n entityRef,\n token,\n });\n\n if (!isSupportedTemplate(template)) {\n throw new InputError(\n `Unsupported apiVersion field in schema entity, ${\n (template as Entity).apiVersion\n }`,\n );\n }\n\n if (!permissions) {\n return template;\n }\n\n const [parameterDecision, stepDecision] =\n await permissions.authorizeConditional(\n [\n { permission: templateParameterReadPermission },\n { permission: templateStepReadPermission },\n ],\n { credentials },\n );\n\n // Authorize parameters\n if (Array.isArray(template.spec.parameters)) {\n template.spec.parameters = template.spec.parameters.filter(step =>\n isAuthorized(parameterDecision, step),\n );\n } else if (\n template.spec.parameters &&\n !isAuthorized(parameterDecision, template.spec.parameters)\n ) {\n template.spec.parameters = undefined;\n }\n\n // Authorize steps\n template.spec.steps = template.spec.steps.filter(step =>\n isAuthorized(stepDecision, step),\n );\n\n return template;\n }\n\n return app;\n}\n"],"names":["RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","RESOURCE_TYPE_SCAFFOLDER_ACTION","parseEntityRef","stringifyError","config","readDurationFromConfig","Router","express","HostDiscovery","createLegacyAuthAdapters","DefaultAuditLogger","getWorkingDirectory","ScmIntegrations","DatabaseTaskStore","StorageTaskBroker","Duration","TemplateActionRegistry","TaskWorker","createBuiltinActions","createDryRunner","scaffolderTemplateRules","scaffolderActionRules","createConditionAuthorizer","createPermissionIntegrationRouter","scaffolderTemplatePermissions","scaffolderActionPermissions","scaffolderTaskPermissions","checkPermission","taskCreatePermission","cloneDeep","result","validate","getEntityBaseUrl","stringifyEntityRef","taskReadPermission","parseStringsParam","InputError","parseNumberParam","NotFoundError","taskCancelPermission","z","templateEntityV1beta3Validator","findTemplate","templateParameterReadPermission","templateStepReadPermission"],"mappings":"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"} +\ No newline at end of file diff --git a/.yarn/patches/@backstage-plugin-scaffolder-node-npm-0.5.0.patch b/.yarn/patches/@backstage-plugin-scaffolder-node-npm-0.5.0.patch new file mode 100644 index 0000000000..20242852c6 --- /dev/null +++ b/.yarn/patches/@backstage-plugin-scaffolder-node-npm-0.5.0.patch @@ -0,0 +1,12 @@ +diff --git a/dist/index.d.ts b/dist/index.d.ts +index b88643b24b813cf5d9f1cfd17b182618c0937f8b..2407a197e182d7714607132ff2f306cb4a0ad16a 100644 +--- a/dist/index.d.ts ++++ b/dist/index.d.ts +@@ -89,6 +89,7 @@ type TaskBrokerDispatchOptions = { + * @public + */ + interface TaskContext { ++ taskId: string; + cancelSignal: AbortSignal; + spec: TaskSpec; + secrets?: TaskSecrets; diff --git a/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs b/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs new file mode 100644 index 0000000000..4e89c7c352 --- /dev/null +++ b/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs @@ -0,0 +1,28 @@ +/* eslint-disable */ +//prettier-ignore +module.exports = { +name: "@yarnpkg/plugin-workspace-tools", +factory: function (require) { +var plugin=(()=>{var yr=Object.create;var we=Object.defineProperty;var _r=Object.getOwnPropertyDescriptor;var Er=Object.getOwnPropertyNames;var br=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty;var W=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var q=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports),Cr=(e,r)=>{for(var t in r)we(e,t,{get:r[t],enumerable:!0})},Je=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Er(r))!xr.call(e,s)&&s!==t&&we(e,s,{get:()=>r[s],enumerable:!(n=_r(r,s))||n.enumerable});return e};var Be=(e,r,t)=>(t=e!=null?yr(br(e)):{},Je(r||!e||!e.__esModule?we(t,"default",{value:e,enumerable:!0}):t,e)),wr=e=>Je(we({},"__esModule",{value:!0}),e);var ve=q(ee=>{"use strict";ee.isInteger=e=>typeof e=="number"?Number.isInteger(e):typeof e=="string"&&e.trim()!==""?Number.isInteger(Number(e)):!1;ee.find=(e,r)=>e.nodes.find(t=>t.type===r);ee.exceedsLimit=(e,r,t=1,n)=>n===!1||!ee.isInteger(e)||!ee.isInteger(r)?!1:(Number(r)-Number(e))/Number(t)>=n;ee.escapeNode=(e,r=0,t)=>{let n=e.nodes[r];!n||(t&&n.type===t||n.type==="open"||n.type==="close")&&n.escaped!==!0&&(n.value="\\"+n.value,n.escaped=!0)};ee.encloseBrace=e=>e.type!=="brace"?!1:e.commas>>0+e.ranges>>0===0?(e.invalid=!0,!0):!1;ee.isInvalidBrace=e=>e.type!=="brace"?!1:e.invalid===!0||e.dollar?!0:e.commas>>0+e.ranges>>0===0||e.open!==!0||e.close!==!0?(e.invalid=!0,!0):!1;ee.isOpenOrClose=e=>e.type==="open"||e.type==="close"?!0:e.open===!0||e.close===!0;ee.reduce=e=>e.reduce((r,t)=>(t.type==="text"&&r.push(t.value),t.type==="range"&&(t.type="text"),r),[]);ee.flatten=(...e)=>{let r=[],t=n=>{for(let s=0;s{"use strict";var tt=ve();rt.exports=(e,r={})=>{let t=(n,s={})=>{let i=r.escapeInvalid&&tt.isInvalidBrace(s),a=n.invalid===!0&&r.escapeInvalid===!0,c="";if(n.value)return(i||a)&&tt.isOpenOrClose(n)?"\\"+n.value:n.value;if(n.value)return n.value;if(n.nodes)for(let p of n.nodes)c+=t(p);return c};return t(e)}});var st=q((Vn,nt)=>{"use strict";nt.exports=function(e){return typeof e=="number"?e-e===0:typeof e=="string"&&e.trim()!==""?Number.isFinite?Number.isFinite(+e):isFinite(+e):!1}});var ht=q((Jn,pt)=>{"use strict";var at=st(),le=(e,r,t)=>{if(at(e)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(r===void 0||e===r)return String(e);if(at(r)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let n={relaxZeros:!0,...t};typeof n.strictZeros=="boolean"&&(n.relaxZeros=n.strictZeros===!1);let s=String(n.relaxZeros),i=String(n.shorthand),a=String(n.capture),c=String(n.wrap),p=e+":"+r+"="+s+i+a+c;if(le.cache.hasOwnProperty(p))return le.cache[p].result;let m=Math.min(e,r),h=Math.max(e,r);if(Math.abs(m-h)===1){let y=e+"|"+r;return n.capture?`(${y})`:n.wrap===!1?y:`(?:${y})`}let R=ft(e)||ft(r),f={min:e,max:r,a:m,b:h},$=[],_=[];if(R&&(f.isPadded=R,f.maxLen=String(f.max).length),m<0){let y=h<0?Math.abs(h):1;_=it(y,Math.abs(m),f,n),m=f.a=0}return h>=0&&($=it(m,h,f,n)),f.negatives=_,f.positives=$,f.result=Sr(_,$,n),n.capture===!0?f.result=`(${f.result})`:n.wrap!==!1&&$.length+_.length>1&&(f.result=`(?:${f.result})`),le.cache[p]=f,f.result};function Sr(e,r,t){let n=Pe(e,r,"-",!1,t)||[],s=Pe(r,e,"",!1,t)||[],i=Pe(e,r,"-?",!0,t)||[];return n.concat(i).concat(s).join("|")}function vr(e,r){let t=1,n=1,s=ut(e,t),i=new Set([r]);for(;e<=s&&s<=r;)i.add(s),t+=1,s=ut(e,t);for(s=ct(r+1,n)-1;e1&&c.count.pop(),c.count.push(h.count[0]),c.string=c.pattern+lt(c.count),a=m+1;continue}t.isPadded&&(R=Lr(m,t,n)),h.string=R+h.pattern+lt(h.count),i.push(h),a=m+1,c=h}return i}function Pe(e,r,t,n,s){let i=[];for(let a of e){let{string:c}=a;!n&&!ot(r,"string",c)&&i.push(t+c),n&&ot(r,"string",c)&&i.push(t+c)}return i}function $r(e,r){let t=[];for(let n=0;nr?1:r>e?-1:0}function ot(e,r,t){return e.some(n=>n[r]===t)}function ut(e,r){return Number(String(e).slice(0,-r)+"9".repeat(r))}function ct(e,r){return e-e%Math.pow(10,r)}function lt(e){let[r=0,t=""]=e;return t||r>1?`{${r+(t?","+t:"")}}`:""}function kr(e,r,t){return`[${e}${r-e===1?"":"-"}${r}]`}function ft(e){return/^-?(0+)\d/.test(e)}function Lr(e,r,t){if(!r.isPadded)return e;let n=Math.abs(r.maxLen-String(e).length),s=t.relaxZeros!==!1;switch(n){case 0:return"";case 1:return s?"0?":"0";case 2:return s?"0{0,2}":"00";default:return s?`0{0,${n}}`:`0{${n}}`}}le.cache={};le.clearCache=()=>le.cache={};pt.exports=le});var Ue=q((es,Et)=>{"use strict";var Or=W("util"),At=ht(),dt=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),Nr=e=>r=>e===!0?Number(r):String(r),Me=e=>typeof e=="number"||typeof e=="string"&&e!=="",Ae=e=>Number.isInteger(+e),De=e=>{let r=`${e}`,t=-1;if(r[0]==="-"&&(r=r.slice(1)),r==="0")return!1;for(;r[++t]==="0";);return t>0},Ir=(e,r,t)=>typeof e=="string"||typeof r=="string"?!0:t.stringify===!0,Br=(e,r,t)=>{if(r>0){let n=e[0]==="-"?"-":"";n&&(e=e.slice(1)),e=n+e.padStart(n?r-1:r,"0")}return t===!1?String(e):e},gt=(e,r)=>{let t=e[0]==="-"?"-":"";for(t&&(e=e.slice(1),r--);e.length{e.negatives.sort((a,c)=>ac?1:0),e.positives.sort((a,c)=>ac?1:0);let t=r.capture?"":"?:",n="",s="",i;return e.positives.length&&(n=e.positives.join("|")),e.negatives.length&&(s=`-(${t}${e.negatives.join("|")})`),n&&s?i=`${n}|${s}`:i=n||s,r.wrap?`(${t}${i})`:i},mt=(e,r,t,n)=>{if(t)return At(e,r,{wrap:!1,...n});let s=String.fromCharCode(e);if(e===r)return s;let i=String.fromCharCode(r);return`[${s}-${i}]`},Rt=(e,r,t)=>{if(Array.isArray(e)){let n=t.wrap===!0,s=t.capture?"":"?:";return n?`(${s}${e.join("|")})`:e.join("|")}return At(e,r,t)},yt=(...e)=>new RangeError("Invalid range arguments: "+Or.inspect(...e)),_t=(e,r,t)=>{if(t.strictRanges===!0)throw yt([e,r]);return[]},Mr=(e,r)=>{if(r.strictRanges===!0)throw new TypeError(`Expected step "${e}" to be a number`);return[]},Dr=(e,r,t=1,n={})=>{let s=Number(e),i=Number(r);if(!Number.isInteger(s)||!Number.isInteger(i)){if(n.strictRanges===!0)throw yt([e,r]);return[]}s===0&&(s=0),i===0&&(i=0);let a=s>i,c=String(e),p=String(r),m=String(t);t=Math.max(Math.abs(t),1);let h=De(c)||De(p)||De(m),R=h?Math.max(c.length,p.length,m.length):0,f=h===!1&&Ir(e,r,n)===!1,$=n.transform||Nr(f);if(n.toRegex&&t===1)return mt(gt(e,R),gt(r,R),!0,n);let _={negatives:[],positives:[]},y=T=>_[T<0?"negatives":"positives"].push(Math.abs(T)),E=[],S=0;for(;a?s>=i:s<=i;)n.toRegex===!0&&t>1?y(s):E.push(Br($(s,S),R,f)),s=a?s-t:s+t,S++;return n.toRegex===!0?t>1?Pr(_,n):Rt(E,null,{wrap:!1,...n}):E},Ur=(e,r,t=1,n={})=>{if(!Ae(e)&&e.length>1||!Ae(r)&&r.length>1)return _t(e,r,n);let s=n.transform||(f=>String.fromCharCode(f)),i=`${e}`.charCodeAt(0),a=`${r}`.charCodeAt(0),c=i>a,p=Math.min(i,a),m=Math.max(i,a);if(n.toRegex&&t===1)return mt(p,m,!1,n);let h=[],R=0;for(;c?i>=a:i<=a;)h.push(s(i,R)),i=c?i-t:i+t,R++;return n.toRegex===!0?Rt(h,null,{wrap:!1,options:n}):h},$e=(e,r,t,n={})=>{if(r==null&&Me(e))return[e];if(!Me(e)||!Me(r))return _t(e,r,n);if(typeof t=="function")return $e(e,r,1,{transform:t});if(dt(t))return $e(e,r,0,t);let s={...n};return s.capture===!0&&(s.wrap=!0),t=t||s.step||1,Ae(t)?Ae(e)&&Ae(r)?Dr(e,r,t,s):Ur(e,r,Math.max(Math.abs(t),1),s):t!=null&&!dt(t)?Mr(t,s):$e(e,r,1,t)};Et.exports=$e});var Ct=q((ts,xt)=>{"use strict";var Gr=Ue(),bt=ve(),qr=(e,r={})=>{let t=(n,s={})=>{let i=bt.isInvalidBrace(s),a=n.invalid===!0&&r.escapeInvalid===!0,c=i===!0||a===!0,p=r.escapeInvalid===!0?"\\":"",m="";if(n.isOpen===!0||n.isClose===!0)return p+n.value;if(n.type==="open")return c?p+n.value:"(";if(n.type==="close")return c?p+n.value:")";if(n.type==="comma")return n.prev.type==="comma"?"":c?n.value:"|";if(n.value)return n.value;if(n.nodes&&n.ranges>0){let h=bt.reduce(n.nodes),R=Gr(...h,{...r,wrap:!1,toRegex:!0});if(R.length!==0)return h.length>1&&R.length>1?`(${R})`:R}if(n.nodes)for(let h of n.nodes)m+=t(h,n);return m};return t(e)};xt.exports=qr});var vt=q((rs,St)=>{"use strict";var Kr=Ue(),wt=He(),he=ve(),fe=(e="",r="",t=!1)=>{let n=[];if(e=[].concat(e),r=[].concat(r),!r.length)return e;if(!e.length)return t?he.flatten(r).map(s=>`{${s}}`):r;for(let s of e)if(Array.isArray(s))for(let i of s)n.push(fe(i,r,t));else for(let i of r)t===!0&&typeof i=="string"&&(i=`{${i}}`),n.push(Array.isArray(i)?fe(s,i,t):s+i);return he.flatten(n)},Wr=(e,r={})=>{let t=r.rangeLimit===void 0?1e3:r.rangeLimit,n=(s,i={})=>{s.queue=[];let a=i,c=i.queue;for(;a.type!=="brace"&&a.type!=="root"&&a.parent;)a=a.parent,c=a.queue;if(s.invalid||s.dollar){c.push(fe(c.pop(),wt(s,r)));return}if(s.type==="brace"&&s.invalid!==!0&&s.nodes.length===2){c.push(fe(c.pop(),["{}"]));return}if(s.nodes&&s.ranges>0){let R=he.reduce(s.nodes);if(he.exceedsLimit(...R,r.step,t))throw new RangeError("expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.");let f=Kr(...R,r);f.length===0&&(f=wt(s,r)),c.push(fe(c.pop(),f)),s.nodes=[];return}let p=he.encloseBrace(s),m=s.queue,h=s;for(;h.type!=="brace"&&h.type!=="root"&&h.parent;)h=h.parent,m=h.queue;for(let R=0;R{"use strict";Ht.exports={MAX_LENGTH:1024*64,CHAR_0:"0",CHAR_9:"9",CHAR_UPPERCASE_A:"A",CHAR_LOWERCASE_A:"a",CHAR_UPPERCASE_Z:"Z",CHAR_LOWERCASE_Z:"z",CHAR_LEFT_PARENTHESES:"(",CHAR_RIGHT_PARENTHESES:")",CHAR_ASTERISK:"*",CHAR_AMPERSAND:"&",CHAR_AT:"@",CHAR_BACKSLASH:"\\",CHAR_BACKTICK:"`",CHAR_CARRIAGE_RETURN:"\r",CHAR_CIRCUMFLEX_ACCENT:"^",CHAR_COLON:":",CHAR_COMMA:",",CHAR_DOLLAR:"$",CHAR_DOT:".",CHAR_DOUBLE_QUOTE:'"',CHAR_EQUAL:"=",CHAR_EXCLAMATION_MARK:"!",CHAR_FORM_FEED:"\f",CHAR_FORWARD_SLASH:"/",CHAR_HASH:"#",CHAR_HYPHEN_MINUS:"-",CHAR_LEFT_ANGLE_BRACKET:"<",CHAR_LEFT_CURLY_BRACE:"{",CHAR_LEFT_SQUARE_BRACKET:"[",CHAR_LINE_FEED:` +`,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var Nt=q((ss,Ot)=>{"use strict";var jr=He(),{MAX_LENGTH:Tt,CHAR_BACKSLASH:Ge,CHAR_BACKTICK:Fr,CHAR_COMMA:Qr,CHAR_DOT:Xr,CHAR_LEFT_PARENTHESES:Zr,CHAR_RIGHT_PARENTHESES:Yr,CHAR_LEFT_CURLY_BRACE:zr,CHAR_RIGHT_CURLY_BRACE:Vr,CHAR_LEFT_SQUARE_BRACKET:kt,CHAR_RIGHT_SQUARE_BRACKET:Lt,CHAR_DOUBLE_QUOTE:Jr,CHAR_SINGLE_QUOTE:en,CHAR_NO_BREAK_SPACE:tn,CHAR_ZERO_WIDTH_NOBREAK_SPACE:rn}=$t(),nn=(e,r={})=>{if(typeof e!="string")throw new TypeError("Expected a string");let t=r||{},n=typeof t.maxLength=="number"?Math.min(Tt,t.maxLength):Tt;if(e.length>n)throw new SyntaxError(`Input length (${e.length}), exceeds max characters (${n})`);let s={type:"root",input:e,nodes:[]},i=[s],a=s,c=s,p=0,m=e.length,h=0,R=0,f,$={},_=()=>e[h++],y=E=>{if(E.type==="text"&&c.type==="dot"&&(c.type="text"),c&&c.type==="text"&&E.type==="text"){c.value+=E.value;return}return a.nodes.push(E),E.parent=a,E.prev=c,c=E,E};for(y({type:"bos"});h0){if(a.ranges>0){a.ranges=0;let E=a.nodes.shift();a.nodes=[E,{type:"text",value:jr(a)}]}y({type:"comma",value:f}),a.commas++;continue}if(f===Xr&&R>0&&a.commas===0){let E=a.nodes;if(R===0||E.length===0){y({type:"text",value:f});continue}if(c.type==="dot"){if(a.range=[],c.value+=f,c.type="range",a.nodes.length!==3&&a.nodes.length!==5){a.invalid=!0,a.ranges=0,c.type="text";continue}a.ranges++,a.args=[];continue}if(c.type==="range"){E.pop();let S=E[E.length-1];S.value+=c.value+f,c=S,a.ranges--;continue}y({type:"dot",value:f});continue}y({type:"text",value:f})}do if(a=i.pop(),a.type!=="root"){a.nodes.forEach(T=>{T.nodes||(T.type==="open"&&(T.isOpen=!0),T.type==="close"&&(T.isClose=!0),T.nodes||(T.type="text"),T.invalid=!0)});let E=i[i.length-1],S=E.nodes.indexOf(a);E.nodes.splice(S,1,...a.nodes)}while(i.length>0);return y({type:"eos"}),s};Ot.exports=nn});var Pt=q((as,Bt)=>{"use strict";var It=He(),sn=Ct(),an=vt(),on=Nt(),Z=(e,r={})=>{let t=[];if(Array.isArray(e))for(let n of e){let s=Z.create(n,r);Array.isArray(s)?t.push(...s):t.push(s)}else t=[].concat(Z.create(e,r));return r&&r.expand===!0&&r.nodupes===!0&&(t=[...new Set(t)]),t};Z.parse=(e,r={})=>on(e,r);Z.stringify=(e,r={})=>It(typeof e=="string"?Z.parse(e,r):e,r);Z.compile=(e,r={})=>(typeof e=="string"&&(e=Z.parse(e,r)),sn(e,r));Z.expand=(e,r={})=>{typeof e=="string"&&(e=Z.parse(e,r));let t=an(e,r);return r.noempty===!0&&(t=t.filter(Boolean)),r.nodupes===!0&&(t=[...new Set(t)]),t};Z.create=(e,r={})=>e===""||e.length<3?[e]:r.expand!==!0?Z.compile(e,r):Z.expand(e,r);Bt.exports=Z});var me=q((is,qt)=>{"use strict";var un=W("path"),se="\\\\/",Mt=`[^${se}]`,ie="\\.",cn="\\+",ln="\\?",Te="\\/",fn="(?=.)",Dt="[^/]",qe=`(?:${Te}|$)`,Ut=`(?:^|${Te})`,Ke=`${ie}{1,2}${qe}`,pn=`(?!${ie})`,hn=`(?!${Ut}${Ke})`,dn=`(?!${ie}{0,1}${qe})`,gn=`(?!${Ke})`,An=`[^.${Te}]`,mn=`${Dt}*?`,Gt={DOT_LITERAL:ie,PLUS_LITERAL:cn,QMARK_LITERAL:ln,SLASH_LITERAL:Te,ONE_CHAR:fn,QMARK:Dt,END_ANCHOR:qe,DOTS_SLASH:Ke,NO_DOT:pn,NO_DOTS:hn,NO_DOT_SLASH:dn,NO_DOTS_SLASH:gn,QMARK_NO_DOT:An,STAR:mn,START_ANCHOR:Ut},Rn={...Gt,SLASH_LITERAL:`[${se}]`,QMARK:Mt,STAR:`${Mt}*?`,DOTS_SLASH:`${ie}{1,2}(?:[${se}]|$)`,NO_DOT:`(?!${ie})`,NO_DOTS:`(?!(?:^|[${se}])${ie}{1,2}(?:[${se}]|$))`,NO_DOT_SLASH:`(?!${ie}{0,1}(?:[${se}]|$))`,NO_DOTS_SLASH:`(?!${ie}{1,2}(?:[${se}]|$))`,QMARK_NO_DOT:`[^.${se}]`,START_ANCHOR:`(?:^|[${se}])`,END_ANCHOR:`(?:[${se}]|$)`},yn={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};qt.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:yn,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:un.sep,extglobChars(e){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${e.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(e){return e===!0?Rn:Gt}}});var Re=q(Q=>{"use strict";var _n=W("path"),En=process.platform==="win32",{REGEX_BACKSLASH:bn,REGEX_REMOVE_BACKSLASH:xn,REGEX_SPECIAL_CHARS:Cn,REGEX_SPECIAL_CHARS_GLOBAL:wn}=me();Q.isObject=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);Q.hasRegexChars=e=>Cn.test(e);Q.isRegexChar=e=>e.length===1&&Q.hasRegexChars(e);Q.escapeRegex=e=>e.replace(wn,"\\$1");Q.toPosixSlashes=e=>e.replace(bn,"/");Q.removeBackslashes=e=>e.replace(xn,r=>r==="\\"?"":r);Q.supportsLookbehinds=()=>{let e=process.version.slice(1).split(".").map(Number);return e.length===3&&e[0]>=9||e[0]===8&&e[1]>=10};Q.isWindows=e=>e&&typeof e.windows=="boolean"?e.windows:En===!0||_n.sep==="\\";Q.escapeLast=(e,r,t)=>{let n=e.lastIndexOf(r,t);return n===-1?e:e[n-1]==="\\"?Q.escapeLast(e,r,n-1):`${e.slice(0,n)}\\${e.slice(n)}`};Q.removePrefix=(e,r={})=>{let t=e;return t.startsWith("./")&&(t=t.slice(2),r.prefix="./"),t};Q.wrapOutput=(e,r={},t={})=>{let n=t.contains?"":"^",s=t.contains?"":"$",i=`${n}(?:${e})${s}`;return r.negated===!0&&(i=`(?:^(?!${i}).*$)`),i}});var Yt=q((us,Zt)=>{"use strict";var Kt=Re(),{CHAR_ASTERISK:We,CHAR_AT:Sn,CHAR_BACKWARD_SLASH:ye,CHAR_COMMA:vn,CHAR_DOT:je,CHAR_EXCLAMATION_MARK:Fe,CHAR_FORWARD_SLASH:Xt,CHAR_LEFT_CURLY_BRACE:Qe,CHAR_LEFT_PARENTHESES:Xe,CHAR_LEFT_SQUARE_BRACKET:Hn,CHAR_PLUS:$n,CHAR_QUESTION_MARK:Wt,CHAR_RIGHT_CURLY_BRACE:Tn,CHAR_RIGHT_PARENTHESES:jt,CHAR_RIGHT_SQUARE_BRACKET:kn}=me(),Ft=e=>e===Xt||e===ye,Qt=e=>{e.isPrefix!==!0&&(e.depth=e.isGlobstar?1/0:1)},Ln=(e,r)=>{let t=r||{},n=e.length-1,s=t.parts===!0||t.scanToEnd===!0,i=[],a=[],c=[],p=e,m=-1,h=0,R=0,f=!1,$=!1,_=!1,y=!1,E=!1,S=!1,T=!1,L=!1,z=!1,I=!1,re=0,K,g,v={value:"",depth:0,isGlob:!1},k=()=>m>=n,l=()=>p.charCodeAt(m+1),H=()=>(K=g,p.charCodeAt(++m));for(;m0&&(B=p.slice(0,h),p=p.slice(h),R-=h),w&&_===!0&&R>0?(w=p.slice(0,R),o=p.slice(R)):_===!0?(w="",o=p):w=p,w&&w!==""&&w!=="/"&&w!==p&&Ft(w.charCodeAt(w.length-1))&&(w=w.slice(0,-1)),t.unescape===!0&&(o&&(o=Kt.removeBackslashes(o)),w&&T===!0&&(w=Kt.removeBackslashes(w)));let u={prefix:B,input:e,start:h,base:w,glob:o,isBrace:f,isBracket:$,isGlob:_,isExtglob:y,isGlobstar:E,negated:L,negatedExtglob:z};if(t.tokens===!0&&(u.maxDepth=0,Ft(g)||a.push(v),u.tokens=a),t.parts===!0||t.tokens===!0){let P;for(let b=0;b{"use strict";var ke=me(),Y=Re(),{MAX_LENGTH:Le,POSIX_REGEX_SOURCE:On,REGEX_NON_SPECIAL_CHARS:Nn,REGEX_SPECIAL_CHARS_BACKREF:In,REPLACEMENTS:zt}=ke,Bn=(e,r)=>{if(typeof r.expandRange=="function")return r.expandRange(...e,r);e.sort();let t=`[${e.join("-")}]`;try{new RegExp(t)}catch{return e.map(s=>Y.escapeRegex(s)).join("..")}return t},de=(e,r)=>`Missing ${e}: "${r}" - use "\\\\${r}" to match literal characters`,Vt=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");e=zt[e]||e;let t={...r},n=typeof t.maxLength=="number"?Math.min(Le,t.maxLength):Le,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);let i={type:"bos",value:"",output:t.prepend||""},a=[i],c=t.capture?"":"?:",p=Y.isWindows(r),m=ke.globChars(p),h=ke.extglobChars(m),{DOT_LITERAL:R,PLUS_LITERAL:f,SLASH_LITERAL:$,ONE_CHAR:_,DOTS_SLASH:y,NO_DOT:E,NO_DOT_SLASH:S,NO_DOTS_SLASH:T,QMARK:L,QMARK_NO_DOT:z,STAR:I,START_ANCHOR:re}=m,K=A=>`(${c}(?:(?!${re}${A.dot?y:R}).)*?)`,g=t.dot?"":E,v=t.dot?L:z,k=t.bash===!0?K(t):I;t.capture&&(k=`(${k})`),typeof t.noext=="boolean"&&(t.noextglob=t.noext);let l={input:e,index:-1,start:0,dot:t.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:a};e=Y.removePrefix(e,l),s=e.length;let H=[],w=[],B=[],o=i,u,P=()=>l.index===s-1,b=l.peek=(A=1)=>e[l.index+A],V=l.advance=()=>e[++l.index]||"",J=()=>e.slice(l.index+1),X=(A="",O=0)=>{l.consumed+=A,l.index+=O},Ee=A=>{l.output+=A.output!=null?A.output:A.value,X(A.value)},mr=()=>{let A=1;for(;b()==="!"&&(b(2)!=="("||b(3)==="?");)V(),l.start++,A++;return A%2===0?!1:(l.negated=!0,l.start++,!0)},be=A=>{l[A]++,B.push(A)},oe=A=>{l[A]--,B.pop()},C=A=>{if(o.type==="globstar"){let O=l.braces>0&&(A.type==="comma"||A.type==="brace"),d=A.extglob===!0||H.length&&(A.type==="pipe"||A.type==="paren");A.type!=="slash"&&A.type!=="paren"&&!O&&!d&&(l.output=l.output.slice(0,-o.output.length),o.type="star",o.value="*",o.output=k,l.output+=o.output)}if(H.length&&A.type!=="paren"&&(H[H.length-1].inner+=A.value),(A.value||A.output)&&Ee(A),o&&o.type==="text"&&A.type==="text"){o.value+=A.value,o.output=(o.output||"")+A.value;return}A.prev=o,a.push(A),o=A},xe=(A,O)=>{let d={...h[O],conditions:1,inner:""};d.prev=o,d.parens=l.parens,d.output=l.output;let x=(t.capture?"(":"")+d.open;be("parens"),C({type:A,value:O,output:l.output?"":_}),C({type:"paren",extglob:!0,value:V(),output:x}),H.push(d)},Rr=A=>{let O=A.close+(t.capture?")":""),d;if(A.type==="negate"){let x=k;A.inner&&A.inner.length>1&&A.inner.includes("/")&&(x=K(t)),(x!==k||P()||/^\)+$/.test(J()))&&(O=A.close=`)$))${x}`),A.inner.includes("*")&&(d=J())&&/^\.[^\\/.]+$/.test(d)&&(O=A.close=`)${d})${x})`),A.prev.type==="bos"&&(l.negatedExtglob=!0)}C({type:"paren",extglob:!0,value:u,output:O}),oe("parens")};if(t.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(e)){let A=!1,O=e.replace(In,(d,x,M,j,G,Ie)=>j==="\\"?(A=!0,d):j==="?"?x?x+j+(G?L.repeat(G.length):""):Ie===0?v+(G?L.repeat(G.length):""):L.repeat(M.length):j==="."?R.repeat(M.length):j==="*"?x?x+j+(G?k:""):k:x?d:`\\${d}`);return A===!0&&(t.unescape===!0?O=O.replace(/\\/g,""):O=O.replace(/\\+/g,d=>d.length%2===0?"\\\\":d?"\\":"")),O===e&&t.contains===!0?(l.output=e,l):(l.output=Y.wrapOutput(O,l,r),l)}for(;!P();){if(u=V(),u==="\0")continue;if(u==="\\"){let d=b();if(d==="/"&&t.bash!==!0||d==="."||d===";")continue;if(!d){u+="\\",C({type:"text",value:u});continue}let x=/^\\+/.exec(J()),M=0;if(x&&x[0].length>2&&(M=x[0].length,l.index+=M,M%2!==0&&(u+="\\")),t.unescape===!0?u=V():u+=V(),l.brackets===0){C({type:"text",value:u});continue}}if(l.brackets>0&&(u!=="]"||o.value==="["||o.value==="[^")){if(t.posix!==!1&&u===":"){let d=o.value.slice(1);if(d.includes("[")&&(o.posix=!0,d.includes(":"))){let x=o.value.lastIndexOf("["),M=o.value.slice(0,x),j=o.value.slice(x+2),G=On[j];if(G){o.value=M+G,l.backtrack=!0,V(),!i.output&&a.indexOf(o)===1&&(i.output=_);continue}}}(u==="["&&b()!==":"||u==="-"&&b()==="]")&&(u=`\\${u}`),u==="]"&&(o.value==="["||o.value==="[^")&&(u=`\\${u}`),t.posix===!0&&u==="!"&&o.value==="["&&(u="^"),o.value+=u,Ee({value:u});continue}if(l.quotes===1&&u!=='"'){u=Y.escapeRegex(u),o.value+=u,Ee({value:u});continue}if(u==='"'){l.quotes=l.quotes===1?0:1,t.keepQuotes===!0&&C({type:"text",value:u});continue}if(u==="("){be("parens"),C({type:"paren",value:u});continue}if(u===")"){if(l.parens===0&&t.strictBrackets===!0)throw new SyntaxError(de("opening","("));let d=H[H.length-1];if(d&&l.parens===d.parens+1){Rr(H.pop());continue}C({type:"paren",value:u,output:l.parens?")":"\\)"}),oe("parens");continue}if(u==="["){if(t.nobracket===!0||!J().includes("]")){if(t.nobracket!==!0&&t.strictBrackets===!0)throw new SyntaxError(de("closing","]"));u=`\\${u}`}else be("brackets");C({type:"bracket",value:u});continue}if(u==="]"){if(t.nobracket===!0||o&&o.type==="bracket"&&o.value.length===1){C({type:"text",value:u,output:`\\${u}`});continue}if(l.brackets===0){if(t.strictBrackets===!0)throw new SyntaxError(de("opening","["));C({type:"text",value:u,output:`\\${u}`});continue}oe("brackets");let d=o.value.slice(1);if(o.posix!==!0&&d[0]==="^"&&!d.includes("/")&&(u=`/${u}`),o.value+=u,Ee({value:u}),t.literalBrackets===!1||Y.hasRegexChars(d))continue;let x=Y.escapeRegex(o.value);if(l.output=l.output.slice(0,-o.value.length),t.literalBrackets===!0){l.output+=x,o.value=x;continue}o.value=`(${c}${x}|${o.value})`,l.output+=o.value;continue}if(u==="{"&&t.nobrace!==!0){be("braces");let d={type:"brace",value:u,output:"(",outputIndex:l.output.length,tokensIndex:l.tokens.length};w.push(d),C(d);continue}if(u==="}"){let d=w[w.length-1];if(t.nobrace===!0||!d){C({type:"text",value:u,output:u});continue}let x=")";if(d.dots===!0){let M=a.slice(),j=[];for(let G=M.length-1;G>=0&&(a.pop(),M[G].type!=="brace");G--)M[G].type!=="dots"&&j.unshift(M[G].value);x=Bn(j,t),l.backtrack=!0}if(d.comma!==!0&&d.dots!==!0){let M=l.output.slice(0,d.outputIndex),j=l.tokens.slice(d.tokensIndex);d.value=d.output="\\{",u=x="\\}",l.output=M;for(let G of j)l.output+=G.output||G.value}C({type:"brace",value:u,output:x}),oe("braces"),w.pop();continue}if(u==="|"){H.length>0&&H[H.length-1].conditions++,C({type:"text",value:u});continue}if(u===","){let d=u,x=w[w.length-1];x&&B[B.length-1]==="braces"&&(x.comma=!0,d="|"),C({type:"comma",value:u,output:d});continue}if(u==="/"){if(o.type==="dot"&&l.index===l.start+1){l.start=l.index+1,l.consumed="",l.output="",a.pop(),o=i;continue}C({type:"slash",value:u,output:$});continue}if(u==="."){if(l.braces>0&&o.type==="dot"){o.value==="."&&(o.output=R);let d=w[w.length-1];o.type="dots",o.output+=u,o.value+=u,d.dots=!0;continue}if(l.braces+l.parens===0&&o.type!=="bos"&&o.type!=="slash"){C({type:"text",value:u,output:R});continue}C({type:"dot",value:u,output:R});continue}if(u==="?"){if(!(o&&o.value==="(")&&t.noextglob!==!0&&b()==="("&&b(2)!=="?"){xe("qmark",u);continue}if(o&&o.type==="paren"){let x=b(),M=u;if(x==="<"&&!Y.supportsLookbehinds())throw new Error("Node.js v10 or higher is required for regex lookbehinds");(o.value==="("&&!/[!=<:]/.test(x)||x==="<"&&!/<([!=]|\w+>)/.test(J()))&&(M=`\\${u}`),C({type:"text",value:u,output:M});continue}if(t.dot!==!0&&(o.type==="slash"||o.type==="bos")){C({type:"qmark",value:u,output:z});continue}C({type:"qmark",value:u,output:L});continue}if(u==="!"){if(t.noextglob!==!0&&b()==="("&&(b(2)!=="?"||!/[!=<:]/.test(b(3)))){xe("negate",u);continue}if(t.nonegate!==!0&&l.index===0){mr();continue}}if(u==="+"){if(t.noextglob!==!0&&b()==="("&&b(2)!=="?"){xe("plus",u);continue}if(o&&o.value==="("||t.regex===!1){C({type:"plus",value:u,output:f});continue}if(o&&(o.type==="bracket"||o.type==="paren"||o.type==="brace")||l.parens>0){C({type:"plus",value:u});continue}C({type:"plus",value:f});continue}if(u==="@"){if(t.noextglob!==!0&&b()==="("&&b(2)!=="?"){C({type:"at",extglob:!0,value:u,output:""});continue}C({type:"text",value:u});continue}if(u!=="*"){(u==="$"||u==="^")&&(u=`\\${u}`);let d=Nn.exec(J());d&&(u+=d[0],l.index+=d[0].length),C({type:"text",value:u});continue}if(o&&(o.type==="globstar"||o.star===!0)){o.type="star",o.star=!0,o.value+=u,o.output=k,l.backtrack=!0,l.globstar=!0,X(u);continue}let A=J();if(t.noextglob!==!0&&/^\([^?]/.test(A)){xe("star",u);continue}if(o.type==="star"){if(t.noglobstar===!0){X(u);continue}let d=o.prev,x=d.prev,M=d.type==="slash"||d.type==="bos",j=x&&(x.type==="star"||x.type==="globstar");if(t.bash===!0&&(!M||A[0]&&A[0]!=="/")){C({type:"star",value:u,output:""});continue}let G=l.braces>0&&(d.type==="comma"||d.type==="brace"),Ie=H.length&&(d.type==="pipe"||d.type==="paren");if(!M&&d.type!=="paren"&&!G&&!Ie){C({type:"star",value:u,output:""});continue}for(;A.slice(0,3)==="/**";){let Ce=e[l.index+4];if(Ce&&Ce!=="/")break;A=A.slice(3),X("/**",3)}if(d.type==="bos"&&P()){o.type="globstar",o.value+=u,o.output=K(t),l.output=o.output,l.globstar=!0,X(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&!j&&P()){l.output=l.output.slice(0,-(d.output+o.output).length),d.output=`(?:${d.output}`,o.type="globstar",o.output=K(t)+(t.strictSlashes?")":"|$)"),o.value+=u,l.globstar=!0,l.output+=d.output+o.output,X(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&A[0]==="/"){let Ce=A[1]!==void 0?"|$":"";l.output=l.output.slice(0,-(d.output+o.output).length),d.output=`(?:${d.output}`,o.type="globstar",o.output=`${K(t)}${$}|${$}${Ce})`,o.value+=u,l.output+=d.output+o.output,l.globstar=!0,X(u+V()),C({type:"slash",value:"/",output:""});continue}if(d.type==="bos"&&A[0]==="/"){o.type="globstar",o.value+=u,o.output=`(?:^|${$}|${K(t)}${$})`,l.output=o.output,l.globstar=!0,X(u+V()),C({type:"slash",value:"/",output:""});continue}l.output=l.output.slice(0,-o.output.length),o.type="globstar",o.output=K(t),o.value+=u,l.output+=o.output,l.globstar=!0,X(u);continue}let O={type:"star",value:u,output:k};if(t.bash===!0){O.output=".*?",(o.type==="bos"||o.type==="slash")&&(O.output=g+O.output),C(O);continue}if(o&&(o.type==="bracket"||o.type==="paren")&&t.regex===!0){O.output=u,C(O);continue}(l.index===l.start||o.type==="slash"||o.type==="dot")&&(o.type==="dot"?(l.output+=S,o.output+=S):t.dot===!0?(l.output+=T,o.output+=T):(l.output+=g,o.output+=g),b()!=="*"&&(l.output+=_,o.output+=_)),C(O)}for(;l.brackets>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing","]"));l.output=Y.escapeLast(l.output,"["),oe("brackets")}for(;l.parens>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing",")"));l.output=Y.escapeLast(l.output,"("),oe("parens")}for(;l.braces>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing","}"));l.output=Y.escapeLast(l.output,"{"),oe("braces")}if(t.strictSlashes!==!0&&(o.type==="star"||o.type==="bracket")&&C({type:"maybe_slash",value:"",output:`${$}?`}),l.backtrack===!0){l.output="";for(let A of l.tokens)l.output+=A.output!=null?A.output:A.value,A.suffix&&(l.output+=A.suffix)}return l};Vt.fastpaths=(e,r)=>{let t={...r},n=typeof t.maxLength=="number"?Math.min(Le,t.maxLength):Le,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);e=zt[e]||e;let i=Y.isWindows(r),{DOT_LITERAL:a,SLASH_LITERAL:c,ONE_CHAR:p,DOTS_SLASH:m,NO_DOT:h,NO_DOTS:R,NO_DOTS_SLASH:f,STAR:$,START_ANCHOR:_}=ke.globChars(i),y=t.dot?R:h,E=t.dot?f:h,S=t.capture?"":"?:",T={negated:!1,prefix:""},L=t.bash===!0?".*?":$;t.capture&&(L=`(${L})`);let z=g=>g.noglobstar===!0?L:`(${S}(?:(?!${_}${g.dot?m:a}).)*?)`,I=g=>{switch(g){case"*":return`${y}${p}${L}`;case".*":return`${a}${p}${L}`;case"*.*":return`${y}${L}${a}${p}${L}`;case"*/*":return`${y}${L}${c}${p}${E}${L}`;case"**":return y+z(t);case"**/*":return`(?:${y}${z(t)}${c})?${E}${p}${L}`;case"**/*.*":return`(?:${y}${z(t)}${c})?${E}${L}${a}${p}${L}`;case"**/.*":return`(?:${y}${z(t)}${c})?${a}${p}${L}`;default:{let v=/^(.*?)\.(\w+)$/.exec(g);if(!v)return;let k=I(v[1]);return k?k+a+v[2]:void 0}}},re=Y.removePrefix(e,T),K=I(re);return K&&t.strictSlashes!==!0&&(K+=`${c}?`),K};Jt.exports=Vt});var rr=q((ls,tr)=>{"use strict";var Pn=W("path"),Mn=Yt(),Ze=er(),Ye=Re(),Dn=me(),Un=e=>e&&typeof e=="object"&&!Array.isArray(e),D=(e,r,t=!1)=>{if(Array.isArray(e)){let h=e.map(f=>D(f,r,t));return f=>{for(let $ of h){let _=$(f);if(_)return _}return!1}}let n=Un(e)&&e.tokens&&e.input;if(e===""||typeof e!="string"&&!n)throw new TypeError("Expected pattern to be a non-empty string");let s=r||{},i=Ye.isWindows(r),a=n?D.compileRe(e,r):D.makeRe(e,r,!1,!0),c=a.state;delete a.state;let p=()=>!1;if(s.ignore){let h={...r,ignore:null,onMatch:null,onResult:null};p=D(s.ignore,h,t)}let m=(h,R=!1)=>{let{isMatch:f,match:$,output:_}=D.test(h,a,r,{glob:e,posix:i}),y={glob:e,state:c,regex:a,posix:i,input:h,output:_,match:$,isMatch:f};return typeof s.onResult=="function"&&s.onResult(y),f===!1?(y.isMatch=!1,R?y:!1):p(h)?(typeof s.onIgnore=="function"&&s.onIgnore(y),y.isMatch=!1,R?y:!1):(typeof s.onMatch=="function"&&s.onMatch(y),R?y:!0)};return t&&(m.state=c),m};D.test=(e,r,t,{glob:n,posix:s}={})=>{if(typeof e!="string")throw new TypeError("Expected input to be a string");if(e==="")return{isMatch:!1,output:""};let i=t||{},a=i.format||(s?Ye.toPosixSlashes:null),c=e===n,p=c&&a?a(e):e;return c===!1&&(p=a?a(e):e,c=p===n),(c===!1||i.capture===!0)&&(i.matchBase===!0||i.basename===!0?c=D.matchBase(e,r,t,s):c=r.exec(p)),{isMatch:Boolean(c),match:c,output:p}};D.matchBase=(e,r,t,n=Ye.isWindows(t))=>(r instanceof RegExp?r:D.makeRe(r,t)).test(Pn.basename(e));D.isMatch=(e,r,t)=>D(r,t)(e);D.parse=(e,r)=>Array.isArray(e)?e.map(t=>D.parse(t,r)):Ze(e,{...r,fastpaths:!1});D.scan=(e,r)=>Mn(e,r);D.compileRe=(e,r,t=!1,n=!1)=>{if(t===!0)return e.output;let s=r||{},i=s.contains?"":"^",a=s.contains?"":"$",c=`${i}(?:${e.output})${a}`;e&&e.negated===!0&&(c=`^(?!${c}).*$`);let p=D.toRegex(c,r);return n===!0&&(p.state=e),p};D.makeRe=(e,r={},t=!1,n=!1)=>{if(!e||typeof e!="string")throw new TypeError("Expected a non-empty string");let s={negated:!1,fastpaths:!0};return r.fastpaths!==!1&&(e[0]==="."||e[0]==="*")&&(s.output=Ze.fastpaths(e,r)),s.output||(s=Ze(e,r)),D.compileRe(s,r,t,n)};D.toRegex=(e,r)=>{try{let t=r||{};return new RegExp(e,t.flags||(t.nocase?"i":""))}catch(t){if(r&&r.debug===!0)throw t;return/$^/}};D.constants=Dn;tr.exports=D});var sr=q((fs,nr)=>{"use strict";nr.exports=rr()});var cr=q((ps,ur)=>{"use strict";var ir=W("util"),or=Pt(),ae=sr(),ze=Re(),ar=e=>e===""||e==="./",N=(e,r,t)=>{r=[].concat(r),e=[].concat(e);let n=new Set,s=new Set,i=new Set,a=0,c=h=>{i.add(h.output),t&&t.onResult&&t.onResult(h)};for(let h=0;h!n.has(h));if(t&&m.length===0){if(t.failglob===!0)throw new Error(`No matches found for "${r.join(", ")}"`);if(t.nonull===!0||t.nullglob===!0)return t.unescape?r.map(h=>h.replace(/\\/g,"")):r}return m};N.match=N;N.matcher=(e,r)=>ae(e,r);N.isMatch=(e,r,t)=>ae(r,t)(e);N.any=N.isMatch;N.not=(e,r,t={})=>{r=[].concat(r).map(String);let n=new Set,s=[],a=N(e,r,{...t,onResult:c=>{t.onResult&&t.onResult(c),s.push(c.output)}});for(let c of s)a.includes(c)||n.add(c);return[...n]};N.contains=(e,r,t)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${ir.inspect(e)}"`);if(Array.isArray(r))return r.some(n=>N.contains(e,n,t));if(typeof r=="string"){if(ar(e)||ar(r))return!1;if(e.includes(r)||e.startsWith("./")&&e.slice(2).includes(r))return!0}return N.isMatch(e,r,{...t,contains:!0})};N.matchKeys=(e,r,t)=>{if(!ze.isObject(e))throw new TypeError("Expected the first argument to be an object");let n=N(Object.keys(e),r,t),s={};for(let i of n)s[i]=e[i];return s};N.some=(e,r,t)=>{let n=[].concat(e);for(let s of[].concat(r)){let i=ae(String(s),t);if(n.some(a=>i(a)))return!0}return!1};N.every=(e,r,t)=>{let n=[].concat(e);for(let s of[].concat(r)){let i=ae(String(s),t);if(!n.every(a=>i(a)))return!1}return!0};N.all=(e,r,t)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${ir.inspect(e)}"`);return[].concat(r).every(n=>ae(n,t)(e))};N.capture=(e,r,t)=>{let n=ze.isWindows(t),i=ae.makeRe(String(e),{...t,capture:!0}).exec(n?ze.toPosixSlashes(r):r);if(i)return i.slice(1).map(a=>a===void 0?"":a)};N.makeRe=(...e)=>ae.makeRe(...e);N.scan=(...e)=>ae.scan(...e);N.parse=(e,r)=>{let t=[];for(let n of[].concat(e||[]))for(let s of or(String(n),r))t.push(ae.parse(s,r));return t};N.braces=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");return r&&r.nobrace===!0||!/\{.*\}/.test(e)?[e]:or(e,r)};N.braceExpand=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");return N.braces(e,{...r,expand:!0})};ur.exports=N});var fr=q((hs,lr)=>{"use strict";lr.exports=(e,...r)=>new Promise(t=>{t(e(...r))})});var hr=q((ds,Ve)=>{"use strict";var Gn=fr(),pr=e=>{if(e<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let r=[],t=0,n=()=>{t--,r.length>0&&r.shift()()},s=(c,p,...m)=>{t++;let h=Gn(c,...m);p(h),h.then(n,n)},i=(c,p,...m)=>{tnew Promise(m=>i(c,m,...p));return Object.defineProperties(a,{activeCount:{get:()=>t},pendingCount:{get:()=>r.length}}),a};Ve.exports=pr;Ve.exports.default=pr});var jn={};Cr(jn,{default:()=>Wn});var Se=W("@yarnpkg/cli"),ne=W("@yarnpkg/core"),et=W("@yarnpkg/core"),ue=W("clipanion"),ce=class extends Se.BaseCommand{constructor(){super(...arguments);this.json=ue.Option.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=ue.Option.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=ue.Option.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=ue.Option.Rest()}async execute(){let t=await ne.Configuration.find(this.context.cwd,this.context.plugins),{project:n,workspace:s}=await ne.Project.find(t,this.context.cwd),i=await ne.Cache.find(t);await n.restoreInstallState({restoreResolutions:!1});let a;if(this.all)a=new Set(n.workspaces);else if(this.workspaces.length===0){if(!s)throw new Se.WorkspaceRequiredError(n.cwd,this.context.cwd);a=new Set([s])}else a=new Set(this.workspaces.map(p=>n.getWorkspaceByIdent(et.structUtils.parseIdent(p))));for(let p of a)for(let m of this.production?["dependencies"]:ne.Manifest.hardDependencies)for(let h of p.manifest.getForScope(m).values()){let R=n.tryWorkspaceByDescriptor(h);R!==null&&a.add(R)}for(let p of n.workspaces)a.has(p)?this.production&&p.manifest.devDependencies.clear():(p.manifest.installConfig=p.manifest.installConfig||{},p.manifest.installConfig.selfReferences=!1,p.manifest.dependencies.clear(),p.manifest.devDependencies.clear(),p.manifest.peerDependencies.clear(),p.manifest.scripts.clear());return(await ne.StreamReport.start({configuration:t,json:this.json,stdout:this.context.stdout,includeLogs:!0},async p=>{await n.install({cache:i,report:p,persistProject:!1})})).exitCode()}};ce.paths=[["workspaces","focus"]],ce.usage=ue.Command.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "});var Ne=W("@yarnpkg/cli"),ge=W("@yarnpkg/core"),_e=W("@yarnpkg/core"),F=W("@yarnpkg/core"),gr=W("@yarnpkg/plugin-git"),U=W("clipanion"),Oe=Be(cr()),Ar=Be(hr()),te=Be(W("typanion")),pe=class extends Ne.BaseCommand{constructor(){super(...arguments);this.recursive=U.Option.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.from=U.Option.Array("--from",[],{description:"An array of glob pattern idents from which to base any recursion"});this.all=U.Option.Boolean("-A,--all",!1,{description:"Run the command on all workspaces of a project"});this.verbose=U.Option.Boolean("-v,--verbose",!1,{description:"Prefix each output line with the name of the originating workspace"});this.parallel=U.Option.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=U.Option.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=U.Option.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:te.isOneOf([te.isEnum(["unlimited"]),te.applyCascade(te.isNumber(),[te.isInteger(),te.isAtLeast(1)])])});this.topological=U.Option.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=U.Option.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=U.Option.Array("--include",[],{description:"An array of glob pattern idents; only matching workspaces will be traversed"});this.exclude=U.Option.Array("--exclude",[],{description:"An array of glob pattern idents; matching workspaces won't be traversed"});this.publicOnly=U.Option.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=U.Option.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.commandName=U.Option.String();this.args=U.Option.Proxy()}async execute(){let t=await ge.Configuration.find(this.context.cwd,this.context.plugins),{project:n,workspace:s}=await ge.Project.find(t,this.context.cwd);if(!this.all&&!s)throw new Ne.WorkspaceRequiredError(n.cwd,this.context.cwd);await n.restoreInstallState();let i=this.cli.process([this.commandName,...this.args]),a=i.path.length===1&&i.path[0]==="run"&&typeof i.scriptName<"u"?i.scriptName:null;if(i.path.length===0)throw new U.UsageError("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let c=this.all?n.topLevelWorkspace:s,p=this.since?Array.from(await gr.gitUtils.fetchChangedWorkspaces({ref:this.since,project:n})):[c,...this.from.length>0?c.getRecursiveWorkspaceChildren():[]],m=g=>Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.from),h=this.from.length>0?p.filter(m):p,R=new Set([...h,...h.map(g=>[...this.recursive?this.since?g.getRecursiveWorkspaceDependents():g.getRecursiveWorkspaceDependencies():g.getRecursiveWorkspaceChildren()]).flat()]),f=[],$=!1;if(a!=null&&a.includes(":")){for(let g of n.workspaces)if(g.manifest.scripts.has(a)&&($=!$,$===!1))break}for(let g of R)a&&!g.manifest.scripts.has(a)&&!$&&!(await ge.scriptUtils.getWorkspaceAccessibleBinaries(g)).has(a)||a===process.env.npm_lifecycle_event&&g.cwd===s.cwd||this.include.length>0&&!Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.include)||this.exclude.length>0&&Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.exclude)||this.publicOnly&&g.manifest.private===!0||f.push(g);let _=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(F.nodeUtils.availableParallelism()/2):1,y=_===1?!1:this.parallel,E=y?this.interlaced:!0,S=(0,Ar.default)(_),T=new Map,L=new Set,z=0,I=null,re=!1,K=await _e.StreamReport.start({configuration:t,stdout:this.context.stdout,includePrefix:!1},async g=>{let v=async(k,{commandIndex:l})=>{if(re)return-1;!y&&this.verbose&&l>1&&g.reportSeparator();let H=qn(k,{configuration:t,verbose:this.verbose,commandIndex:l}),[w,B]=dr(g,{prefix:H,interlaced:E}),[o,u]=dr(g,{prefix:H,interlaced:E});try{this.verbose&&g.reportInfo(null,`${H} Process started`);let P=Date.now(),b=await this.cli.run([this.commandName,...this.args],{cwd:k.cwd,stdout:w,stderr:o})||0;w.end(),o.end(),await B,await u;let V=Date.now();if(this.verbose){let J=t.get("enableTimers")?`, completed in ${F.formatUtils.pretty(t,V-P,F.formatUtils.Type.DURATION)}`:"";g.reportInfo(null,`${H} Process exited (exit code ${b})${J}`)}return b===130&&(re=!0,I=b),b}catch(P){throw w.end(),o.end(),await B,await u,P}};for(let k of f)T.set(k.anchoredLocator.locatorHash,k);for(;T.size>0&&!g.hasErrors();){let k=[];for(let[w,B]of T){if(L.has(B.anchoredDescriptor.descriptorHash))continue;let o=!0;if(this.topological||this.topologicalDev){let u=this.topologicalDev?new Map([...B.manifest.dependencies,...B.manifest.devDependencies]):B.manifest.dependencies;for(let P of u.values()){let b=n.tryWorkspaceByDescriptor(P);if(o=b===null||!T.has(b.anchoredLocator.locatorHash),!o)break}}if(!!o&&(L.add(B.anchoredDescriptor.descriptorHash),k.push(S(async()=>{let u=await v(B,{commandIndex:++z});return T.delete(w),L.delete(B.anchoredDescriptor.descriptorHash),u})),!y))break}if(k.length===0){let w=Array.from(T.values()).map(B=>F.structUtils.prettyLocator(t,B.anchoredLocator)).join(", ");g.reportError(_e.MessageName.CYCLIC_DEPENDENCIES,`Dependency cycle detected (${w})`);return}let H=(await Promise.all(k)).find(w=>w!==0);I===null&&(I=typeof H<"u"?1:I),(this.topological||this.topologicalDev)&&typeof H<"u"&&g.reportError(_e.MessageName.UNNAMED,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return I!==null?I:K.exitCode()}};pe.paths=[["workspaces","foreach"]],pe.usage=U.Command.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project. By default yarn runs the command only on current and all its descendant workspaces.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n Adding the `-v,--verbose` flag will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish current and all descendant packages","yarn workspaces foreach npm publish --tolerate-republish"],["Run build script on current and all descendant packages","yarn workspaces foreach run build"],["Run build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -pt run build"],["Run build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -ptR --from '{workspace-a,workspace-b}' run build"]]});function dr(e,{prefix:r,interlaced:t}){let n=e.createStreamReporter(r),s=new F.miscUtils.DefaultStream;s.pipe(n,{end:!1}),s.on("finish",()=>{n.end()});let i=new Promise(c=>{n.on("finish",()=>{c(s.active)})});if(t)return[s,i];let a=new F.miscUtils.BufferStream;return a.pipe(s,{end:!1}),a.on("finish",()=>{s.end()}),[a,i]}function qn(e,{configuration:r,commandIndex:t,verbose:n}){if(!n)return null;let i=`[${F.structUtils.stringifyIdent(e.locator)}]:`,a=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],c=a[t%a.length];return F.formatUtils.pretty(r,i,c)}var Kn={commands:[ce,pe]},Wn=Kn;return wr(jn);})(); +/*! + * fill-range + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Licensed under the MIT License. + */ +/*! + * is-number + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. + */ +/*! + * to-regex-range + * + * Copyright (c) 2015-present, Jon Schlinkert. + * Released under the MIT License. + */ +return plugin; +} +}; diff --git a/.yarn/releases/yarn-1.22.19.cjs b/.yarn/releases/yarn-1.22.19.cjs deleted file mode 100755 index bca1f214f6..0000000000 --- a/.yarn/releases/yarn-1.22.19.cjs +++ /dev/null @@ -1,147529 +0,0 @@ -#!/usr/bin/env node -module.exports = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 517); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = require("path"); - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = __extends; -/* unused harmony export __assign */ -/* unused harmony export __rest */ -/* unused harmony export __decorate */ -/* unused harmony export __param */ -/* unused harmony export __metadata */ -/* unused harmony export __awaiter */ -/* unused harmony export __generator */ -/* unused harmony export __exportStar */ -/* unused harmony export __values */ -/* unused harmony export __read */ -/* unused harmony export __spread */ -/* unused harmony export __await */ -/* unused harmony export __asyncGenerator */ -/* unused harmony export __asyncDelegator */ -/* unused harmony export __asyncValues */ -/* unused harmony export __makeTemplateObject */ -/* unused harmony export __importStar */ -/* unused harmony export __importDefault */ -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -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 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ -/* global Reflect, Promise */ - -var extendStatics = function(d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); -}; - -function __extends(d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -} - -var __assign = function() { - __assign = Object.assign || function __assign(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - } - return __assign.apply(this, arguments); -} - -function __rest(s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) - t[p[i]] = s[p[i]]; - return t; -} - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - -function __param(paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } -} - -function __metadata(metadataKey, metadataValue) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); -} - -function __awaiter(thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -function __generator(thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -} - -function __exportStar(m, exports) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} - -function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; - if (m) return m.call(o); - return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; -} - -function __read(o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; -} - -function __spread() { - for (var ar = [], i = 0; i < arguments.length; i++) - ar = ar.concat(__read(arguments[i])); - return ar; -} - -function __await(v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); -} - -function __asyncGenerator(thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; - function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } - function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } - function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } - function fulfill(value) { resume("next", value); } - function reject(value) { resume("throw", value); } - function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } -} - -function __asyncDelegator(o) { - var i, p; - return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } -} - -function __asyncValues(o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -} - -function __makeTemplateObject(cooked, raw) { - if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } - return cooked; -}; - -function __importStar(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; - result.default = mod; - return result; -} - -function __importDefault(mod) { - return (mod && mod.__esModule) ? mod : { default: mod }; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -var _promise = __webpack_require__(224); - -var _promise2 = _interopRequireDefault(_promise); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function (fn) { - return function () { - var gen = fn.apply(this, arguments); - return new _promise2.default(function (resolve, reject) { - function step(key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error) { - reject(error); - return; - } - - if (info.done) { - resolve(value); - } else { - return _promise2.default.resolve(value).then(function (value) { - step("next", value); - }, function (err) { - step("throw", err); - }); - } - } - - return step("next"); - }); - }; -}; - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -module.exports = require("util"); - -/***/ }), -/* 4 */ -/***/ (function(module, exports) { - -module.exports = require("fs"); - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getFirstSuitableFolder = exports.readFirstAvailableStream = exports.makeTempDir = exports.hardlinksWork = exports.writeFilePreservingEol = exports.getFileSizeOnDisk = exports.walk = exports.symlink = exports.find = exports.readJsonAndFile = exports.readJson = exports.readFileAny = exports.hardlinkBulk = exports.copyBulk = exports.unlink = exports.glob = exports.link = exports.chmod = exports.lstat = exports.exists = exports.mkdirp = exports.stat = exports.access = exports.rename = exports.readdir = exports.realpath = exports.readlink = exports.writeFile = exports.open = exports.readFileBuffer = exports.lockQueue = exports.constants = undefined; - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -let buildActionsForCopy = (() => { - var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { - - // - let build = (() => { - var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - const src = data.src, - dest = data.dest, - type = data.type; - - const onFresh = data.onFresh || noop; - const onDone = data.onDone || noop; - - // TODO https://github.com/yarnpkg/yarn/issues/3751 - // related to bundled dependencies handling - if (files.has(dest.toLowerCase())) { - reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); - } else { - files.add(dest.toLowerCase()); - } - - if (type === 'symlink') { - yield mkdirp((_path || _load_path()).default.dirname(dest)); - onFresh(); - actions.symlink.push({ - dest, - linkname: src - }); - onDone(); - return; - } - - if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { - // ignored file - return; - } - - const srcStat = yield lstat(src); - let srcFiles; - - if (srcStat.isDirectory()) { - srcFiles = yield readdir(src); - } - - let destStat; - try { - // try accessing the destination - destStat = yield lstat(dest); - } catch (e) { - // proceed if destination doesn't exist, otherwise error - if (e.code !== 'ENOENT') { - throw e; - } - } - - // if destination exists - if (destStat) { - const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); - const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); - const bothFiles = srcStat.isFile() && destStat.isFile(); - - // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving - // us modes that aren't valid. investigate this, it's generally safe to proceed. - - /* if (srcStat.mode !== destStat.mode) { - try { - await access(dest, srcStat.mode); - } catch (err) {} - } */ - - if (bothFiles && artifactFiles.has(dest)) { - // this file gets changed during build, likely by a custom install script. Don't bother checking it. - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); - return; - } - - if (bothFiles && srcStat.size === destStat.size && (0, (_fsNormalized || _load_fsNormalized()).fileDatesEqual)(srcStat.mtime, destStat.mtime)) { - // we can safely assume this is the same file - onDone(); - reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); - return; - } - - if (bothSymlinks) { - const srcReallink = yield readlink(src); - if (srcReallink === (yield readlink(dest))) { - // if both symlinks are the same then we can continue on - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); - return; - } - } - - if (bothFolders) { - // mark files that aren't in this folder as possibly extraneous - const destFiles = yield readdir(dest); - invariant(srcFiles, 'src files not initialised'); - - for (var _iterator4 = destFiles, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref6; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref6 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref6 = _i4.value; - } - - const file = _ref6; - - if (srcFiles.indexOf(file) < 0) { - const loc = (_path || _load_path()).default.join(dest, file); - possibleExtraneous.add(loc); - - if ((yield lstat(loc)).isDirectory()) { - for (var _iterator5 = yield readdir(loc), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref7; - - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref7 = _iterator5[_i5++]; - } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref7 = _i5.value; - } - - const file = _ref7; - - possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); - } - } - } - } - } - } - - if (destStat && destStat.isSymbolicLink()) { - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); - destStat = null; - } - - if (srcStat.isSymbolicLink()) { - onFresh(); - const linkname = yield readlink(src); - actions.symlink.push({ - dest, - linkname - }); - onDone(); - } else if (srcStat.isDirectory()) { - if (!destStat) { - reporter.verbose(reporter.lang('verboseFileFolder', dest)); - yield mkdirp(dest); - } - - const destParts = dest.split((_path || _load_path()).default.sep); - while (destParts.length) { - files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); - destParts.pop(); - } - - // push all files to queue - invariant(srcFiles, 'src files not initialised'); - let remaining = srcFiles.length; - if (!remaining) { - onDone(); - } - for (var _iterator6 = srcFiles, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { - var _ref8; - - if (_isArray6) { - if (_i6 >= _iterator6.length) break; - _ref8 = _iterator6[_i6++]; - } else { - _i6 = _iterator6.next(); - if (_i6.done) break; - _ref8 = _i6.value; - } - - const file = _ref8; - - queue.push({ - dest: (_path || _load_path()).default.join(dest, file), - onFresh, - onDone: function (_onDone) { - function onDone() { - return _onDone.apply(this, arguments); - } - - onDone.toString = function () { - return _onDone.toString(); - }; - - return onDone; - }(function () { - if (--remaining === 0) { - onDone(); - } - }), - src: (_path || _load_path()).default.join(src, file) - }); - } - } else if (srcStat.isFile()) { - onFresh(); - actions.file.push({ - src, - dest, - atime: srcStat.atime, - mtime: srcStat.mtime, - mode: srcStat.mode - }); - onDone(); - } else { - throw new Error(`unsure how to copy this: ${src}`); - } - }); - - return function build(_x5) { - return _ref5.apply(this, arguments); - }; - })(); - - const artifactFiles = new Set(events.artifactFiles || []); - const files = new Set(); - - // initialise events - for (var _iterator = queue, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref2; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref2 = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref2 = _i.value; - } - - const item = _ref2; - - const onDone = item.onDone; - item.onDone = function () { - events.onProgress(item.dest); - if (onDone) { - onDone(); - } - }; - } - events.onStart(queue.length); - - // start building actions - const actions = { - file: [], - symlink: [], - link: [] - }; - - // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items - // at a time due to the requirement to push items onto the queue - while (queue.length) { - const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); - yield Promise.all(items.map(build)); - } - - // simulate the existence of some files to prevent considering them extraneous - for (var _iterator2 = artifactFiles, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { - var _ref3; - - if (_isArray2) { - if (_i2 >= _iterator2.length) break; - _ref3 = _iterator2[_i2++]; - } else { - _i2 = _iterator2.next(); - if (_i2.done) break; - _ref3 = _i2.value; - } - - const file = _ref3; - - if (possibleExtraneous.has(file)) { - reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); - possibleExtraneous.delete(file); - } - } - - for (var _iterator3 = possibleExtraneous, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref4; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref4 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref4 = _i3.value; - } - - const loc = _ref4; - - if (files.has(loc.toLowerCase())) { - possibleExtraneous.delete(loc); - } - } - - return actions; - }); - - return function buildActionsForCopy(_x, _x2, _x3, _x4) { - return _ref.apply(this, arguments); - }; -})(); - -let buildActionsForHardlink = (() => { - var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { - - // - let build = (() => { - var _ref13 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - const src = data.src, - dest = data.dest; - - const onFresh = data.onFresh || noop; - const onDone = data.onDone || noop; - if (files.has(dest.toLowerCase())) { - // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 - // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, - // package-linker passes that modules A1 and B1 need to be hardlinked, - // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case - // an exception. - onDone(); - return; - } - files.add(dest.toLowerCase()); - - if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { - // ignored file - return; - } - - const srcStat = yield lstat(src); - let srcFiles; - - if (srcStat.isDirectory()) { - srcFiles = yield readdir(src); - } - - const destExists = yield exists(dest); - if (destExists) { - const destStat = yield lstat(dest); - - const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); - const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); - const bothFiles = srcStat.isFile() && destStat.isFile(); - - if (srcStat.mode !== destStat.mode) { - try { - yield access(dest, srcStat.mode); - } catch (err) { - // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving - // us modes that aren't valid. investigate this, it's generally safe to proceed. - reporter.verbose(err); - } - } - - if (bothFiles && artifactFiles.has(dest)) { - // this file gets changed during build, likely by a custom install script. Don't bother checking it. - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); - return; - } - - // correct hardlink - if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { - onDone(); - reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); - return; - } - - if (bothSymlinks) { - const srcReallink = yield readlink(src); - if (srcReallink === (yield readlink(dest))) { - // if both symlinks are the same then we can continue on - onDone(); - reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); - return; - } - } - - if (bothFolders) { - // mark files that aren't in this folder as possibly extraneous - const destFiles = yield readdir(dest); - invariant(srcFiles, 'src files not initialised'); - - for (var _iterator10 = destFiles, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { - var _ref14; - - if (_isArray10) { - if (_i10 >= _iterator10.length) break; - _ref14 = _iterator10[_i10++]; - } else { - _i10 = _iterator10.next(); - if (_i10.done) break; - _ref14 = _i10.value; - } - - const file = _ref14; - - if (srcFiles.indexOf(file) < 0) { - const loc = (_path || _load_path()).default.join(dest, file); - possibleExtraneous.add(loc); - - if ((yield lstat(loc)).isDirectory()) { - for (var _iterator11 = yield readdir(loc), _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { - var _ref15; - - if (_isArray11) { - if (_i11 >= _iterator11.length) break; - _ref15 = _iterator11[_i11++]; - } else { - _i11 = _iterator11.next(); - if (_i11.done) break; - _ref15 = _i11.value; - } - - const file = _ref15; - - possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); - } - } - } - } - } - } - - if (srcStat.isSymbolicLink()) { - onFresh(); - const linkname = yield readlink(src); - actions.symlink.push({ - dest, - linkname - }); - onDone(); - } else if (srcStat.isDirectory()) { - reporter.verbose(reporter.lang('verboseFileFolder', dest)); - yield mkdirp(dest); - - const destParts = dest.split((_path || _load_path()).default.sep); - while (destParts.length) { - files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); - destParts.pop(); - } - - // push all files to queue - invariant(srcFiles, 'src files not initialised'); - let remaining = srcFiles.length; - if (!remaining) { - onDone(); - } - for (var _iterator12 = srcFiles, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { - var _ref16; - - if (_isArray12) { - if (_i12 >= _iterator12.length) break; - _ref16 = _iterator12[_i12++]; - } else { - _i12 = _iterator12.next(); - if (_i12.done) break; - _ref16 = _i12.value; - } - - const file = _ref16; - - queue.push({ - onFresh, - src: (_path || _load_path()).default.join(src, file), - dest: (_path || _load_path()).default.join(dest, file), - onDone: function (_onDone2) { - function onDone() { - return _onDone2.apply(this, arguments); - } - - onDone.toString = function () { - return _onDone2.toString(); - }; - - return onDone; - }(function () { - if (--remaining === 0) { - onDone(); - } - }) - }); - } - } else if (srcStat.isFile()) { - onFresh(); - actions.link.push({ - src, - dest, - removeDest: destExists - }); - onDone(); - } else { - throw new Error(`unsure how to copy this: ${src}`); - } - }); - - return function build(_x10) { - return _ref13.apply(this, arguments); - }; - })(); - - const artifactFiles = new Set(events.artifactFiles || []); - const files = new Set(); - - // initialise events - for (var _iterator7 = queue, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { - var _ref10; - - if (_isArray7) { - if (_i7 >= _iterator7.length) break; - _ref10 = _iterator7[_i7++]; - } else { - _i7 = _iterator7.next(); - if (_i7.done) break; - _ref10 = _i7.value; - } - - const item = _ref10; - - const onDone = item.onDone || noop; - item.onDone = function () { - events.onProgress(item.dest); - onDone(); - }; - } - events.onStart(queue.length); - - // start building actions - const actions = { - file: [], - symlink: [], - link: [] - }; - - // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items - // at a time due to the requirement to push items onto the queue - while (queue.length) { - const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); - yield Promise.all(items.map(build)); - } - - // simulate the existence of some files to prevent considering them extraneous - for (var _iterator8 = artifactFiles, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { - var _ref11; - - if (_isArray8) { - if (_i8 >= _iterator8.length) break; - _ref11 = _iterator8[_i8++]; - } else { - _i8 = _iterator8.next(); - if (_i8.done) break; - _ref11 = _i8.value; - } - - const file = _ref11; - - if (possibleExtraneous.has(file)) { - reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); - possibleExtraneous.delete(file); - } - } - - for (var _iterator9 = possibleExtraneous, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { - var _ref12; - - if (_isArray9) { - if (_i9 >= _iterator9.length) break; - _ref12 = _iterator9[_i9++]; - } else { - _i9 = _iterator9.next(); - if (_i9.done) break; - _ref12 = _i9.value; - } - - const loc = _ref12; - - if (files.has(loc.toLowerCase())) { - possibleExtraneous.delete(loc); - } - } - - return actions; - }); - - return function buildActionsForHardlink(_x6, _x7, _x8, _x9) { - return _ref9.apply(this, arguments); - }; -})(); - -let copyBulk = exports.copyBulk = (() => { - var _ref17 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { - const events = { - onStart: _events && _events.onStart || noop, - onProgress: _events && _events.onProgress || noop, - possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), - ignoreBasenames: _events && _events.ignoreBasenames || [], - artifactFiles: _events && _events.artifactFiles || [] - }; - - const actions = yield buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); - events.onStart(actions.file.length + actions.symlink.length + actions.link.length); - - const fileActions = actions.file; - - const currentlyWriting = new Map(); - - yield (_promise || _load_promise()).queue(fileActions, (() => { - var _ref18 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - let writePromise; - while (writePromise = currentlyWriting.get(data.dest)) { - yield writePromise; - } - - reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); - const copier = (0, (_fsNormalized || _load_fsNormalized()).copyFile)(data, function () { - return currentlyWriting.delete(data.dest); - }); - currentlyWriting.set(data.dest, copier); - events.onProgress(data.dest); - return copier; - }); - - return function (_x14) { - return _ref18.apply(this, arguments); - }; - })(), CONCURRENT_QUEUE_ITEMS); - - // we need to copy symlinks last as they could reference files we were copying - const symlinkActions = actions.symlink; - yield (_promise || _load_promise()).queue(symlinkActions, function (data) { - const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); - reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); - return symlink(linkname, data.dest); - }); - }); - - return function copyBulk(_x11, _x12, _x13) { - return _ref17.apply(this, arguments); - }; -})(); - -let hardlinkBulk = exports.hardlinkBulk = (() => { - var _ref19 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { - const events = { - onStart: _events && _events.onStart || noop, - onProgress: _events && _events.onProgress || noop, - possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), - artifactFiles: _events && _events.artifactFiles || [], - ignoreBasenames: [] - }; - - const actions = yield buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); - events.onStart(actions.file.length + actions.symlink.length + actions.link.length); - - const fileActions = actions.link; - - yield (_promise || _load_promise()).queue(fileActions, (() => { - var _ref20 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { - reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); - if (data.removeDest) { - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(data.dest); - } - yield link(data.src, data.dest); - }); - - return function (_x18) { - return _ref20.apply(this, arguments); - }; - })(), CONCURRENT_QUEUE_ITEMS); - - // we need to copy symlinks last as they could reference files we were copying - const symlinkActions = actions.symlink; - yield (_promise || _load_promise()).queue(symlinkActions, function (data) { - const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); - reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); - return symlink(linkname, data.dest); - }); - }); - - return function hardlinkBulk(_x15, _x16, _x17) { - return _ref19.apply(this, arguments); - }; -})(); - -let readFileAny = exports.readFileAny = (() => { - var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (files) { - for (var _iterator13 = files, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { - var _ref22; - - if (_isArray13) { - if (_i13 >= _iterator13.length) break; - _ref22 = _iterator13[_i13++]; - } else { - _i13 = _iterator13.next(); - if (_i13.done) break; - _ref22 = _i13.value; - } - - const file = _ref22; - - if (yield exists(file)) { - return readFile(file); - } - } - return null; - }); - - return function readFileAny(_x19) { - return _ref21.apply(this, arguments); - }; -})(); - -let readJson = exports.readJson = (() => { - var _ref23 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { - return (yield readJsonAndFile(loc)).object; - }); - - return function readJson(_x20) { - return _ref23.apply(this, arguments); - }; -})(); - -let readJsonAndFile = exports.readJsonAndFile = (() => { - var _ref24 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { - const file = yield readFile(loc); - try { - return { - object: (0, (_map || _load_map()).default)(JSON.parse(stripBOM(file))), - content: file - }; - } catch (err) { - err.message = `${loc}: ${err.message}`; - throw err; - } - }); - - return function readJsonAndFile(_x21) { - return _ref24.apply(this, arguments); - }; -})(); - -let find = exports.find = (() => { - var _ref25 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (filename, dir) { - const parts = dir.split((_path || _load_path()).default.sep); - - while (parts.length) { - const loc = parts.concat(filename).join((_path || _load_path()).default.sep); - - if (yield exists(loc)) { - return loc; - } else { - parts.pop(); - } - } - - return false; - }); - - return function find(_x22, _x23) { - return _ref25.apply(this, arguments); - }; -})(); - -let symlink = exports.symlink = (() => { - var _ref26 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (src, dest) { - if (process.platform !== 'win32') { - // use relative paths otherwise which will be retained if the directory is moved - src = (_path || _load_path()).default.relative((_path || _load_path()).default.dirname(dest), src); - // When path.relative returns an empty string for the current directory, we should instead use - // '.', which is a valid fs.symlink target. - src = src || '.'; - } - - try { - const stats = yield lstat(dest); - if (stats.isSymbolicLink()) { - const resolved = dest; - if (resolved === src) { - return; - } - } - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; - } - } - - // We use rimraf for unlink which never throws an ENOENT on missing target - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); - - if (process.platform === 'win32') { - // use directory junctions if possible on win32, this requires absolute paths - yield fsSymlink(src, dest, 'junction'); - } else { - yield fsSymlink(src, dest); - } - }); - - return function symlink(_x24, _x25) { - return _ref26.apply(this, arguments); - }; -})(); - -let walk = exports.walk = (() => { - var _ref27 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir, relativeDir, ignoreBasenames = new Set()) { - let files = []; - - let filenames = yield readdir(dir); - if (ignoreBasenames.size) { - filenames = filenames.filter(function (name) { - return !ignoreBasenames.has(name); - }); - } - - for (var _iterator14 = filenames, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { - var _ref28; - - if (_isArray14) { - if (_i14 >= _iterator14.length) break; - _ref28 = _iterator14[_i14++]; - } else { - _i14 = _iterator14.next(); - if (_i14.done) break; - _ref28 = _i14.value; - } - - const name = _ref28; - - const relative = relativeDir ? (_path || _load_path()).default.join(relativeDir, name) : name; - const loc = (_path || _load_path()).default.join(dir, name); - const stat = yield lstat(loc); - - files.push({ - relative, - basename: name, - absolute: loc, - mtime: +stat.mtime - }); - - if (stat.isDirectory()) { - files = files.concat((yield walk(loc, relative, ignoreBasenames))); - } - } - - return files; - }); - - return function walk(_x26, _x27) { - return _ref27.apply(this, arguments); - }; -})(); - -let getFileSizeOnDisk = exports.getFileSizeOnDisk = (() => { - var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { - const stat = yield lstat(loc); - const size = stat.size, - blockSize = stat.blksize; - - - return Math.ceil(size / blockSize) * blockSize; - }); - - return function getFileSizeOnDisk(_x28) { - return _ref29.apply(this, arguments); - }; -})(); - -let getEolFromFile = (() => { - var _ref30 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path) { - if (!(yield exists(path))) { - return undefined; - } - - const buffer = yield readFileBuffer(path); - - for (let i = 0; i < buffer.length; ++i) { - if (buffer[i] === cr) { - return '\r\n'; - } - if (buffer[i] === lf) { - return '\n'; - } - } - return undefined; - }); - - return function getEolFromFile(_x29) { - return _ref30.apply(this, arguments); - }; -})(); - -let writeFilePreservingEol = exports.writeFilePreservingEol = (() => { - var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path, data) { - const eol = (yield getEolFromFile(path)) || (_os || _load_os()).default.EOL; - if (eol !== '\n') { - data = data.replace(/\n/g, eol); - } - yield writeFile(path, data); - }); - - return function writeFilePreservingEol(_x30, _x31) { - return _ref31.apply(this, arguments); - }; -})(); - -let hardlinksWork = exports.hardlinksWork = (() => { - var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) { - const filename = 'test-file' + Math.random(); - const file = (_path || _load_path()).default.join(dir, filename); - const fileLink = (_path || _load_path()).default.join(dir, filename + '-link'); - try { - yield writeFile(file, 'test'); - yield link(file, fileLink); - } catch (err) { - return false; - } finally { - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(file); - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(fileLink); - } - return true; - }); - - return function hardlinksWork(_x32) { - return _ref32.apply(this, arguments); - }; -})(); - -// not a strict polyfill for Node's fs.mkdtemp - - -let makeTempDir = exports.makeTempDir = (() => { - var _ref33 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (prefix) { - const dir = (_path || _load_path()).default.join((_os || _load_os()).default.tmpdir(), `yarn-${prefix || ''}-${Date.now()}-${Math.random()}`); - yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dir); - yield mkdirp(dir); - return dir; - }); - - return function makeTempDir(_x33) { - return _ref33.apply(this, arguments); - }; -})(); - -let readFirstAvailableStream = exports.readFirstAvailableStream = (() => { - var _ref34 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths) { - for (var _iterator15 = paths, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { - var _ref35; - - if (_isArray15) { - if (_i15 >= _iterator15.length) break; - _ref35 = _iterator15[_i15++]; - } else { - _i15 = _iterator15.next(); - if (_i15.done) break; - _ref35 = _i15.value; - } - - const path = _ref35; - - try { - const fd = yield open(path, 'r'); - return (_fs || _load_fs()).default.createReadStream(path, { fd }); - } catch (err) { - // Try the next one - } - } - return null; - }); - - return function readFirstAvailableStream(_x34) { - return _ref34.apply(this, arguments); - }; -})(); - -let getFirstSuitableFolder = exports.getFirstSuitableFolder = (() => { - var _ref36 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths, mode = constants.W_OK | constants.X_OK) { - const result = { - skipped: [], - folder: null - }; - - for (var _iterator16 = paths, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { - var _ref37; - - if (_isArray16) { - if (_i16 >= _iterator16.length) break; - _ref37 = _iterator16[_i16++]; - } else { - _i16 = _iterator16.next(); - if (_i16.done) break; - _ref37 = _i16.value; - } - - const folder = _ref37; - - try { - yield mkdirp(folder); - yield access(folder, mode); - - result.folder = folder; - - return result; - } catch (error) { - result.skipped.push({ - error, - folder - }); - } - } - return result; - }); - - return function getFirstSuitableFolder(_x35) { - return _ref36.apply(this, arguments); - }; -})(); - -exports.copy = copy; -exports.readFile = readFile; -exports.readFileRaw = readFileRaw; -exports.normalizeOS = normalizeOS; - -var _fs; - -function _load_fs() { - return _fs = _interopRequireDefault(__webpack_require__(4)); -} - -var _glob; - -function _load_glob() { - return _glob = _interopRequireDefault(__webpack_require__(99)); -} - -var _os; - -function _load_os() { - return _os = _interopRequireDefault(__webpack_require__(46)); -} - -var _path; - -function _load_path() { - return _path = _interopRequireDefault(__webpack_require__(0)); -} - -var _blockingQueue; - -function _load_blockingQueue() { - return _blockingQueue = _interopRequireDefault(__webpack_require__(110)); -} - -var _promise; - -function _load_promise() { - return _promise = _interopRequireWildcard(__webpack_require__(51)); -} - -var _promise2; - -function _load_promise2() { - return _promise2 = __webpack_require__(51); -} - -var _map; - -function _load_map() { - return _map = _interopRequireDefault(__webpack_require__(29)); -} - -var _fsNormalized; - -function _load_fsNormalized() { - return _fsNormalized = __webpack_require__(216); -} - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const constants = exports.constants = typeof (_fs || _load_fs()).default.constants !== 'undefined' ? (_fs || _load_fs()).default.constants : { - R_OK: (_fs || _load_fs()).default.R_OK, - W_OK: (_fs || _load_fs()).default.W_OK, - X_OK: (_fs || _load_fs()).default.X_OK -}; - -const lockQueue = exports.lockQueue = new (_blockingQueue || _load_blockingQueue()).default('fs lock'); - -const readFileBuffer = exports.readFileBuffer = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readFile); -const open = exports.open = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.open); -const writeFile = exports.writeFile = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.writeFile); -const readlink = exports.readlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readlink); -const realpath = exports.realpath = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.realpath); -const readdir = exports.readdir = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readdir); -const rename = exports.rename = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.rename); -const access = exports.access = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.access); -const stat = exports.stat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.stat); -const mkdirp = exports.mkdirp = (0, (_promise2 || _load_promise2()).promisify)(__webpack_require__(145)); -const exists = exports.exists = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.exists, true); -const lstat = exports.lstat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.lstat); -const chmod = exports.chmod = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.chmod); -const link = exports.link = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.link); -const glob = exports.glob = (0, (_promise2 || _load_promise2()).promisify)((_glob || _load_glob()).default); -exports.unlink = (_fsNormalized || _load_fsNormalized()).unlink; - -// fs.copyFile uses the native file copying instructions on the system, performing much better -// than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the -// concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. - -const CONCURRENT_QUEUE_ITEMS = (_fs || _load_fs()).default.copyFile ? 128 : 4; - -const fsSymlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.symlink); -const invariant = __webpack_require__(9); -const stripBOM = __webpack_require__(160); - -const noop = () => {}; - -function copy(src, dest, reporter) { - return copyBulk([{ src, dest }], reporter); -} - -function _readFile(loc, encoding) { - return new Promise((resolve, reject) => { - (_fs || _load_fs()).default.readFile(loc, encoding, function (err, content) { - if (err) { - reject(err); - } else { - resolve(content); - } - }); - }); -} - -function readFile(loc) { - return _readFile(loc, 'utf8').then(normalizeOS); -} - -function readFileRaw(loc) { - return _readFile(loc, 'binary'); -} - -function normalizeOS(body) { - return body.replace(/\r\n/g, '\n'); -} - -const cr = '\r'.charCodeAt(0); -const lf = '\n'.charCodeAt(0); - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -class MessageError extends Error { - constructor(msg, code) { - super(msg); - this.code = code; - } - -} - -exports.MessageError = MessageError; -class ProcessSpawnError extends MessageError { - constructor(msg, code, process) { - super(msg, code); - this.process = process; - } - -} - -exports.ProcessSpawnError = ProcessSpawnError; -class SecurityError extends MessageError {} - -exports.SecurityError = SecurityError; -class ProcessTermError extends MessageError {} - -exports.ProcessTermError = ProcessTermError; -class ResponseError extends Error { - constructor(msg, responseCode) { - super(msg); - this.responseCode = responseCode; - } - -} - -exports.ResponseError = ResponseError; -class OneTimePasswordError extends Error { - constructor(notice) { - super(); - this.notice = notice; - } - -} -exports.OneTimePasswordError = OneTimePasswordError; - -/***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscriber; }); -/* unused harmony export SafeSubscriber */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isFunction__ = __webpack_require__(154); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Observer__ = __webpack_require__(420); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__ = __webpack_require__(321); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__config__ = __webpack_require__(186); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__ = __webpack_require__(323); -/** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ - - - - - - - -var Subscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subscriber, _super); - function Subscriber(destinationOrNext, error, complete) { - var _this = _super.call(this) || this; - _this.syncErrorValue = null; - _this.syncErrorThrown = false; - _this.syncErrorThrowable = false; - _this.isStopped = false; - _this._parentSubscription = null; - switch (arguments.length) { - case 0: - _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; - break; - case 1: - if (!destinationOrNext) { - _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; - break; - } - if (typeof destinationOrNext === 'object') { - if (destinationOrNext instanceof Subscriber) { - _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; - _this.destination = destinationOrNext; - destinationOrNext.add(_this); - } - else { - _this.syncErrorThrowable = true; - _this.destination = new SafeSubscriber(_this, destinationOrNext); - } - break; - } - default: - _this.syncErrorThrowable = true; - _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); - break; - } - return _this; - } - Subscriber.prototype[__WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { return this; }; - Subscriber.create = function (next, error, complete) { - var subscriber = new Subscriber(next, error, complete); - subscriber.syncErrorThrowable = false; - return subscriber; - }; - Subscriber.prototype.next = function (value) { - if (!this.isStopped) { - this._next(value); - } - }; - Subscriber.prototype.error = function (err) { - if (!this.isStopped) { - this.isStopped = true; - this._error(err); - } - }; - Subscriber.prototype.complete = function () { - if (!this.isStopped) { - this.isStopped = true; - this._complete(); - } - }; - Subscriber.prototype.unsubscribe = function () { - if (this.closed) { - return; - } - this.isStopped = true; - _super.prototype.unsubscribe.call(this); - }; - Subscriber.prototype._next = function (value) { - this.destination.next(value); - }; - Subscriber.prototype._error = function (err) { - this.destination.error(err); - this.unsubscribe(); - }; - Subscriber.prototype._complete = function () { - this.destination.complete(); - this.unsubscribe(); - }; - Subscriber.prototype._unsubscribeAndRecycle = function () { - var _a = this, _parent = _a._parent, _parents = _a._parents; - this._parent = null; - this._parents = null; - this.unsubscribe(); - this.closed = false; - this.isStopped = false; - this._parent = _parent; - this._parents = _parents; - this._parentSubscription = null; - return this; - }; - return Subscriber; -}(__WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */])); - -var SafeSubscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SafeSubscriber, _super); - function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { - var _this = _super.call(this) || this; - _this._parentSubscriber = _parentSubscriber; - var next; - var context = _this; - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(observerOrNext)) { - next = observerOrNext; - } - else if (observerOrNext) { - next = observerOrNext.next; - error = observerOrNext.error; - complete = observerOrNext.complete; - if (observerOrNext !== __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]) { - context = Object.create(observerOrNext); - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(context.unsubscribe)) { - _this.add(context.unsubscribe.bind(context)); - } - context.unsubscribe = _this.unsubscribe.bind(_this); - } - } - _this._context = context; - _this._next = next; - _this._error = error; - _this._complete = complete; - return _this; - } - SafeSubscriber.prototype.next = function (value) { - if (!this.isStopped && this._next) { - var _parentSubscriber = this._parentSubscriber; - if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { - this.__tryOrUnsub(this._next, value); - } - else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { - this.unsubscribe(); - } - } - }; - SafeSubscriber.prototype.error = function (err) { - if (!this.isStopped) { - var _parentSubscriber = this._parentSubscriber; - var useDeprecatedSynchronousErrorHandling = __WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling; - if (this._error) { - if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { - this.__tryOrUnsub(this._error, err); - this.unsubscribe(); - } - else { - this.__tryOrSetError(_parentSubscriber, this._error, err); - this.unsubscribe(); - } - } - else if (!_parentSubscriber.syncErrorThrowable) { - this.unsubscribe(); - if (useDeprecatedSynchronousErrorHandling) { - throw err; - } - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - } - else { - if (useDeprecatedSynchronousErrorHandling) { - _parentSubscriber.syncErrorValue = err; - _parentSubscriber.syncErrorThrown = true; - } - else { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - } - this.unsubscribe(); - } - } - }; - SafeSubscriber.prototype.complete = function () { - var _this = this; - if (!this.isStopped) { - var _parentSubscriber = this._parentSubscriber; - if (this._complete) { - var wrappedComplete = function () { return _this._complete.call(_this._context); }; - if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { - this.__tryOrUnsub(wrappedComplete); - this.unsubscribe(); - } - else { - this.__tryOrSetError(_parentSubscriber, wrappedComplete); - this.unsubscribe(); - } - } - else { - this.unsubscribe(); - } - } - }; - SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { - try { - fn.call(this._context, value); - } - catch (err) { - this.unsubscribe(); - if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - throw err; - } - else { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - } - } - }; - SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { - if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - throw new Error('bad call'); - } - try { - fn.call(this._context, value); - } - catch (err) { - if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - parent.syncErrorValue = err; - parent.syncErrorThrown = true; - return true; - } - else { - __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); - return true; - } - } - return false; - }; - SafeSubscriber.prototype._unsubscribe = function () { - var _parentSubscriber = this._parentSubscriber; - this._context = null; - this._parentSubscriber = null; - _parentSubscriber.unsubscribe(); - }; - return SafeSubscriber; -}(Subscriber)); - -//# sourceMappingURL=Subscriber.js.map - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getPathKey = getPathKey; -const os = __webpack_require__(46); -const path = __webpack_require__(0); -const userHome = __webpack_require__(67).default; - -var _require = __webpack_require__(222); - -const getCacheDir = _require.getCacheDir, - getConfigDir = _require.getConfigDir, - getDataDir = _require.getDataDir; - -const isWebpackBundle = __webpack_require__(278); - -const DEPENDENCY_TYPES = exports.DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies', 'peerDependencies']; -const OWNED_DEPENDENCY_TYPES = exports.OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies']; - -const RESOLUTIONS = exports.RESOLUTIONS = 'resolutions'; -const MANIFEST_FIELDS = exports.MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; - -const SUPPORTED_NODE_VERSIONS = exports.SUPPORTED_NODE_VERSIONS = '^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0'; - -const YARN_REGISTRY = exports.YARN_REGISTRY = 'https://registry.yarnpkg.com'; -const NPM_REGISTRY_RE = exports.NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; - -const YARN_DOCS = exports.YARN_DOCS = 'https://yarnpkg.com/en/docs/cli/'; -const YARN_INSTALLER_SH = exports.YARN_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; -const YARN_INSTALLER_MSI = exports.YARN_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; - -const SELF_UPDATE_VERSION_URL = exports.SELF_UPDATE_VERSION_URL = 'https://yarnpkg.com/latest-version'; - -// cache version, bump whenever we make backwards incompatible changes -const CACHE_VERSION = exports.CACHE_VERSION = 6; - -// lockfile version, bump whenever we make backwards incompatible changes -const LOCKFILE_VERSION = exports.LOCKFILE_VERSION = 1; - -// max amount of network requests to perform concurrently -const NETWORK_CONCURRENCY = exports.NETWORK_CONCURRENCY = 8; - -// HTTP timeout used when downloading packages -const NETWORK_TIMEOUT = exports.NETWORK_TIMEOUT = 30 * 1000; // in milliseconds - -// max amount of child processes to execute concurrently -const CHILD_CONCURRENCY = exports.CHILD_CONCURRENCY = 5; - -const REQUIRED_PACKAGE_KEYS = exports.REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; - -function getPreferredCacheDirectories() { - const preferredCacheDirectories = [getCacheDir()]; - - if (process.getuid) { - // $FlowFixMe: process.getuid exists, dammit - preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache-${process.getuid()}`)); - } - - preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache`)); - - return preferredCacheDirectories; -} - -const PREFERRED_MODULE_CACHE_DIRECTORIES = exports.PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); -const CONFIG_DIRECTORY = exports.CONFIG_DIRECTORY = getConfigDir(); -const DATA_DIRECTORY = exports.DATA_DIRECTORY = getDataDir(); -const LINK_REGISTRY_DIRECTORY = exports.LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); -const GLOBAL_MODULE_DIRECTORY = exports.GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); - -const NODE_BIN_PATH = exports.NODE_BIN_PATH = process.execPath; -const YARN_BIN_PATH = exports.YARN_BIN_PATH = getYarnBinPath(); - -// Webpack needs to be configured with node.__dirname/__filename = false -function getYarnBinPath() { - if (isWebpackBundle) { - return __filename; - } else { - return path.join(__dirname, '..', 'bin', 'yarn.js'); - } -} - -const NODE_MODULES_FOLDER = exports.NODE_MODULES_FOLDER = 'node_modules'; -const NODE_PACKAGE_JSON = exports.NODE_PACKAGE_JSON = 'package.json'; - -const PNP_FILENAME = exports.PNP_FILENAME = '.pnp.js'; - -const POSIX_GLOBAL_PREFIX = exports.POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; -const FALLBACK_GLOBAL_PREFIX = exports.FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'); - -const META_FOLDER = exports.META_FOLDER = '.yarn-meta'; -const INTEGRITY_FILENAME = exports.INTEGRITY_FILENAME = '.yarn-integrity'; -const LOCKFILE_FILENAME = exports.LOCKFILE_FILENAME = 'yarn.lock'; -const METADATA_FILENAME = exports.METADATA_FILENAME = '.yarn-metadata.json'; -const TARBALL_FILENAME = exports.TARBALL_FILENAME = '.yarn-tarball.tgz'; -const CLEAN_FILENAME = exports.CLEAN_FILENAME = '.yarnclean'; - -const NPM_LOCK_FILENAME = exports.NPM_LOCK_FILENAME = 'package-lock.json'; -const NPM_SHRINKWRAP_FILENAME = exports.NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; - -const DEFAULT_INDENT = exports.DEFAULT_INDENT = ' '; -const SINGLE_INSTANCE_PORT = exports.SINGLE_INSTANCE_PORT = 31997; -const SINGLE_INSTANCE_FILENAME = exports.SINGLE_INSTANCE_FILENAME = '.yarn-single-instance'; - -const ENV_PATH_KEY = exports.ENV_PATH_KEY = getPathKey(process.platform, process.env); - -function getPathKey(platform, env) { - let pathKey = 'PATH'; - - // windows calls its path "Path" usually, but this is not guaranteed. - if (platform === 'win32') { - pathKey = 'Path'; - - for (const key in env) { - if (key.toLowerCase() === 'path') { - pathKey = key; - } - } - } - - return pathKey; -} - -const VERSION_COLOR_SCHEME = exports.VERSION_COLOR_SCHEME = { - major: 'red', - premajor: 'red', - minor: 'yellow', - preminor: 'yellow', - patch: 'green', - prepatch: 'green', - prerelease: 'red', - unchanged: 'white', - unknown: 'red' -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - - - -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var NODE_ENV = process.env.NODE_ENV; - -var invariant = function(condition, format, a, b, c, d, e, f) { - if (NODE_ENV !== 'production') { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - } - - if (!condition) { - var error; - if (format === undefined) { - error = new Error( - 'Minified exception occurred; use the non-minified dev environment ' + - 'for the full error message and additional helpful warnings.' - ); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error( - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); - error.name = 'Invariant Violation'; - } - - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -}; - -module.exports = invariant; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var YAMLException = __webpack_require__(55); - -var TYPE_CONSTRUCTOR_OPTIONS = [ - 'kind', - 'resolve', - 'construct', - 'instanceOf', - 'predicate', - 'represent', - 'defaultStyle', - 'styleAliases' -]; - -var YAML_NODE_KINDS = [ - 'scalar', - 'sequence', - 'mapping' -]; - -function compileStyleAliases(map) { - var result = {}; - - if (map !== null) { - Object.keys(map).forEach(function (style) { - map[style].forEach(function (alias) { - result[String(alias)] = style; - }); - }); - } - - return result; -} - -function Type(tag, options) { - options = options || {}; - - Object.keys(options).forEach(function (name) { - if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { - throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); - } - }); - - // TODO: Add tag format check. - this.tag = tag; - this.kind = options['kind'] || null; - this.resolve = options['resolve'] || function () { return true; }; - this.construct = options['construct'] || function (data) { return data; }; - this.instanceOf = options['instanceOf'] || null; - this.predicate = options['predicate'] || null; - this.represent = options['represent'] || null; - this.defaultStyle = options['defaultStyle'] || null; - this.styleAliases = compileStyleAliases(options['styleAliases'] || null); - - if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { - throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); - } -} - -module.exports = Type; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - -module.exports = require("crypto"); - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Observable; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_canReportError__ = __webpack_require__(322); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__ = __webpack_require__(932); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__ = __webpack_require__(118); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(324); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(186); -/** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ - - - - - -var Observable = /*@__PURE__*/ (function () { - function Observable(subscribe) { - this._isScalar = false; - if (subscribe) { - this._subscribe = subscribe; - } - } - Observable.prototype.lift = function (operator) { - var observable = new Observable(); - observable.source = this; - observable.operator = operator; - return observable; - }; - Observable.prototype.subscribe = function (observerOrNext, error, complete) { - var operator = this.operator; - var sink = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__["a" /* toSubscriber */])(observerOrNext, error, complete); - if (operator) { - operator.call(sink, this.source); - } - else { - sink.add(this.source || (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? - this._subscribe(sink) : - this._trySubscribe(sink)); - } - if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - if (sink.syncErrorThrowable) { - sink.syncErrorThrowable = false; - if (sink.syncErrorThrown) { - throw sink.syncErrorValue; - } - } - } - return sink; - }; - Observable.prototype._trySubscribe = function (sink) { - try { - return this._subscribe(sink); - } - catch (err) { - if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { - sink.syncErrorThrown = true; - sink.syncErrorValue = err; - } - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_canReportError__["a" /* canReportError */])(sink)) { - sink.error(err); - } - else { - console.warn(err); - } - } - }; - Observable.prototype.forEach = function (next, promiseCtor) { - var _this = this; - promiseCtor = getPromiseCtor(promiseCtor); - return new promiseCtor(function (resolve, reject) { - var subscription; - subscription = _this.subscribe(function (value) { - try { - next(value); - } - catch (err) { - reject(err); - if (subscription) { - subscription.unsubscribe(); - } - } - }, reject, resolve); - }); - }; - Observable.prototype._subscribe = function (subscriber) { - var source = this.source; - return source && source.subscribe(subscriber); - }; - Observable.prototype[__WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__["a" /* observable */]] = function () { - return this; - }; - Observable.prototype.pipe = function () { - var operations = []; - for (var _i = 0; _i < arguments.length; _i++) { - operations[_i] = arguments[_i]; - } - if (operations.length === 0) { - return this; - } - return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_pipe__["b" /* pipeFromArray */])(operations)(this); - }; - Observable.prototype.toPromise = function (promiseCtor) { - var _this = this; - promiseCtor = getPromiseCtor(promiseCtor); - return new promiseCtor(function (resolve, reject) { - var value; - _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); - }); - }; - Observable.create = function (subscribe) { - return new Observable(subscribe); - }; - return Observable; -}()); - -function getPromiseCtor(promiseCtor) { - if (!promiseCtor) { - promiseCtor = __WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].Promise || Promise; - } - if (!promiseCtor) { - throw new Error('no Promise impl found'); - } - return promiseCtor; -} -//# sourceMappingURL=Observable.js.map - - -/***/ }), -/* 13 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return OuterSubscriber; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - - -var OuterSubscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](OuterSubscriber, _super); - function OuterSubscriber() { - return _super !== null && _super.apply(this, arguments) || this; - } - OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.destination.next(innerValue); - }; - OuterSubscriber.prototype.notifyError = function (error, innerSub) { - this.destination.error(error); - }; - OuterSubscriber.prototype.notifyComplete = function (innerSub) { - this.destination.complete(); - }; - return OuterSubscriber; -}(__WEBPACK_IMPORTED_MODULE_1__Subscriber__["a" /* Subscriber */])); - -//# sourceMappingURL=OuterSubscriber.js.map - - -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = subscribeToResult; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__ = __webpack_require__(84); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__subscribeTo__ = __webpack_require__(446); -/** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */ - - -function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, destination) { - if (destination === void 0) { - destination = new __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__["a" /* InnerSubscriber */](outerSubscriber, outerValue, outerIndex); - } - if (destination.closed) { - return; - } - return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__subscribeTo__["a" /* subscribeTo */])(result)(destination); -} -//# sourceMappingURL=subscribeToResult.js.map - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* eslint-disable node/no-deprecated-api */ - - - -var buffer = __webpack_require__(64) -var Buffer = buffer.Buffer - -var safer = {} - -var key - -for (key in buffer) { - if (!buffer.hasOwnProperty(key)) continue - if (key === 'SlowBuffer' || key === 'Buffer') continue - safer[key] = buffer[key] -} - -var Safer = safer.Buffer = {} -for (key in Buffer) { - if (!Buffer.hasOwnProperty(key)) continue - if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue - Safer[key] = Buffer[key] -} - -safer.Buffer.prototype = Buffer.prototype - -if (!Safer.from || Safer.from === Uint8Array.from) { - Safer.from = function (value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) - } - if (value && typeof value.length === 'undefined') { - throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) - } - return Buffer(value, encodingOrOffset, length) - } -} - -if (!Safer.alloc) { - Safer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) - } - if (size < 0 || size >= 2 * (1 << 30)) { - throw new RangeError('The value "' + size + '" is invalid for option "size"') - } - var buf = Buffer(size) - if (!fill || fill.length === 0) { - buf.fill(0) - } else if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - return buf - } -} - -if (!safer.kStringMaxLength) { - try { - safer.kStringMaxLength = process.binding('buffer').kStringMaxLength - } catch (e) { - // we can't determine kStringMaxLength in environments where process.binding - // is unsupported, so let's not set it - } -} - -if (!safer.constants) { - safer.constants = { - MAX_LENGTH: safer.kMaxLength - } - if (safer.kStringMaxLength) { - safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength - } -} - -module.exports = safer - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright (c) 2012, Mark Cavage. All rights reserved. -// Copyright 2015 Joyent, Inc. - -var assert = __webpack_require__(28); -var Stream = __webpack_require__(23).Stream; -var util = __webpack_require__(3); - - -///--- Globals - -/* JSSTYLED */ -var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; - - -///--- Internal - -function _capitalize(str) { - return (str.charAt(0).toUpperCase() + str.slice(1)); -} - -function _toss(name, expected, oper, arg, actual) { - throw new assert.AssertionError({ - message: util.format('%s (%s) is required', name, expected), - actual: (actual === undefined) ? typeof (arg) : actual(arg), - expected: expected, - operator: oper || '===', - stackStartFunction: _toss.caller - }); -} - -function _getClass(arg) { - return (Object.prototype.toString.call(arg).slice(8, -1)); -} - -function noop() { - // Why even bother with asserts? -} - - -///--- Exports - -var types = { - bool: { - check: function (arg) { return typeof (arg) === 'boolean'; } - }, - func: { - check: function (arg) { return typeof (arg) === 'function'; } - }, - string: { - check: function (arg) { return typeof (arg) === 'string'; } - }, - object: { - check: function (arg) { - return typeof (arg) === 'object' && arg !== null; - } - }, - number: { - check: function (arg) { - return typeof (arg) === 'number' && !isNaN(arg); - } - }, - finite: { - check: function (arg) { - return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); - } - }, - buffer: { - check: function (arg) { return Buffer.isBuffer(arg); }, - operator: 'Buffer.isBuffer' - }, - array: { - check: function (arg) { return Array.isArray(arg); }, - operator: 'Array.isArray' - }, - stream: { - check: function (arg) { return arg instanceof Stream; }, - operator: 'instanceof', - actual: _getClass - }, - date: { - check: function (arg) { return arg instanceof Date; }, - operator: 'instanceof', - actual: _getClass - }, - regexp: { - check: function (arg) { return arg instanceof RegExp; }, - operator: 'instanceof', - actual: _getClass - }, - uuid: { - check: function (arg) { - return typeof (arg) === 'string' && UUID_REGEXP.test(arg); - }, - operator: 'isUUID' - } -}; - -function _setExports(ndebug) { - var keys = Object.keys(types); - var out; - - /* re-export standard assert */ - if (process.env.NODE_NDEBUG) { - out = noop; - } else { - out = function (arg, msg) { - if (!arg) { - _toss(msg, 'true', arg); - } - }; - } - - /* standard checks */ - keys.forEach(function (k) { - if (ndebug) { - out[k] = noop; - return; - } - var type = types[k]; - out[k] = function (arg, msg) { - if (!type.check(arg)) { - _toss(msg, k, type.operator, arg, type.actual); - } - }; - }); - - /* optional checks */ - keys.forEach(function (k) { - var name = 'optional' + _capitalize(k); - if (ndebug) { - out[name] = noop; - return; - } - var type = types[k]; - out[name] = function (arg, msg) { - if (arg === undefined || arg === null) { - return; - } - if (!type.check(arg)) { - _toss(msg, k, type.operator, arg, type.actual); - } - }; - }); - - /* arrayOf checks */ - keys.forEach(function (k) { - var name = 'arrayOf' + _capitalize(k); - if (ndebug) { - out[name] = noop; - return; - } - var type = types[k]; - var expected = '[' + k + ']'; - out[name] = function (arg, msg) { - if (!Array.isArray(arg)) { - _toss(msg, expected, type.operator, arg, type.actual); - } - var i; - for (i = 0; i < arg.length; i++) { - if (!type.check(arg[i])) { - _toss(msg, expected, type.operator, arg, type.actual); - } - } - }; - }); - - /* optionalArrayOf checks */ - keys.forEach(function (k) { - var name = 'optionalArrayOf' + _capitalize(k); - if (ndebug) { - out[name] = noop; - return; - } - var type = types[k]; - var expected = '[' + k + ']'; - out[name] = function (arg, msg) { - if (arg === undefined || arg === null) { - return; - } - if (!Array.isArray(arg)) { - _toss(msg, expected, type.operator, arg, type.actual); - } - var i; - for (i = 0; i < arg.length; i++) { - if (!type.check(arg[i])) { - _toss(msg, expected, type.operator, arg, type.actual); - } - } - }; - }); - - /* re-export built-in assertions */ - Object.keys(assert).forEach(function (k) { - if (k === 'AssertionError') { - out[k] = assert[k]; - return; - } - if (ndebug) { - out[k] = noop; - return; - } - out[k] = assert[k]; - }); - - /* export ourselves (for unit tests _only_) */ - out._setExports = _setExports; - - return out; -} - -module.exports = _setExports(process.env.NODE_NDEBUG); - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 -var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self - // eslint-disable-next-line no-new-func - : Function('return this')(); -if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.sortAlpha = sortAlpha; -exports.sortOptionsByFlags = sortOptionsByFlags; -exports.entries = entries; -exports.removePrefix = removePrefix; -exports.removeSuffix = removeSuffix; -exports.addSuffix = addSuffix; -exports.hyphenate = hyphenate; -exports.camelCase = camelCase; -exports.compareSortedArrays = compareSortedArrays; -exports.sleep = sleep; -const _camelCase = __webpack_require__(227); - -function sortAlpha(a, b) { - // sort alphabetically in a deterministic way - const shortLen = Math.min(a.length, b.length); - for (let i = 0; i < shortLen; i++) { - const aChar = a.charCodeAt(i); - const bChar = b.charCodeAt(i); - if (aChar !== bChar) { - return aChar - bChar; - } - } - return a.length - b.length; -} - -function sortOptionsByFlags(a, b) { - const aOpt = a.flags.replace(/-/g, ''); - const bOpt = b.flags.replace(/-/g, ''); - return sortAlpha(aOpt, bOpt); -} - -function entries(obj) { - const entries = []; - if (obj) { - for (const key in obj) { - entries.push([key, obj[key]]); - } - } - return entries; -} - -function removePrefix(pattern, prefix) { - if (pattern.startsWith(prefix)) { - pattern = pattern.slice(prefix.length); - } - - return pattern; -} - -function removeSuffix(pattern, suffix) { - if (pattern.endsWith(suffix)) { - return pattern.slice(0, -suffix.length); - } - - return pattern; -} - -function addSuffix(pattern, suffix) { - if (!pattern.endsWith(suffix)) { - return pattern + suffix; - } - - return pattern; -} - -function hyphenate(str) { - return str.replace(/[A-Z]/g, match => { - return '-' + match.charAt(0).toLowerCase(); - }); -} - -function camelCase(str) { - if (/[A-Z]/.test(str)) { - return null; - } else { - return _camelCase(str); - } -} - -function compareSortedArrays(array1, array2) { - if (array1.length !== array2.length) { - return false; - } - for (let i = 0, len = array1.length; i < len; i++) { - if (array1[i] !== array2[i]) { - return false; - } - } - return true; -} - -function sleep(ms) { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.stringify = exports.parse = undefined; - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -var _parse; - -function _load_parse() { - return _parse = __webpack_require__(106); -} - -Object.defineProperty(exports, 'parse', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_parse || _load_parse()).default; - } -}); - -var _stringify; - -function _load_stringify() { - return _stringify = __webpack_require__(200); -} - -Object.defineProperty(exports, 'stringify', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_stringify || _load_stringify()).default; - } -}); -exports.implodeEntry = implodeEntry; -exports.explodeEntry = explodeEntry; - -var _misc; - -function _load_misc() { - return _misc = __webpack_require__(18); -} - -var _normalizePattern; - -function _load_normalizePattern() { - return _normalizePattern = __webpack_require__(37); -} - -var _parse2; - -function _load_parse2() { - return _parse2 = _interopRequireDefault(__webpack_require__(106)); -} - -var _constants; - -function _load_constants() { - return _constants = __webpack_require__(8); -} - -var _fs; - -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(5)); -} - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const invariant = __webpack_require__(9); - -const path = __webpack_require__(0); -const ssri = __webpack_require__(65); - -function getName(pattern) { - return (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern).name; -} - -function blankObjectUndefined(obj) { - return obj && Object.keys(obj).length ? obj : undefined; -} - -function keyForRemote(remote) { - return remote.resolved || (remote.reference && remote.hash ? `${remote.reference}#${remote.hash}` : null); -} - -function serializeIntegrity(integrity) { - // We need this because `Integrity.toString()` does not use sorting to ensure a stable string output - // See https://git.io/vx2Hy - return integrity.toString().split(' ').sort().join(' '); -} - -function implodeEntry(pattern, obj) { - const inferredName = getName(pattern); - const integrity = obj.integrity ? serializeIntegrity(obj.integrity) : ''; - const imploded = { - name: inferredName === obj.name ? undefined : obj.name, - version: obj.version, - uid: obj.uid === obj.version ? undefined : obj.uid, - resolved: obj.resolved, - registry: obj.registry === 'npm' ? undefined : obj.registry, - dependencies: blankObjectUndefined(obj.dependencies), - optionalDependencies: blankObjectUndefined(obj.optionalDependencies), - permissions: blankObjectUndefined(obj.permissions), - prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants) - }; - if (integrity) { - imploded.integrity = integrity; - } - return imploded; -} - -function explodeEntry(pattern, obj) { - obj.optionalDependencies = obj.optionalDependencies || {}; - obj.dependencies = obj.dependencies || {}; - obj.uid = obj.uid || obj.version; - obj.permissions = obj.permissions || {}; - obj.registry = obj.registry || 'npm'; - obj.name = obj.name || getName(pattern); - const integrity = obj.integrity; - if (integrity && integrity.isIntegrity) { - obj.integrity = ssri.parse(integrity); - } - return obj; -} - -class Lockfile { - constructor({ cache, source, parseResultType } = {}) { - this.source = source || ''; - this.cache = cache; - this.parseResultType = parseResultType; - } - - // source string if the `cache` was parsed - - - // if true, we're parsing an old yarn file and need to update integrity fields - hasEntriesExistWithoutIntegrity() { - if (!this.cache) { - return false; - } - - for (const key in this.cache) { - // $FlowFixMe - `this.cache` is clearly defined at this point - if (!/^.*@(file:|http)/.test(key) && this.cache[key] && !this.cache[key].integrity) { - return true; - } - } - - return false; - } - - static fromDirectory(dir, reporter) { - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // read the manifest in this directory - const lockfileLoc = path.join(dir, (_constants || _load_constants()).LOCKFILE_FILENAME); - - let lockfile; - let rawLockfile = ''; - let parseResult; - - if (yield (_fs || _load_fs()).exists(lockfileLoc)) { - rawLockfile = yield (_fs || _load_fs()).readFile(lockfileLoc); - parseResult = (0, (_parse2 || _load_parse2()).default)(rawLockfile, lockfileLoc); - - if (reporter) { - if (parseResult.type === 'merge') { - reporter.info(reporter.lang('lockfileMerged')); - } else if (parseResult.type === 'conflict') { - reporter.warn(reporter.lang('lockfileConflict')); - } - } - - lockfile = parseResult.object; - } else if (reporter) { - reporter.info(reporter.lang('noLockfileFound')); - } - - if (lockfile && lockfile.__metadata) { - const lockfilev2 = lockfile; - lockfile = {}; - } - - return new Lockfile({ cache: lockfile, source: rawLockfile, parseResultType: parseResult && parseResult.type }); - })(); - } - - getLocked(pattern) { - const cache = this.cache; - if (!cache) { - return undefined; - } - - const shrunk = pattern in cache && cache[pattern]; - - if (typeof shrunk === 'string') { - return this.getLocked(shrunk); - } else if (shrunk) { - explodeEntry(pattern, shrunk); - return shrunk; - } - - return undefined; - } - - removePattern(pattern) { - const cache = this.cache; - if (!cache) { - return; - } - delete cache[pattern]; - } - - getLockfile(patterns) { - const lockfile = {}; - const seen = new Map(); - - // order by name so that lockfile manifest is assigned to the first dependency with this manifest - // the others that have the same remoteKey will just refer to the first - // ordering allows for consistency in lockfile when it is serialized - const sortedPatternsKeys = Object.keys(patterns).sort((_misc || _load_misc()).sortAlpha); - - for (var _iterator = sortedPatternsKeys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; - } - - const pattern = _ref; - - const pkg = patterns[pattern]; - const remote = pkg._remote, - ref = pkg._reference; - - invariant(ref, 'Package is missing a reference'); - invariant(remote, 'Package is missing a remote'); - - const remoteKey = keyForRemote(remote); - const seenPattern = remoteKey && seen.get(remoteKey); - if (seenPattern) { - // no point in duplicating it - lockfile[pattern] = seenPattern; - - // if we're relying on our name being inferred and two of the patterns have - // different inferred names then we need to set it - if (!seenPattern.name && getName(pattern) !== pkg.name) { - seenPattern.name = pkg.name; - } - continue; - } - const obj = implodeEntry(pattern, { - name: pkg.name, - version: pkg.version, - uid: pkg._uid, - resolved: remote.resolved, - integrity: remote.integrity, - registry: remote.registry, - dependencies: pkg.dependencies, - peerDependencies: pkg.peerDependencies, - optionalDependencies: pkg.optionalDependencies, - permissions: ref.permissions, - prebuiltVariants: pkg.prebuiltVariants - }); - - lockfile[pattern] = obj; - - if (remoteKey) { - seen.set(remoteKey, obj); - } - } - - return lockfile; - } -} -exports.default = Lockfile; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -var _assign = __webpack_require__(559); - -var _assign2 = _interopRequireDefault(_assign); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = _assign2.default || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; -}; - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var store = __webpack_require__(133)('wks'); -var uid = __webpack_require__(137); -var Symbol = __webpack_require__(17).Symbol; -var USE_SYMBOL = typeof Symbol == 'function'; - -var $exports = module.exports = function (name) { - return store[name] || (store[name] = - USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); -}; - -$exports.store = store; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports) { - -exports = module.exports = SemVer; - -// The debug function is excluded entirely from the minified version. -/* nomin */ var debug; -/* nomin */ if (typeof process === 'object' && - /* nomin */ process.env && - /* nomin */ process.env.NODE_DEBUG && - /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) - /* nomin */ debug = function() { - /* nomin */ var args = Array.prototype.slice.call(arguments, 0); - /* nomin */ args.unshift('SEMVER'); - /* nomin */ console.log.apply(console, args); - /* nomin */ }; -/* nomin */ else - /* nomin */ debug = function() {}; - -// Note: this is the semver.org version of the spec that it implements -// Not necessarily the package version of this code. -exports.SEMVER_SPEC_VERSION = '2.0.0'; - -var MAX_LENGTH = 256; -var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; - -// Max safe segment length for coercion. -var MAX_SAFE_COMPONENT_LENGTH = 16; - -// The actual regexps go on exports.re -var re = exports.re = []; -var src = exports.src = []; -var R = 0; - -// The following Regular Expressions can be used for tokenizing, -// validating, and parsing SemVer version strings. - -// ## Numeric Identifier -// A single `0`, or a non-zero digit followed by zero or more digits. - -var NUMERICIDENTIFIER = R++; -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; -var NUMERICIDENTIFIERLOOSE = R++; -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; - - -// ## Non-numeric Identifier -// Zero or more digits, followed by a letter or hyphen, and then zero or -// more letters, digits, or hyphens. - -var NONNUMERICIDENTIFIER = R++; -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; - - -// ## Main Version -// Three dot-separated numeric identifiers. - -var MAINVERSION = R++; -src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')'; - -var MAINVERSIONLOOSE = R++; -src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; - -// ## Pre-release Version Identifier -// A numeric identifier, or a non-numeric identifier. - -var PRERELEASEIDENTIFIER = R++; -src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - -var PRERELEASEIDENTIFIERLOOSE = R++; -src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - - -// ## Pre-release Version -// Hyphen, followed by one or more dot-separated pre-release version -// identifiers. - -var PRERELEASE = R++; -src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; - -var PRERELEASELOOSE = R++; -src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; - -// ## Build Metadata Identifier -// Any combination of digits, letters, or hyphens. - -var BUILDIDENTIFIER = R++; -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; - -// ## Build Metadata -// Plus sign, followed by one or more period-separated build metadata -// identifiers. - -var BUILD = R++; -src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; - - -// ## Full Version String -// A main version, followed optionally by a pre-release version and -// build metadata. - -// Note that the only major, minor, patch, and pre-release sections of -// the version string are capturing groups. The build metadata is not a -// capturing group, because it should not ever be used in version -// comparison. - -var FULL = R++; -var FULLPLAIN = 'v?' + src[MAINVERSION] + - src[PRERELEASE] + '?' + - src[BUILD] + '?'; - -src[FULL] = '^' + FULLPLAIN + '$'; - -// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. -// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty -// common in the npm registry. -var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + - src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?'; - -var LOOSE = R++; -src[LOOSE] = '^' + LOOSEPLAIN + '$'; - -var GTLT = R++; -src[GTLT] = '((?:<|>)?=?)'; - -// Something like "2.*" or "1.2.x". -// Note that "x.x" is a valid xRange identifer, meaning "any version" -// Only the first item is strictly required. -var XRANGEIDENTIFIERLOOSE = R++; -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; -var XRANGEIDENTIFIER = R++; -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; - -var XRANGEPLAIN = R++; -src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:' + src[PRERELEASE] + ')?' + - src[BUILD] + '?' + - ')?)?'; - -var XRANGEPLAINLOOSE = R++; -src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:' + src[PRERELEASELOOSE] + ')?' + - src[BUILD] + '?' + - ')?)?'; - -var XRANGE = R++; -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; -var XRANGELOOSE = R++; -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; - -// Coercion. -// Extract anything that could conceivably be a part of a valid semver -var COERCE = R++; -src[COERCE] = '(?:^|[^\\d])' + - '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + - '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + - '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + - '(?:$|[^\\d])'; - -// Tilde ranges. -// Meaning is "reasonably at or greater than" -var LONETILDE = R++; -src[LONETILDE] = '(?:~>?)'; - -var TILDETRIM = R++; -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; -re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); -var tildeTrimReplace = '$1~'; - -var TILDE = R++; -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; -var TILDELOOSE = R++; -src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; - -// Caret ranges. -// Meaning is "at least and backwards compatible with" -var LONECARET = R++; -src[LONECARET] = '(?:\\^)'; - -var CARETTRIM = R++; -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; -re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); -var caretTrimReplace = '$1^'; - -var CARET = R++; -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; -var CARETLOOSE = R++; -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; - -// A simple gt/lt/eq thing, or just "" to indicate "any version" -var COMPARATORLOOSE = R++; -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; -var COMPARATOR = R++; -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; - - -// An expression to strip any whitespace between the gtlt and the thing -// it modifies, so that `> 1.2.3` ==> `>1.2.3` -var COMPARATORTRIM = R++; -src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; - -// this one has to use the /g flag -re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); -var comparatorTrimReplace = '$1$2$3'; - - -// Something like `1.2.3 - 1.2.4` -// Note that these all use the loose form, because they'll be -// checked against either the strict or loose comparator form -// later. -var HYPHENRANGE = R++; -src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAIN] + ')' + - '\\s*$'; - -var HYPHENRANGELOOSE = R++; -src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s*$'; - -// Star ranges basically just allow anything at all. -var STAR = R++; -src[STAR] = '(<|>)?=?\\s*\\*'; - -// Compile to actual regexp objects. -// All are flag-free, unless they were created above with a flag. -for (var i = 0; i < R; i++) { - debug(i, src[i]); - if (!re[i]) - re[i] = new RegExp(src[i]); -} - -exports.parse = parse; -function parse(version, loose) { - if (version instanceof SemVer) - return version; - - if (typeof version !== 'string') - return null; - - if (version.length > MAX_LENGTH) - return null; - - var r = loose ? re[LOOSE] : re[FULL]; - if (!r.test(version)) - return null; - - try { - return new SemVer(version, loose); - } catch (er) { - return null; - } -} - -exports.valid = valid; -function valid(version, loose) { - var v = parse(version, loose); - return v ? v.version : null; -} - - -exports.clean = clean; -function clean(version, loose) { - var s = parse(version.trim().replace(/^[=v]+/, ''), loose); - return s ? s.version : null; -} - -exports.SemVer = SemVer; - -function SemVer(version, loose) { - if (version instanceof SemVer) { - if (version.loose === loose) - return version; - else - version = version.version; - } else if (typeof version !== 'string') { - throw new TypeError('Invalid Version: ' + version); - } - - if (version.length > MAX_LENGTH) - throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') - - if (!(this instanceof SemVer)) - return new SemVer(version, loose); - - debug('SemVer', version, loose); - this.loose = loose; - var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); - - if (!m) - throw new TypeError('Invalid Version: ' + version); - - this.raw = version; - - // these are actually numbers - this.major = +m[1]; - this.minor = +m[2]; - this.patch = +m[3]; - - if (this.major > MAX_SAFE_INTEGER || this.major < 0) - throw new TypeError('Invalid major version') - - if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) - throw new TypeError('Invalid minor version') - - if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) - throw new TypeError('Invalid patch version') - - // numberify any prerelease numeric ids - if (!m[4]) - this.prerelease = []; - else - this.prerelease = m[4].split('.').map(function(id) { - if (/^[0-9]+$/.test(id)) { - var num = +id; - if (num >= 0 && num < MAX_SAFE_INTEGER) - return num; - } - return id; - }); - - this.build = m[5] ? m[5].split('.') : []; - this.format(); -} - -SemVer.prototype.format = function() { - this.version = this.major + '.' + this.minor + '.' + this.patch; - if (this.prerelease.length) - this.version += '-' + this.prerelease.join('.'); - return this.version; -}; - -SemVer.prototype.toString = function() { - return this.version; -}; - -SemVer.prototype.compare = function(other) { - debug('SemVer.compare', this.version, this.loose, other); - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - return this.compareMain(other) || this.comparePre(other); -}; - -SemVer.prototype.compareMain = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - return compareIdentifiers(this.major, other.major) || - compareIdentifiers(this.minor, other.minor) || - compareIdentifiers(this.patch, other.patch); -}; - -SemVer.prototype.comparePre = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - // NOT having a prerelease is > having one - if (this.prerelease.length && !other.prerelease.length) - return -1; - else if (!this.prerelease.length && other.prerelease.length) - return 1; - else if (!this.prerelease.length && !other.prerelease.length) - return 0; - - var i = 0; - do { - var a = this.prerelease[i]; - var b = other.prerelease[i]; - debug('prerelease compare', i, a, b); - if (a === undefined && b === undefined) - return 0; - else if (b === undefined) - return 1; - else if (a === undefined) - return -1; - else if (a === b) - continue; - else - return compareIdentifiers(a, b); - } while (++i); -}; - -// preminor will bump the version up to the next minor release, and immediately -// down to pre-release. premajor and prepatch work the same way. -SemVer.prototype.inc = function(release, identifier) { - switch (release) { - case 'premajor': - this.prerelease.length = 0; - this.patch = 0; - this.minor = 0; - this.major++; - this.inc('pre', identifier); - break; - case 'preminor': - this.prerelease.length = 0; - this.patch = 0; - this.minor++; - this.inc('pre', identifier); - break; - case 'prepatch': - // If this is already a prerelease, it will bump to the next version - // drop any prereleases that might already exist, since they are not - // relevant at this point. - this.prerelease.length = 0; - this.inc('patch', identifier); - this.inc('pre', identifier); - break; - // If the input is a non-prerelease version, this acts the same as - // prepatch. - case 'prerelease': - if (this.prerelease.length === 0) - this.inc('patch', identifier); - this.inc('pre', identifier); - break; - - case 'major': - // If this is a pre-major version, bump up to the same major version. - // Otherwise increment major. - // 1.0.0-5 bumps to 1.0.0 - // 1.1.0 bumps to 2.0.0 - if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) - this.major++; - this.minor = 0; - this.patch = 0; - this.prerelease = []; - break; - case 'minor': - // If this is a pre-minor version, bump up to the same minor version. - // Otherwise increment minor. - // 1.2.0-5 bumps to 1.2.0 - // 1.2.1 bumps to 1.3.0 - if (this.patch !== 0 || this.prerelease.length === 0) - this.minor++; - this.patch = 0; - this.prerelease = []; - break; - case 'patch': - // If this is not a pre-release version, it will increment the patch. - // If it is a pre-release it will bump up to the same patch version. - // 1.2.0-5 patches to 1.2.0 - // 1.2.0 patches to 1.2.1 - if (this.prerelease.length === 0) - this.patch++; - this.prerelease = []; - break; - // This probably shouldn't be used publicly. - // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. - case 'pre': - if (this.prerelease.length === 0) - this.prerelease = [0]; - else { - var i = this.prerelease.length; - while (--i >= 0) { - if (typeof this.prerelease[i] === 'number') { - this.prerelease[i]++; - i = -2; - } - } - if (i === -1) // didn't increment anything - this.prerelease.push(0); - } - if (identifier) { - // 1.2.0-beta.1 bumps to 1.2.0-beta.2, - // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 - if (this.prerelease[0] === identifier) { - if (isNaN(this.prerelease[1])) - this.prerelease = [identifier, 0]; - } else - this.prerelease = [identifier, 0]; - } - break; - - default: - throw new Error('invalid increment argument: ' + release); - } - this.format(); - this.raw = this.version; - return this; -}; - -exports.inc = inc; -function inc(version, release, loose, identifier) { - if (typeof(loose) === 'string') { - identifier = loose; - loose = undefined; - } - - try { - return new SemVer(version, loose).inc(release, identifier).version; - } catch (er) { - return null; - } -} - -exports.diff = diff; -function diff(version1, version2) { - if (eq(version1, version2)) { - return null; - } else { - var v1 = parse(version1); - var v2 = parse(version2); - if (v1.prerelease.length || v2.prerelease.length) { - for (var key in v1) { - if (key === 'major' || key === 'minor' || key === 'patch') { - if (v1[key] !== v2[key]) { - return 'pre'+key; - } - } - } - return 'prerelease'; - } - for (var key in v1) { - if (key === 'major' || key === 'minor' || key === 'patch') { - if (v1[key] !== v2[key]) { - return key; - } - } - } - } -} - -exports.compareIdentifiers = compareIdentifiers; - -var numeric = /^[0-9]+$/; -function compareIdentifiers(a, b) { - var anum = numeric.test(a); - var bnum = numeric.test(b); - - if (anum && bnum) { - a = +a; - b = +b; - } - - return (anum && !bnum) ? -1 : - (bnum && !anum) ? 1 : - a < b ? -1 : - a > b ? 1 : - 0; -} - -exports.rcompareIdentifiers = rcompareIdentifiers; -function rcompareIdentifiers(a, b) { - return compareIdentifiers(b, a); -} - -exports.major = major; -function major(a, loose) { - return new SemVer(a, loose).major; -} - -exports.minor = minor; -function minor(a, loose) { - return new SemVer(a, loose).minor; -} - -exports.patch = patch; -function patch(a, loose) { - return new SemVer(a, loose).patch; -} - -exports.compare = compare; -function compare(a, b, loose) { - return new SemVer(a, loose).compare(new SemVer(b, loose)); -} - -exports.compareLoose = compareLoose; -function compareLoose(a, b) { - return compare(a, b, true); -} - -exports.rcompare = rcompare; -function rcompare(a, b, loose) { - return compare(b, a, loose); -} - -exports.sort = sort; -function sort(list, loose) { - return list.sort(function(a, b) { - return exports.compare(a, b, loose); - }); -} - -exports.rsort = rsort; -function rsort(list, loose) { - return list.sort(function(a, b) { - return exports.rcompare(a, b, loose); - }); -} - -exports.gt = gt; -function gt(a, b, loose) { - return compare(a, b, loose) > 0; -} - -exports.lt = lt; -function lt(a, b, loose) { - return compare(a, b, loose) < 0; -} - -exports.eq = eq; -function eq(a, b, loose) { - return compare(a, b, loose) === 0; -} - -exports.neq = neq; -function neq(a, b, loose) { - return compare(a, b, loose) !== 0; -} - -exports.gte = gte; -function gte(a, b, loose) { - return compare(a, b, loose) >= 0; -} - -exports.lte = lte; -function lte(a, b, loose) { - return compare(a, b, loose) <= 0; -} - -exports.cmp = cmp; -function cmp(a, op, b, loose) { - var ret; - switch (op) { - case '===': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a === b; - break; - case '!==': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a !== b; - break; - case '': case '=': case '==': ret = eq(a, b, loose); break; - case '!=': ret = neq(a, b, loose); break; - case '>': ret = gt(a, b, loose); break; - case '>=': ret = gte(a, b, loose); break; - case '<': ret = lt(a, b, loose); break; - case '<=': ret = lte(a, b, loose); break; - default: throw new TypeError('Invalid operator: ' + op); - } - return ret; -} - -exports.Comparator = Comparator; -function Comparator(comp, loose) { - if (comp instanceof Comparator) { - if (comp.loose === loose) - return comp; - else - comp = comp.value; - } - - if (!(this instanceof Comparator)) - return new Comparator(comp, loose); - - debug('comparator', comp, loose); - this.loose = loose; - this.parse(comp); - - if (this.semver === ANY) - this.value = ''; - else - this.value = this.operator + this.semver.version; - - debug('comp', this); -} - -var ANY = {}; -Comparator.prototype.parse = function(comp) { - var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var m = comp.match(r); - - if (!m) - throw new TypeError('Invalid comparator: ' + comp); - - this.operator = m[1]; - if (this.operator === '=') - this.operator = ''; - - // if it literally is just '>' or '' then allow anything. - if (!m[2]) - this.semver = ANY; - else - this.semver = new SemVer(m[2], this.loose); -}; - -Comparator.prototype.toString = function() { - return this.value; -}; - -Comparator.prototype.test = function(version) { - debug('Comparator.test', version, this.loose); - - if (this.semver === ANY) - return true; - - if (typeof version === 'string') - version = new SemVer(version, this.loose); - - return cmp(version, this.operator, this.semver, this.loose); -}; - -Comparator.prototype.intersects = function(comp, loose) { - if (!(comp instanceof Comparator)) { - throw new TypeError('a Comparator is required'); - } - - var rangeTmp; - - if (this.operator === '') { - rangeTmp = new Range(comp.value, loose); - return satisfies(this.value, rangeTmp, loose); - } else if (comp.operator === '') { - rangeTmp = new Range(this.value, loose); - return satisfies(comp.semver, rangeTmp, loose); - } - - var sameDirectionIncreasing = - (this.operator === '>=' || this.operator === '>') && - (comp.operator === '>=' || comp.operator === '>'); - var sameDirectionDecreasing = - (this.operator === '<=' || this.operator === '<') && - (comp.operator === '<=' || comp.operator === '<'); - var sameSemVer = this.semver.version === comp.semver.version; - var differentDirectionsInclusive = - (this.operator === '>=' || this.operator === '<=') && - (comp.operator === '>=' || comp.operator === '<='); - var oppositeDirectionsLessThan = - cmp(this.semver, '<', comp.semver, loose) && - ((this.operator === '>=' || this.operator === '>') && - (comp.operator === '<=' || comp.operator === '<')); - var oppositeDirectionsGreaterThan = - cmp(this.semver, '>', comp.semver, loose) && - ((this.operator === '<=' || this.operator === '<') && - (comp.operator === '>=' || comp.operator === '>')); - - return sameDirectionIncreasing || sameDirectionDecreasing || - (sameSemVer && differentDirectionsInclusive) || - oppositeDirectionsLessThan || oppositeDirectionsGreaterThan; -}; - - -exports.Range = Range; -function Range(range, loose) { - if (range instanceof Range) { - if (range.loose === loose) { - return range; - } else { - return new Range(range.raw, loose); - } - } - - if (range instanceof Comparator) { - return new Range(range.value, loose); - } - - if (!(this instanceof Range)) - return new Range(range, loose); - - this.loose = loose; - - // First, split based on boolean or || - this.raw = range; - this.set = range.split(/\s*\|\|\s*/).map(function(range) { - return this.parseRange(range.trim()); - }, this).filter(function(c) { - // throw out any that are not relevant for whatever reason - return c.length; - }); - - if (!this.set.length) { - throw new TypeError('Invalid SemVer Range: ' + range); - } - - this.format(); -} - -Range.prototype.format = function() { - this.range = this.set.map(function(comps) { - return comps.join(' ').trim(); - }).join('||').trim(); - return this.range; -}; - -Range.prototype.toString = function() { - return this.range; -}; - -Range.prototype.parseRange = function(range) { - var loose = this.loose; - range = range.trim(); - debug('range', range, loose); - // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; - range = range.replace(hr, hyphenReplace); - debug('hyphen replace', range); - // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); - debug('comparator trim', range, re[COMPARATORTRIM]); - - // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[TILDETRIM], tildeTrimReplace); - - // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[CARETTRIM], caretTrimReplace); - - // normalize spaces - range = range.split(/\s+/).join(' '); - - // At this point, the range is completely trimmed and - // ready to be split into comparators. - - var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var set = range.split(' ').map(function(comp) { - return parseComparator(comp, loose); - }).join(' ').split(/\s+/); - if (this.loose) { - // in loose mode, throw out any that are not valid comparators - set = set.filter(function(comp) { - return !!comp.match(compRe); - }); - } - set = set.map(function(comp) { - return new Comparator(comp, loose); - }); - - return set; -}; - -Range.prototype.intersects = function(range, loose) { - if (!(range instanceof Range)) { - throw new TypeError('a Range is required'); - } - - return this.set.some(function(thisComparators) { - return thisComparators.every(function(thisComparator) { - return range.set.some(function(rangeComparators) { - return rangeComparators.every(function(rangeComparator) { - return thisComparator.intersects(rangeComparator, loose); - }); - }); - }); - }); -}; - -// Mostly just for testing and legacy API reasons -exports.toComparators = toComparators; -function toComparators(range, loose) { - return new Range(range, loose).set.map(function(comp) { - return comp.map(function(c) { - return c.value; - }).join(' ').trim().split(' '); - }); -} - -// comprised of xranges, tildes, stars, and gtlt's at this point. -// already replaced the hyphen ranges -// turn into a set of JUST comparators. -function parseComparator(comp, loose) { - debug('comp', comp); - comp = replaceCarets(comp, loose); - debug('caret', comp); - comp = replaceTildes(comp, loose); - debug('tildes', comp); - comp = replaceXRanges(comp, loose); - debug('xrange', comp); - comp = replaceStars(comp, loose); - debug('stars', comp); - return comp; -} - -function isX(id) { - return !id || id.toLowerCase() === 'x' || id === '*'; -} - -// ~, ~> --> * (any, kinda silly) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 -function replaceTildes(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceTilde(comp, loose); - }).join(' '); -} - -function replaceTilde(comp, loose) { - var r = loose ? re[TILDELOOSE] : re[TILDE]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('tilde', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) - // ~1.2 == >=1.2.0 <1.3.0 - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else if (pr) { - debug('replaceTilde pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - // ~1.2.3 == >=1.2.3 <1.3.0 - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - - debug('tilde return', ret); - return ret; - }); -} - -// ^ --> * (any, kinda silly) -// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 -// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 -// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 -// ^1.2.3 --> >=1.2.3 <2.0.0 -// ^1.2.0 --> >=1.2.0 <2.0.0 -function replaceCarets(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceCaret(comp, loose); - }).join(' '); -} - -function replaceCaret(comp, loose) { - debug('caret', comp, loose); - var r = loose ? re[CARETLOOSE] : re[CARET]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('caret', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) { - if (M === '0') - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else - ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; - } else if (pr) { - debug('replaceCaret pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + (+M + 1) + '.0.0'; - } else { - debug('no pr'); - if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + - ' <' + (+M + 1) + '.0.0'; - } - - debug('caret return', ret); - return ret; - }); -} - -function replaceXRanges(comp, loose) { - debug('replaceXRanges', comp, loose); - return comp.split(/\s+/).map(function(comp) { - return replaceXRange(comp, loose); - }).join(' '); -} - -function replaceXRange(comp, loose) { - comp = comp.trim(); - var r = loose ? re[XRANGELOOSE] : re[XRANGE]; - return comp.replace(r, function(ret, gtlt, M, m, p, pr) { - debug('xRange', comp, ret, gtlt, M, m, p, pr); - var xM = isX(M); - var xm = xM || isX(m); - var xp = xm || isX(p); - var anyX = xp; - - if (gtlt === '=' && anyX) - gtlt = ''; - - if (xM) { - if (gtlt === '>' || gtlt === '<') { - // nothing is allowed - ret = '<0.0.0'; - } else { - // nothing is forbidden - ret = '*'; - } - } else if (gtlt && anyX) { - // replace X with 0 - if (xm) - m = 0; - if (xp) - p = 0; - - if (gtlt === '>') { - // >1 => >=2.0.0 - // >1.2 => >=1.3.0 - // >1.2.3 => >= 1.2.4 - gtlt = '>='; - if (xm) { - M = +M + 1; - m = 0; - p = 0; - } else if (xp) { - m = +m + 1; - p = 0; - } - } else if (gtlt === '<=') { - // <=0.7.x is actually <0.8.0, since any 0.7.x should - // pass. Similarly, <=7.x is actually <8.0.0, etc. - gtlt = '<'; - if (xm) - M = +M + 1; - else - m = +m + 1; - } - - ret = gtlt + M + '.' + m + '.' + p; - } else if (xm) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - } else if (xp) { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - } - - debug('xRange return', ret); - - return ret; - }); -} - -// Because * is AND-ed with everything else in the comparator, -// and '' means "any version", just remove the *s entirely. -function replaceStars(comp, loose) { - debug('replaceStars', comp, loose); - // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[STAR], ''); -} - -// This function is passed to string.replace(re[HYPHENRANGE]) -// M, m, patch, prerelease, build -// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 -// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do -// 1.2 - 3.4 => >=1.2.0 <3.5.0 -function hyphenReplace($0, - from, fM, fm, fp, fpr, fb, - to, tM, tm, tp, tpr, tb) { - - if (isX(fM)) - from = ''; - else if (isX(fm)) - from = '>=' + fM + '.0.0'; - else if (isX(fp)) - from = '>=' + fM + '.' + fm + '.0'; - else - from = '>=' + from; - - if (isX(tM)) - to = ''; - else if (isX(tm)) - to = '<' + (+tM + 1) + '.0.0'; - else if (isX(tp)) - to = '<' + tM + '.' + (+tm + 1) + '.0'; - else if (tpr) - to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; - else - to = '<=' + to; - - return (from + ' ' + to).trim(); -} - - -// if ANY of the sets match ALL of its comparators, then pass -Range.prototype.test = function(version) { - if (!version) - return false; - - if (typeof version === 'string') - version = new SemVer(version, this.loose); - - for (var i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version)) - return true; - } - return false; -}; - -function testSet(set, version) { - for (var i = 0; i < set.length; i++) { - if (!set[i].test(version)) - return false; - } - - if (version.prerelease.length) { - // Find the set of versions that are allowed to have prereleases - // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 - // That should allow `1.2.3-pr.2` to pass. - // However, `1.2.4-alpha.notready` should NOT be allowed, - // even though it's within the range set by the comparators. - for (var i = 0; i < set.length; i++) { - debug(set[i].semver); - if (set[i].semver === ANY) - continue; - - if (set[i].semver.prerelease.length > 0) { - var allowed = set[i].semver; - if (allowed.major === version.major && - allowed.minor === version.minor && - allowed.patch === version.patch) - return true; - } - } - - // Version has a -pre, but it's not one of the ones we like. - return false; - } - - return true; -} - -exports.satisfies = satisfies; -function satisfies(version, range, loose) { - try { - range = new Range(range, loose); - } catch (er) { - return false; - } - return range.test(version); -} - -exports.maxSatisfying = maxSatisfying; -function maxSatisfying(versions, range, loose) { - var max = null; - var maxSV = null; - try { - var rangeObj = new Range(range, loose); - } catch (er) { - return null; - } - versions.forEach(function (v) { - if (rangeObj.test(v)) { // satisfies(v, range, loose) - if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) - max = v; - maxSV = new SemVer(max, loose); - } - } - }) - return max; -} - -exports.minSatisfying = minSatisfying; -function minSatisfying(versions, range, loose) { - var min = null; - var minSV = null; - try { - var rangeObj = new Range(range, loose); - } catch (er) { - return null; - } - versions.forEach(function (v) { - if (rangeObj.test(v)) { // satisfies(v, range, loose) - if (!min || minSV.compare(v) === 1) { // compare(min, v, true) - min = v; - minSV = new SemVer(min, loose); - } - } - }) - return min; -} - -exports.validRange = validRange; -function validRange(range, loose) { - try { - // Return '*' instead of '' so that truthiness works. - // This will throw if it's invalid anyway - return new Range(range, loose).range || '*'; - } catch (er) { - return null; - } -} - -// Determine if version is less than all the versions possible in the range -exports.ltr = ltr; -function ltr(version, range, loose) { - return outside(version, range, '<', loose); -} - -// Determine if version is greater than all the versions possible in the range. -exports.gtr = gtr; -function gtr(version, range, loose) { - return outside(version, range, '>', loose); -} - -exports.outside = outside; -function outside(version, range, hilo, loose) { - version = new SemVer(version, loose); - range = new Range(range, loose); - - var gtfn, ltefn, ltfn, comp, ecomp; - switch (hilo) { - case '>': - gtfn = gt; - ltefn = lte; - ltfn = lt; - comp = '>'; - ecomp = '>='; - break; - case '<': - gtfn = lt; - ltefn = gte; - ltfn = gt; - comp = '<'; - ecomp = '<='; - break; - default: - throw new TypeError('Must provide a hilo val of "<" or ">"'); - } - - // If it satisifes the range it is not outside - if (satisfies(version, range, loose)) { - return false; - } - - // From now on, variable terms are as if we're in "gtr" mode. - // but note that everything is flipped for the "ltr" function. - - for (var i = 0; i < range.set.length; ++i) { - var comparators = range.set[i]; - - var high = null; - var low = null; - - comparators.forEach(function(comparator) { - if (comparator.semver === ANY) { - comparator = new Comparator('>=0.0.0') - } - high = high || comparator; - low = low || comparator; - if (gtfn(comparator.semver, high.semver, loose)) { - high = comparator; - } else if (ltfn(comparator.semver, low.semver, loose)) { - low = comparator; - } - }); - - // If the edge version comparator has a operator then our version - // isn't outside it - if (high.operator === comp || high.operator === ecomp) { - return false; - } - - // If the lowest version comparator has an operator and our version - // is less than it then it isn't higher than the range - if ((!low.operator || low.operator === comp) && - ltefn(version, low.semver)) { - return false; - } else if (low.operator === ecomp && ltfn(version, low.semver)) { - return false; - } - } - return true; -} - -exports.prerelease = prerelease; -function prerelease(version, loose) { - var parsed = parse(version, loose); - return (parsed && parsed.prerelease.length) ? parsed.prerelease : null; -} - -exports.intersects = intersects; -function intersects(r1, r2, loose) { - r1 = new Range(r1, loose) - r2 = new Range(r2, loose) - return r1.intersects(r2) -} - -exports.coerce = coerce; -function coerce(version) { - if (version instanceof SemVer) - return version; - - if (typeof version !== 'string') - return null; - - var match = version.match(re[COERCE]); - - if (match == null) - return null; - - return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); -} - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = require("stream"); - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = require("url"); - -/***/ }), -/* 25 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscription; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_isArray__ = __webpack_require__(41); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isObject__ = __webpack_require__(444); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isFunction__ = __webpack_require__(154); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_tryCatch__ = __webpack_require__(57); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_errorObject__ = __webpack_require__(48); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__ = __webpack_require__(441); -/** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */ - - - - - - -var Subscription = /*@__PURE__*/ (function () { - function Subscription(unsubscribe) { - this.closed = false; - this._parent = null; - this._parents = null; - this._subscriptions = null; - if (unsubscribe) { - this._unsubscribe = unsubscribe; - } - } - Subscription.prototype.unsubscribe = function () { - var hasErrors = false; - var errors; - if (this.closed) { - return; - } - var _a = this, _parent = _a._parent, _parents = _a._parents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; - this.closed = true; - this._parent = null; - this._parents = null; - this._subscriptions = null; - var index = -1; - var len = _parents ? _parents.length : 0; - while (_parent) { - _parent.remove(this); - _parent = ++index < len && _parents[index] || null; - } - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__util_isFunction__["a" /* isFunction */])(_unsubscribe)) { - var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(_unsubscribe).call(this); - if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { - hasErrors = true; - errors = errors || (__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */] ? - flattenUnsubscriptionErrors(__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e.errors) : [__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e]); - } - } - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_isArray__["a" /* isArray */])(_subscriptions)) { - index = -1; - len = _subscriptions.length; - while (++index < len) { - var sub = _subscriptions[index]; - if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isObject__["a" /* isObject */])(sub)) { - var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(sub.unsubscribe).call(sub); - if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { - hasErrors = true; - errors = errors || []; - var err = __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e; - if (err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) { - errors = errors.concat(flattenUnsubscriptionErrors(err.errors)); - } - else { - errors.push(err); - } - } - } - } - } - if (hasErrors) { - throw new __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */](errors); - } - }; - Subscription.prototype.add = function (teardown) { - if (!teardown || (teardown === Subscription.EMPTY)) { - return Subscription.EMPTY; - } - if (teardown === this) { - return this; - } - var subscription = teardown; - switch (typeof teardown) { - case 'function': - subscription = new Subscription(teardown); - case 'object': - if (subscription.closed || typeof subscription.unsubscribe !== 'function') { - return subscription; - } - else if (this.closed) { - subscription.unsubscribe(); - return subscription; - } - else if (typeof subscription._addParent !== 'function') { - var tmp = subscription; - subscription = new Subscription(); - subscription._subscriptions = [tmp]; - } - break; - default: - throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); - } - var subscriptions = this._subscriptions || (this._subscriptions = []); - subscriptions.push(subscription); - subscription._addParent(this); - return subscription; - }; - Subscription.prototype.remove = function (subscription) { - var subscriptions = this._subscriptions; - if (subscriptions) { - var subscriptionIndex = subscriptions.indexOf(subscription); - if (subscriptionIndex !== -1) { - subscriptions.splice(subscriptionIndex, 1); - } - } - }; - Subscription.prototype._addParent = function (parent) { - var _a = this, _parent = _a._parent, _parents = _a._parents; - if (!_parent || _parent === parent) { - this._parent = parent; - } - else if (!_parents) { - this._parents = [parent]; - } - else if (_parents.indexOf(parent) === -1) { - _parents.push(parent); - } - }; - Subscription.EMPTY = (function (empty) { - empty.closed = true; - return empty; - }(new Subscription())); - return Subscription; -}()); - -function flattenUnsubscriptionErrors(errors) { - return errors.reduce(function (errs, err) { return errs.concat((err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) ? err.errors : err); }, []); -} -//# sourceMappingURL=Subscription.js.map - - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2015 Joyent, Inc. - -module.exports = { - bufferSplit: bufferSplit, - addRSAMissing: addRSAMissing, - calculateDSAPublic: calculateDSAPublic, - calculateED25519Public: calculateED25519Public, - calculateX25519Public: calculateX25519Public, - mpNormalize: mpNormalize, - mpDenormalize: mpDenormalize, - ecNormalize: ecNormalize, - countZeros: countZeros, - assertCompatible: assertCompatible, - isCompatible: isCompatible, - opensslKeyDeriv: opensslKeyDeriv, - opensshCipherInfo: opensshCipherInfo, - publicFromPrivateECDSA: publicFromPrivateECDSA, - zeroPadToLength: zeroPadToLength, - writeBitString: writeBitString, - readBitString: readBitString -}; - -var assert = __webpack_require__(16); -var Buffer = __webpack_require__(15).Buffer; -var PrivateKey = __webpack_require__(33); -var Key = __webpack_require__(27); -var crypto = __webpack_require__(11); -var algs = __webpack_require__(32); -var asn1 = __webpack_require__(66); - -var ec, jsbn; -var nacl; - -var MAX_CLASS_DEPTH = 3; - -function isCompatible(obj, klass, needVer) { - if (obj === null || typeof (obj) !== 'object') - return (false); - if (needVer === undefined) - needVer = klass.prototype._sshpkApiVersion; - if (obj instanceof klass && - klass.prototype._sshpkApiVersion[0] == needVer[0]) - return (true); - var proto = Object.getPrototypeOf(obj); - var depth = 0; - while (proto.constructor.name !== klass.name) { - proto = Object.getPrototypeOf(proto); - if (!proto || ++depth > MAX_CLASS_DEPTH) - return (false); - } - if (proto.constructor.name !== klass.name) - return (false); - var ver = proto._sshpkApiVersion; - if (ver === undefined) - ver = klass._oldVersionDetect(obj); - if (ver[0] != needVer[0] || ver[1] < needVer[1]) - return (false); - return (true); -} - -function assertCompatible(obj, klass, needVer, name) { - if (name === undefined) - name = 'object'; - assert.ok(obj, name + ' must not be null'); - assert.object(obj, name + ' must be an object'); - if (needVer === undefined) - needVer = klass.prototype._sshpkApiVersion; - if (obj instanceof klass && - klass.prototype._sshpkApiVersion[0] == needVer[0]) - return; - var proto = Object.getPrototypeOf(obj); - var depth = 0; - while (proto.constructor.name !== klass.name) { - proto = Object.getPrototypeOf(proto); - assert.ok(proto && ++depth <= MAX_CLASS_DEPTH, - name + ' must be a ' + klass.name + ' instance'); - } - assert.strictEqual(proto.constructor.name, klass.name, - name + ' must be a ' + klass.name + ' instance'); - var ver = proto._sshpkApiVersion; - if (ver === undefined) - ver = klass._oldVersionDetect(obj); - assert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1], - name + ' must be compatible with ' + klass.name + ' klass ' + - 'version ' + needVer[0] + '.' + needVer[1]); -} - -var CIPHER_LEN = { - 'des-ede3-cbc': { key: 7, iv: 8 }, - 'aes-128-cbc': { key: 16, iv: 16 } -}; -var PKCS5_SALT_LEN = 8; - -function opensslKeyDeriv(cipher, salt, passphrase, count) { - assert.buffer(salt, 'salt'); - assert.buffer(passphrase, 'passphrase'); - assert.number(count, 'iteration count'); - - var clen = CIPHER_LEN[cipher]; - assert.object(clen, 'supported cipher'); - - salt = salt.slice(0, PKCS5_SALT_LEN); - - var D, D_prev, bufs; - var material = Buffer.alloc(0); - while (material.length < clen.key + clen.iv) { - bufs = []; - if (D_prev) - bufs.push(D_prev); - bufs.push(passphrase); - bufs.push(salt); - D = Buffer.concat(bufs); - for (var j = 0; j < count; ++j) - D = crypto.createHash('md5').update(D).digest(); - material = Buffer.concat([material, D]); - D_prev = D; - } - - return ({ - key: material.slice(0, clen.key), - iv: material.slice(clen.key, clen.key + clen.iv) - }); -} - -/* Count leading zero bits on a buffer */ -function countZeros(buf) { - var o = 0, obit = 8; - while (o < buf.length) { - var mask = (1 << obit); - if ((buf[o] & mask) === mask) - break; - obit--; - if (obit < 0) { - o++; - obit = 8; - } - } - return (o*8 + (8 - obit) - 1); -} - -function bufferSplit(buf, chr) { - assert.buffer(buf); - assert.string(chr); - - var parts = []; - var lastPart = 0; - var matches = 0; - for (var i = 0; i < buf.length; ++i) { - if (buf[i] === chr.charCodeAt(matches)) - ++matches; - else if (buf[i] === chr.charCodeAt(0)) - matches = 1; - else - matches = 0; - - if (matches >= chr.length) { - var newPart = i + 1; - parts.push(buf.slice(lastPart, newPart - matches)); - lastPart = newPart; - matches = 0; - } - } - if (lastPart <= buf.length) - parts.push(buf.slice(lastPart, buf.length)); - - return (parts); -} - -function ecNormalize(buf, addZero) { - assert.buffer(buf); - if (buf[0] === 0x00 && buf[1] === 0x04) { - if (addZero) - return (buf); - return (buf.slice(1)); - } else if (buf[0] === 0x04) { - if (!addZero) - return (buf); - } else { - while (buf[0] === 0x00) - buf = buf.slice(1); - if (buf[0] === 0x02 || buf[0] === 0x03) - throw (new Error('Compressed elliptic curve points ' + - 'are not supported')); - if (buf[0] !== 0x04) - throw (new Error('Not a valid elliptic curve point')); - if (!addZero) - return (buf); - } - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x0; - buf.copy(b, 1); - return (b); -} - -function readBitString(der, tag) { - if (tag === undefined) - tag = asn1.Ber.BitString; - var buf = der.readString(tag, true); - assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + - 'not supported (0x' + buf[0].toString(16) + ')'); - return (buf.slice(1)); -} - -function writeBitString(der, buf, tag) { - if (tag === undefined) - tag = asn1.Ber.BitString; - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x00; - buf.copy(b, 1); - der.writeBuffer(b, tag); -} - -function mpNormalize(buf) { - assert.buffer(buf); - while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00) - buf = buf.slice(1); - if ((buf[0] & 0x80) === 0x80) { - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x00; - buf.copy(b, 1); - buf = b; - } - return (buf); -} - -function mpDenormalize(buf) { - assert.buffer(buf); - while (buf.length > 1 && buf[0] === 0x00) - buf = buf.slice(1); - return (buf); -} - -function zeroPadToLength(buf, len) { - assert.buffer(buf); - assert.number(len); - while (buf.length > len) { - assert.equal(buf[0], 0x00); - buf = buf.slice(1); - } - while (buf.length < len) { - var b = Buffer.alloc(buf.length + 1); - b[0] = 0x00; - buf.copy(b, 1); - buf = b; - } - return (buf); -} - -function bigintToMpBuf(bigint) { - var buf = Buffer.from(bigint.toByteArray()); - buf = mpNormalize(buf); - return (buf); -} - -function calculateDSAPublic(g, p, x) { - assert.buffer(g); - assert.buffer(p); - assert.buffer(x); - try { - var bigInt = __webpack_require__(81).BigInteger; - } catch (e) { - throw (new Error('To load a PKCS#8 format DSA private key, ' + - 'the node jsbn library is required.')); - } - g = new bigInt(g); - p = new bigInt(p); - x = new bigInt(x); - var y = g.modPow(x, p); - var ybuf = bigintToMpBuf(y); - return (ybuf); -} - -function calculateED25519Public(k) { - assert.buffer(k); - - if (nacl === undefined) - nacl = __webpack_require__(76); - - var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); - return (Buffer.from(kp.publicKey)); -} - -function calculateX25519Public(k) { - assert.buffer(k); - - if (nacl === undefined) - nacl = __webpack_require__(76); - - var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); - return (Buffer.from(kp.publicKey)); -} - -function addRSAMissing(key) { - assert.object(key); - assertCompatible(key, PrivateKey, [1, 1]); - try { - var bigInt = __webpack_require__(81).BigInteger; - } catch (e) { - throw (new Error('To write a PEM private key from ' + - 'this source, the node jsbn lib is required.')); - } - - var d = new bigInt(key.part.d.data); - var buf; - - if (!key.part.dmodp) { - var p = new bigInt(key.part.p.data); - var dmodp = d.mod(p.subtract(1)); - - buf = bigintToMpBuf(dmodp); - key.part.dmodp = {name: 'dmodp', data: buf}; - key.parts.push(key.part.dmodp); - } - if (!key.part.dmodq) { - var q = new bigInt(key.part.q.data); - var dmodq = d.mod(q.subtract(1)); - - buf = bigintToMpBuf(dmodq); - key.part.dmodq = {name: 'dmodq', data: buf}; - key.parts.push(key.part.dmodq); - } -} - -function publicFromPrivateECDSA(curveName, priv) { - assert.string(curveName, 'curveName'); - assert.buffer(priv); - if (ec === undefined) - ec = __webpack_require__(139); - if (jsbn === undefined) - jsbn = __webpack_require__(81).BigInteger; - var params = algs.curves[curveName]; - var p = new jsbn(params.p); - var a = new jsbn(params.a); - var b = new jsbn(params.b); - var curve = new ec.ECCurveFp(p, a, b); - var G = curve.decodePointHex(params.G.toString('hex')); - - var d = new jsbn(mpNormalize(priv)); - var pub = G.multiply(d); - pub = Buffer.from(curve.encodePointHex(pub), 'hex'); - - var parts = []; - parts.push({name: 'curve', data: Buffer.from(curveName)}); - parts.push({name: 'Q', data: pub}); - - var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); - return (key); -} - -function opensshCipherInfo(cipher) { - var inf = {}; - switch (cipher) { - case '3des-cbc': - inf.keySize = 24; - inf.blockSize = 8; - inf.opensslName = 'des-ede3-cbc'; - break; - case 'blowfish-cbc': - inf.keySize = 16; - inf.blockSize = 8; - inf.opensslName = 'bf-cbc'; - break; - case 'aes128-cbc': - case 'aes128-ctr': - case 'aes128-gcm@openssh.com': - inf.keySize = 16; - inf.blockSize = 16; - inf.opensslName = 'aes-128-' + cipher.slice(7, 10); - break; - case 'aes192-cbc': - case 'aes192-ctr': - case 'aes192-gcm@openssh.com': - inf.keySize = 24; - inf.blockSize = 16; - inf.opensslName = 'aes-192-' + cipher.slice(7, 10); - break; - case 'aes256-cbc': - case 'aes256-ctr': - case 'aes256-gcm@openssh.com': - inf.keySize = 32; - inf.blockSize = 16; - inf.opensslName = 'aes-256-' + cipher.slice(7, 10); - break; - default: - throw (new Error( - 'Unsupported openssl cipher "' + cipher + '"')); - } - return (inf); -} - - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2017 Joyent, Inc. - -module.exports = Key; - -var assert = __webpack_require__(16); -var algs = __webpack_require__(32); -var crypto = __webpack_require__(11); -var Fingerprint = __webpack_require__(156); -var Signature = __webpack_require__(75); -var DiffieHellman = __webpack_require__(325).DiffieHellman; -var errs = __webpack_require__(74); -var utils = __webpack_require__(26); -var PrivateKey = __webpack_require__(33); -var edCompat; - -try { - edCompat = __webpack_require__(454); -} catch (e) { - /* Just continue through, and bail out if we try to use it. */ -} - -var InvalidAlgorithmError = errs.InvalidAlgorithmError; -var KeyParseError = errs.KeyParseError; - -var formats = {}; -formats['auto'] = __webpack_require__(455); -formats['pem'] = __webpack_require__(86); -formats['pkcs1'] = __webpack_require__(327); -formats['pkcs8'] = __webpack_require__(157); -formats['rfc4253'] = __webpack_require__(103); -formats['ssh'] = __webpack_require__(456); -formats['ssh-private'] = __webpack_require__(193); -formats['openssh'] = formats['ssh-private']; -formats['dnssec'] = __webpack_require__(326); - -function Key(opts) { - assert.object(opts, 'options'); - assert.arrayOfObject(opts.parts, 'options.parts'); - assert.string(opts.type, 'options.type'); - assert.optionalString(opts.comment, 'options.comment'); - - var algInfo = algs.info[opts.type]; - if (typeof (algInfo) !== 'object') - throw (new InvalidAlgorithmError(opts.type)); - - var partLookup = {}; - for (var i = 0; i < opts.parts.length; ++i) { - var part = opts.parts[i]; - partLookup[part.name] = part; - } - - this.type = opts.type; - this.parts = opts.parts; - this.part = partLookup; - this.comment = undefined; - this.source = opts.source; - - /* for speeding up hashing/fingerprint operations */ - this._rfc4253Cache = opts._rfc4253Cache; - this._hashCache = {}; - - var sz; - this.curve = undefined; - if (this.type === 'ecdsa') { - var curve = this.part.curve.data.toString(); - this.curve = curve; - sz = algs.curves[curve].size; - } else if (this.type === 'ed25519' || this.type === 'curve25519') { - sz = 256; - this.curve = 'curve25519'; - } else { - var szPart = this.part[algInfo.sizePart]; - sz = szPart.data.length; - sz = sz * 8 - utils.countZeros(szPart.data); - } - this.size = sz; -} - -Key.formats = formats; - -Key.prototype.toBuffer = function (format, options) { - if (format === undefined) - format = 'ssh'; - assert.string(format, 'format'); - assert.object(formats[format], 'formats[format]'); - assert.optionalObject(options, 'options'); - - if (format === 'rfc4253') { - if (this._rfc4253Cache === undefined) - this._rfc4253Cache = formats['rfc4253'].write(this); - return (this._rfc4253Cache); - } - - return (formats[format].write(this, options)); -}; - -Key.prototype.toString = function (format, options) { - return (this.toBuffer(format, options).toString()); -}; - -Key.prototype.hash = function (algo) { - assert.string(algo, 'algorithm'); - algo = algo.toLowerCase(); - if (algs.hashAlgs[algo] === undefined) - throw (new InvalidAlgorithmError(algo)); - - if (this._hashCache[algo]) - return (this._hashCache[algo]); - var hash = crypto.createHash(algo). - update(this.toBuffer('rfc4253')).digest(); - this._hashCache[algo] = hash; - return (hash); -}; - -Key.prototype.fingerprint = function (algo) { - if (algo === undefined) - algo = 'sha256'; - assert.string(algo, 'algorithm'); - var opts = { - type: 'key', - hash: this.hash(algo), - algorithm: algo - }; - return (new Fingerprint(opts)); -}; - -Key.prototype.defaultHashAlgorithm = function () { - var hashAlgo = 'sha1'; - if (this.type === 'rsa') - hashAlgo = 'sha256'; - if (this.type === 'dsa' && this.size > 1024) - hashAlgo = 'sha256'; - if (this.type === 'ed25519') - hashAlgo = 'sha512'; - if (this.type === 'ecdsa') { - if (this.size <= 256) - hashAlgo = 'sha256'; - else if (this.size <= 384) - hashAlgo = 'sha384'; - else - hashAlgo = 'sha512'; - } - return (hashAlgo); -}; - -Key.prototype.createVerify = function (hashAlgo) { - if (hashAlgo === undefined) - hashAlgo = this.defaultHashAlgorithm(); - assert.string(hashAlgo, 'hash algorithm'); - - /* ED25519 is not supported by OpenSSL, use a javascript impl. */ - if (this.type === 'ed25519' && edCompat !== undefined) - return (new edCompat.Verifier(this, hashAlgo)); - if (this.type === 'curve25519') - throw (new Error('Curve25519 keys are not suitable for ' + - 'signing or verification')); - - var v, nm, err; - try { - nm = hashAlgo.toUpperCase(); - v = crypto.createVerify(nm); - } catch (e) { - err = e; - } - if (v === undefined || (err instanceof Error && - err.message.match(/Unknown message digest/))) { - nm = 'RSA-'; - nm += hashAlgo.toUpperCase(); - v = crypto.createVerify(nm); - } - assert.ok(v, 'failed to create verifier'); - var oldVerify = v.verify.bind(v); - var key = this.toBuffer('pkcs8'); - var curve = this.curve; - var self = this; - v.verify = function (signature, fmt) { - if (Signature.isSignature(signature, [2, 0])) { - if (signature.type !== self.type) - return (false); - if (signature.hashAlgorithm && - signature.hashAlgorithm !== hashAlgo) - return (false); - if (signature.curve && self.type === 'ecdsa' && - signature.curve !== curve) - return (false); - return (oldVerify(key, signature.toBuffer('asn1'))); - - } else if (typeof (signature) === 'string' || - Buffer.isBuffer(signature)) { - return (oldVerify(key, signature, fmt)); - - /* - * Avoid doing this on valid arguments, walking the prototype - * chain can be quite slow. - */ - } else if (Signature.isSignature(signature, [1, 0])) { - throw (new Error('signature was created by too old ' + - 'a version of sshpk and cannot be verified')); - - } else { - throw (new TypeError('signature must be a string, ' + - 'Buffer, or Signature object')); - } - }; - return (v); -}; - -Key.prototype.createDiffieHellman = function () { - if (this.type === 'rsa') - throw (new Error('RSA keys do not support Diffie-Hellman')); - - return (new DiffieHellman(this)); -}; -Key.prototype.createDH = Key.prototype.createDiffieHellman; - -Key.parse = function (data, format, options) { - if (typeof (data) !== 'string') - assert.buffer(data, 'data'); - if (format === undefined) - format = 'auto'; - assert.string(format, 'format'); - if (typeof (options) === 'string') - options = { filename: options }; - assert.optionalObject(options, 'options'); - if (options === undefined) - options = {}; - assert.optionalString(options.filename, 'options.filename'); - if (options.filename === undefined) - options.filename = '(unnamed)'; - - assert.object(formats[format], 'formats[format]'); - - try { - var k = formats[format].read(data, options); - if (k instanceof PrivateKey) - k = k.toPublic(); - if (!k.comment) - k.comment = options.filename; - return (k); - } catch (e) { - if (e.name === 'KeyEncryptedError') - throw (e); - throw (new KeyParseError(options.filename, format, e)); - } -}; - -Key.isKey = function (obj, ver) { - return (utils.isCompatible(obj, Key, ver)); -}; - -/* - * API versions for Key: - * [1,0] -- initial ver, may take Signature for createVerify or may not - * [1,1] -- added pkcs1, pkcs8 formats - * [1,2] -- added auto, ssh-private, openssh formats - * [1,3] -- added defaultHashAlgorithm - * [1,4] -- added ed support, createDH - * [1,5] -- first explicitly tagged version - * [1,6] -- changed ed25519 part names - */ -Key.prototype._sshpkApiVersion = [1, 6]; - -Key._oldVersionDetect = function (obj) { - assert.func(obj.toBuffer); - assert.func(obj.fingerprint); - if (obj.createDH) - return ([1, 4]); - if (obj.defaultHashAlgorithm) - return ([1, 3]); - if (obj.formats['auto']) - return ([1, 2]); - if (obj.formats['pkcs1']) - return ([1, 1]); - return ([1, 0]); -}; - - -/***/ }), -/* 28 */ -/***/ (function(module, exports) { - -module.exports = require("assert"); - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = nullify; -function nullify(obj = {}) { - if (Array.isArray(obj)) { - for (var _iterator = obj, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; - } - - const item = _ref; - - nullify(item); - } - } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') { - Object.setPrototypeOf(obj, null); - - // for..in can only be applied to 'object', not 'function' - if (typeof obj === 'object') { - for (const key in obj) { - nullify(obj[key]); - } - } - } - - return obj; -} - -/***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const escapeStringRegexp = __webpack_require__(382); -const ansiStyles = __webpack_require__(474); -const stdoutColor = __webpack_require__(566).stdout; - -const template = __webpack_require__(567); - -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); - -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; - -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); - -const styles = Object.create(null); - -function applyOptions(obj, options) { - options = options || {}; - - // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; -} - -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); - - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = Chalk; - - return chalk.template; - } - - applyOptions(this, options); -} - -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} - -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); - } - }; -} - -styles.visible = { - get() { - return build.call(this, this._styles || [], true, 'visible'); - } -}; - -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } - - styles[model] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; -} - -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } - - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; -} - -const proto = Object.defineProperties(() => {}, styles); - -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; - - builder._styles = _styles; - builder._empty = _empty; - - const self = this; - - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); - - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); - - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; - - // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype - builder.__proto__ = proto; // eslint-disable-line no-proto - - return builder; -} - -function applyStyle() { - // Support varags, but simply cast to string in case there's only one arg - const args = arguments; - const argsLen = args.length; - let str = String(arguments[0]); - - if (argsLen === 0) { - return ''; - } - - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } - - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } - - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; - } - - for (const code of this._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; - - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); - } - - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; - - return str; -} - -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); - } - - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; - - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); - } - - return template(chalk, parts.join('')); -} - -Object.defineProperties(Chalk.prototype, styles); - -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript - - -/***/ }), -/* 31 */ -/***/ (function(module, exports) { - -var core = module.exports = { version: '2.5.7' }; -if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef - - -/***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2015 Joyent, Inc. - -var Buffer = __webpack_require__(15).Buffer; - -var algInfo = { - 'dsa': { - parts: ['p', 'q', 'g', 'y'], - sizePart: 'p' - }, - 'rsa': { - parts: ['e', 'n'], - sizePart: 'n' - }, - 'ecdsa': { - parts: ['curve', 'Q'], - sizePart: 'Q' - }, - 'ed25519': { - parts: ['A'], - sizePart: 'A' - } -}; -algInfo['curve25519'] = algInfo['ed25519']; - -var algPrivInfo = { - 'dsa': { - parts: ['p', 'q', 'g', 'y', 'x'] - }, - 'rsa': { - parts: ['n', 'e', 'd', 'iqmp', 'p', 'q'] - }, - 'ecdsa': { - parts: ['curve', 'Q', 'd'] - }, - 'ed25519': { - parts: ['A', 'k'] - } -}; -algPrivInfo['curve25519'] = algPrivInfo['ed25519']; - -var hashAlgs = { - 'md5': true, - 'sha1': true, - 'sha256': true, - 'sha384': true, - 'sha512': true -}; - -/* - * Taken from - * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf - */ -var curves = { - 'nistp256': { - size: 256, - pkcs8oid: '1.2.840.10045.3.1.7', - p: Buffer.from(('00' + - 'ffffffff 00000001 00000000 00000000' + - '00000000 ffffffff ffffffff ffffffff'). - replace(/ /g, ''), 'hex'), - a: Buffer.from(('00' + - 'FFFFFFFF 00000001 00000000 00000000' + - '00000000 FFFFFFFF FFFFFFFF FFFFFFFC'). - replace(/ /g, ''), 'hex'), - b: Buffer.from(( - '5ac635d8 aa3a93e7 b3ebbd55 769886bc' + - '651d06b0 cc53b0f6 3bce3c3e 27d2604b'). - replace(/ /g, ''), 'hex'), - s: Buffer.from(('00' + - 'c49d3608 86e70493 6a6678e1 139d26b7' + - '819f7e90'). - replace(/ /g, ''), 'hex'), - n: Buffer.from(('00' + - 'ffffffff 00000000 ffffffff ffffffff' + - 'bce6faad a7179e84 f3b9cac2 fc632551'). - replace(/ /g, ''), 'hex'), - G: Buffer.from(('04' + - '6b17d1f2 e12c4247 f8bce6e5 63a440f2' + - '77037d81 2deb33a0 f4a13945 d898c296' + - '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' + - '2bce3357 6b315ece cbb64068 37bf51f5'). - replace(/ /g, ''), 'hex') - }, - 'nistp384': { - size: 384, - pkcs8oid: '1.3.132.0.34', - p: Buffer.from(('00' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff fffffffe' + - 'ffffffff 00000000 00000000 ffffffff'). - replace(/ /g, ''), 'hex'), - a: Buffer.from(('00' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' + - 'FFFFFFFF 00000000 00000000 FFFFFFFC'). - replace(/ /g, ''), 'hex'), - b: Buffer.from(( - 'b3312fa7 e23ee7e4 988e056b e3f82d19' + - '181d9c6e fe814112 0314088f 5013875a' + - 'c656398d 8a2ed19d 2a85c8ed d3ec2aef'). - replace(/ /g, ''), 'hex'), - s: Buffer.from(('00' + - 'a335926a a319a27a 1d00896a 6773a482' + - '7acdac73'). - replace(/ /g, ''), 'hex'), - n: Buffer.from(('00' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff c7634d81 f4372ddf' + - '581a0db2 48b0a77a ecec196a ccc52973'). - replace(/ /g, ''), 'hex'), - G: Buffer.from(('04' + - 'aa87ca22 be8b0537 8eb1c71e f320ad74' + - '6e1d3b62 8ba79b98 59f741e0 82542a38' + - '5502f25d bf55296c 3a545e38 72760ab7' + - '3617de4a 96262c6f 5d9e98bf 9292dc29' + - 'f8f41dbd 289a147c e9da3113 b5f0b8c0' + - '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'). - replace(/ /g, ''), 'hex') - }, - 'nistp521': { - size: 521, - pkcs8oid: '1.3.132.0.35', - p: Buffer.from(( - '01ffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffff').replace(/ /g, ''), 'hex'), - a: Buffer.from(('01FF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + - 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'). - replace(/ /g, ''), 'hex'), - b: Buffer.from(('51' + - '953eb961 8e1c9a1f 929a21a0 b68540ee' + - 'a2da725b 99b315f3 b8b48991 8ef109e1' + - '56193951 ec7e937b 1652c0bd 3bb1bf07' + - '3573df88 3d2c34f1 ef451fd4 6b503f00'). - replace(/ /g, ''), 'hex'), - s: Buffer.from(('00' + - 'd09e8800 291cb853 96cc6717 393284aa' + - 'a0da64ba').replace(/ /g, ''), 'hex'), - n: Buffer.from(('01ff' + - 'ffffffff ffffffff ffffffff ffffffff' + - 'ffffffff ffffffff ffffffff fffffffa' + - '51868783 bf2f966b 7fcc0148 f709a5d0' + - '3bb5c9b8 899c47ae bb6fb71e 91386409'). - replace(/ /g, ''), 'hex'), - G: Buffer.from(('04' + - '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' + - '9c648139 053fb521 f828af60 6b4d3dba' + - 'a14b5e77 efe75928 fe1dc127 a2ffa8de' + - '3348b3c1 856a429b f97e7e31 c2e5bd66' + - '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' + - '98f54449 579b4468 17afbd17 273e662c' + - '97ee7299 5ef42640 c550b901 3fad0761' + - '353c7086 a272c240 88be9476 9fd16650'). - replace(/ /g, ''), 'hex') - } -}; - -module.exports = { - info: algInfo, - privInfo: algPrivInfo, - hashAlgs: hashAlgs, - curves: curves -}; - - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2017 Joyent, Inc. - -module.exports = PrivateKey; - -var assert = __webpack_require__(16); -var Buffer = __webpack_require__(15).Buffer; -var algs = __webpack_require__(32); -var crypto = __webpack_require__(11); -var Fingerprint = __webpack_require__(156); -var Signature = __webpack_require__(75); -var errs = __webpack_require__(74); -var util = __webpack_require__(3); -var utils = __webpack_require__(26); -var dhe = __webpack_require__(325); -var generateECDSA = dhe.generateECDSA; -var generateED25519 = dhe.generateED25519; -var edCompat; -var nacl; - -try { - edCompat = __webpack_require__(454); -} catch (e) { - /* Just continue through, and bail out if we try to use it. */ -} - -var Key = __webpack_require__(27); - -var InvalidAlgorithmError = errs.InvalidAlgorithmError; -var KeyParseError = errs.KeyParseError; -var KeyEncryptedError = errs.KeyEncryptedError; - -var formats = {}; -formats['auto'] = __webpack_require__(455); -formats['pem'] = __webpack_require__(86); -formats['pkcs1'] = __webpack_require__(327); -formats['pkcs8'] = __webpack_require__(157); -formats['rfc4253'] = __webpack_require__(103); -formats['ssh-private'] = __webpack_require__(193); -formats['openssh'] = formats['ssh-private']; -formats['ssh'] = formats['ssh-private']; -formats['dnssec'] = __webpack_require__(326); - -function PrivateKey(opts) { - assert.object(opts, 'options'); - Key.call(this, opts); - - this._pubCache = undefined; -} -util.inherits(PrivateKey, Key); - -PrivateKey.formats = formats; - -PrivateKey.prototype.toBuffer = function (format, options) { - if (format === undefined) - format = 'pkcs1'; - assert.string(format, 'format'); - assert.object(formats[format], 'formats[format]'); - assert.optionalObject(options, 'options'); - - return (formats[format].write(this, options)); -}; - -PrivateKey.prototype.hash = function (algo) { - return (this.toPublic().hash(algo)); -}; - -PrivateKey.prototype.toPublic = function () { - if (this._pubCache) - return (this._pubCache); - - var algInfo = algs.info[this.type]; - var pubParts = []; - for (var i = 0; i < algInfo.parts.length; ++i) { - var p = algInfo.parts[i]; - pubParts.push(this.part[p]); - } - - this._pubCache = new Key({ - type: this.type, - source: this, - parts: pubParts - }); - if (this.comment) - this._pubCache.comment = this.comment; - return (this._pubCache); -}; - -PrivateKey.prototype.derive = function (newType) { - assert.string(newType, 'type'); - var priv, pub, pair; - - if (this.type === 'ed25519' && newType === 'curve25519') { - if (nacl === undefined) - nacl = __webpack_require__(76); - - priv = this.part.k.data; - if (priv[0] === 0x00) - priv = priv.slice(1); - - pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); - pub = Buffer.from(pair.publicKey); - - return (new PrivateKey({ - type: 'curve25519', - parts: [ - { name: 'A', data: utils.mpNormalize(pub) }, - { name: 'k', data: utils.mpNormalize(priv) } - ] - })); - } else if (this.type === 'curve25519' && newType === 'ed25519') { - if (nacl === undefined) - nacl = __webpack_require__(76); - - priv = this.part.k.data; - if (priv[0] === 0x00) - priv = priv.slice(1); - - pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); - pub = Buffer.from(pair.publicKey); - - return (new PrivateKey({ - type: 'ed25519', - parts: [ - { name: 'A', data: utils.mpNormalize(pub) }, - { name: 'k', data: utils.mpNormalize(priv) } - ] - })); - } - throw (new Error('Key derivation not supported from ' + this.type + - ' to ' + newType)); -}; - -PrivateKey.prototype.createVerify = function (hashAlgo) { - return (this.toPublic().createVerify(hashAlgo)); -}; - -PrivateKey.prototype.createSign = function (hashAlgo) { - if (hashAlgo === undefined) - hashAlgo = this.defaultHashAlgorithm(); - assert.string(hashAlgo, 'hash algorithm'); - - /* ED25519 is not supported by OpenSSL, use a javascript impl. */ - if (this.type === 'ed25519' && edCompat !== undefined) - return (new edCompat.Signer(this, hashAlgo)); - if (this.type === 'curve25519') - throw (new Error('Curve25519 keys are not suitable for ' + - 'signing or verification')); - - var v, nm, err; - try { - nm = hashAlgo.toUpperCase(); - v = crypto.createSign(nm); - } catch (e) { - err = e; - } - if (v === undefined || (err instanceof Error && - err.message.match(/Unknown message digest/))) { - nm = 'RSA-'; - nm += hashAlgo.toUpperCase(); - v = crypto.createSign(nm); - } - assert.ok(v, 'failed to create verifier'); - var oldSign = v.sign.bind(v); - var key = this.toBuffer('pkcs1'); - var type = this.type; - var curve = this.curve; - v.sign = function () { - var sig = oldSign(key); - if (typeof (sig) === 'string') - sig = Buffer.from(sig, 'binary'); - sig = Signature.parse(sig, type, 'asn1'); - sig.hashAlgorithm = hashAlgo; - sig.curve = curve; - return (sig); - }; - return (v); -}; - -PrivateKey.parse = function (data, format, options) { - if (typeof (data) !== 'string') - assert.buffer(data, 'data'); - if (format === undefined) - format = 'auto'; - assert.string(format, 'format'); - if (typeof (options) === 'string') - options = { filename: options }; - assert.optionalObject(options, 'options'); - if (options === undefined) - options = {}; - assert.optionalString(options.filename, 'options.filename'); - if (options.filename === undefined) - options.filename = '(unnamed)'; - - assert.object(formats[format], 'formats[format]'); - - try { - var k = formats[format].read(data, options); - assert.ok(k instanceof PrivateKey, 'key is not a private key'); - if (!k.comment) - k.comment = options.filename; - return (k); - } catch (e) { - if (e.name === 'KeyEncryptedError') - throw (e); - throw (new KeyParseError(options.filename, format, e)); - } -}; - -PrivateKey.isPrivateKey = function (obj, ver) { - return (utils.isCompatible(obj, PrivateKey, ver)); -}; - -PrivateKey.generate = function (type, options) { - if (options === undefined) - options = {}; - assert.object(options, 'options'); - - switch (type) { - case 'ecdsa': - if (options.curve === undefined) - options.curve = 'nistp256'; - assert.string(options.curve, 'options.curve'); - return (generateECDSA(options.curve)); - case 'ed25519': - return (generateED25519()); - default: - throw (new Error('Key generation not supported with key ' + - 'type "' + type + '"')); - } -}; - -/* - * API versions for PrivateKey: - * [1,0] -- initial ver - * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats - * [1,2] -- added defaultHashAlgorithm - * [1,3] -- added derive, ed, createDH - * [1,4] -- first tagged version - * [1,5] -- changed ed25519 part names and format - */ -PrivateKey.prototype._sshpkApiVersion = [1, 5]; - -PrivateKey._oldVersionDetect = function (obj) { - assert.func(obj.toPublic); - assert.func(obj.createSign); - if (obj.derive) - return ([1, 3]); - if (obj.defaultHashAlgorithm) - return ([1, 2]); - if (obj.formats['auto']) - return ([1, 1]); - return ([1, 0]); -}; - - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefined; - -var _extends2; - -function _load_extends() { - return _extends2 = _interopRequireDefault(__webpack_require__(20)); -} - -var _asyncToGenerator2; - -function _load_asyncToGenerator() { - return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); -} - -let install = exports.install = (() => { - var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, lockfile) { - yield wrapLifecycle(config, flags, (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const install = new Install(flags, config, reporter, lockfile); - yield install.init(); - })); - }); - - return function install(_x7, _x8, _x9, _x10) { - return _ref29.apply(this, arguments); - }; -})(); - -let run = exports.run = (() => { - var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { - let lockfile; - let error = 'installCommandRenamed'; - if (flags.lockfile === false) { - lockfile = new (_lockfile || _load_lockfile()).default(); - } else { - lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); - } - - if (args.length) { - const exampleArgs = args.slice(); - - if (flags.saveDev) { - exampleArgs.push('--dev'); - } - if (flags.savePeer) { - exampleArgs.push('--peer'); - } - if (flags.saveOptional) { - exampleArgs.push('--optional'); - } - if (flags.saveExact) { - exampleArgs.push('--exact'); - } - if (flags.saveTilde) { - exampleArgs.push('--tilde'); - } - let command = 'add'; - if (flags.global) { - error = 'globalFlagRemoved'; - command = 'global add'; - } - throw new (_errors || _load_errors()).MessageError(reporter.lang(error, `yarn ${command} ${exampleArgs.join(' ')}`)); - } - - yield install(config, reporter, flags, lockfile); - }); - - return function run(_x11, _x12, _x13, _x14) { - return _ref31.apply(this, arguments); - }; -})(); - -let wrapLifecycle = exports.wrapLifecycle = (() => { - var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags, factory) { - yield config.executeLifecycleScript('preinstall'); - - yield factory(); - - // npm behaviour, seems kinda funky but yay compatibility - yield config.executeLifecycleScript('install'); - yield config.executeLifecycleScript('postinstall'); - - if (!config.production) { - if (!config.disablePrepublish) { - yield config.executeLifecycleScript('prepublish'); - } - yield config.executeLifecycleScript('prepare'); - } - }); - - return function wrapLifecycle(_x15, _x16, _x17) { - return _ref32.apply(this, arguments); - }; -})(); - -exports.hasWrapper = hasWrapper; -exports.setFlags = setFlags; - -var _objectPath; - -function _load_objectPath() { - return _objectPath = _interopRequireDefault(__webpack_require__(304)); -} - -var _hooks; - -function _load_hooks() { - return _hooks = __webpack_require__(368); -} - -var _index; - -function _load_index() { - return _index = _interopRequireDefault(__webpack_require__(218)); -} - -var _errors; - -function _load_errors() { - return _errors = __webpack_require__(6); -} - -var _integrityChecker; - -function _load_integrityChecker() { - return _integrityChecker = _interopRequireDefault(__webpack_require__(206)); -} - -var _lockfile; - -function _load_lockfile() { - return _lockfile = _interopRequireDefault(__webpack_require__(19)); -} - -var _lockfile2; - -function _load_lockfile2() { - return _lockfile2 = __webpack_require__(19); -} - -var _packageFetcher; - -function _load_packageFetcher() { - return _packageFetcher = _interopRequireWildcard(__webpack_require__(208)); -} - -var _packageInstallScripts; - -function _load_packageInstallScripts() { - return _packageInstallScripts = _interopRequireDefault(__webpack_require__(525)); -} - -var _packageCompatibility; - -function _load_packageCompatibility() { - return _packageCompatibility = _interopRequireWildcard(__webpack_require__(207)); -} - -var _packageResolver; - -function _load_packageResolver() { - return _packageResolver = _interopRequireDefault(__webpack_require__(360)); -} - -var _packageLinker; - -function _load_packageLinker() { - return _packageLinker = _interopRequireDefault(__webpack_require__(209)); -} - -var _index2; - -function _load_index2() { - return _index2 = __webpack_require__(58); -} - -var _index3; - -function _load_index3() { - return _index3 = __webpack_require__(78); -} - -var _autoclean; - -function _load_autoclean() { - return _autoclean = __webpack_require__(348); -} - -var _constants; - -function _load_constants() { - return _constants = _interopRequireWildcard(__webpack_require__(8)); -} - -var _normalizePattern; - -function _load_normalizePattern() { - return _normalizePattern = __webpack_require__(37); -} - -var _fs; - -function _load_fs() { - return _fs = _interopRequireWildcard(__webpack_require__(5)); -} - -var _map; - -function _load_map() { - return _map = _interopRequireDefault(__webpack_require__(29)); -} - -var _yarnVersion; - -function _load_yarnVersion() { - return _yarnVersion = __webpack_require__(105); -} - -var _generatePnpMap; - -function _load_generatePnpMap() { - return _generatePnpMap = __webpack_require__(547); -} - -var _workspaceLayout; - -function _load_workspaceLayout() { - return _workspaceLayout = _interopRequireDefault(__webpack_require__(90)); -} - -var _resolutionMap; - -function _load_resolutionMap() { - return _resolutionMap = _interopRequireDefault(__webpack_require__(212)); -} - -var _guessName; - -function _load_guessName() { - return _guessName = _interopRequireDefault(__webpack_require__(169)); -} - -var _audit; - -function _load_audit() { - return _audit = _interopRequireDefault(__webpack_require__(347)); -} - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const deepEqual = __webpack_require__(599); - -const emoji = __webpack_require__(302); -const invariant = __webpack_require__(9); -const path = __webpack_require__(0); -const semver = __webpack_require__(22); -const uuid = __webpack_require__(120); -const ssri = __webpack_require__(65); - -const ONE_DAY = 1000 * 60 * 60 * 24; - -/** - * Try and detect the installation method for Yarn and provide a command to update it with. - */ - -function getUpdateCommand(installationMethod) { - if (installationMethod === 'tar') { - return `curl --compressed -o- -L ${(_constants || _load_constants()).YARN_INSTALLER_SH} | bash`; - } - - if (installationMethod === 'homebrew') { - return 'brew upgrade yarn'; - } - - if (installationMethod === 'deb') { - return 'sudo apt-get update && sudo apt-get install yarn'; - } - - if (installationMethod === 'rpm') { - return 'sudo yum install yarn'; - } - - if (installationMethod === 'npm') { - return 'npm install --global yarn'; - } - - if (installationMethod === 'chocolatey') { - return 'choco upgrade yarn'; - } - - if (installationMethod === 'apk') { - return 'apk update && apk add -u yarn'; - } - - if (installationMethod === 'portage') { - return 'sudo emerge --sync && sudo emerge -au sys-apps/yarn'; - } - - return null; -} - -function getUpdateInstaller(installationMethod) { - // Windows - if (installationMethod === 'msi') { - return (_constants || _load_constants()).YARN_INSTALLER_MSI; - } - - return null; -} - -function normalizeFlags(config, rawFlags) { - const flags = { - // install - har: !!rawFlags.har, - ignorePlatform: !!rawFlags.ignorePlatform, - ignoreEngines: !!rawFlags.ignoreEngines, - ignoreScripts: !!rawFlags.ignoreScripts, - ignoreOptional: !!rawFlags.ignoreOptional, - force: !!rawFlags.force, - flat: !!rawFlags.flat, - lockfile: rawFlags.lockfile !== false, - pureLockfile: !!rawFlags.pureLockfile, - updateChecksums: !!rawFlags.updateChecksums, - skipIntegrityCheck: !!rawFlags.skipIntegrityCheck, - frozenLockfile: !!rawFlags.frozenLockfile, - linkDuplicates: !!rawFlags.linkDuplicates, - checkFiles: !!rawFlags.checkFiles, - audit: !!rawFlags.audit, - - // add - peer: !!rawFlags.peer, - dev: !!rawFlags.dev, - optional: !!rawFlags.optional, - exact: !!rawFlags.exact, - tilde: !!rawFlags.tilde, - ignoreWorkspaceRootCheck: !!rawFlags.ignoreWorkspaceRootCheck, - - // outdated, update-interactive - includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps, - - // add, remove, update - workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false - }; - - if (config.getOption('ignore-scripts')) { - flags.ignoreScripts = true; - } - - if (config.getOption('ignore-platform')) { - flags.ignorePlatform = true; - } - - if (config.getOption('ignore-engines')) { - flags.ignoreEngines = true; - } - - if (config.getOption('ignore-optional')) { - flags.ignoreOptional = true; - } - - if (config.getOption('force')) { - flags.force = true; - } - - return flags; -} - -class Install { - constructor(flags, config, reporter, lockfile) { - this.rootManifestRegistries = []; - this.rootPatternsToOrigin = (0, (_map || _load_map()).default)(); - this.lockfile = lockfile; - this.reporter = reporter; - this.config = config; - this.flags = normalizeFlags(config, flags); - this.resolutions = (0, (_map || _load_map()).default)(); // Legacy resolutions field used for flat install mode - this.resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config); // Selective resolutions for nested dependencies - this.resolver = new (_packageResolver || _load_packageResolver()).default(config, lockfile, this.resolutionMap); - this.integrityChecker = new (_integrityChecker || _load_integrityChecker()).default(config); - this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); - this.scripts = new (_packageInstallScripts || _load_packageInstallScripts()).default(config, this.resolver, this.flags.force); - } - - /** - * Create a list of dependency requests from the current directories manifests. - */ - - fetchRequestFromCwd(excludePatterns = [], ignoreUnusedPatterns = false) { - var _this = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const patterns = []; - const deps = []; - let resolutionDeps = []; - const manifest = {}; - - const ignorePatterns = []; - const usedPatterns = []; - let workspaceLayout; - - // some commands should always run in the context of the entire workspace - const cwd = _this.flags.includeWorkspaceDeps || _this.flags.workspaceRootIsCwd ? _this.config.lockfileFolder : _this.config.cwd; - - // non-workspaces are always root, otherwise check for workspace root - const cwdIsRoot = !_this.config.workspaceRootFolder || _this.config.lockfileFolder === cwd; - - // exclude package names that are in install args - const excludeNames = []; - for (var _iterator = excludePatterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { - var _ref; - - if (_isArray) { - if (_i >= _iterator.length) break; - _ref = _iterator[_i++]; - } else { - _i = _iterator.next(); - if (_i.done) break; - _ref = _i.value; - } - - const pattern = _ref; - - if ((0, (_index3 || _load_index3()).getExoticResolver)(pattern)) { - excludeNames.push((0, (_guessName || _load_guessName()).default)(pattern)); - } else { - // extract the name - const parts = (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern); - excludeNames.push(parts.name); - } - } - - const stripExcluded = function stripExcluded(manifest) { - for (var _iterator2 = excludeNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { - var _ref2; - - if (_isArray2) { - if (_i2 >= _iterator2.length) break; - _ref2 = _iterator2[_i2++]; - } else { - _i2 = _iterator2.next(); - if (_i2.done) break; - _ref2 = _i2.value; - } - - const exclude = _ref2; - - if (manifest.dependencies && manifest.dependencies[exclude]) { - delete manifest.dependencies[exclude]; - } - if (manifest.devDependencies && manifest.devDependencies[exclude]) { - delete manifest.devDependencies[exclude]; - } - if (manifest.optionalDependencies && manifest.optionalDependencies[exclude]) { - delete manifest.optionalDependencies[exclude]; - } - } - }; - - for (var _iterator3 = Object.keys((_index2 || _load_index2()).registries), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref3; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref3 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref3 = _i3.value; - } - - const registry = _ref3; - - const filename = (_index2 || _load_index2()).registries[registry].filename; - - const loc = path.join(cwd, filename); - if (!(yield (_fs || _load_fs()).exists(loc))) { - continue; - } - - _this.rootManifestRegistries.push(registry); - - const projectManifestJson = yield _this.config.readJson(loc); - yield (0, (_index || _load_index()).default)(projectManifestJson, cwd, _this.config, cwdIsRoot); - - Object.assign(_this.resolutions, projectManifestJson.resolutions); - Object.assign(manifest, projectManifestJson); - - _this.resolutionMap.init(_this.resolutions); - for (var _iterator4 = Object.keys(_this.resolutionMap.resolutionsByPackage), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref4; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref4 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref4 = _i4.value; - } - - const packageName = _ref4; - - const optional = (_objectPath || _load_objectPath()).default.has(manifest.optionalDependencies, packageName) && _this.flags.ignoreOptional; - for (var _iterator8 = _this.resolutionMap.resolutionsByPackage[packageName], _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { - var _ref9; - - if (_isArray8) { - if (_i8 >= _iterator8.length) break; - _ref9 = _iterator8[_i8++]; - } else { - _i8 = _iterator8.next(); - if (_i8.done) break; - _ref9 = _i8.value; - } - - const _ref8 = _ref9; - const pattern = _ref8.pattern; - - resolutionDeps = [...resolutionDeps, { registry, pattern, optional, hint: 'resolution' }]; - } - } - - const pushDeps = function pushDeps(depType, manifest, { hint, optional }, isUsed) { - if (ignoreUnusedPatterns && !isUsed) { - return; - } - // We only take unused dependencies into consideration to get deterministic hoisting. - // Since flat mode doesn't care about hoisting and everything is top level and specified then we can safely - // leave these out. - if (_this.flags.flat && !isUsed) { - return; - } - const depMap = manifest[depType]; - for (const name in depMap) { - if (excludeNames.indexOf(name) >= 0) { - continue; - } - - let pattern = name; - if (!_this.lockfile.getLocked(pattern)) { - // when we use --save we save the dependency to the lockfile with just the name rather than the - // version combo - pattern += '@' + depMap[name]; - } - - // normalization made sure packages are mentioned only once - if (isUsed) { - usedPatterns.push(pattern); - } else { - ignorePatterns.push(pattern); - } - - _this.rootPatternsToOrigin[pattern] = depType; - patterns.push(pattern); - deps.push({ pattern, registry, hint, optional, workspaceName: manifest.name, workspaceLoc: manifest._loc }); - } - }; - - if (cwdIsRoot) { - pushDeps('dependencies', projectManifestJson, { hint: null, optional: false }, true); - pushDeps('devDependencies', projectManifestJson, { hint: 'dev', optional: false }, !_this.config.production); - pushDeps('optionalDependencies', projectManifestJson, { hint: 'optional', optional: true }, true); - } - - if (_this.config.workspaceRootFolder) { - const workspaceLoc = cwdIsRoot ? loc : path.join(_this.config.lockfileFolder, filename); - const workspacesRoot = path.dirname(workspaceLoc); - - let workspaceManifestJson = projectManifestJson; - if (!cwdIsRoot) { - // the manifest we read before was a child workspace, so get the root - workspaceManifestJson = yield _this.config.readJson(workspaceLoc); - yield (0, (_index || _load_index()).default)(workspaceManifestJson, workspacesRoot, _this.config, true); - } - - const workspaces = yield _this.config.resolveWorkspaces(workspacesRoot, workspaceManifestJson); - workspaceLayout = new (_workspaceLayout || _load_workspaceLayout()).default(workspaces, _this.config); - - // add virtual manifest that depends on all workspaces, this way package hoisters and resolvers will work fine - const workspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.dependencies); - for (var _iterator5 = Object.keys(workspaces), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref5; - - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref5 = _iterator5[_i5++]; - } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref5 = _i5.value; - } - - const workspaceName = _ref5; - - const workspaceManifest = workspaces[workspaceName].manifest; - workspaceDependencies[workspaceName] = workspaceManifest.version; - - // include dependencies from all workspaces - if (_this.flags.includeWorkspaceDeps) { - pushDeps('dependencies', workspaceManifest, { hint: null, optional: false }, true); - pushDeps('devDependencies', workspaceManifest, { hint: 'dev', optional: false }, !_this.config.production); - pushDeps('optionalDependencies', workspaceManifest, { hint: 'optional', optional: true }, true); - } - } - const virtualDependencyManifest = { - _uid: '', - name: `workspace-aggregator-${uuid.v4()}`, - version: '1.0.0', - _registry: 'npm', - _loc: workspacesRoot, - dependencies: workspaceDependencies, - devDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.devDependencies), - optionalDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.optionalDependencies), - private: workspaceManifestJson.private, - workspaces: workspaceManifestJson.workspaces - }; - workspaceLayout.virtualManifestName = virtualDependencyManifest.name; - const virtualDep = {}; - virtualDep[virtualDependencyManifest.name] = virtualDependencyManifest.version; - workspaces[virtualDependencyManifest.name] = { loc: workspacesRoot, manifest: virtualDependencyManifest }; - - // ensure dependencies that should be excluded are stripped from the correct manifest - stripExcluded(cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest); - - pushDeps('workspaces', { workspaces: virtualDep }, { hint: 'workspaces', optional: false }, true); - - const implicitWorkspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceDependencies); - - for (var _iterator6 = (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { - var _ref6; - - if (_isArray6) { - if (_i6 >= _iterator6.length) break; - _ref6 = _iterator6[_i6++]; - } else { - _i6 = _iterator6.next(); - if (_i6.done) break; - _ref6 = _i6.value; - } - - const type = _ref6; - - for (var _iterator7 = Object.keys(projectManifestJson[type] || {}), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { - var _ref7; - - if (_isArray7) { - if (_i7 >= _iterator7.length) break; - _ref7 = _iterator7[_i7++]; - } else { - _i7 = _iterator7.next(); - if (_i7.done) break; - _ref7 = _i7.value; - } - - const dependencyName = _ref7; - - delete implicitWorkspaceDependencies[dependencyName]; - } - } - - pushDeps('dependencies', { dependencies: implicitWorkspaceDependencies }, { hint: 'workspaces', optional: false }, true); - } - - break; - } - - // inherit root flat flag - if (manifest.flat) { - _this.flags.flat = true; - } - - return { - requests: [...resolutionDeps, ...deps], - patterns, - manifest, - usedPatterns, - ignorePatterns, - workspaceLayout - }; - })(); - } - - /** - * TODO description - */ - - prepareRequests(requests) { - return requests; - } - - preparePatterns(patterns) { - return patterns; - } - preparePatternsForLinking(patterns, cwdManifest, cwdIsRoot) { - return patterns; - } - - prepareManifests() { - var _this2 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const manifests = yield _this2.config.getRootManifests(); - return manifests; - })(); - } - - bailout(patterns, workspaceLayout) { - var _this3 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // We don't want to skip the audit - it could yield important errors - if (_this3.flags.audit) { - return false; - } - // PNP is so fast that the integrity check isn't pertinent - if (_this3.config.plugnplayEnabled) { - return false; - } - if (_this3.flags.skipIntegrityCheck || _this3.flags.force) { - return false; - } - const lockfileCache = _this3.lockfile.cache; - if (!lockfileCache) { - return false; - } - const lockfileClean = _this3.lockfile.parseResultType === 'success'; - const match = yield _this3.integrityChecker.check(patterns, lockfileCache, _this3.flags, workspaceLayout); - if (_this3.flags.frozenLockfile && (!lockfileClean || match.missingPatterns.length > 0)) { - throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('frozenLockfileError')); - } - - const haveLockfile = yield (_fs || _load_fs()).exists(path.join(_this3.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME)); - - const lockfileIntegrityPresent = !_this3.lockfile.hasEntriesExistWithoutIntegrity(); - const integrityBailout = lockfileIntegrityPresent || !_this3.config.autoAddIntegrity; - - if (match.integrityMatches && haveLockfile && lockfileClean && integrityBailout) { - _this3.reporter.success(_this3.reporter.lang('upToDate')); - return true; - } - - if (match.integrityFileMissing && haveLockfile) { - // Integrity file missing, force script installations - _this3.scripts.setForce(true); - return false; - } - - if (match.hardRefreshRequired) { - // e.g. node version doesn't match, force script installations - _this3.scripts.setForce(true); - return false; - } - - if (!patterns.length && !match.integrityFileMissing) { - _this3.reporter.success(_this3.reporter.lang('nothingToInstall')); - yield _this3.createEmptyManifestFolders(); - yield _this3.saveLockfileAndIntegrity(patterns, workspaceLayout); - return true; - } - - return false; - })(); - } - - /** - * Produce empty folders for all used root manifests. - */ - - createEmptyManifestFolders() { - var _this4 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (_this4.config.modulesFolder) { - // already created - return; - } - - for (var _iterator9 = _this4.rootManifestRegistries, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { - var _ref10; - - if (_isArray9) { - if (_i9 >= _iterator9.length) break; - _ref10 = _iterator9[_i9++]; - } else { - _i9 = _iterator9.next(); - if (_i9.done) break; - _ref10 = _i9.value; - } - - const registryName = _ref10; - const folder = _this4.config.registries[registryName].folder; - - yield (_fs || _load_fs()).mkdirp(path.join(_this4.config.lockfileFolder, folder)); - } - })(); - } - - /** - * TODO description - */ - - markIgnored(patterns) { - for (var _iterator10 = patterns, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { - var _ref11; - - if (_isArray10) { - if (_i10 >= _iterator10.length) break; - _ref11 = _iterator10[_i10++]; - } else { - _i10 = _iterator10.next(); - if (_i10.done) break; - _ref11 = _i10.value; - } - - const pattern = _ref11; - - const manifest = this.resolver.getStrictResolvedPattern(pattern); - const ref = manifest._reference; - invariant(ref, 'expected package reference'); - - // just mark the package as ignored. if the package is used by a required package, the hoister - // will take care of that. - ref.ignore = true; - } - } - - /** - * helper method that gets only recent manifests - * used by global.ls command - */ - getFlattenedDeps() { - var _this5 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - var _ref12 = yield _this5.fetchRequestFromCwd(); - - const depRequests = _ref12.requests, - rawPatterns = _ref12.patterns; - - - yield _this5.resolver.init(depRequests, {}); - - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this5.resolver.getManifests(), _this5.config); - _this5.resolver.updateManifests(manifests); - - return _this5.flatten(rawPatterns); - })(); - } - - /** - * TODO description - */ - - init() { - var _this6 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.checkUpdate(); - - // warn if we have a shrinkwrap - if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_SHRINKWRAP_FILENAME))) { - _this6.reporter.warn(_this6.reporter.lang('shrinkwrapWarning')); - } - - // warn if we have an npm lockfile - if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_LOCK_FILENAME))) { - _this6.reporter.warn(_this6.reporter.lang('npmLockfileWarning')); - } - - if (_this6.config.plugnplayEnabled) { - _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L1')); - _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L2')); - } - - let flattenedTopLevelPatterns = []; - const steps = []; - - var _ref13 = yield _this6.fetchRequestFromCwd(); - - const depRequests = _ref13.requests, - rawPatterns = _ref13.patterns, - ignorePatterns = _ref13.ignorePatterns, - workspaceLayout = _ref13.workspaceLayout, - manifest = _ref13.manifest; - - let topLevelPatterns = []; - - const artifacts = yield _this6.integrityChecker.getArtifacts(); - if (artifacts) { - _this6.linker.setArtifacts(artifacts); - _this6.scripts.setArtifacts(artifacts); - } - - if ((_packageCompatibility || _load_packageCompatibility()).shouldCheck(manifest, _this6.flags)) { - steps.push((() => { - var _ref14 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { - _this6.reporter.step(curr, total, _this6.reporter.lang('checkingManifest'), emoji.get('mag')); - yield _this6.checkCompatibility(); - }); - - return function (_x, _x2) { - return _ref14.apply(this, arguments); - }; - })()); - } - - const audit = new (_audit || _load_audit()).default(_this6.config, _this6.reporter, { groups: (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES }); - let auditFoundProblems = false; - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('resolveStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.reporter.step(curr, total, _this6.reporter.lang('resolvingPackages'), emoji.get('mag')); - yield _this6.resolver.init(_this6.prepareRequests(depRequests), { - isFlat: _this6.flags.flat, - isFrozen: _this6.flags.frozenLockfile, - workspaceLayout - }); - topLevelPatterns = _this6.preparePatterns(rawPatterns); - flattenedTopLevelPatterns = yield _this6.flatten(topLevelPatterns); - return { bailout: !_this6.flags.audit && (yield _this6.bailout(topLevelPatterns, workspaceLayout)) }; - })); - }); - - if (_this6.flags.audit) { - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('auditStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.reporter.step(curr, total, _this6.reporter.lang('auditRunning'), emoji.get('mag')); - if (_this6.flags.offline) { - _this6.reporter.warn(_this6.reporter.lang('auditOffline')); - return { bailout: false }; - } - const preparedManifests = yield _this6.prepareManifests(); - // $FlowFixMe - Flow considers `m` in the map operation to be "mixed", so does not recognize `m.object` - const mergedManifest = Object.assign({}, ...Object.values(preparedManifests).map(function (m) { - return m.object; - })); - const auditVulnerabilityCounts = yield audit.performAudit(mergedManifest, _this6.lockfile, _this6.resolver, _this6.linker, topLevelPatterns); - auditFoundProblems = auditVulnerabilityCounts.info || auditVulnerabilityCounts.low || auditVulnerabilityCounts.moderate || auditVulnerabilityCounts.high || auditVulnerabilityCounts.critical; - return { bailout: yield _this6.bailout(topLevelPatterns, workspaceLayout) }; - })); - }); - } - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('fetchStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.markIgnored(ignorePatterns); - _this6.reporter.step(curr, total, _this6.reporter.lang('fetchingPackages'), emoji.get('truck')); - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this6.resolver.getManifests(), _this6.config); - _this6.resolver.updateManifests(manifests); - yield (_packageCompatibility || _load_packageCompatibility()).check(_this6.resolver.getManifests(), _this6.config, _this6.flags.ignoreEngines); - })); - }); - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('linkStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // remove integrity hash to make this operation atomic - yield _this6.integrityChecker.removeIntegrityFile(); - _this6.reporter.step(curr, total, _this6.reporter.lang('linkingDependencies'), emoji.get('link')); - flattenedTopLevelPatterns = _this6.preparePatternsForLinking(flattenedTopLevelPatterns, manifest, _this6.config.lockfileFolder === _this6.config.cwd); - yield _this6.linker.init(flattenedTopLevelPatterns, workspaceLayout, { - linkDuplicates: _this6.flags.linkDuplicates, - ignoreOptional: _this6.flags.ignoreOptional - }); - })); - }); - - if (_this6.config.plugnplayEnabled) { - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('pnpStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const pnpPath = `${_this6.config.lockfileFolder}/${(_constants || _load_constants()).PNP_FILENAME}`; - - const code = yield (0, (_generatePnpMap || _load_generatePnpMap()).generatePnpMap)(_this6.config, flattenedTopLevelPatterns, { - resolver: _this6.resolver, - reporter: _this6.reporter, - targetPath: pnpPath, - workspaceLayout - }); - - try { - const file = yield (_fs || _load_fs()).readFile(pnpPath); - if (file === code) { - return; - } - } catch (error) {} - - yield (_fs || _load_fs()).writeFile(pnpPath, code); - yield (_fs || _load_fs()).chmod(pnpPath, 0o755); - })); - }); - } - - steps.push(function (curr, total) { - return (0, (_hooks || _load_hooks()).callThroughHook)('buildStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - _this6.reporter.step(curr, total, _this6.flags.force ? _this6.reporter.lang('rebuildingPackages') : _this6.reporter.lang('buildingFreshPackages'), emoji.get('hammer')); - - if (_this6.config.ignoreScripts) { - _this6.reporter.warn(_this6.reporter.lang('ignoredScripts')); - } else { - yield _this6.scripts.init(flattenedTopLevelPatterns); - } - })); - }); - - if (_this6.flags.har) { - steps.push((() => { - var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { - const formattedDate = new Date().toISOString().replace(/:/g, '-'); - const filename = `yarn-install_${formattedDate}.har`; - _this6.reporter.step(curr, total, _this6.reporter.lang('savingHar', filename), emoji.get('black_circle_for_record')); - yield _this6.config.requestManager.saveHar(filename); - }); - - return function (_x3, _x4) { - return _ref21.apply(this, arguments); - }; - })()); - } - - if (yield _this6.shouldClean()) { - steps.push((() => { - var _ref22 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { - _this6.reporter.step(curr, total, _this6.reporter.lang('cleaningModules'), emoji.get('recycle')); - yield (0, (_autoclean || _load_autoclean()).clean)(_this6.config, _this6.reporter); - }); - - return function (_x5, _x6) { - return _ref22.apply(this, arguments); - }; - })()); - } - - let currentStep = 0; - for (var _iterator11 = steps, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { - var _ref23; - - if (_isArray11) { - if (_i11 >= _iterator11.length) break; - _ref23 = _iterator11[_i11++]; - } else { - _i11 = _iterator11.next(); - if (_i11.done) break; - _ref23 = _i11.value; - } - - const step = _ref23; - - const stepResult = yield step(++currentStep, steps.length); - if (stepResult && stepResult.bailout) { - if (_this6.flags.audit) { - audit.summary(); - } - if (auditFoundProblems) { - _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); - } - _this6.maybeOutputUpdate(); - return flattenedTopLevelPatterns; - } - } - - // fin! - if (_this6.flags.audit) { - audit.summary(); - } - if (auditFoundProblems) { - _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); - } - yield _this6.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); - yield _this6.persistChanges(); - _this6.maybeOutputUpdate(); - _this6.config.requestManager.clearCache(); - return flattenedTopLevelPatterns; - })(); - } - - checkCompatibility() { - var _this7 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - var _ref24 = yield _this7.fetchRequestFromCwd(); - - const manifest = _ref24.manifest; - - yield (_packageCompatibility || _load_packageCompatibility()).checkOne(manifest, _this7.config, _this7.flags.ignoreEngines); - })(); - } - - persistChanges() { - var _this8 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - // get all the different registry manifests in this folder - const manifests = yield _this8.config.getRootManifests(); - - if (yield _this8.applyChanges(manifests)) { - yield _this8.config.saveRootManifests(manifests); - } - })(); - } - - applyChanges(manifests) { - let hasChanged = false; - - if (this.config.plugnplayPersist) { - const object = manifests.npm.object; - - - if (typeof object.installConfig !== 'object') { - object.installConfig = {}; - } - - if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { - object.installConfig.pnp = true; - hasChanged = true; - } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { - delete object.installConfig.pnp; - hasChanged = true; - } - - if (Object.keys(object.installConfig).length === 0) { - delete object.installConfig; - } - } - - return Promise.resolve(hasChanged); - } - - /** - * Check if we should run the cleaning step. - */ - - shouldClean() { - return (_fs || _load_fs()).exists(path.join(this.config.lockfileFolder, (_constants || _load_constants()).CLEAN_FILENAME)); - } - - /** - * TODO - */ - - flatten(patterns) { - var _this9 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - if (!_this9.flags.flat) { - return patterns; - } - - const flattenedPatterns = []; - - for (var _iterator12 = _this9.resolver.getAllDependencyNamesByLevelOrder(patterns), _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { - var _ref25; - - if (_isArray12) { - if (_i12 >= _iterator12.length) break; - _ref25 = _iterator12[_i12++]; - } else { - _i12 = _iterator12.next(); - if (_i12.done) break; - _ref25 = _i12.value; - } - - const name = _ref25; - - const infos = _this9.resolver.getAllInfoForPackageName(name).filter(function (manifest) { - const ref = manifest._reference; - invariant(ref, 'expected package reference'); - return !ref.ignore; - }); - - if (infos.length === 0) { - continue; - } - - if (infos.length === 1) { - // single version of this package - // take out a single pattern as multiple patterns may have resolved to this package - flattenedPatterns.push(_this9.resolver.patternsByPackage[name][0]); - continue; - } - - const options = infos.map(function (info) { - const ref = info._reference; - invariant(ref, 'expected reference'); - return { - // TODO `and is required by {PARENT}`, - name: _this9.reporter.lang('manualVersionResolutionOption', ref.patterns.join(', '), info.version), - - value: info.version - }; - }); - const versions = infos.map(function (info) { - return info.version; - }); - let version; - - const resolutionVersion = _this9.resolutions[name]; - if (resolutionVersion && versions.indexOf(resolutionVersion) >= 0) { - // use json `resolution` version - version = resolutionVersion; - } else { - version = yield _this9.reporter.select(_this9.reporter.lang('manualVersionResolution', name), _this9.reporter.lang('answer'), options); - _this9.resolutions[name] = version; - } - - flattenedPatterns.push(_this9.resolver.collapseAllVersionsOfPackage(name, version)); - } - - // save resolutions to their appropriate root manifest - if (Object.keys(_this9.resolutions).length) { - const manifests = yield _this9.config.getRootManifests(); - - for (const name in _this9.resolutions) { - const version = _this9.resolutions[name]; - - const patterns = _this9.resolver.patternsByPackage[name]; - if (!patterns) { - continue; - } - - let manifest; - for (var _iterator13 = patterns, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { - var _ref26; - - if (_isArray13) { - if (_i13 >= _iterator13.length) break; - _ref26 = _iterator13[_i13++]; - } else { - _i13 = _iterator13.next(); - if (_i13.done) break; - _ref26 = _i13.value; - } - - const pattern = _ref26; - - manifest = _this9.resolver.getResolvedPattern(pattern); - if (manifest) { - break; - } - } - invariant(manifest, 'expected manifest'); - - const ref = manifest._reference; - invariant(ref, 'expected reference'); - - const object = manifests[ref.registry].object; - object.resolutions = object.resolutions || {}; - object.resolutions[name] = version; - } - - yield _this9.config.saveRootManifests(manifests); - } - - return flattenedPatterns; - })(); - } - - /** - * Remove offline tarballs that are no longer required - */ - - pruneOfflineMirror(lockfile) { - var _this10 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const mirror = _this10.config.getOfflineMirrorPath(); - if (!mirror) { - return; - } - - const requiredTarballs = new Set(); - for (const dependency in lockfile) { - const resolved = lockfile[dependency].resolved; - if (resolved) { - const basename = path.basename(resolved.split('#')[0]); - if (dependency[0] === '@' && basename[0] !== '@') { - requiredTarballs.add(`${dependency.split('/')[0]}-${basename}`); - } - requiredTarballs.add(basename); - } - } - - const mirrorFiles = yield (_fs || _load_fs()).walk(mirror); - for (var _iterator14 = mirrorFiles, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { - var _ref27; - - if (_isArray14) { - if (_i14 >= _iterator14.length) break; - _ref27 = _iterator14[_i14++]; - } else { - _i14 = _iterator14.next(); - if (_i14.done) break; - _ref27 = _i14.value; - } - - const file = _ref27; - - const isTarball = path.extname(file.basename) === '.tgz'; - // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt packages - const hasPrebuiltPackage = file.relative.startsWith('prebuilt/'); - if (isTarball && !hasPrebuiltPackage && !requiredTarballs.has(file.basename)) { - yield (_fs || _load_fs()).unlink(file.absolute); - } - } - })(); - } - - /** - * Save updated integrity and lockfiles. - */ - - saveLockfileAndIntegrity(patterns, workspaceLayout) { - var _this11 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const resolvedPatterns = {}; - Object.keys(_this11.resolver.patterns).forEach(function (pattern) { - if (!workspaceLayout || !workspaceLayout.getManifestByPattern(pattern)) { - resolvedPatterns[pattern] = _this11.resolver.patterns[pattern]; - } - }); - - // TODO this code is duplicated in a few places, need a common way to filter out workspace patterns from lockfile - patterns = patterns.filter(function (p) { - return !workspaceLayout || !workspaceLayout.getManifestByPattern(p); - }); - - const lockfileBasedOnResolver = _this11.lockfile.getLockfile(resolvedPatterns); - - if (_this11.config.pruneOfflineMirror) { - yield _this11.pruneOfflineMirror(lockfileBasedOnResolver); - } - - // write integrity hash - if (!_this11.config.plugnplayEnabled) { - yield _this11.integrityChecker.save(patterns, lockfileBasedOnResolver, _this11.flags, workspaceLayout, _this11.scripts.getArtifacts()); - } - - // --no-lockfile or --pure-lockfile or --frozen-lockfile - if (_this11.flags.lockfile === false || _this11.flags.pureLockfile || _this11.flags.frozenLockfile) { - return; - } - - const lockFileHasAllPatterns = patterns.every(function (p) { - return _this11.lockfile.getLocked(p); - }); - const lockfilePatternsMatch = Object.keys(_this11.lockfile.cache || {}).every(function (p) { - return lockfileBasedOnResolver[p]; - }); - const resolverPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { - const manifest = _this11.lockfile.getLocked(pattern); - return manifest && manifest.resolved === lockfileBasedOnResolver[pattern].resolved && deepEqual(manifest.prebuiltVariants, lockfileBasedOnResolver[pattern].prebuiltVariants); - }); - const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { - const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity; - if (!existingIntegrityInfo) { - // if this entry does not have an integrity, no need to re-write the lockfile because of it - return true; - } - const manifest = _this11.lockfile.getLocked(pattern); - if (manifest && manifest.integrity) { - const manifestIntegrity = ssri.stringify(manifest.integrity); - return manifestIntegrity === existingIntegrityInfo; - } - return false; - }); - - // remove command is followed by install with force, lockfile will be rewritten in any case then - if (!_this11.flags.force && _this11.lockfile.parseResultType === 'success' && lockFileHasAllPatterns && lockfilePatternsMatch && resolverPatternsAreSameAsInLockfile && integrityPatternsAreSameAsInLockfile && patterns.length) { - return; - } - - // build lockfile location - const loc = path.join(_this11.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME); - - // write lockfile - const lockSource = (0, (_lockfile2 || _load_lockfile2()).stringify)(lockfileBasedOnResolver, false, _this11.config.enableLockfileVersions); - yield (_fs || _load_fs()).writeFilePreservingEol(loc, lockSource); - - _this11._logSuccessSaveLockfile(); - })(); - } - - _logSuccessSaveLockfile() { - this.reporter.success(this.reporter.lang('savedLockfile')); - } - - /** - * Load the dependency graph of the current install. Only does package resolving and wont write to the cwd. - */ - hydrate(ignoreUnusedPatterns) { - var _this12 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - const request = yield _this12.fetchRequestFromCwd([], ignoreUnusedPatterns); - const depRequests = request.requests, - rawPatterns = request.patterns, - ignorePatterns = request.ignorePatterns, - workspaceLayout = request.workspaceLayout; - - - yield _this12.resolver.init(depRequests, { - isFlat: _this12.flags.flat, - isFrozen: _this12.flags.frozenLockfile, - workspaceLayout - }); - yield _this12.flatten(rawPatterns); - _this12.markIgnored(ignorePatterns); - - // fetch packages, should hit cache most of the time - const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this12.resolver.getManifests(), _this12.config); - _this12.resolver.updateManifests(manifests); - yield (_packageCompatibility || _load_packageCompatibility()).check(_this12.resolver.getManifests(), _this12.config, _this12.flags.ignoreEngines); - - // expand minimal manifests - for (var _iterator15 = _this12.resolver.getManifests(), _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { - var _ref28; - - if (_isArray15) { - if (_i15 >= _iterator15.length) break; - _ref28 = _iterator15[_i15++]; - } else { - _i15 = _iterator15.next(); - if (_i15.done) break; - _ref28 = _i15.value; - } - - const manifest = _ref28; - - const ref = manifest._reference; - invariant(ref, 'expected reference'); - const type = ref.remote.type; - // link specifier won't ever hit cache - - let loc = ''; - if (type === 'link') { - continue; - } else if (type === 'workspace') { - if (!ref.remote.reference) { - continue; - } - loc = ref.remote.reference; - } else { - loc = _this12.config.generateModuleCachePath(ref); - } - const newPkg = yield _this12.config.readManifest(loc); - yield _this12.resolver.updateManifest(ref, newPkg); - } - - return request; - })(); - } - - /** - * Check for updates every day and output a nag message if there's a newer version. - */ - - checkUpdate() { - if (this.config.nonInteractive) { - // don't show upgrade dialog on CI or non-TTY terminals - return; - } - - // don't check if disabled - if (this.config.getOption('disable-self-update-check')) { - return; - } - - // only check for updates once a day - const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0; - if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) { - return; - } - - // don't bug for updates on tagged releases - if ((_yarnVersion || _load_yarnVersion()).version.indexOf('-') >= 0) { - return; - } - - this._checkUpdate().catch(() => { - // swallow errors - }); - } - - _checkUpdate() { - var _this13 = this; - - return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { - let latestVersion = yield _this13.config.requestManager.request({ - url: (_constants || _load_constants()).SELF_UPDATE_VERSION_URL - }); - invariant(typeof latestVersion === 'string', 'expected string'); - latestVersion = latestVersion.trim(); - if (!semver.valid(latestVersion)) { - return; - } - - // ensure we only check for updates periodically - _this13.config.registries.yarn.saveHomeConfig({ - lastUpdateCheck: Date.now() - }); - - if (semver.gt(latestVersion, (_yarnVersion || _load_yarnVersion()).version)) { - const installationMethod = yield (0, (_yarnVersion || _load_yarnVersion()).getInstallationMethod)(); - _this13.maybeOutputUpdate = function () { - _this13.reporter.warn(_this13.reporter.lang('yarnOutdated', latestVersion, (_yarnVersion || _load_yarnVersion()).version)); - - const command = getUpdateCommand(installationMethod); - if (command) { - _this13.reporter.info(_this13.reporter.lang('yarnOutdatedCommand')); - _this13.reporter.command(command); - } else { - const installer = getUpdateInstaller(installationMethod); - if (installer) { - _this13.reporter.info(_this13.reporter.lang('yarnOutdatedInstaller', installer)); - } - } - }; - } - })(); - } - - /** - * Method to override with a possible upgrade message. - */ - - maybeOutputUpdate() {} -} - -exports.Install = Install; -function hasWrapper(commander, args) { - return true; -} - -function setFlags(commander) { - commander.description('Yarn install is used to install all dependencies for a project.'); - commander.usage('install [flags]'); - commander.option('-A, --audit', 'Run vulnerability audit on installed packages'); - commander.option('-g, --global', 'DEPRECATED'); - commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`'); - commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`'); - commander.option('-P, --save-peer', 'DEPRECATED - save package to your `peerDependencies`'); - commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`'); - commander.option('-E, --save-exact', 'DEPRECATED'); - commander.option('-T, --save-tilde', 'DEPRECATED'); -} - -/***/ }), -/* 35 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(53); -module.exports = function (it) { - if (!isObject(it)) throw TypeError(it + ' is not an object!'); - return it; -}; - - -/***/ }), -/* 36 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return SubjectSubscriber; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subject; }); -/* unused harmony export AnonymousSubject */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Observable__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Subscriber__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__ = __webpack_require__(190); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__ = __webpack_require__(422); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__ = __webpack_require__(321); -/** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ - - - - - - - -var SubjectSubscriber = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SubjectSubscriber, _super); - function SubjectSubscriber(destination) { - var _this = _super.call(this, destination) || this; - _this.destination = destination; - return _this; - } - return SubjectSubscriber; -}(__WEBPACK_IMPORTED_MODULE_2__Subscriber__["a" /* Subscriber */])); - -var Subject = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subject, _super); - function Subject() { - var _this = _super.call(this) || this; - _this.observers = []; - _this.closed = false; - _this.isStopped = false; - _this.hasError = false; - _this.thrownError = null; - return _this; - } - Subject.prototype[__WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { - return new SubjectSubscriber(this); - }; - Subject.prototype.lift = function (operator) { - var subject = new AnonymousSubject(this, this); - subject.operator = operator; - return subject; - }; - Subject.prototype.next = function (value) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - if (!this.isStopped) { - var observers = this.observers; - var len = observers.length; - var copy = observers.slice(); - for (var i = 0; i < len; i++) { - copy[i].next(value); - } - } - }; - Subject.prototype.error = function (err) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - this.hasError = true; - this.thrownError = err; - this.isStopped = true; - var observers = this.observers; - var len = observers.length; - var copy = observers.slice(); - for (var i = 0; i < len; i++) { - copy[i].error(err); - } - this.observers.length = 0; - }; - Subject.prototype.complete = function () { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - this.isStopped = true; - var observers = this.observers; - var len = observers.length; - var copy = observers.slice(); - for (var i = 0; i < len; i++) { - copy[i].complete(); - } - this.observers.length = 0; - }; - Subject.prototype.unsubscribe = function () { - this.isStopped = true; - this.closed = true; - this.observers = null; - }; - Subject.prototype._trySubscribe = function (subscriber) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - else { - return _super.prototype._trySubscribe.call(this, subscriber); - } - }; - Subject.prototype._subscribe = function (subscriber) { - if (this.closed) { - throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); - } - else if (this.hasError) { - subscriber.error(this.thrownError); - return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; - } - else if (this.isStopped) { - subscriber.complete(); - return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; - } - else { - this.observers.push(subscriber); - return new __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__["a" /* SubjectSubscription */](this, subscriber); - } - }; - Subject.prototype.asObservable = function () { - var observable = new __WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */](); - observable.source = this; - return observable; - }; - Subject.create = function (destination, source) { - return new AnonymousSubject(destination, source); - }; - return Subject; -}(__WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */])); - -var AnonymousSubject = /*@__PURE__*/ (function (_super) { - __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](AnonymousSubject, _super); - function AnonymousSubject(destination, source) { - var _this = _super.call(this) || this; - _this.destination = destination; - _this.source = source; - return _this; - } - AnonymousSubject.prototype.next = function (value) { - var destination = this.destination; - if (destination && destination.next) { - destination.next(value); - } - }; - AnonymousSubject.prototype.error = function (err) { - var destination = this.destination; - if (destination && destination.error) { - this.destination.error(err); - } - }; - AnonymousSubject.prototype.complete = function () { - var destination = this.destination; - if (destination && destination.complete) { - this.destination.complete(); - } - }; - AnonymousSubject.prototype._subscribe = function (subscriber) { - var source = this.source; - if (source) { - return this.source.subscribe(subscriber); - } - else { - return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; - } - }; - return AnonymousSubject; -}(Subject)); - -//# sourceMappingURL=Subject.js.map - - -/***/ }), -/* 37 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.normalizePattern = normalizePattern; - -/** - * Explode and normalize a pattern into its name and range. - */ - -function normalizePattern(pattern) { - let hasVersion = false; - let range = 'latest'; - let name = pattern; - - // if we're a scope then remove the @ and add it back later - let isScoped = false; - if (name[0] === '@') { - isScoped = true; - name = name.slice(1); - } - - // take first part as the name - const parts = name.split('@'); - if (parts.length > 1) { - name = parts.shift(); - range = parts.join('@'); - - if (range) { - hasVersion = true; - } else { - range = '*'; - } - } - - // add back @ scope suffix - if (isScoped) { - name = `@${name}`; - } - - return { name, range, hasVersion }; -} - -/***/ }), -/* 38 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {var __WEBPACK_AMD_DEFINE_RESULT__;/** - * @license - * Lodash - * Copyright JS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '4.17.10'; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Error message constants. */ - var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', - FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; - - /** Used as the maximum memoize cache size. */ - var MAX_MEMOIZE_SIZE = 500; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** Used to compose bitmasks for cloning. */ - var CLONE_DEEP_FLAG = 1, - CLONE_FLAT_FLAG = 2, - CLONE_SYMBOLS_FLAG = 4; - - /** Used to compose bitmasks for value comparisons. */ - var COMPARE_PARTIAL_FLAG = 1, - COMPARE_UNORDERED_FLAG = 2; - - /** Used to compose bitmasks for function metadata. */ - var WRAP_BIND_FLAG = 1, - WRAP_BIND_KEY_FLAG = 2, - WRAP_CURRY_BOUND_FLAG = 4, - WRAP_CURRY_FLAG = 8, - WRAP_CURRY_RIGHT_FLAG = 16, - WRAP_PARTIAL_FLAG = 32, - WRAP_PARTIAL_RIGHT_FLAG = 64, - WRAP_ARY_FLAG = 128, - WRAP_REARG_FLAG = 256, - WRAP_FLIP_FLAG = 512; - - /** Used as default options for `_.truncate`. */ - var DEFAULT_TRUNC_LENGTH = 30, - DEFAULT_TRUNC_OMISSION = '...'; - - /** Used to detect hot functions by number of calls within a span of milliseconds. */ - var HOT_COUNT = 800, - HOT_SPAN = 16; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2, - LAZY_WHILE_FLAG = 3; - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308, - NAN = 0 / 0; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** Used to associate wrap methods with their bit flags. */ - var wrapFlags = [ - ['ary', WRAP_ARY_FLAG], - ['bind', WRAP_BIND_FLAG], - ['bindKey', WRAP_BIND_KEY_FLAG], - ['curry', WRAP_CURRY_FLAG], - ['curryRight', WRAP_CURRY_RIGHT_FLAG], - ['flip', WRAP_FLIP_FLAG], - ['partial', WRAP_PARTIAL_FLAG], - ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], - ['rearg', WRAP_REARG_FLAG] - ]; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - asyncTag = '[object AsyncFunction]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - domExcTag = '[object DOMException]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - nullTag = '[object Null]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - proxyTag = '[object Proxy]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - undefinedTag = '[object Undefined]', - weakMapTag = '[object WeakMap]', - weakSetTag = '[object WeakSet]'; - - var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, - reEvaluate = /<%([\s\S]+?)%>/g, - reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - - /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, - reHasRegExpChar = RegExp(reRegExpChar.source); - - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g, - reTrimStart = /^\s+/, - reTrimEnd = /\s+$/; - - /** Used to match wrap detail comments. */ - var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, - reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, - reSplitDetails = /,? & /; - - /** Used to match words composed of alphanumeric characters. */ - var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** - * Used to match - * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). - */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect bad signed hexadecimal string values. */ - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - - /** Used to detect binary string values. */ - var reIsBinary = /^0b[01]+$/i; - - /** Used to detect host constructors (Safari). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect octal string values. */ - var reIsOctal = /^0o[0-7]+$/i; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; - - /** Used to match Latin Unicode letters (excluding mathematical operators). */ - var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; - - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - - /** Used to compose unicode character classes. */ - var rsAstralRange = '\\ud800-\\udfff', - rsComboMarksRange = '\\u0300-\\u036f', - reComboHalfMarksRange = '\\ufe20-\\ufe2f', - rsComboSymbolsRange = '\\u20d0-\\u20ff', - rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, - rsDingbatRange = '\\u2700-\\u27bf', - rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', - rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', - rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', - rsPunctuationRange = '\\u2000-\\u206f', - rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', - rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', - rsVarRange = '\\ufe0e\\ufe0f', - rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; - - /** Used to compose unicode capture groups. */ - var rsApos = "['\u2019]", - rsAstral = '[' + rsAstralRange + ']', - rsBreak = '[' + rsBreakRange + ']', - rsCombo = '[' + rsComboRange + ']', - rsDigits = '\\d+', - rsDingbat = '[' + rsDingbatRange + ']', - rsLower = '[' + rsLowerRange + ']', - rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', - rsFitz = '\\ud83c[\\udffb-\\udfff]', - rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', - rsNonAstral = '[^' + rsAstralRange + ']', - rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', - rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', - rsUpper = '[' + rsUpperRange + ']', - rsZWJ = '\\u200d'; - - /** Used to compose unicode regexes. */ - var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', - rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', - rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', - rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', - reOptMod = rsModifier + '?', - rsOptVar = '[' + rsVarRange + ']?', - rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', - rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', - rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', - rsSeq = rsOptVar + reOptMod + rsOptJoin, - rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, - rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; - - /** Used to match apostrophes. */ - var reApos = RegExp(rsApos, 'g'); - - /** - * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and - * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). - */ - var reComboMark = RegExp(rsCombo, 'g'); - - /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ - var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); - - /** Used to match complex or compound words. */ - var reUnicodeWord = RegExp([ - rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', - rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', - rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, - rsUpper + '+' + rsOptContrUpper, - rsOrdUpper, - rsOrdLower, - rsDigits, - rsEmoji - ].join('|'), 'g'); - - /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ - var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); - - /** Used to detect strings that need a more robust regexp to match words. */ - var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; - - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', - 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' - ]; - - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = - typedArrayTags[errorTag] = typedArrayTags[funcTag] = - typedArrayTags[mapTag] = typedArrayTags[numberTag] = - typedArrayTags[objectTag] = typedArrayTags[regexpTag] = - typedArrayTags[setTag] = typedArrayTags[stringTag] = - typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = - cloneableTags[boolTag] = cloneableTags[dateTag] = - cloneableTags[float32Tag] = cloneableTags[float64Tag] = - cloneableTags[int8Tag] = cloneableTags[int16Tag] = - cloneableTags[int32Tag] = cloneableTags[mapTag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[setTag] = - cloneableTags[stringTag] = cloneableTags[symbolTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map Latin Unicode letters to basic Latin letters. */ - var deburredLetters = { - // Latin-1 Supplement block. - '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', - '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', - '\xc7': 'C', '\xe7': 'c', - '\xd0': 'D', '\xf0': 'd', - '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', - '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', - '\xd1': 'N', '\xf1': 'n', - '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', - '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', - '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', - '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', - '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', - '\xc6': 'Ae', '\xe6': 'ae', - '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss', - // Latin Extended-A block. - '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', - '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', - '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', - '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', - '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', - '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', - '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', - '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', - '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', - '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', - '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', - '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', - '\u0134': 'J', '\u0135': 'j', - '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', - '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', - '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', - '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', - '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', - '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', - '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', - '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', - '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', - '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', - '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', - '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', - '\u0163': 't', '\u0165': 't', '\u0167': 't', - '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', - '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', - '\u0174': 'W', '\u0175': 'w', - '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', - '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', - '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', - '\u0132': 'IJ', '\u0133': 'ij', - '\u0152': 'Oe', '\u0153': 'oe', - '\u0149': "'n", '\u017f': 's' - }; - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - }; - - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" - }; - - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - /** Built-in method references without a dependency on `root`. */ - var freeParseFloat = parseFloat, - freeParseInt = parseInt; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; - - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; - - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - // Use `util.types` for Node.js 10+. - var types = freeModule && freeModule.require && freeModule.require('util').types; - - if (types) { - return types; - } - - // Legacy `process.binding('util')` for Node.js < 10. - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} - }()); - - /* Node.js helper references. */ - var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, - nodeIsDate = nodeUtil && nodeUtil.isDate, - nodeIsMap = nodeUtil && nodeUtil.isMap, - nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, - nodeIsSet = nodeUtil && nodeUtil.isSet, - nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - - /*--------------------------------------------------------------------------*/ - - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } - - /** - * A specialized version of `baseAggregator` for arrays. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function arrayAggregator(array, setter, iteratee, accumulator) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - var value = array[index]; - setter(accumulator, value, iteratee(value), array); - } - return accumulator; - } - - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.forEachRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEachRight(array, iteratee) { - var length = array == null ? 0 : array.length; - - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - - /** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludes(array, value) { - var length = array == null ? 0 : array.length; - return !!length && baseIndexOf(array, value, 0) > -1; - } - - /** - * This function is like `arrayIncludes` except that it accepts a comparator. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @param {Function} comparator The comparator invoked per element. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludesWith(array, value, comparator) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (comparator(value, array[index])) { - return true; - } - } - return false; - } - - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } - - /** - * A specialized version of `_.reduce` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the first element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initAccum) { - var index = -1, - length = array == null ? 0 : array.length; - - if (initAccum && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - - /** - * A specialized version of `_.reduceRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the last element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initAccum) { - var length = array == null ? 0 : array.length; - if (initAccum && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } - - /** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } - - /** - * Gets the size of an ASCII `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - var asciiSize = baseProperty('length'); - - /** - * Converts an ASCII `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function asciiToArray(string) { - return string.split(''); - } - - /** - * Splits an ASCII `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function asciiWords(string) { - return string.match(reAsciiWord) || []; - } - - /** - * The base implementation of methods like `_.findKey` and `_.findLastKey`, - * without support for iteratee shorthands, which iterates over `collection` - * using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFindKey(collection, predicate, eachFunc) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = key; - return false; - } - }); - return result; - } - - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - return value === value - ? strictIndexOf(array, value, fromIndex) - : baseFindIndex(array, baseIsNaN, fromIndex); - } - - /** - * This function is like `baseIndexOf` except that it accepts a comparator. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @param {Function} comparator The comparator invoked per element. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOfWith(array, value, fromIndex, comparator) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (comparator(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.isNaN` without support for number objects. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - */ - function baseIsNaN(value) { - return value !== value; - } - - /** - * The base implementation of `_.mean` and `_.meanBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the mean. - */ - function baseMean(array, iteratee) { - var length = array == null ? 0 : array.length; - return length ? (baseSum(array, iteratee) / length) : NAN; - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.propertyOf` without support for deep paths. - * - * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.sortBy` which uses `comparer` to define the - * sort order of `array` and replaces criteria objects with their corresponding - * values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - - /** - * The base implementation of `_.sum` and `_.sumBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(array, iteratee) { - var result, - index = -1, - length = array.length; - - while (++index < length) { - var current = iteratee(array[index]); - if (current !== undefined) { - result = result === undefined ? current : (result + current); - } - } - return result; - } - - /** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ - function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; - } - - /** - * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array - * of key-value pairs for `object` corresponding to the property names of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the key-value pairs. - */ - function baseToPairs(object, props) { - return arrayMap(props, function(key) { - return [key, object[key]]; - }); - } - - /** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ - function baseUnary(func) { - return function(value) { - return func(value); - }; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); - } - - /** - * Checks if a `cache` value for `key` exists. - * - * @private - * @param {Object} cache The cache to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function cacheHas(cache, key) { - return cache.has(key); - } - - /** - * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the first unmatched string symbol. - */ - function charsStartIndex(strSymbols, chrSymbols) { - var index = -1, - length = strSymbols.length; - - while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the last unmatched string symbol. - */ - function charsEndIndex(strSymbols, chrSymbols) { - var index = strSymbols.length; - - while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Gets the number of `placeholder` occurrences in `array`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} placeholder The placeholder to search for. - * @returns {number} Returns the placeholder count. - */ - function countHolders(array, placeholder) { - var length = array.length, - result = 0; - - while (length--) { - if (array[length] === placeholder) { - ++result; - } - } - return result; - } - - /** - * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A - * letters to basic Latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - var deburrLetter = basePropertyOf(deburredLetters); - - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); - - /** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; - } - - /** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function getValue(object, key) { - return object == null ? undefined : object[key]; - } - - /** - * Checks if `string` contains Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a symbol is found, else `false`. - */ - function hasUnicode(string) { - return reHasUnicode.test(string); - } - - /** - * Checks if `string` contains a word composed of Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a word is found, else `false`. - */ - function hasUnicodeWord(string) { - return reHasUnicodeWord.test(string); - } - - /** - * Converts `iterator` to an array. - * - * @private - * @param {Object} iterator The iterator to convert. - * @returns {Array} Returns the converted array. - */ - function iteratorToArray(iterator) { - var data, - result = []; - - while (!(data = iterator.next()).done) { - result.push(data.value); - } - return result; - } - - /** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ - function mapToArray(map) { - var index = -1, - result = Array(map.size); - - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } - - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; - } - - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value === placeholder || value === PLACEHOLDER) { - array[index] = PLACEHOLDER; - result[resIndex++] = index; - } - } - return result; - } - - /** - * Gets the value at `key`, unless `key` is "__proto__". - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function safeGet(object, key) { - return key == '__proto__' - ? undefined - : object[key]; - } - - /** - * Converts `set` to an array of its values. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. - */ - function setToArray(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = value; - }); - return result; - } - - /** - * Converts `set` to its value-value pairs. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the value-value pairs. - */ - function setToPairs(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = [value, value]; - }); - return result; - } - - /** - * A specialized version of `_.indexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictIndexOf(array, value, fromIndex) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * A specialized version of `_.lastIndexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictLastIndexOf(array, value, fromIndex) { - var index = fromIndex + 1; - while (index--) { - if (array[index] === value) { - return index; - } - } - return index; - } - - /** - * Gets the number of symbols in `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the string size. - */ - function stringSize(string) { - return hasUnicode(string) - ? unicodeSize(string) - : asciiSize(string); - } - - /** - * Converts `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function stringToArray(string) { - return hasUnicode(string) - ? unicodeToArray(string) - : asciiToArray(string); - } - - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - var unescapeHtmlChar = basePropertyOf(htmlUnescapes); - - /** - * Gets the size of a Unicode `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - function unicodeSize(string) { - var result = reUnicode.lastIndex = 0; - while (reUnicode.test(string)) { - ++result; - } - return result; - } - - /** - * Converts a Unicode `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function unicodeToArray(string) { - return string.match(reUnicode) || []; - } - - /** - * Splits a Unicode `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function unicodeWords(string) { - return string.match(reUnicodeWord) || []; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Create a new pristine `lodash` function using the `context` object. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Util - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // Create a suped-up `defer` in Node.js. - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - var runInContext = (function runInContext(context) { - context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); - - /** Built-in constructor references. */ - var Array = context.Array, - Date = context.Date, - Error = context.Error, - Function = context.Function, - Math = context.Math, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** Used for built-in method references. */ - var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype; - - /** Used to detect overreaching core-js shims. */ - var coreJsData = context['__core-js_shared__']; - - /** Used to resolve the decompiled source of functions. */ - var funcToString = funcProto.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** Used to detect methods masquerading as native. */ - var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; - }()); - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var nativeObjectToString = objectProto.toString; - - /** Used to infer the `Object` constructor. */ - var objectCtorString = funcToString.call(Object); - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); - - /** Built-in value references. */ - var Buffer = moduleExports ? context.Buffer : undefined, - Symbol = context.Symbol, - Uint8Array = context.Uint8Array, - allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, - getPrototype = overArg(Object.getPrototypeOf, Object), - objectCreate = Object.create, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - splice = arrayProto.splice, - spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, - symIterator = Symbol ? Symbol.iterator : undefined, - symToStringTag = Symbol ? Symbol.toStringTag : undefined; - - var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} - }()); - - /** Mocked built-ins. */ - var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, - ctxNow = Date && Date.now !== root.Date.now && Date.now, - ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeFloor = Math.floor, - nativeGetSymbols = Object.getOwnPropertySymbols, - nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, - nativeIsFinite = context.isFinite, - nativeJoin = arrayProto.join, - nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max, - nativeMin = Math.min, - nativeNow = Date.now, - nativeParseInt = context.parseInt, - nativeRandom = Math.random, - nativeReverse = arrayProto.reverse; - - /* Built-in method references that are verified to be native. */ - var DataView = getNative(context, 'DataView'), - Map = getNative(context, 'Map'), - Promise = getNative(context, 'Promise'), - Set = getNative(context, 'Set'), - WeakMap = getNative(context, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /** Used to detect maps, sets, and weakmaps. */ - var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. - * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array and iteratees accept only - * one argument. The heuristic for whether a section qualifies for shortcut - * fusion is subject to change. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, - * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, - * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, - * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, - * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, - * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, - * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, - * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, - * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, - * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, - * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, - * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, - * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, - * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, - * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, - * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, - * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, - * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, - * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, - * `upperFirst`, `value`, and `words` - * - * @name _ - * @constructor - * @category Seq - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2, 3]); - * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); - * // => 6 - * - * // Returns a wrapped value. - * var squares = wrapped.map(square); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} proto The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = (function() { - function object() {} - return function(proto) { - if (!isObject(proto)) { - return {}; - } - if (objectCreate) { - return objectCreate(proto); - } - object.prototype = proto; - var result = new object; - object.prototype = undefined; - return result; - }; - }()); - - /** - * The function whose prototype chain sequence wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } - - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. - */ - function LodashWrapper(value, chainAll) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__chain__ = !!chainAll; - this.__index__ = 0; - this.__values__ = undefined; - } - - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB) as well as ES2015 template strings. Change the - * following template settings to use alternative delimiters. - * - * @static - * @memberOf _ - * @type {Object} - */ - lodash.templateSettings = { - - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'escape': reEscape, - - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'evaluate': reEvaluate, - - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'interpolate': reInterpolate, - - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type {string} - */ - 'variable': '', - - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type {Object} - */ - 'imports': { - - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type {Function} - */ - '_': lodash - } - }; - - // Ensure wrappers are instances of `baseLodash`. - lodash.prototype = baseLodash.prototype; - lodash.prototype.constructor = lodash; - - LodashWrapper.prototype = baseCreate(baseLodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @constructor - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = MAX_ARRAY_LENGTH; - this.__views__ = []; - } - - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = copyArray(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = copyArray(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = copyArray(this.__views__); - return result; - } - - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } - - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || (!isRight && arrLength == length && takeCount == length)) { - return baseWrapperValue(array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - result[resIndex++] = value; - } - return result; - } - - // Ensure `LazyWrapper` is an instance of `baseLodash`. - LazyWrapper.prototype = baseCreate(baseLodash.prototype); - LazyWrapper.prototype.constructor = LazyWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Hash(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; - } - - /** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; - } - - /** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; - } - - /** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); - } - - /** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ - function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; - } - - // Add methods to `Hash`. - Hash.prototype.clear = hashClear; - Hash.prototype['delete'] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ - function listCacheClear() { - this.__data__ = []; - this.size = 0; - } - - /** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; - } - - /** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; - } - - /** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; - } - - /** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ - function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; - } - - // Add methods to `ListCache`. - ListCache.prototype.clear = listCacheClear; - ListCache.prototype['delete'] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function MapCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ - function mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; - } - - /** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; - } - - /** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - - /** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - - /** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ - function mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; - } - - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var index = -1, - length = values == null ? 0 : values.length; - - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } - } - - /** - * Adds `value` to the array cache. - * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. - */ - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } - - /** - * Checks if `value` is in the array cache. - * - * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. - */ - function setCacheHas(value) { - return this.__data__.has(value); - } - - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Stack(entries) { - var data = this.__data__ = new ListCache(entries); - this.size = data.size; - } - - /** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ - function stackClear() { - this.__data__ = new ListCache; - this.size = 0; - } - - /** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function stackDelete(key) { - var data = this.__data__, - result = data['delete'](key); - - this.size = data.size; - return result; - } - - /** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function stackGet(key) { - return this.__data__.get(key); - } - - /** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function stackHas(key) { - return this.__data__.has(key); - } - - /** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ - function stackSet(key, value) { - var data = this.__data__; - if (data instanceof ListCache) { - var pairs = data.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - this.size = ++data.size; - return this; - } - data = this.__data__ = new MapCache(pairs); - } - data.set(key, value); - this.size = data.size; - return this; - } - - // Add methods to `Stack`. - Stack.prototype.clear = stackClear; - Stack.prototype['delete'] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ - function arrayLikeKeys(value, inherited) { - var isArr = isArray(value), - isArg = !isArr && isArguments(value), - isBuff = !isArr && !isArg && isBuffer(value), - isType = !isArr && !isArg && !isBuff && isTypedArray(value), - skipIndexes = isArr || isArg || isBuff || isType, - result = skipIndexes ? baseTimes(value.length, String) : [], - length = result.length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && ( - // Safari 9 has enumerable `arguments.length` in strict mode. - key == 'length' || - // Node.js 0.10 has enumerable non-index properties on buffers. - (isBuff && (key == 'offset' || key == 'parent')) || - // PhantomJS 2 has enumerable non-index properties on typed arrays. - (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || - // Skip index properties. - isIndex(key, length) - ))) { - result.push(key); - } - } - return result; - } - - /** - * A specialized version of `_.sample` for arrays. - * - * @private - * @param {Array} array The array to sample. - * @returns {*} Returns the random element. - */ - function arraySample(array) { - var length = array.length; - return length ? array[baseRandom(0, length - 1)] : undefined; - } - - /** - * A specialized version of `_.sampleSize` for arrays. - * - * @private - * @param {Array} array The array to sample. - * @param {number} n The number of elements to sample. - * @returns {Array} Returns the random elements. - */ - function arraySampleSize(array, n) { - return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); - } - - /** - * A specialized version of `_.shuffle` for arrays. - * - * @private - * @param {Array} array The array to shuffle. - * @returns {Array} Returns the new shuffled array. - */ - function arrayShuffle(array) { - return shuffleSelf(copyArray(array)); - } - - /** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } - - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } - - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; - } - - /** - * Aggregates elements of `collection` on `accumulator` with keys transformed - * by `iteratee` and values set by `setter`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function baseAggregator(collection, setter, iteratee, accumulator) { - baseEach(collection, function(value, key, collection) { - setter(accumulator, value, iteratee(value), collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); - } - - /** - * The base implementation of `_.assignIn` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssignIn(object, source) { - return object && copyObject(source, keysIn(source), object); - } - - /** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); - } else { - object[key] = value; - } - } - - /** - * The base implementation of `_.at` without support for individual paths. - * - * @private - * @param {Object} object The object to iterate over. - * @param {string[]} paths The property paths to pick. - * @returns {Array} Returns the picked elements. - */ - function baseAt(object, paths) { - var index = -1, - length = paths.length, - result = Array(length), - skip = object == null; - - while (++index < length) { - result[index] = skip ? undefined : get(object, paths[index]); - } - return result; - } - - /** - * The base implementation of `_.clamp` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - */ - function baseClamp(number, lower, upper) { - if (number === number) { - if (upper !== undefined) { - number = number <= upper ? number : upper; - } - if (lower !== undefined) { - number = number >= lower ? number : lower; - } - } - return number; - } - - /** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} bitmask The bitmask flags. - * 1 - Deep clone - * 2 - Flatten inherited properties - * 4 - Clone symbols - * @param {Function} [customizer] The function to customize cloning. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, bitmask, customizer, key, object, stack) { - var result, - isDeep = bitmask & CLONE_DEEP_FLAG, - isFlat = bitmask & CLONE_FLAT_FLAG, - isFull = bitmask & CLONE_SYMBOLS_FLAG; - - if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return copyArray(value, result); - } - } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; - - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = (isFlat || isFunc) ? {} : initCloneObject(value); - if (!isDeep) { - return isFlat - ? copySymbolsIn(value, baseAssignIn(result, value)) - : copySymbols(value, baseAssign(result, value)); - } - } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, isDeep); - } - } - // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); - - if (isSet(value)) { - value.forEach(function(subValue) { - result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); - }); - - return result; - } - - if (isMap(value)) { - value.forEach(function(subValue, key) { - result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - - return result; - } - - var keysFunc = isFull - ? (isFlat ? getAllKeysIn : getAllKeys) - : (isFlat ? keysIn : keys); - - var props = isArr ? undefined : keysFunc(value); - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; - } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - return result; - } - - /** - * The base implementation of `_.conforms` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new spec function. - */ - function baseConforms(source) { - var props = keys(source); - return function(object) { - return baseConformsTo(object, source, props); - }; - } - - /** - * The base implementation of `_.conformsTo` which accepts `props` to check. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - */ - function baseConformsTo(object, source, props) { - var length = props.length; - if (object == null) { - return !length; - } - object = Object(object); - while (length--) { - var key = props[length], - predicate = source[key], - value = object[key]; - - if ((value === undefined && !(key in object)) || !predicate(value)) { - return false; - } - } - return true; - } - - /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * The base implementation of methods like `_.difference` without support - * for excluding multiple arrays or iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - isCommon = true, - length = array.length, - result = [], - valuesLength = values.length; - - if (!length) { - return result; - } - if (iteratee) { - values = arrayMap(values, baseUnary(iteratee)); - } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; - } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee == null ? value : iteratee(value); - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } - } - result.push(value); - } - else if (!includes(values, computed, comparator)) { - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.forEach` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.forEachRight` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); - - /** - * The base implementation of `_.every` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } - - /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index], - current = iteratee(value); - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : comparator(current, computed) - )) { - var computed = current, - result = value; - } - } - return result; - } - - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; - - start = toInteger(start); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : toInteger(end); - if (end < 0) { - end += length; - } - end = start > end ? 0 : toLength(end); - while (start < end) { - array[start++] = value; - } - return array; - } - - /** - * The base implementation of `_.filter` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } - - /** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } - - /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); - } - - /** - * The base implementation of `_.forOwnRight` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return object && baseForRight(object, iteratee, keys); - } - - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. - */ - function baseFunctions(object, props) { - return arrayFilter(props, function(key) { - return isFunction(object[key]); - }); - } - - /** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path) { - path = castPath(path, object); - - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; - } - - /** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ - function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); - } - - /** - * The base implementation of `getTag` without fallbacks for buggy environments. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - function baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); - } - - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } - - /** - * The base implementation of `_.has` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHas(object, key) { - return object != null && hasOwnProperty.call(object, key); - } - - /** - * The base implementation of `_.hasIn` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHasIn(object, key) { - return object != null && key in Object(object); - } - - /** - * The base implementation of `_.inRange` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to check. - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - */ - function baseInRange(number, start, end) { - return number >= nativeMin(start, end) && number < nativeMax(start, end); - } - - /** - * The base implementation of methods like `_.intersection`, without support - * for iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of shared values. - */ - function baseIntersection(arrays, iteratee, comparator) { - var includes = comparator ? arrayIncludesWith : arrayIncludes, - length = arrays[0].length, - othLength = arrays.length, - othIndex = othLength, - caches = Array(othLength), - maxLength = Infinity, - result = []; - - while (othIndex--) { - var array = arrays[othIndex]; - if (othIndex && iteratee) { - array = arrayMap(array, baseUnary(iteratee)); - } - maxLength = nativeMin(array.length, maxLength); - caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) - ? new SetCache(othIndex && array) - : undefined; - } - array = arrays[0]; - - var index = -1, - seen = caches[0]; - - outer: - while (++index < length && result.length < maxLength) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (!(seen - ? cacheHas(seen, computed) - : includes(result, computed, comparator) - )) { - othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if (!(cache - ? cacheHas(cache, computed) - : includes(arrays[othIndex], computed, comparator)) - ) { - continue outer; - } - } - if (seen) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.invert` and `_.invertBy` which inverts - * `object` with values transformed by `iteratee` and set by `setter`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform values. - * @param {Object} accumulator The initial inverted object. - * @returns {Function} Returns `accumulator`. - */ - function baseInverter(object, setter, iteratee, accumulator) { - baseForOwn(object, function(value, key, object) { - setter(accumulator, iteratee(value), key, object); - }); - return accumulator; - } - - /** - * The base implementation of `_.invoke` without support for individual - * method arguments. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function baseInvoke(object, path, args) { - path = castPath(path, object); - object = parent(object, path); - var func = object == null ? object : object[toKey(last(path))]; - return func == null ? undefined : apply(func, object, args); - } - - /** - * The base implementation of `_.isArguments`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - */ - function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; - } - - /** - * The base implementation of `_.isArrayBuffer` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - */ - function baseIsArrayBuffer(value) { - return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; - } - - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && baseGetTag(value) == dateTag; - } - - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {boolean} bitmask The bitmask flags. - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Function} [customizer] The function to customize comparisons. - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, bitmask, customizer, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); - } - - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = objIsArr ? arrayTag : getTag(object), - othTag = othIsArr ? arrayTag : getTag(other); - - objTag = objTag == argsTag ? objectTag : objTag; - othTag = othTag == argsTag ? objectTag : othTag; - - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; - - if (isSameTag && isBuffer(object)) { - if (!isBuffer(other)) { - return false; - } - objIsArr = true; - objIsObj = false; - } - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) - : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); - } - if (!(bitmask & COMPARE_PARTIAL_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; - - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack); - return equalObjects(object, other, bitmask, customizer, equalFunc, stack); - } - - /** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ - function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; - } - - /** - * The base implementation of `_.isMatch` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Array} matchData The property names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, source, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; - - if (object == null) { - return !length; - } - object = Object(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } - } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; - } - } else { - var stack = new Stack; - if (customizer) { - var result = customizer(objValue, srcValue, key, object, source, stack); - } - if (!(result === undefined - ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) - : result - )) { - return false; - } - } - } - return true; - } - - /** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ - function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); - } - - /** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObjectLike(value) && baseGetTag(value) == regexpTag; - } - - /** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ - function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; - } - - /** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ - function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; - } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(value) { - // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. - // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. - if (typeof value == 'function') { - return value; - } - if (value == null) { - return identity; - } - if (typeof value == 'object') { - return isArray(value) - ? baseMatchesProperty(value[0], value[1]) - : baseMatches(value); - } - return property(value); - } - - /** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } - - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } - - /** - * The base implementation of `_.matches` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - return matchesStrictComparable(matchData[0][0], matchData[0][1]); - } - return function(object) { - return object === source || baseIsMatch(object, source, matchData); - }; - } - - /** - * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatchesProperty(path, srcValue) { - if (isKey(path) && isStrictComparable(srcValue)) { - return matchesStrictComparable(toKey(path), srcValue); - } - return function(object) { - var objValue = get(object, path); - return (objValue === undefined && objValue === srcValue) - ? hasIn(object, path) - : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); - }; - } - - /** - * The base implementation of `_.merge` without support for multiple sources. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. - * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - baseFor(source, function(srcValue, key) { - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); - } - else { - var newValue = customizer - ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) - : undefined; - - if (newValue === undefined) { - newValue = srcValue; - } - assignMergeValue(object, key, newValue); - } - }, keysIn); - } - - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = safeGet(object, key), - srcValue = safeGet(source, key), - stacked = stack.get(srcValue); - - if (stacked) { - assignMergeValue(object, key, stacked); - return; - } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; - - var isCommon = newValue === undefined; - - if (isCommon) { - var isArr = isArray(srcValue), - isBuff = !isArr && isBuffer(srcValue), - isTyped = !isArr && !isBuff && isTypedArray(srcValue); - - newValue = srcValue; - if (isArr || isBuff || isTyped) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else if (isBuff) { - isCommon = false; - newValue = cloneBuffer(srcValue, true); - } - else if (isTyped) { - isCommon = false; - newValue = cloneTypedArray(srcValue, true); - } - else { - newValue = []; - } - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - newValue = objValue; - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - newValue = initCloneObject(srcValue); - } - } - else { - isCommon = false; - } - } - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); - } - assignMergeValue(object, key, newValue); - } - - /** - * The base implementation of `_.nth` which doesn't coerce arguments. - * - * @private - * @param {Array} array The array to query. - * @param {number} n The index of the element to return. - * @returns {*} Returns the nth element of `array`. - */ - function baseNth(array, n) { - var length = array.length; - if (!length) { - return; - } - n += n < 0 ? length : 0; - return isIndex(n, length) ? array[n] : undefined; - } - - /** - * The base implementation of `_.orderBy` without param guards. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {string[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseOrderBy(collection, iteratees, orders) { - var index = -1; - iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); - - var result = baseMap(collection, function(value, key, collection) { - var criteria = arrayMap(iteratees, function(iteratee) { - return iteratee(value); - }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); - - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } - - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, paths) { - return basePickBy(object, paths, function(value, path) { - return hasIn(object, path); - }); - } - - /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. - */ - function basePickBy(object, paths, predicate) { - var index = -1, - length = paths.length, - result = {}; - - while (++index < length) { - var path = paths[index], - value = baseGet(object, path); - - if (predicate(value, path)) { - baseSet(result, castPath(path, object), value); - } - } - return result; - } - - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyDeep(path) { - return function(object) { - return baseGet(object, path); - }; - } - - /** - * The base implementation of `_.pullAllBy` without support for iteratee - * shorthands. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - */ - function basePullAll(array, values, iteratee, comparator) { - var indexOf = comparator ? baseIndexOfWith : baseIndexOf, - index = -1, - length = values.length, - seen = array; - - if (array === values) { - values = copyArray(values); - } - if (iteratee) { - seen = arrayMap(array, baseUnary(iteratee)); - } - while (++index < length) { - var fromIndex = 0, - value = values[index], - computed = iteratee ? iteratee(value) : value; - - while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { - if (seen !== array) { - splice.call(seen, fromIndex, 1); - } - splice.call(array, fromIndex, 1); - } - } - return array; - } - - /** - * The base implementation of `_.pullAt` without support for individual - * indexes or capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0, - lastIndex = length - 1; - - while (length--) { - var index = indexes[length]; - if (length == lastIndex || index !== previous) { - var previous = index; - if (isIndex(index)) { - splice.call(array, index, 1); - } else { - baseUnset(array, index); - } - } - } - return array; - } - - /** - * The base implementation of `_.random` without support for returning - * floating-point numbers. - * - * @private - * @param {number} lower The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the random number. - */ - function baseRandom(lower, upper) { - return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); - } - - /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments. - * - * @private - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @param {number} step The value to increment or decrement by. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the range of numbers. - */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; - } - return result; - } - - /** - * The base implementation of `_.repeat` which doesn't coerce arguments. - * - * @private - * @param {string} string The string to repeat. - * @param {number} n The number of times to repeat the string. - * @returns {string} Returns the repeated string. - */ - function baseRepeat(string, n) { - var result = ''; - if (!string || n < 1 || n > MAX_SAFE_INTEGER) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - if (n) { - string += string; - } - } while (n); - - return result; - } - - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); - } - - /** - * The base implementation of `_.sample`. - * - * @private - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - */ - function baseSample(collection) { - return arraySample(values(collection)); - } - - /** - * The base implementation of `_.sampleSize` without param guards. - * - * @private - * @param {Array|Object} collection The collection to sample. - * @param {number} n The number of elements to sample. - * @returns {Array} Returns the random elements. - */ - function baseSampleSize(collection, n) { - var array = values(collection); - return shuffleSelf(array, baseClamp(n, 0, array.length)); - } - - /** - * The base implementation of `_.set`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; - } - path = castPath(path, object); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; - - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } - } - assignValue(nested, key, newValue); - nested = nested[key]; - } - return object; - } - - /** - * The base implementation of `setData` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; - - /** - * The base implementation of `setToString` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); - }; - - /** - * The base implementation of `_.shuffle`. - * - * @private - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - */ - function baseShuffle(collection) { - return shuffleSelf(values(collection)); - } - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = end > length ? length : end; - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - - /** - * The base implementation of `_.some` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - /** - * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which - * performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndex(array, value, retHighest) { - var low = 0, - high = array == null ? low : array.length; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if (computed !== null && !isSymbol(computed) && - (retHighest ? (computed <= value) : (computed < value))) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return baseSortedIndexBy(array, value, identity, retHighest); - } - - /** - * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` - * which invokes `iteratee` for `value` and each element of `array` to compute - * their sort ranking. The iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The iteratee invoked per element. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array == null ? 0 : array.length, - valIsNaN = value !== value, - valIsNull = value === null, - valIsSymbol = isSymbol(value), - valIsUndefined = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - othIsDefined = computed !== undefined, - othIsNull = computed === null, - othIsReflexive = computed === computed, - othIsSymbol = isSymbol(computed); - - if (valIsNaN) { - var setLow = retHighest || othIsReflexive; - } else if (valIsUndefined) { - setLow = othIsReflexive && (retHighest || othIsDefined); - } else if (valIsNull) { - setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); - } else if (valIsSymbol) { - setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); - } else if (othIsNull || othIsSymbol) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } - - /** - * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseSortedUniq(array, iteratee) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - if (!index || !eq(computed, seen)) { - var seen = computed; - result[resIndex++] = value === 0 ? 0 : value; - } - } - return result; - } - - /** - * The base implementation of `_.toNumber` which doesn't ensure correct - * conversions of binary, hexadecimal, or octal string values. - * - * @private - * @param {*} value The value to process. - * @returns {number} Returns the number. - */ - function baseToNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - return +value; - } - - /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * The base implementation of `_.uniqBy` without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - length = array.length, - isCommon = true, - result = [], - seen = result; - - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } - else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache; - } - else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (!includes(seen, computed, comparator)) { - if (seen !== result) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.unset`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The property path to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - */ - function baseUnset(object, path) { - path = castPath(path, object); - object = parent(object, path); - return object == null || delete object[toKey(last(path))]; - } - - /** - * The base implementation of `_.update`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to update. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseUpdate(object, path, updater, customizer) { - return baseSet(object, path, updater(baseGet(object, path)), customizer); - } - - /** - * The base implementation of methods like `_.dropWhile` and `_.takeWhile` - * without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length) && - predicate(array[index], index, array)) {} - - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - return arrayReduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); - } - - /** - * The base implementation of methods like `_.xor`, without support for - * iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of values. - */ - function baseXor(arrays, iteratee, comparator) { - var length = arrays.length; - if (length < 2) { - return length ? baseUniq(arrays[0]) : []; - } - var index = -1, - result = Array(length); - - while (++index < length) { - var array = arrays[index], - othIndex = -1; - - while (++othIndex < length) { - if (othIndex != index) { - result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); - } - } - } - return baseUniq(baseFlatten(result, 1), iteratee, comparator); - } - - /** - * This base implementation of `_.zipObject` which assigns values using `assignFunc`. - * - * @private - * @param {Array} props The property identifiers. - * @param {Array} values The property values. - * @param {Function} assignFunc The function to assign values. - * @returns {Object} Returns the new object. - */ - function baseZipObject(props, values, assignFunc) { - var index = -1, - length = props.length, - valsLength = values.length, - result = {}; - - while (++index < length) { - var value = index < valsLength ? values[index] : undefined; - assignFunc(result, props[index], value); - } - return result; - } - - /** - * Casts `value` to an empty array if it's not an array like object. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array|Object} Returns the cast array-like object. - */ - function castArrayLikeObject(value) { - return isArrayLikeObject(value) ? value : []; - } - - /** - * Casts `value` to `identity` if it's not a function. - * - * @private - * @param {*} value The value to inspect. - * @returns {Function} Returns cast function. - */ - function castFunction(value) { - return typeof value == 'function' ? value : identity; - } - - /** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value, object) { - if (isArray(value)) { - return value; - } - return isKey(value, object) ? [value] : stringToPath(toString(value)); - } - - /** - * A `baseRest` alias which can be replaced with `identity` by module - * replacement plugins. - * - * @private - * @type {Function} - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - var castRest = baseRest; - - /** - * Casts `array` to a slice if it's needed. - * - * @private - * @param {Array} array The array to inspect. - * @param {number} start The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the cast slice. - */ - function castSlice(array, start, end) { - var length = array.length; - end = end === undefined ? length : end; - return (!start && end >= length) ? array : baseSlice(array, start, end); - } - - /** - * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). - * - * @private - * @param {number|Object} id The timer id or timeout object of the timer to clear. - */ - var clearTimeout = ctxClearTimeout || function(id) { - return root.clearTimeout(id); - }; - - /** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ - function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var length = buffer.length, - result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); - - buffer.copy(result); - return result; - } - - /** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); - return result; - } - - /** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ - function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); - } - - /** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ - function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; - } - - /** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ - function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; - } - - /** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ - function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); - } - - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = isSymbol(value); - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = isSymbol(other); - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } - - /** - * Used by `_.orderBy` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, - * specify an order of "desc" for descending or "asc" for ascending sort order - * of corresponding values. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]|string[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = compareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * (order == 'desc' ? -1 : 1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersLength = holders.length, - leftIndex = -1, - leftLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(leftLength + rangeLength), - isUncurried = !isCurried; - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - } - while (rangeLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } - - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersIndex = -1, - holdersLength = holders.length, - rightIndex = -1, - rightLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(rangeLength + rightLength), - isUncurried = !isCurried; - - while (++argsIndex < rangeLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - } - return result; - } - - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - var isNew = !object; - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - if (newValue === undefined) { - newValue = source[key]; - } - if (isNew) { - baseAssignValue(object, key, newValue); - } else { - assignValue(object, key, newValue); - } - } - return object; - } - - /** - * Copies own symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); - } - - /** - * Copies own and inherited symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbolsIn(source, object) { - return copyObject(source, getSymbolsIn(source), object); - } - - /** - * Creates a function like `_.groupBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} [initializer] The accumulator object initializer. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee) { - var func = isArray(collection) ? arrayAggregator : baseAggregator, - accumulator = initializer ? initializer() : {}; - - return func(collection, setter, getIteratee(iteratee, 2), accumulator); - }; - } - - /** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); - } - - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { - return eachFunc(collection, iteratee); - } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - - /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - - /** - * Creates a function that wraps `func` to invoke it with the optional `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createBind(func, bitmask, thisArg) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, arguments); - } - return wrapper; - } - - /** - * Creates a function like `_.lowerFirst`. - * - * @private - * @param {string} methodName The name of the `String` case method to use. - * @returns {Function} Returns the new case function. - */ - function createCaseFirst(methodName) { - return function(string) { - string = toString(string); - - var strSymbols = hasUnicode(string) - ? stringToArray(string) - : undefined; - - var chr = strSymbols - ? strSymbols[0] - : string.charAt(0); - - var trailing = strSymbols - ? castSlice(strSymbols, 1).join('') - : string.slice(1); - - return chr[methodName]() + trailing; - }; - } - - /** - * Creates a function like `_.camelCase`. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function(string) { - return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); - }; - } - - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtor(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - - /** - * Creates a function that wraps `func` to enable currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {number} arity The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createCurry(func, bitmask, arity) { - var Ctor = createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length, - placeholder = getHolder(wrapper); - - while (index--) { - args[index] = arguments[index]; - } - var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) - ? [] - : replaceHolders(args, placeholder); - - length -= holders.length; - if (length < arity) { - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, undefined, - args, holders, undefined, undefined, arity - length); - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return apply(fn, this, args); - } - return wrapper; - } - - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} findIndexFunc The function to find the collection index. - * @returns {Function} Returns the new find function. - */ - function createFind(findIndexFunc) { - return function(collection, predicate, fromIndex) { - var iterable = Object(collection); - if (!isArrayLike(collection)) { - var iteratee = getIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; - } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; - }; - } - - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return flatRest(function(funcs) { - var length = funcs.length, - index = length, - prereq = LodashWrapper.prototype.thru; - - if (fromRight) { - funcs.reverse(); - } - while (index--) { - var func = funcs[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (prereq && !wrapper && getFuncName(func) == 'wrapper') { - var wrapper = new LodashWrapper([], true); - } - } - index = wrapper ? index : length; - while (++index < length) { - func = funcs[index]; - - var funcName = getFuncName(func), - data = funcName == 'wrapper' ? getData(func) : undefined; - - if (data && isLaziable(data[0]) && - data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && - !data[4].length && data[9] == 1 - ) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = (func.length == 1 && isLaziable(func)) - ? wrapper[funcName]() - : wrapper.thru(func); - } - } - return function() { - var args = arguments, - value = args[0]; - - if (wrapper && args.length == 1 && isArray(value)) { - return wrapper.plant(value).value(); - } - var index = 0, - result = length ? funcs[index].apply(this, args) : value; - - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }); - } - - /** - * Creates a function that wraps `func` to invoke it with optional `this` - * binding of `thisArg`, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided - * to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & WRAP_ARY_FLAG, - isBind = bitmask & WRAP_BIND_FLAG, - isBindKey = bitmask & WRAP_BIND_KEY_FLAG, - isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), - isFlip = bitmask & WRAP_FLIP_FLAG, - Ctor = isBindKey ? undefined : createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length; - - while (index--) { - args[index] = arguments[index]; - } - if (isCurried) { - var placeholder = getHolder(wrapper), - holdersCount = countHolders(args, placeholder); - } - if (partials) { - args = composeArgs(args, partials, holders, isCurried); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight, isCurried); - } - length -= holdersCount; - if (isCurried && length < arity) { - var newHolders = replaceHolders(args, placeholder); - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, thisArg, - args, newHolders, argPos, ary, arity - length - ); - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; - - length = args.length; - if (argPos) { - args = reorder(args, argPos); - } else if (isFlip && length > 1) { - args.reverse(); - } - if (isAry && ary < length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtor(fn); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } - - /** - * Creates a function like `_.invertBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} toIteratee The function to resolve iteratees. - * @returns {Function} Returns the new inverter function. - */ - function createInverter(setter, toIteratee) { - return function(object, iteratee) { - return baseInverter(object, setter, toIteratee(iteratee), {}); - }; - } - - /** - * Creates a function that performs a mathematical operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @param {number} [defaultValue] The value used for `undefined` arguments. - * @returns {Function} Returns the new mathematical operation function. - */ - function createMathOperation(operator, defaultValue) { - return function(value, other) { - var result; - if (value === undefined && other === undefined) { - return defaultValue; - } - if (value !== undefined) { - result = value; - } - if (other !== undefined) { - if (result === undefined) { - return other; - } - if (typeof value == 'string' || typeof other == 'string') { - value = baseToString(value); - other = baseToString(other); - } else { - value = baseToNumber(value); - other = baseToNumber(other); - } - result = operator(value, other); - } - return result; - }; - } - - /** - * Creates a function like `_.over`. - * - * @private - * @param {Function} arrayFunc The function to iterate over iteratees. - * @returns {Function} Returns the new over function. - */ - function createOver(arrayFunc) { - return flatRest(function(iteratees) { - iteratees = arrayMap(iteratees, baseUnary(getIteratee())); - return baseRest(function(args) { - var thisArg = this; - return arrayFunc(iteratees, function(iteratee) { - return apply(iteratee, thisArg, args); - }); - }); - }); - } - - /** - * Creates the padding for `string` based on `length`. The `chars` string - * is truncated if the number of characters exceeds `length`. - * - * @private - * @param {number} length The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padding for `string`. - */ - function createPadding(length, chars) { - chars = chars === undefined ? ' ' : baseToString(chars); - - var charsLength = chars.length; - if (charsLength < 2) { - return charsLength ? baseRepeat(chars, length) : chars; - } - var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); - return hasUnicode(chars) - ? castSlice(stringToArray(result), 0, length).join('') - : result.slice(0, length); - } - - /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. - */ - function createPartial(func, bitmask, thisArg, partials) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - return apply(fn, isBind ? thisArg : this, args); - } - return wrapper; - } - - /** - * Creates a `_.range` or `_.rangeRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new range function. - */ - function createRange(fromRight) { - return function(start, end, step) { - if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { - end = step = undefined; - } - // Ensure the sign of `-0` is preserved. - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); - return baseRange(start, end, step, fromRight); - }; - } - - /** - * Creates a function that performs a relational operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @returns {Function} Returns the new relational operation function. - */ - function createRelationalOperation(operator) { - return function(value, other) { - if (!(typeof value == 'string' && typeof other == 'string')) { - value = toNumber(value); - other = toNumber(other); - } - return operator(value, other); - }; - } - - /** - * Creates a function that wraps `func` to continue currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {Function} wrapFunc The function to create the `func` wrapper. - * @param {*} placeholder The placeholder value. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { - var isCurry = bitmask & WRAP_CURRY_FLAG, - newHolders = isCurry ? holders : undefined, - newHoldersRight = isCurry ? undefined : holders, - newPartials = isCurry ? partials : undefined, - newPartialsRight = isCurry ? undefined : partials; - - bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); - - if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { - bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); - } - var newData = [ - func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, - newHoldersRight, argPos, ary, arity - ]; - - var result = wrapFunc.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return setWrapToString(result, func, bitmask); - } - - /** - * Creates a function like `_.round`. - * - * @private - * @param {string} methodName The name of the `Math` method to use when rounding. - * @returns {Function} Returns the new round function. - */ - function createRound(methodName) { - var func = Math[methodName]; - return function(number, precision) { - number = toNumber(number); - precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); - if (precision) { - // Shift with exponential notation to avoid floating-point issues. - // See [MDN](https://mdn.io/round#Examples) for more details. - var pair = (toString(number) + 'e').split('e'), - value = func(pair[0] + 'e' + (+pair[1] + precision)); - - pair = (toString(value) + 'e').split('e'); - return +(pair[0] + 'e' + (+pair[1] - precision)); - } - return func(number); - }; - } - - /** - * Creates a set object of `values`. - * - * @private - * @param {Array} values The values to add to the set. - * @returns {Object} Returns the new set. - */ - var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { - return new Set(values); - }; - - /** - * Creates a `_.toPairs` or `_.toPairsIn` function. - * - * @private - * @param {Function} keysFunc The function to get the keys of a given object. - * @returns {Function} Returns the new pairs function. - */ - function createToPairs(keysFunc) { - return function(object) { - var tag = getTag(object); - if (tag == mapTag) { - return mapToArray(object); - } - if (tag == setTag) { - return setToPairs(object); - } - return baseToPairs(object, keysFunc(object)); - }; - } - - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * 512 - `_.flip` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); - arity = arity === undefined ? arity : toInteger(arity); - length -= holders ? holders.length : 0; - - if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; - - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func); - - var newData = [ - func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, - argPos, ary, arity - ]; - - if (data) { - mergeData(newData, data); - } - func = newData[0]; - bitmask = newData[1]; - thisArg = newData[2]; - partials = newData[3]; - holders = newData[4]; - arity = newData[9] = newData[9] === undefined - ? (isBindKey ? 0 : func.length) - : nativeMax(newData[9] - length, 0); - - if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { - bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); - } - if (!bitmask || bitmask == WRAP_BIND_FLAG) { - var result = createBind(func, bitmask, thisArg); - } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { - result = createCurry(func, bitmask, arity); - } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { - result = createPartial(func, bitmask, thisArg, partials); - } else { - result = createHybrid.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setWrapToString(setter(result, newData), func, bitmask); - } - - /** - * Used by `_.defaults` to customize its `_.assignIn` use to assign properties - * of source objects to the destination object for all destination properties - * that resolve to `undefined`. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. - */ - function customDefaultsAssignIn(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; - } - - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source - * objects into destination objects that are passed thru. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to merge. - * @param {Object} object The parent object of `objValue`. - * @param {Object} source The parent object of `srcValue`. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - * @returns {*} Returns the value to assign. - */ - function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { - if (isObject(objValue) && isObject(srcValue)) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, objValue); - baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); - stack['delete'](srcValue); - } - return objValue; - } - - /** - * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain - * objects. - * - * @private - * @param {*} value The value to inspect. - * @param {string} key The key of the property to inspect. - * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. - */ - function customOmitClone(value) { - return isPlainObject(value) ? undefined : value; - } - - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!arraySome(other, function(othValue, othIndex) { - if (!cacheHas(seen, othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { - return seen.push(othIndex); - } - })) { - result = false; - break; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, bitmask, customizer, stack) - )) { - result = false; - break; - } - } - stack['delete'](array); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { - switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; - } - return true; - - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); - - case errorTag: - return object.name == other.name && object.message == other.message; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); - - case mapTag: - var convert = mapToArray; - - case setTag: - var isPartial = bitmask & COMPARE_PARTIAL_FLAG; - convert || (convert = setToArray); - - if (object.size != other.size && !isPartial) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; - } - bitmask |= COMPARE_UNORDERED_FLAG; - - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); - stack['delete'](object); - return result; - - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } - } - return false; - } - - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - objProps = getAllKeys(object), - objLength = objProps.length, - othProps = getAllKeys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - stack['delete'](object); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseRest` which flattens the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - function flatRest(func) { - return setToString(overRest(func, undefined, flatten), func + ''); - } - - /** - * Creates an array of own enumerable property names and symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); - } - - /** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); - } - - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; - - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = (func.name + ''), - array = realNames[result], - length = hasOwnProperty.call(realNames, result) ? array.length : 0; - - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - } - - /** - * Gets the argument placeholder value for `func`. - * - * @private - * @param {Function} func The function to inspect. - * @returns {*} Returns the placeholder value. - */ - function getHolder(func) { - var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; - return object.placeholder; - } - - /** - * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, - * this function returns the custom method, otherwise it returns `baseIteratee`. - * If arguments are provided, the chosen function is invoked with them and - * its result is returned. - * - * @private - * @param {*} [value] The value to convert to an iteratee. - * @param {number} [arity] The arity of the created iteratee. - * @returns {Function} Returns the chosen function or its result. - */ - function getIteratee() { - var result = lodash.iteratee || iteratee; - result = result === iteratee ? baseIteratee : result; - return arguments.length ? result(arguments[0], arguments[1]) : result; - } - - /** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; - } - - /** - * Gets the property names, values, and compare flags of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = keys(object), - length = result.length; - - while (length--) { - var key = result[length], - value = object[key]; - - result[length] = [key, value, isStrictComparable(value)]; - } - return result; - } - - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; - } - - /** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. - */ - function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), - tag = value[symToStringTag]; - - try { - value[symToStringTag] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; - } - - /** - * Creates an array of the own enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = !nativeGetSymbols ? stubArray : function(object) { - if (object == null) { - return []; - } - object = Object(object); - return arrayFilter(nativeGetSymbols(object), function(symbol) { - return propertyIsEnumerable.call(object, symbol); - }); - }; - - /** - * Creates an array of the own and inherited enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; - }; - - /** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - var getTag = baseGetTag; - - // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. - if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = baseGetTag(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : ''; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; - } - - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; - - while (++index < length) { - var data = transforms[index], - size = data.size; - - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } - - /** - * Extracts wrapper details from the `source` body comment. - * - * @private - * @param {string} source The source to inspect. - * @returns {Array} Returns the wrapper details. - */ - function getWrapDetails(source) { - var match = source.match(reWrapDetails); - return match ? match[1].split(reSplitDetails) : []; - } - - /** - * Checks if `path` exists on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @param {Function} hasFunc The function to check properties. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - */ - function hasPath(object, path, hasFunc) { - path = castPath(path, object); - - var index = -1, - length = path.length, - result = false; - - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; - } - object = object[key]; - } - if (result || ++index != length) { - return result; - } - length = object == null ? 0 : object.length; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } - - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); - - // Add properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } - - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; - } - - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return cloneArrayBuffer(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case dataViewTag: - return cloneDataView(object, isDeep); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); - - case mapTag: - return new Ctor; - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - return cloneRegExp(object); - - case setTag: - return new Ctor; - - case symbolTag: - return cloneSymbol(object); - } - } - - /** - * Inserts wrapper `details` in a comment at the top of the `source` body. - * - * @private - * @param {string} source The source to modify. - * @returns {Array} details The details to insert. - * @returns {string} Returns the modified source. - */ - function insertWrapDetails(source, details) { - var length = details.length; - if (!length) { - return source; - } - var lastIndex = length - 1; - details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; - details = details.join(length > 2 ? ', ' : ' '); - return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); - } - - /** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); - } - - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER : length; - - return !!length && - (type == 'number' || - (type != 'symbol' && reIsUint.test(value))) && - (value > -1 && value % 1 == 0 && value < length); - } - - /** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; - } - - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - if (isArray(value)) { - return false; - } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); - } - - /** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); - } - - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, - * else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func), - other = lodash[funcName]; - - if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { - return false; - } - if (func === other) { - return true; - } - var data = getData(other); - return !!data && func === data[0]; - } - - /** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ - function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); - } - - /** - * Checks if `func` is capable of being masked. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `func` is maskable, else `false`. - */ - var isMaskable = coreJsData ? isFunction : stubFalse; - - /** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ - function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; - } - - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } - - /** - * A specialized version of `matchesProperty` for source values suitable - * for strict equality comparisons, i.e. `===`. - * - * @private - * @param {string} key The key of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function matchesStrictComparable(key, srcValue) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === srcValue && - (srcValue !== undefined || (key in Object(object))); - }; - } - - /** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. - * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. - */ - function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; - }); - - var cache = result.cache; - return result; - } - - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers used to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and - * `_.rearg` modify function arguments, making the order in which they are - * executed important, preventing the merging of metadata. However, we make - * an exception for a safe combined case where curried functions have `_.ary` - * and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); - - var isCombo = - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || - ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & WRAP_BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : value; - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = value; - } - // Use source `ary` if it's smaller. - if (srcBitmask & WRAP_ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; - - return data; - } - - /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; - } - - /** - * Converts `value` to a string using `Object.prototype.toString`. - * - * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - */ - function objectToString(value) { - return nativeObjectToString.call(value); - } - - /** - * A specialized version of `baseRest` which transforms the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. - */ - function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; - } - - /** - * Gets the parent value at `path` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path to get the parent value of. - * @returns {*} Returns the parent value. - */ - function parent(object, path) { - return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); - } - - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = copyArray(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } - - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity - * function to avoid garbage collection pauses in V8. See - * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = shortOut(baseSetData); - - /** - * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @returns {number|Object} Returns the timer id or timeout object. - */ - var setTimeout = ctxSetTimeout || function(func, wait) { - return root.setTimeout(func, wait); - }; - - /** - * Sets the `toString` method of `func` to return `string`. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var setToString = shortOut(baseSetToString); - - /** - * Sets the `toString` method of `wrapper` to mimic the source of `reference` - * with wrapper details in a comment at the top of the source body. - * - * @private - * @param {Function} wrapper The function to modify. - * @param {Function} reference The reference function. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Function} Returns `wrapper`. - */ - function setWrapToString(wrapper, reference, bitmask) { - var source = (reference + ''); - return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); - } - - /** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. - * - * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable function. - */ - function shortOut(func) { - var count = 0, - lastCalled = 0; - - return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; - } - return func.apply(undefined, arguments); - }; - } - - /** - * A specialized version of `_.shuffle` which mutates and sets the size of `array`. - * - * @private - * @param {Array} array The array to shuffle. - * @param {number} [size=array.length] The size of `array`. - * @returns {Array} Returns `array`. - */ - function shuffleSelf(array, size) { - var index = -1, - length = array.length, - lastIndex = length - 1; - - size = size === undefined ? length : size; - while (++index < size) { - var rand = baseRandom(index, lastIndex), - value = array[rand]; - - array[rand] = array[index]; - array[index] = value; - } - array.length = size; - return array; - } - - /** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ - var stringToPath = memoizeCapped(function(string) { - var result = []; - if (string.charCodeAt(0) === 46 /* . */) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, subString) { - result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - }); - - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. - */ - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; - } - - /** - * Updates wrapper `details` based on `bitmask` flags. - * - * @private - * @returns {Array} details The details to modify. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Array} Returns `details`. - */ - function updateWrapDetails(details, bitmask) { - arrayEach(wrapFlags, function(pair) { - var value = '_.' + pair[0]; - if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { - details.push(value); - } - }); - return details.sort(); - } - - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - if (wrapper instanceof LazyWrapper) { - return wrapper.clone(); - } - var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); - result.__actions__ = copyArray(wrapper.__actions__); - result.__index__ = wrapper.__index__; - result.__values__ = wrapper.__values__; - return result; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements split into groups the length of `size`. - * If `array` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to process. - * @param {number} [size=1] The length of each chunk - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the new array of chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { - size = 1; - } else { - size = nativeMax(toInteger(size), 0); - } - var length = array == null ? 0 : array.length; - if (!length || size < 1) { - return []; - } - var index = 0, - resIndex = 0, - result = Array(nativeCeil(length / size)); - - while (index < length) { - result[resIndex++] = baseSlice(array, index, (index += size)); - } - return result; - } - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length; - if (!length) { - return []; - } - var args = Array(length - 1), - array = arguments[0], - index = length; - - while (index--) { - args[index - 1] = arguments[index]; - } - return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); - } - - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.without, _.xor - * @example - * - * _.difference([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `iteratee` which - * is invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The order and references of result values are - * determined by the first array. The iteratee is invoked with one argument: - * (value). - * - * **Note:** Unlike `_.pullAllBy`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [1.2] - * - * // The `_.property` iteratee shorthand. - * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); - * // => [{ 'x': 2 }] - */ - var differenceBy = baseRest(function(array, values) { - var iteratee = last(values); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `comparator` - * which is invoked to compare elements of `array` to `values`. The order and - * references of result values are determined by the first array. The comparator - * is invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.pullAllWith`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * - * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); - * // => [{ 'x': 2, 'y': 1 }] - */ - var differenceWith = baseRest(function(array, values) { - var comparator = last(values); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) - : []; - }); - - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.dropRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney'] - * - * // The `_.matches` iteratee shorthand. - * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropRightWhile(users, ['active', false]); - * // => objects for ['barney'] - * - * // The `_.property` iteratee shorthand. - * _.dropRightWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true, true) - : []; - } - - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.dropWhile(users, function(o) { return !o.active; }); - * // => objects for ['pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.dropWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropWhile(users, ['active', false]); - * // => objects for ['pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.dropWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true) - : []; - } - - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8, 10], '*', 1, 3); - * // => [4, '*', '*', 10] - */ - function fill(array, value, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); - * // => 0 - * - * // The `_.matches` iteratee shorthand. - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.findIndex(users, 'active'); - * // => 2 - */ - function findIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseFindIndex(array, getIteratee(predicate, 3), index); - } - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); - * // => 2 - * - * // The `_.matches` iteratee shorthand. - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastIndex(users, ['active', false]); - * // => 2 - * - * // The `_.property` iteratee shorthand. - * _.findLastIndex(users, 'active'); - * // => 0 - */ - function findLastIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length - 1; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = fromIndex < 0 - ? nativeMax(length + index, 0) - : nativeMin(index, length - 1); - } - return baseFindIndex(array, getIteratee(predicate, 3), index, true); - } - - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, 1) : []; - } - - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, INFINITY) : []; - } - - /** - * Recursively flatten `array` up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Array - * @param {Array} array The array to flatten. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * var array = [1, [2, [3, [4]], 5]]; - * - * _.flattenDepth(array, 1); - * // => [1, 2, [3, [4]], 5] - * - * _.flattenDepth(array, 2); - * // => [1, 2, 3, [4], 5] - */ - function flattenDepth(array, depth) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(array, depth); - } - - /** - * The inverse of `_.toPairs`; this method returns an object composed - * from key-value `pairs`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} pairs The key-value pairs. - * @returns {Object} Returns the new object. - * @example - * - * _.fromPairs([['a', 1], ['b', 2]]); - * // => { 'a': 1, 'b': 2 } - */ - function fromPairs(pairs) { - var index = -1, - length = pairs == null ? 0 : pairs.length, - result = {}; - - while (++index < length) { - var pair = pairs[index]; - result[pair[0]] = pair[1]; - } - return result; - } - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias first - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.head([1, 2, 3]); - * // => 1 - * - * _.head([]); - * // => undefined - */ - function head(array) { - return (array && array.length) ? array[0] : undefined; - } - - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // Search from the `fromIndex`. - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseIndexOf(array, value, index); - } - - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 0, -1) : []; - } - - /** - * Creates an array of unique values that are included in all given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersection([2, 1], [2, 3]); - * // => [2] - */ - var intersection = baseRest(function(arrays) { - var mapped = arrayMap(arrays, castArrayLikeObject); - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : []; - }); - - /** - * This method is like `_.intersection` except that it accepts `iteratee` - * which is invoked for each element of each `arrays` to generate the criterion - * by which they're compared. The order and references of result values are - * determined by the first array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [2.1] - * - * // The `_.property` iteratee shorthand. - * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }] - */ - var intersectionBy = baseRest(function(arrays) { - var iteratee = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - if (iteratee === last(mapped)) { - iteratee = undefined; - } else { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.intersection` except that it accepts `comparator` - * which is invoked to compare elements of `arrays`. The order and references - * of result values are determined by the first array. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.intersectionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }] - */ - var intersectionWith = baseRest(function(arrays) { - var comparator = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - comparator = typeof comparator == 'function' ? comparator : undefined; - if (comparator) { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, undefined, comparator) - : []; - }); - - /** - * Converts all elements in `array` into a string separated by `separator`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to convert. - * @param {string} [separator=','] The element separator. - * @returns {string} Returns the joined string. - * @example - * - * _.join(['a', 'b', 'c'], '~'); - * // => 'a~b~c' - */ - function join(array, separator) { - return array == null ? '' : nativeJoin.call(array, separator); - } - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array == null ? 0 : array.length; - return length ? array[length - 1] : undefined; - } - - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // Search from the `fromIndex`. - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); - } - return value === value - ? strictLastIndexOf(array, value, index) - : baseFindIndex(array, baseIsNaN, index, true); - } - - /** - * Gets the element at index `n` of `array`. If `n` is negative, the nth - * element from the end is returned. - * - * @static - * @memberOf _ - * @since 4.11.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=0] The index of the element to return. - * @returns {*} Returns the nth element of `array`. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * - * _.nth(array, 1); - * // => 'b' - * - * _.nth(array, -2); - * // => 'c'; - */ - function nth(array, n) { - return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; - } - - /** - * Removes all given values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` - * to remove elements from an array by predicate. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pull(array, 'a', 'c'); - * console.log(array); - * // => ['b', 'b'] - */ - var pull = baseRest(pullAll); - - /** - * This method is like `_.pull` except that it accepts an array of values to remove. - * - * **Note:** Unlike `_.difference`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pullAll(array, ['a', 'c']); - * console.log(array); - * // => ['b', 'b'] - */ - function pullAll(array, values) { - return (array && array.length && values && values.length) - ? basePullAll(array, values) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `iteratee` which is - * invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.differenceBy`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - * - * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); - * console.log(array); - * // => [{ 'x': 2 }] - */ - function pullAllBy(array, values, iteratee) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, getIteratee(iteratee, 2)) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `comparator` which - * is invoked to compare elements of `array` to `values`. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.differenceWith`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; - * - * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); - * console.log(array); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] - */ - function pullAllWith(array, values, comparator) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, undefined, comparator) - : array; - } - - /** - * Removes elements from `array` corresponding to `indexes` and returns an - * array of removed elements. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * var pulled = _.pullAt(array, [1, 3]); - * - * console.log(array); - * // => ['a', 'c'] - * - * console.log(pulled); - * // => ['b', 'd'] - */ - var pullAt = flatRest(function(array, indexes) { - var length = array == null ? 0 : array.length, - result = baseAt(array, indexes); - - basePullAt(array, arrayMap(indexes, function(index) { - return isIndex(index, length) ? +index : index; - }).sort(compareAscending)); - - return result; - }); - - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is invoked - * with three arguments: (value, index, array). - * - * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` - * to pull elements from an array by value. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, - indexes = [], - length = array.length; - - predicate = getIteratee(predicate, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } - - /** - * Reverses `array` so that the first element becomes the last, the second - * element becomes the second to last, and so on. - * - * **Note:** This method mutates `array` and is based on - * [`Array#reverse`](https://mdn.io/Array/reverse). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.reverse(array); - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function reverse(array) { - return array == null ? array : nativeReverse.call(array); - } - - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - else { - start = start == null ? 0 : toInteger(start); - end = end === undefined ? length : toInteger(end); - } - return baseSlice(array, start, end); - } - - /** - * Uses a binary search to determine the lowest index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - */ - function sortedIndex(array, value) { - return baseSortedIndex(array, value); - } - - /** - * This method is like `_.sortedIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); - * // => 0 - */ - function sortedIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); - } - - /** - * This method is like `_.indexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedIndexOf([4, 5, 5, 5, 6], 5); - * // => 1 - */ - function sortedIndexOf(array, value) { - var length = array == null ? 0 : array.length; - if (length) { - var index = baseSortedIndex(array, value); - if (index < length && eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 5, 5, 5, 6], 5); - * // => 4 - */ - function sortedLastIndex(array, value) { - return baseSortedIndex(array, value, true); - } - - /** - * This method is like `_.sortedLastIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 1 - * - * // The `_.property` iteratee shorthand. - * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); - * // => 1 - */ - function sortedLastIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); - } - - /** - * This method is like `_.lastIndexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); - * // => 3 - */ - function sortedLastIndexOf(array, value) { - var length = array == null ? 0 : array.length; - if (length) { - var index = baseSortedIndex(array, value, true) - 1; - if (eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.uniq` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniq([1, 1, 2]); - * // => [1, 2] - */ - function sortedUniq(array) { - return (array && array.length) - ? baseSortedUniq(array) - : []; - } - - /** - * This method is like `_.uniqBy` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); - * // => [1.1, 2.3] - */ - function sortedUniqBy(array, iteratee) { - return (array && array.length) - ? baseSortedUniq(array, getIteratee(iteratee, 2)) - : []; - } - - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.tail([1, 2, 3]); - * // => [2, 3] - */ - function tail(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 1, length) : []; - } - - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - if (!(array && array.length)) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.takeRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeRightWhile(users, ['active', false]); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.takeRightWhile(users, 'active'); - * // => [] - */ - function takeRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), false, true) - : []; - } - - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.takeWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matches` iteratee shorthand. - * _.takeWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeWhile(users, ['active', false]); - * // => objects for ['barney', 'fred'] - * - * // The `_.property` iteratee shorthand. - * _.takeWhile(users, 'active'); - * // => [] - */ - function takeWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3)) - : []; - } - - /** - * Creates an array of unique values, in order, from all given arrays using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([2], [1, 2]); - * // => [2, 1] - */ - var union = baseRest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); - }); - - /** - * This method is like `_.union` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which uniqueness is computed. Result values are chosen from the first - * array in which the value occurs. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.unionBy([2.1], [1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - var unionBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.union` except that it accepts `comparator` which - * is invoked to compare elements of `arrays`. Result values are chosen from - * the first array in which the value occurs. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.unionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var unionWith = baseRest(function(arrays) { - var comparator = last(arrays); - comparator = typeof comparator == 'function' ? comparator : undefined; - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); - }); - - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurrence of each element - * is kept. The order of result values is determined by the order they occur - * in the array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - */ - function uniq(array) { - return (array && array.length) ? baseUniq(array) : []; - } - - /** - * This method is like `_.uniq` except that it accepts `iteratee` which is - * invoked for each element in `array` to generate the criterion by which - * uniqueness is computed. The order of result values is determined by the - * order they occur in the array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniqBy([2.1, 1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniqBy(array, iteratee) { - return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; - } - - /** - * This method is like `_.uniq` except that it accepts `comparator` which - * is invoked to compare elements of `array`. The order of result values is - * determined by the order they occur in the array.The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.uniqWith(objects, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] - */ - function uniqWith(array, comparator) { - comparator = typeof comparator == 'function' ? comparator : undefined; - return (array && array.length) ? baseUniq(array, undefined, comparator) : []; - } - - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @since 1.2.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - * - * _.unzip(zipped); - * // => [['a', 'b'], [1, 2], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var length = 0; - array = arrayFilter(array, function(group) { - if (isArrayLikeObject(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - return baseTimes(length, function(index) { - return arrayMap(array, baseProperty(index)); - }); - } - - /** - * This method is like `_.unzip` except that it accepts `iteratee` to specify - * how regrouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee=_.identity] The function to combine - * regrouped values. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee) { - if (!(array && array.length)) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - return arrayMap(result, function(group) { - return apply(iteratee, undefined, group); - }); - } - - /** - * Creates an array excluding all given values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.pull`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.xor - * @example - * - * _.without([2, 1, 2, 3], 1, 2); - * // => [3] - */ - var without = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, values) - : []; - }); - - /** - * Creates an array of unique values that is the - * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the given arrays. The order of result values is determined by the order - * they occur in the arrays. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.without - * @example - * - * _.xor([2, 1], [2, 3]); - * // => [1, 3] - */ - var xor = baseRest(function(arrays) { - return baseXor(arrayFilter(arrays, isArrayLikeObject)); - }); - - /** - * This method is like `_.xor` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which by which they're compared. The order of result values is determined - * by the order they occur in the arrays. The iteratee is invoked with one - * argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [1.2, 3.4] - * - * // The `_.property` iteratee shorthand. - * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 2 }] - */ - var xorBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.xor` except that it accepts `comparator` which is - * invoked to compare elements of `arrays`. The order of result values is - * determined by the order they occur in the arrays. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.xorWith(objects, others, _.isEqual); - * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var xorWith = baseRest(function(arrays) { - var comparator = last(arrays); - comparator = typeof comparator == 'function' ? comparator : undefined; - return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); - }); - - /** - * Creates an array of grouped elements, the first of which contains the - * first elements of the given arrays, the second of which contains the - * second elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - */ - var zip = baseRest(unzip); - - /** - * This method is like `_.fromPairs` except that it accepts two arrays, - * one of property identifiers and one of corresponding values. - * - * @static - * @memberOf _ - * @since 0.4.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject(['a', 'b'], [1, 2]); - * // => { 'a': 1, 'b': 2 } - */ - function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue); - } - - /** - * This method is like `_.zipObject` except that it supports property paths. - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); - * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } - */ - function zipObjectDeep(props, values) { - return baseZipObject(props || [], values || [], baseSet); - } - - /** - * This method is like `_.zip` except that it accepts `iteratee` to specify - * how grouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee=_.identity] The function to combine - * grouped values. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { - * return a + b + c; - * }); - * // => [111, 222] - */ - var zipWith = baseRest(function(arrays) { - var length = arrays.length, - iteratee = length > 1 ? arrays[length - 1] : undefined; - - iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; - return unzipWith(arrays, iteratee); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Seq - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _ - * .chain(users) - * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; - * }) - * .head() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - - /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * // Mutate input array. - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor) { - interceptor(value); - return value; - } - - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor) { - return interceptor(value); - } - - /** - * This method is the wrapper version of `_.at`. - * - * @name at - * @memberOf _ - * @since 1.0.0 - * @category Seq - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _(object).at(['a[0].b.c', 'a[1]']).value(); - * // => [3, 4] - */ - var wrapperAt = flatRest(function(paths) { - var length = paths.length, - start = length ? paths[0] : 0, - value = this.__wrapped__, - interceptor = function(object) { return baseAt(object, paths); }; - - if (length > 1 || this.__actions__.length || - !(value instanceof LazyWrapper) || !isIndex(start)) { - return this.thru(interceptor); - } - value = value.slice(start, +start + (length ? 1 : 0)); - value.__actions__.push({ - 'func': thru, - 'args': [interceptor], - 'thisArg': undefined - }); - return new LodashWrapper(value, this.__chain__).thru(function(array) { - if (length && !array.length) { - array.push(undefined); - } - return array; - }); - }); - - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. - * - * @name chain - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // A sequence without explicit chaining. - * _(users).head(); - * // => { 'user': 'barney', 'age': 36 } - * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - - /** - * Executes the chain sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } - - /** - * Gets the next value on a wrapped object following the - * [iterator protocol](https://mdn.io/iteration_protocols#iterator). - * - * @name next - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the next iterator value. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped.next(); - * // => { 'done': false, 'value': 1 } - * - * wrapped.next(); - * // => { 'done': false, 'value': 2 } - * - * wrapped.next(); - * // => { 'done': true, 'value': undefined } - */ - function wrapperNext() { - if (this.__values__ === undefined) { - this.__values__ = toArray(this.value()); - } - var done = this.__index__ >= this.__values__.length, - value = done ? undefined : this.__values__[this.__index__++]; - - return { 'done': done, 'value': value }; - } - - /** - * Enables the wrapper to be iterable. - * - * @name Symbol.iterator - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the wrapper object. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped[Symbol.iterator]() === wrapped; - * // => true - * - * Array.from(wrapped); - * // => [1, 2] - */ - function wrapperToIterator() { - return this; - } - - /** - * Creates a clone of the chain sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @param {*} value The value to plant. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2]).map(square); - * var other = wrapped.plant([3, 4]); - * - * other.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - clone.__index__ = 0; - clone.__values__ = undefined; - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } - - /** - * This method is the wrapper version of `_.reverse`. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ - 'func': thru, - 'args': [reverse], - 'thisArg': undefined - }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(reverse); - } - - /** - * Executes the chain sequence to resolve the unwrapped value. - * - * @name value - * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the number of times the key was returned by `iteratee`. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': 1, '6': 2 } - * - * // The `_.property` iteratee shorthand. - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - ++result[key]; - } else { - baseAssignValue(result, key, 1); - } - }); - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, guard) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * **Note:** Unlike `_.remove`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.reject - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] - */ - function filter(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' - * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' - */ - var find = createFind(findIndex); - - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=collection.length-1] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(findLastIndex); - - /** - * Creates a flattened array of values by running each element in `collection` - * thru `iteratee` and flattening the mapped results. The iteratee is invoked - * with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [n, n]; - * } - * - * _.flatMap([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMap(collection, iteratee) { - return baseFlatten(map(collection, iteratee), 1); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDeep([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMapDeep(collection, iteratee) { - return baseFlatten(map(collection, iteratee), INFINITY); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDepth([1, 2], duplicate, 2); - * // => [[1, 1], [2, 2]] - */ - function flatMapDepth(collection, iteratee, depth) { - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(map(collection, iteratee), depth); - } - - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias each - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight - * @example - * - * _.forEach([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. - * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @alias eachRight - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEach - * @example - * - * _.forEachRight([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `2` then `1`. - */ - function forEachRight(collection, iteratee) { - var func = isArray(collection) ? arrayEachRight : baseEachRight; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The order of grouped values - * is determined by the order they occur in `collection`. The corresponding - * value of each key is an array of elements responsible for generating the - * key. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': [4.2], '6': [6.1, 6.3] } - * - * // The `_.property` iteratee shorthand. - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - baseAssignValue(result, key, [value]); - } - }); - - /** - * Checks if `value` is in `collection`. If `collection` is a string, it's - * checked for a substring of `value`, otherwise - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * is used for equality comparisons. If `fromIndex` is negative, it's used as - * the offset from the end of `collection`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {boolean} Returns `true` if `value` is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'a': 1, 'b': 2 }, 1); - * // => true - * - * _.includes('abcd', 'bc'); - * // => true - */ - function includes(collection, value, fromIndex, guard) { - collection = isArrayLike(collection) ? collection : values(collection); - fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; - - var length = collection.length; - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); - } - return isString(collection) - ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) - : (!!length && baseIndexOf(collection, value, fromIndex) > -1); - } - - /** - * Invokes the method at `path` of each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `path` is a function, it's invoked - * for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke each method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invokeMap([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invokeMap = baseRest(function(collection, path, args) { - var index = -1, - isFunc = typeof path == 'function', - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value) { - result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); - }); - return result; - }); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the last element responsible for generating the key. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var array = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.keyBy(array, function(o) { - * return String.fromCharCode(o.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.keyBy(array, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - */ - var keyBy = createAggregator(function(result, value, key) { - baseAssignValue(result, key, value); - }); - - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - * @example - * - * function square(n) { - * return n * n; - * } - * - * _.map([4, 8], square); - * // => [16, 64] - * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // The `_.property` iteratee shorthand. - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee) { - var func = isArray(collection) ? arrayMap : baseMap; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.sortBy` except that it allows specifying the sort - * orders of the iteratees to sort by. If `orders` is unspecified, all values - * are sorted in ascending order. Otherwise, specify an order of "desc" for - * descending or "asc" for ascending sort order of corresponding values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] - * The iteratees to sort by. - * @param {string[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // Sort by `user` in ascending order and by `age` in descending order. - * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - function orderBy(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - orders = guard ? undefined : orders; - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseOrderBy(collection, iteratees, orders); - } - - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, the second of which - * contains elements `predicate` returns falsey for. The predicate is - * invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * _.partition(users, function(o) { return o.active; }); - * // => objects for [['fred'], ['barney', 'pebbles']] - * - * // The `_.matches` iteratee shorthand. - * _.partition(users, { 'age': 1, 'active': false }); - * // => objects for [['pebbles'], ['barney', 'fred']] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.partition(users, ['active', false]); - * // => objects for [['barney', 'pebbles'], ['fred']] - * - * // The `_.property` iteratee shorthand. - * _.partition(users, 'active'); - * // => objects for [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function(result, value, key) { - result[key ? 0 : 1].push(value); - }, function() { return [[], []]; }); - - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduceRight - * @example - * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * return result; - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) - */ - function reduce(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduce : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); - } - - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduce - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - function reduceRight(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduceRight : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); - } - - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.filter - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * _.reject(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.reject(users, { 'age': 40, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.reject(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.reject(users, 'active'); - * // => objects for ['barney'] - */ - function reject(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, negate(getIteratee(predicate, 3))); - } - - /** - * Gets a random element from `collection`. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - */ - function sample(collection) { - var func = isArray(collection) ? arraySample : baseSample; - return func(collection); - } - - /** - * Gets `n` random elements at unique keys from `collection` up to the - * size of `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @param {number} [n=1] The number of elements to sample. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the random elements. - * @example - * - * _.sampleSize([1, 2, 3], 2); - * // => [3, 1] - * - * _.sampleSize([1, 2, 3], 4); - * // => [2, 3, 1] - */ - function sampleSize(collection, n, guard) { - if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - var func = isArray(collection) ? arraySampleSize : baseSampleSize; - return func(collection, n); - } - - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - var func = isArray(collection) ? arrayShuffle : baseShuffle; - return func(collection); - } - - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - if (collection == null) { - return 0; - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length; - } - var tag = getTag(collection); - if (tag == mapTag || tag == setTag) { - return collection.size; - } - return baseKeys(collection).length; - } - - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, guard) { - var func = isArray(collection) ? arraySome : baseSome; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.sortBy(users, [function(o) { return o.user; }]); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - */ - var sortBy = baseRest(function(collection, iteratees) { - if (collection == null) { - return []; - } - var length = iteratees.length; - if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { - iteratees = []; - } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { - iteratees = [iteratees[0]]; - } - return baseOrderBy(collection, baseFlatten(iteratees, 1), []); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ - var now = ctxNow || function() { - return root.Date.now(); - }; - - /*------------------------------------------------------------------------*/ - - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it's called `n` or more times. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => Logs 'done saving!' after the two async saves have completed. - */ - function after(n, func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - - /** - * Creates a function that invokes `func`, with up to `n` arguments, - * ignoring any additional arguments. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - n = guard ? undefined : n; - n = (func && n == null) ? func.length : n; - return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); - } - - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * function greet(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // Bound with placeholders. - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = baseRest(function(func, thisArg, partials) { - var bitmask = WRAP_BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bind)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(func, bitmask, thisArg, partials, holders); - }); - - /** - * Creates a function that invokes the method at `object[key]` with `partials` - * prepended to the arguments it receives. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. See - * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Function - * @param {Object} object The object to invoke the method on. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // Bound with placeholders. - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = baseRest(function(object, key, partials) { - var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bindKey)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(key, bitmask, object, partials, holders); - }); - - /** - * Creates a function that accepts arguments of `func` and either invokes - * `func` returning its result, if at least `arity` number of arguments have - * been provided, or returns a function that accepts the remaining `func` - * arguments, and so on. The arity of `func` may be specified if `func.length` - * is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - function curry(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curry.placeholder; - return result; - } - - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - function curryRight(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryRight.placeholder; - return result; - } - - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ - function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - timeWaiting = wait - timeSinceLastCall; - - return maxing - ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) - : timeWaiting; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; - } - - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // => Logs 'deferred' after one millisecond. - */ - var defer = baseRest(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => Logs 'later' after one second. - */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); - }); - - /** - * Creates a function that invokes `func` with arguments reversed. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to flip arguments for. - * @returns {Function} Returns the new flipped function. - * @example - * - * var flipped = _.flip(function() { - * return _.toArray(arguments); - * }); - * - * flipped('a', 'b', 'c', 'd'); - * // => ['d', 'c', 'b', 'a'] - */ - function flip(func) { - return createWrap(func, WRAP_FLIP_FLAG); - } - - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoized function. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] - * - * object.a = 2; - * values(object); - * // => [1, 2] - * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] - * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; - } - - // Expose `MapCache`. - memoize.Cache = MapCache; - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var args = arguments; - switch (args.length) { - case 0: return !predicate.call(this); - case 1: return !predicate.call(this, args[0]); - case 2: return !predicate.call(this, args[0], args[1]); - case 3: return !predicate.call(this, args[0], args[1], args[2]); - } - return !predicate.apply(this, args); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // => `createApplication` is invoked once - */ - function once(func) { - return before(2, func); - } - - /** - * Creates a function that invokes `func` with its arguments transformed. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms=[_.identity]] - * The argument transforms. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var func = _.overArgs(function(x, y) { - * return [x, y]; - * }, [square, doubled]); - * - * func(9, 3); - * // => [81, 6] - * - * func(10, 5); - * // => [100, 10] - */ - var overArgs = castRest(function(func, transforms) { - transforms = (transforms.length == 1 && isArray(transforms[0])) - ? arrayMap(transforms[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); - - var funcsLength = transforms.length; - return baseRest(function(args) { - var index = -1, - length = nativeMin(args.length, funcsLength); - - while (++index < length) { - args[index] = transforms[index].call(this, args[index]); - } - return apply(func, this, args); - }); - }); - - /** - * Creates a function that invokes `func` with `partials` prepended to the - * arguments it receives. This method is like `_.bind` except it does **not** - * alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 0.2.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // Partially applied with placeholders. - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partial)); - return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); - }); - - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to the arguments it receives. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // Partially applied with placeholders. - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partialRight)); - return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); - }); - - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified `indexes` where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, [2, 0, 1]); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - */ - var rearg = flatRest(function(func, indexes) { - return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); - }); - - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as - * an array. - * - * **Note:** This method is based on the - * [rest parameter](https://mdn.io/rest_parameters). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.rest(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function rest(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start === undefined ? start : toInteger(start); - return baseRest(func, start); - } - - /** - * Creates a function that invokes `func` with the `this` binding of the - * create function and an array of arguments much like - * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). - * - * **Note:** This method is based on the - * [spread operator](https://mdn.io/spread_operator). - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Function - * @param {Function} func The function to spread arguments over. - * @param {number} [start=0] The start position of the spread. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start == null ? 0 : nativeMax(toInteger(start), 0); - return baseRest(function(args) { - var array = args[start], - otherArgs = castSlice(args, 0, start); - - if (array) { - arrayPush(otherArgs, array); - } - return apply(func, this, otherArgs); - }); - } - - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // Avoid excessively updating the position while scrolling. - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); - * - * // Cancel the trailing throttled invocation. - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing - }); - } - - /** - * Creates a function that accepts up to one argument, ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.unary(parseInt)); - * // => [6, 8, 10] - */ - function unary(func) { - return ary(func, 1); - } - - /** - * Creates a function that provides `value` to `wrapper` as its first - * argument. Any additional arguments provided to the function are appended - * to those provided to the `wrapper`. The wrapper is invoked with the `this` - * binding of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {*} value The value to wrap. - * @param {Function} [wrapper=identity] The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

' + func(text) + '

'; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

fred, barney, & pebbles

' - */ - function wrap(value, wrapper) { - return partial(castFunction(wrapper), value); - } - - /*------------------------------------------------------------------------*/ - - /** - * Casts `value` as an array if it's not one. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Lang - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast array. - * @example - * - * _.castArray(1); - * // => [1] - * - * _.castArray({ 'a': 1 }); - * // => [{ 'a': 1 }] - * - * _.castArray('abc'); - * // => ['abc'] - * - * _.castArray(null); - * // => [null] - * - * _.castArray(undefined); - * // => [undefined] - * - * _.castArray(); - * // => [] - * - * var array = [1, 2, 3]; - * console.log(_.castArray(array) === array); - * // => true - */ - function castArray() { - if (!arguments.length) { - return []; - } - var value = arguments[0]; - return isArray(value) ? value : [value]; - } - - /** - * Creates a shallow clone of `value`. - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to clone. - * @returns {*} Returns the cloned value. - * @see _.cloneDeep - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); - * // => true - */ - function clone(value) { - return baseClone(value, CLONE_SYMBOLS_FLAG); - } - - /** - * This method is like `_.clone` except that it accepts `customizer` which - * is invoked to produce the cloned value. If `customizer` returns `undefined`, - * cloning is handled by the method instead. The `customizer` is invoked with - * up to four arguments; (value [, index|key, object, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the cloned value. - * @see _.cloneDeepWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * } - * - * var el = _.cloneWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 0 - */ - function cloneWith(value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); - } - - /** - * This method is like `_.clone` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @returns {*} Returns the deep cloned value. - * @see _.clone - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); - * // => false - */ - function cloneDeep(value) { - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); - } - - /** - * This method is like `_.cloneWith` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the deep cloned value. - * @see _.cloneWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * } - * - * var el = _.cloneDeepWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 20 - */ - function cloneDeepWith(value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); - } - - /** - * Checks if `object` conforms to `source` by invoking the predicate - * properties of `source` with the corresponding property values of `object`. - * - * **Note:** This method is equivalent to `_.conforms` when `source` is - * partially applied. - * - * @static - * @memberOf _ - * @since 4.14.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); - * // => true - * - * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); - * // => false - */ - function conformsTo(object, source) { - return source == null || baseConformsTo(object, source, keys(source)); - } - - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); - } - - /** - * Checks if `value` is greater than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - * @see _.lt - * @example - * - * _.gt(3, 1); - * // => true - * - * _.gt(3, 3); - * // => false - * - * _.gt(1, 3); - * // => false - */ - var gt = createRelationalOperation(baseGt); - - /** - * Checks if `value` is greater than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to - * `other`, else `false`. - * @see _.lte - * @example - * - * _.gte(3, 1); - * // => true - * - * _.gte(3, 3); - * // => true - * - * _.gte(1, 3); - * // => false - */ - var gte = createRelationalOperation(function(value, other) { - return value >= other; - }); - - /** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); - }; - - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ - var isArray = Array.isArray; - - /** - * Checks if `value` is classified as an `ArrayBuffer` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - * @example - * - * _.isArrayBuffer(new ArrayBuffer(2)); - * // => true - * - * _.isArrayBuffer(new Array(2)); - * // => false - */ - var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; - - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && baseGetTag(value) == boolTag); - } - - /** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ - var isBuffer = nativeIsBuffer || stubFalse; - - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; - - /** - * Checks if `value` is likely a DOM element. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); - } - - /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || - isBuffer(value) || isTypedArray(value) || isArguments(value))) { - return !value.length; - } - var tag = getTag(value); - if (tag == mapTag || tag == setTag) { - return !value.size; - } - if (isPrototype(value)) { - return !baseKeys(value).length; - } - for (var key in value) { - if (hasOwnProperty.call(value, key)) { - return false; - } - } - return true; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are compared by strict equality, i.e. `===`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } - - /** - * This method is like `_.isEqual` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with up to - * six arguments: (objValue, othValue [, index|key, object, other, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, othValue) { - * if (isGreeting(objValue) && isGreeting(othValue)) { - * return true; - * } - * } - * - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqualWith(array, other, customizer); - * // => true - */ - function isEqualWith(value, other, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; - } - - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - if (!isObjectLike(value)) { - return false; - } - var tag = baseGetTag(value); - return tag == errorTag || tag == domExcTag || - (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); - } - - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(3); - * // => true - * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); - * // => false - * - * _.isFinite('3'); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } - - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - if (!isObject(value)) { - return false; - } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; - } - - /** - * Checks if `value` is an integer. - * - * **Note:** This method is based on - * [`Number.isInteger`](https://mdn.io/Number/isInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an integer, else `false`. - * @example - * - * _.isInteger(3); - * // => true - * - * _.isInteger(Number.MIN_VALUE); - * // => false - * - * _.isInteger(Infinity); - * // => false - * - * _.isInteger('3'); - * // => false - */ - function isInteger(value) { - return typeof value == 'number' && value == toInteger(value); - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ - function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); - } - - /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return value != null && typeof value == 'object'; - } - - /** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ - var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - - /** - * Performs a partial deep comparison between `object` and `source` to - * determine if `object` contains equivalent property values. - * - * **Note:** This method is equivalent to `_.matches` when `source` is - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.isMatch(object, { 'b': 2 }); - * // => true - * - * _.isMatch(object, { 'b': 1 }); - * // => false - */ - function isMatch(object, source) { - return object === source || baseIsMatch(object, source, getMatchData(source)); - } - - /** - * This method is like `_.isMatch` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with five - * arguments: (objValue, srcValue, index|key, object, source). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, srcValue) { - * if (isGreeting(objValue) && isGreeting(srcValue)) { - * return true; - * } - * } - * - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatchWith(object, source, customizer); - * // => true - */ - function isMatchWith(object, source, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseIsMatch(object, source, getMatchData(source), customizer); - } - - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. - return isNumber(value) && value != +value; - } - - /** - * Checks if `value` is a pristine native function. - * - * **Note:** This method can't reliably detect native functions in the presence - * of the core-js package because core-js circumvents this kind of detection. - * Despite multiple requests, the core-js maintainer has made it clear: any - * attempt to fix the detection will be obstructed. As a result, we're left - * with little choice but to throw an error. Unfortunately, this also affects - * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), - * which rely on core-js. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (isMaskable(value)) { - throw new Error(CORE_ERROR_TEXT); - } - return baseIsNative(value); - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is `null` or `undefined`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is nullish, else `false`. - * @example - * - * _.isNil(null); - * // => true - * - * _.isNil(void 0); - * // => true - * - * _.isNil(NaN); - * // => false - */ - function isNil(value) { - return value == null; - } - - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. - * @example - * - * _.isNumber(3); - * // => true - * - * _.isNumber(Number.MIN_VALUE); - * // => true - * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && baseGetTag(value) == numberTag); - } - - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * @static - * @memberOf _ - * @since 0.8.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - if (!isObjectLike(value) || baseGetTag(value) != objectTag) { - return false; - } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return typeof Ctor == 'function' && Ctor instanceof Ctor && - funcToString.call(Ctor) == objectCtorString; - } - - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; - - /** - * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 - * double precision number which isn't the result of a rounded unsafe integer. - * - * **Note:** This method is based on - * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. - * @example - * - * _.isSafeInteger(3); - * // => true - * - * _.isSafeInteger(Number.MIN_VALUE); - * // => false - * - * _.isSafeInteger(Infinity); - * // => false - * - * _.isSafeInteger('3'); - * // => false - */ - function isSafeInteger(value) { - return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ - var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; - - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); - } - - /** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); - } - - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - - /** - * Checks if `value` is `undefined`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - - /** - * Checks if `value` is classified as a `WeakMap` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. - * @example - * - * _.isWeakMap(new WeakMap); - * // => true - * - * _.isWeakMap(new Map); - * // => false - */ - function isWeakMap(value) { - return isObjectLike(value) && getTag(value) == weakMapTag; - } - - /** - * Checks if `value` is classified as a `WeakSet` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. - * @example - * - * _.isWeakSet(new WeakSet); - * // => true - * - * _.isWeakSet(new Set); - * // => false - */ - function isWeakSet(value) { - return isObjectLike(value) && baseGetTag(value) == weakSetTag; - } - - /** - * Checks if `value` is less than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - * @see _.gt - * @example - * - * _.lt(1, 3); - * // => true - * - * _.lt(3, 3); - * // => false - * - * _.lt(3, 1); - * // => false - */ - var lt = createRelationalOperation(baseLt); - - /** - * Checks if `value` is less than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to - * `other`, else `false`. - * @see _.gte - * @example - * - * _.lte(1, 3); - * // => true - * - * _.lte(3, 3); - * // => true - * - * _.lte(3, 1); - * // => false - */ - var lte = createRelationalOperation(function(value, other) { - return value <= other; - }); - - /** - * Converts `value` to an array. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] - */ - function toArray(value) { - if (!value) { - return []; - } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value); - } - if (symIterator && value[symIterator]) { - return iteratorToArray(value[symIterator]()); - } - var tag = getTag(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - - return func(value); - } - - /** - * Converts `value` to a finite number. - * - * @static - * @memberOf _ - * @since 4.12.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted number. - * @example - * - * _.toFinite(3.2); - * // => 3.2 - * - * _.toFinite(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toFinite(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toFinite('3.2'); - * // => 3.2 - */ - function toFinite(value) { - if (!value) { - return value === 0 ? value : 0; - } - value = toNumber(value); - if (value === INFINITY || value === -INFINITY) { - var sign = (value < 0 ? -1 : 1); - return sign * MAX_INTEGER; - } - return value === value ? value : 0; - } - - /** - * Converts `value` to an integer. - * - * **Note:** This method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - function toInteger(value) { - var result = toFinite(value), - remainder = result % 1; - - return result === result ? (remainder ? result - remainder : result) : 0; - } - - /** - * Converts `value` to an integer suitable for use as the length of an - * array-like object. - * - * **Note:** This method is based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toLength(3.2); - * // => 3 - * - * _.toLength(Number.MIN_VALUE); - * // => 0 - * - * _.toLength(Infinity); - * // => 4294967295 - * - * _.toLength('3.2'); - * // => 3 - */ - function toLength(value) { - return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; - } - - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); - } - - /** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return copyObject(value, keysIn(value)); - } - - /** - * Converts `value` to a safe integer. A safe integer can be compared and - * represented correctly. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toSafeInteger(3.2); - * // => 3 - * - * _.toSafeInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toSafeInteger(Infinity); - * // => 9007199254740991 - * - * _.toSafeInteger('3.2'); - * // => 3 - */ - function toSafeInteger(value) { - return value - ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) - : (value === 0 ? value : 0); - } - - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); - } - - /*------------------------------------------------------------------------*/ - - /** - * Assigns own enumerable string keyed properties of source objects to the - * destination object. Source objects are applied from left to right. - * Subsequent sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object` and is loosely based on - * [`Object.assign`](https://mdn.io/Object/assign). - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assignIn - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assign({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'c': 3 } - */ - var assign = createAssigner(function(object, source) { - if (isPrototype(source) || isArrayLike(source)) { - copyObject(source, keys(source), object); - return; - } - for (var key in source) { - if (hasOwnProperty.call(source, key)) { - assignValue(object, key, source[key]); - } - } - }); - - /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, keysIn(source), object); - }); - - /** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignInWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); - }); - - /** - * This method is like `_.assign` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignInWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keys(source), object, customizer); - }); - - /** - * Creates an array of values corresponding to `paths` of `object`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Array} Returns the picked values. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _.at(object, ['a[0].b.c', 'a[1]']); - * // => [3, 4] - */ - var at = flatRest(baseAt); - - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties == null ? result : baseAssign(result, properties); - } - - /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaultsDeep - * @example - * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var defaults = baseRest(function(object, sources) { - object = Object(object); - - var index = -1; - var length = sources.length; - var guard = length > 2 ? sources[2] : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - length = 1; - } - - while (++index < length) { - var source = sources[index]; - var props = keysIn(source); - var propsIndex = -1; - var propsLength = props.length; - - while (++propsIndex < propsLength) { - var key = props[propsIndex]; - var value = object[key]; - - if (value === undefined || - (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { - object[key] = source[key]; - } - } - } - - return object; - }); - - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaults - * @example - * - * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); - * // => { 'a': { 'b': 2, 'c': 3 } } - */ - var defaultsDeep = baseRest(function(args) { - args.push(undefined, customDefaultsMerge); - return apply(mergeWith, undefined, args); - }); - - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(o) { return o.age < 40; }); - * // => 'barney' (iteration order is not guaranteed) - * - * // The `_.matches` iteratee shorthand. - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findKey(users, 'active'); - * // => 'barney' - */ - function findKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); - } - - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns 'pebbles' assuming `_.findKey` returns 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - function findLastKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); - } - - /** - * Iterates over own and inherited enumerable string keyed properties of an - * object and invokes `iteratee` for each property. The iteratee is invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forInRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). - */ - function forIn(object, iteratee) { - return object == null - ? object - : baseFor(object, getIteratee(iteratee, 3), keysIn); - } - - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forIn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. - */ - function forInRight(object, iteratee) { - return object == null - ? object - : baseForRight(object, getIteratee(iteratee, 3), keysIn); - } - - /** - * Iterates over own enumerable string keyed properties of an object and - * invokes `iteratee` for each property. The iteratee is invoked with three - * arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwnRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forOwn(object, iteratee) { - return object && baseForOwn(object, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. - */ - function forOwnRight(object, iteratee) { - return object && baseForOwnRight(object, getIteratee(iteratee, 3)); - } - - /** - * Creates an array of function property names from own enumerable properties - * of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functionsIn - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functions(new Foo); - * // => ['a', 'b'] - */ - function functions(object) { - return object == null ? [] : baseFunctions(object, keys(object)); - } - - /** - * Creates an array of function property names from own and inherited - * enumerable properties of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functions - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functionsIn(new Foo); - * // => ['a', 'b', 'c'] - */ - function functionsIn(object) { - return object == null ? [] : baseFunctions(object, keysIn(object)); - } - - /** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); - return result === undefined ? defaultValue : result; - } - - /** - * Checks if `path` is a direct property of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b'); - * // => true - * - * _.has(object, ['a', 'b']); - * // => true - * - * _.has(other, 'a'); - * // => false - */ - function has(object, path) { - return object != null && hasPath(object, path, baseHas); - } - - /** - * Checks if `path` is a direct or inherited property of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.hasIn(object, 'a'); - * // => true - * - * _.hasIn(object, 'a.b'); - * // => true - * - * _.hasIn(object, ['a', 'b']); - * // => true - * - * _.hasIn(object, 'b'); - * // => false - */ - function hasIn(object, path) { - return object != null && hasPath(object, path, baseHasIn); - } - - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite - * property assignments of previous values. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Object - * @param {Object} object The object to invert. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - */ - var invert = createInverter(function(result, value, key) { - if (value != null && - typeof value.toString != 'function') { - value = nativeObjectToString.call(value); - } - - result[value] = key; - }, constant(identity)); - - /** - * This method is like `_.invert` except that the inverted object is generated - * from the results of running each element of `object` thru `iteratee`. The - * corresponding inverted value of each inverted key is an array of keys - * responsible for generating the inverted value. The iteratee is invoked - * with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Object - * @param {Object} object The object to invert. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invertBy(object); - * // => { '1': ['a', 'c'], '2': ['b'] } - * - * _.invertBy(object, function(value) { - * return 'group' + value; - * }); - * // => { 'group1': ['a', 'c'], 'group2': ['b'] } - */ - var invertBy = createInverter(function(result, value, key) { - if (value != null && - typeof value.toString != 'function') { - value = nativeObjectToString.call(value); - } - - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - }, getIteratee); - - /** - * Invokes the method at `path` of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - * @example - * - * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; - * - * _.invoke(object, 'a[0].b.c.slice', 1, 3); - * // => [2, 3] - */ - var invoke = baseRest(baseInvoke); - - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); - } - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); - } - - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * string keyed property of `object` thru `iteratee`. The iteratee is invoked - * with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapValues - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - function mapKeys(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - baseAssignValue(result, iteratee(value, key, object), value); - }); - return result; - } - - /** - * Creates an object with the same keys as `object` and values generated - * by running each own enumerable string keyed property of `object` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, key, object). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapKeys - * @example - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * _.mapValues(users, function(o) { return o.age; }); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - * - * // The `_.property` iteratee shorthand. - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - function mapValues(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - baseAssignValue(result, key, iteratee(value, key, object)); - }); - return result; - } - - /** - * This method is like `_.assign` except that it recursively merges own and - * inherited enumerable string keyed properties of source objects into the - * destination object. Source properties that resolve to `undefined` are - * skipped if a destination value exists. Array and plain object properties - * are merged recursively. Other objects and value types are overridden by - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ - var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); - }); - - /** - * This method is like `_.merge` except that it accepts `customizer` which - * is invoked to produce the merged values of the destination and source - * properties. If `customizer` returns `undefined`, merging is handled by the - * method instead. The `customizer` is invoked with six arguments: - * (objValue, srcValue, key, object, source, stack). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * function customizer(objValue, srcValue) { - * if (_.isArray(objValue)) { - * return objValue.concat(srcValue); - * } - * } - * - * var object = { 'a': [1], 'b': [2] }; - * var other = { 'a': [3], 'b': [4] }; - * - * _.mergeWith(object, other, customizer); - * // => { 'a': [1, 3], 'b': [2, 4] } - */ - var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { - baseMerge(object, source, srcIndex, customizer); - }); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable property paths of `object` that are not omitted. - * - * **Note:** This method is considerably slower than `_.pick`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to omit. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omit(object, ['a', 'c']); - * // => { 'b': '2' } - */ - var omit = flatRest(function(object, paths) { - var result = {}; - if (object == null) { - return result; - } - var isDeep = false; - paths = arrayMap(paths, function(path) { - path = castPath(path, object); - isDeep || (isDeep = path.length > 1); - return path; - }); - copyObject(object, getAllKeysIn(object), result); - if (isDeep) { - result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); - } - var length = paths.length; - while (length--) { - baseUnset(result, paths[length]); - } - return result; - }); - - /** - * The opposite of `_.pickBy`; this method creates an object composed of - * the own and inherited enumerable string keyed properties of `object` that - * `predicate` doesn't return truthy for. The predicate is invoked with two - * arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omitBy(object, _.isNumber); - * // => { 'b': '2' } - */ - function omitBy(object, predicate) { - return pickBy(object, negate(getIteratee(predicate))); - } - - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = flatRest(function(object, paths) { - return object == null ? {} : basePick(object, paths); - }); - - /** - * Creates an object composed of the `object` properties `predicate` returns - * truthy for. The predicate is invoked with two arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pickBy(object, _.isNumber); - * // => { 'a': 1, 'c': 3 } - */ - function pickBy(object, predicate) { - if (object == null) { - return {}; - } - var props = arrayMap(getAllKeysIn(object), function(prop) { - return [prop]; - }); - predicate = getIteratee(predicate); - return basePickBy(object, props, function(value, path) { - return predicate(value, path[0]); - }); - } - - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a[0].b.c3', 'default'); - * // => 'default' - * - * _.result(object, 'a[0].b.c3', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - path = castPath(path, object); - - var index = -1, - length = path.length; - - // Ensure the loop is entered when path is empty. - if (!length) { - length = 1; - object = undefined; - } - while (++index < length) { - var value = object == null ? undefined : object[toKey(path[index])]; - if (value === undefined) { - index = length; - value = defaultValue; - } - object = isFunction(value) ? value.call(object) : value; - } - return object; - } - - /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, - * it's created. Arrays are created for missing index properties while objects - * are created for all other missing properties. Use `_.setWith` to customize - * `path` creation. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, ['x', '0', 'y', 'z'], 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - return object == null ? object : baseSet(object, path, value); - } - - /** - * This method is like `_.set` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.setWith(object, '[0][1]', 'a', Object); - * // => { '0': { '1': 'a' } } - */ - function setWith(object, path, value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseSet(object, path, value, customizer); - } - - /** - * Creates an array of own enumerable string keyed-value pairs for `object` - * which can be consumed by `_.fromPairs`. If `object` is a map or set, its - * entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entries - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairs(new Foo); - * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) - */ - var toPairs = createToPairs(keys); - - /** - * Creates an array of own and inherited enumerable string keyed-value pairs - * for `object` which can be consumed by `_.fromPairs`. If `object` is a map - * or set, its entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entriesIn - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) - */ - var toPairsIn = createToPairs(keysIn); - - /** - * An alternative to `_.reduce`; this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own - * enumerable string keyed properties thru `iteratee`, with each invocation - * potentially mutating the `accumulator` object. If `accumulator` is not - * provided, a new object with the same `[[Prototype]]` will be used. The - * iteratee is invoked with four arguments: (accumulator, value, key, object). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @returns {*} Returns the accumulated value. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }, []); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function transform(object, iteratee, accumulator) { - var isArr = isArray(object), - isArrLike = isArr || isBuffer(object) || isTypedArray(object); - - iteratee = getIteratee(iteratee, 4); - if (accumulator == null) { - var Ctor = object && object.constructor; - if (isArrLike) { - accumulator = isArr ? new Ctor : []; - } - else if (isObject(object)) { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; - } - else { - accumulator = {}; - } - } - (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } - - /** - * Removes the property at `path` of `object`. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 7 } }] }; - * _.unset(object, 'a[0].b.c'); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - * - * _.unset(object, ['a', '0', 'b', 'c']); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - */ - function unset(object, path) { - return object == null ? true : baseUnset(object, path); - } - - /** - * This method is like `_.set` except that accepts `updater` to produce the - * value to set. Use `_.updateWith` to customize `path` creation. The `updater` - * is invoked with one argument: (value). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.update(object, 'a[0].b.c', function(n) { return n * n; }); - * console.log(object.a[0].b.c); - * // => 9 - * - * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); - * console.log(object.x[0].y.z); - * // => 0 - */ - function update(object, path, updater) { - return object == null ? object : baseUpdate(object, path, castFunction(updater)); - } - - /** - * This method is like `_.update` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.updateWith(object, '[0][1]', _.constant('a'), Object); - * // => { '0': { '1': 'a' } } - */ - function updateWith(object, path, updater, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); - } - - /** - * Creates an array of the own enumerable string keyed property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return object == null ? [] : baseValues(object, keys(object)); - } - - /** - * Creates an array of the own and inherited enumerable string keyed property - * values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return object == null ? [] : baseValues(object, keysIn(object)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Clamps `number` within the inclusive `lower` and `upper` bounds. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Number - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - * @example - * - * _.clamp(-10, -5, 5); - * // => -5 - * - * _.clamp(10, -5, 5); - * // => 5 - */ - function clamp(number, lower, upper) { - if (upper === undefined) { - upper = lower; - lower = undefined; - } - if (upper !== undefined) { - upper = toNumber(upper); - upper = upper === upper ? upper : 0; - } - if (lower !== undefined) { - lower = toNumber(lower); - lower = lower === lower ? lower : 0; - } - return baseClamp(toNumber(number), lower, upper); - } - - /** - * Checks if `n` is between `start` and up to, but not including, `end`. If - * `end` is not specified, it's set to `start` with `start` then set to `0`. - * If `start` is greater than `end` the params are swapped to support - * negative ranges. - * - * @static - * @memberOf _ - * @since 3.3.0 - * @category Number - * @param {number} number The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - * @see _.range, _.rangeRight - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - * - * _.inRange(-3, -2, -6); - * // => true - */ - function inRange(number, start, end) { - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - number = toNumber(number); - return baseInRange(number, start, end); - } - - /** - * Produces a random number between the inclusive `lower` and `upper` bounds. - * If only one argument is provided a number between `0` and the given number - * is returned. If `floating` is `true`, or either `lower` or `upper` are - * floats, a floating-point number is returned instead of an integer. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Number - * @param {number} [lower=0] The lower bound. - * @param {number} [upper=1] The upper bound. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(lower, upper, floating) { - if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { - upper = floating = undefined; - } - if (floating === undefined) { - if (typeof upper == 'boolean') { - floating = upper; - upper = undefined; - } - else if (typeof lower == 'boolean') { - floating = lower; - lower = undefined; - } - } - if (lower === undefined && upper === undefined) { - lower = 0; - upper = 1; - } - else { - lower = toFinite(lower); - if (upper === undefined) { - upper = lower; - lower = 0; - } else { - upper = toFinite(upper); - } - } - if (lower > upper) { - var temp = lower; - lower = upper; - upper = temp; - } - if (floating || lower % 1 || upper % 1) { - var rand = nativeRandom(); - return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); - } - return baseRandom(lower, upper); - } - - /*------------------------------------------------------------------------*/ - - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar--'); - * // => 'fooBar' - * - * _.camelCase('__FOO_BAR__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function(result, word, index) { - word = word.toLowerCase(); - return result + (index ? capitalize(word) : word); - }); - - /** - * Converts the first character of `string` to upper case and the remaining - * to lower case. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('FRED'); - * // => 'Fred' - */ - function capitalize(string) { - return upperFirst(toString(string).toLowerCase()); - } - - /** - * Deburrs `string` by converting - * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) - * letters to basic Latin letters and removing - * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('déjà vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = toString(string); - return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); - } - - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search up to. - * @returns {boolean} Returns `true` if `string` ends with `target`, - * else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = toString(string); - target = baseToString(target); - - var length = string.length; - position = position === undefined - ? length - : baseClamp(toInteger(position), 0, length); - - var end = position; - position -= target.length; - return position >= 0 && string.slice(position, end) == target; - } - - /** - * Converts the characters "&", "<", ">", '"', and "'" in `string` to their - * corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - string = toString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } - - /** - * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", - * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https://lodash\.com/\)' - */ - function escapeRegExp(string) { - string = toString(string); - return (string && reHasRegExpChar.test(string)) - ? string.replace(reRegExpChar, '\\$&') - : string; - } - - /** - * Converts `string` to - * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__FOO_BAR__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function(result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); - }); - - /** - * Converts `string`, as space separated words, to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the lower cased string. - * @example - * - * _.lowerCase('--Foo-Bar--'); - * // => 'foo bar' - * - * _.lowerCase('fooBar'); - * // => 'foo bar' - * - * _.lowerCase('__FOO_BAR__'); - * // => 'foo bar' - */ - var lowerCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + word.toLowerCase(); - }); - - /** - * Converts the first character of `string` to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.lowerFirst('Fred'); - * // => 'fred' - * - * _.lowerFirst('FRED'); - * // => 'fRED' - */ - var lowerFirst = createCaseFirst('toLowerCase'); - - /** - * Pads `string` on the left and right sides if it's shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - if (!length || strLength >= length) { - return string; - } - var mid = (length - strLength) / 2; - return ( - createPadding(nativeFloor(mid), chars) + - string + - createPadding(nativeCeil(mid), chars) - ); - } - - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padEnd('abc', 6); - * // => 'abc ' - * - * _.padEnd('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padEnd('abc', 3); - * // => 'abc' - */ - function padEnd(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (string + createPadding(length - strLength, chars)) - : string; - } - - /** - * Pads `string` on the left side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padStart('abc', 6); - * // => ' abc' - * - * _.padStart('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padStart('abc', 3); - * // => 'abc' - */ - function padStart(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (createPadding(length - strLength, chars) + string) - : string; - } - - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a - * hexadecimal, in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the - * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category String - * @param {string} string The string to convert. - * @param {number} [radix=10] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - if (guard || radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); - } - - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=1] The number of times to repeat the string. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n, guard) { - if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - return baseRepeat(toString(string), n); - } - - /** - * Replaces matches for `pattern` in `string` with `replacement`. - * - * **Note:** This method is based on - * [`String#replace`](https://mdn.io/String/replace). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to modify. - * @param {RegExp|string} pattern The pattern to replace. - * @param {Function|string} replacement The match replacement. - * @returns {string} Returns the modified string. - * @example - * - * _.replace('Hi Fred', 'Fred', 'Barney'); - * // => 'Hi Barney' - */ - function replace() { - var args = arguments, - string = toString(args[0]); - - return args.length < 3 ? string : string.replace(args[1], args[2]); - } - - /** - * Converts `string` to - * [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--FOO-BAR--'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function(result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); - - /** - * Splits `string` by `separator`. - * - * **Note:** This method is based on - * [`String#split`](https://mdn.io/String/split). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to split. - * @param {RegExp|string} separator The separator pattern to split by. - * @param {number} [limit] The length to truncate results to. - * @returns {Array} Returns the string segments. - * @example - * - * _.split('a-b-c', '-', 2); - * // => ['a', 'b'] - */ - function split(string, separator, limit) { - if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { - separator = limit = undefined; - } - limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; - if (!limit) { - return []; - } - string = toString(string); - if (string && ( - typeof separator == 'string' || - (separator != null && !isRegExp(separator)) - )) { - separator = baseToString(separator); - if (!separator && hasUnicode(string)) { - return castSlice(stringToArray(string), 0, limit); - } - } - return string.split(separator, limit); - } - - /** - * Converts `string` to - * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @since 3.1.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar--'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__FOO_BAR__'); - * // => 'FOO BAR' - */ - var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + upperFirst(word); - }); - - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, - * else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = toString(string); - position = position == null - ? 0 - : baseClamp(toInteger(position), 0, string.length); - - target = baseToString(target); - return string.slice(position, position + target.length) == target; - } - - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is given, it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options={}] The options object. - * @param {RegExp} [options.escape=_.templateSettings.escape] - * The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] - * The "evaluate" delimiter. - * @param {Object} [options.imports=_.templateSettings.imports] - * An object to import into the template as free variables. - * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] - * The "interpolate" delimiter. - * @param {string} [options.sourceURL='lodash.templateSources[n]'] - * The sourceURL of the compiled template. - * @param {string} [options.variable='obj'] - * The data object variable name. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the compiled template function. - * @example - * - * // Use the "interpolate" delimiter to create a compiled template. - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // Use the HTML "escape" delimiter to escape data property values. - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': '`);\n};\n\n/**\n * @public\n * @deprecated Use inline logic to check that the `X-Requested-With` header is set to `'XMLHttpRequest'` instead.\n */\nexport const ensuresXRequestedWith = (req: express.Request) => {\n const requiredHeader = req.header('X-Requested-With');\n if (!requiredHeader || requiredHeader !== 'XMLHttpRequest') {\n return false;\n }\n return true;\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { prepareBackstageIdentityResponse as _prepareBackstageIdentityResponse } from '@backstage/plugin-auth-node';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-auth-node` instead\n */\nexport const prepareBackstageIdentityResponse =\n _prepareBackstageIdentityResponse;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express, { CookieOptions } from 'express';\nimport crypto from 'crypto';\nimport { URL } from 'url';\nimport {\n AuthProviderConfig,\n AuthProviderRouteHandlers,\n BackstageIdentityResponse,\n BackstageSignInResult,\n CookieConfigurer,\n OAuthState,\n} from '@backstage/plugin-auth-node';\nimport {\n AuthenticationError,\n InputError,\n isError,\n NotAllowedError,\n} from '@backstage/errors';\nimport { defaultCookieConfigurer, readState, verifyNonce } from './helpers';\nimport {\n postMessageResponse,\n ensuresXRequestedWith,\n WebMessageResponse,\n} from '../flow';\nimport {\n OAuthHandlers,\n OAuthStartRequest,\n OAuthRefreshRequest,\n OAuthLogoutRequest,\n} from './types';\nimport { prepareBackstageIdentityResponse } from '../../providers/prepareBackstageIdentityResponse';\n\nexport const THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000;\nexport const TEN_MINUTES_MS = 600 * 1000;\n\n/**\n * @public\n * @deprecated Use `createOAuthRouteHandlers` from `@backstage/plugin-auth-node` instead\n */\nexport type OAuthAdapterOptions = {\n providerId: string;\n persistScopes?: boolean;\n appOrigin: string;\n baseUrl: string;\n cookieConfigurer: CookieConfigurer;\n isOriginAllowed: (origin: string) => boolean;\n callbackUrl: string;\n};\n\n/**\n * @public\n * @deprecated Use `createOAuthRouteHandlers` from `@backstage/plugin-auth-node` instead\n */\nexport class OAuthAdapter implements AuthProviderRouteHandlers {\n static fromConfig(\n config: AuthProviderConfig,\n handlers: OAuthHandlers,\n options: Pick<\n OAuthAdapterOptions,\n 'providerId' | 'persistScopes' | 'callbackUrl'\n >,\n ): OAuthAdapter {\n const { appUrl, baseUrl, isOriginAllowed } = config;\n const { origin: appOrigin } = new URL(appUrl);\n\n const cookieConfigurer = config.cookieConfigurer ?? defaultCookieConfigurer;\n\n return new OAuthAdapter(handlers, {\n ...options,\n appOrigin,\n baseUrl,\n cookieConfigurer,\n isOriginAllowed,\n });\n }\n\n private readonly baseCookieOptions: CookieOptions;\n\n constructor(\n private readonly handlers: OAuthHandlers,\n private readonly options: OAuthAdapterOptions,\n ) {\n this.baseCookieOptions = {\n httpOnly: true,\n sameSite: 'lax',\n };\n }\n\n async start(req: express.Request, res: express.Response): Promise {\n // retrieve scopes from request\n const scope = req.query.scope?.toString() ?? '';\n const env = req.query.env?.toString();\n const origin = req.query.origin?.toString();\n const redirectUrl = req.query.redirectUrl?.toString();\n const flow = req.query.flow?.toString();\n\n if (!env) {\n throw new InputError('No env provided in request query parameters');\n }\n\n const cookieConfig = this.getCookieConfig(origin);\n\n const nonce = crypto.randomBytes(16).toString('base64');\n // set a nonce cookie before redirecting to oauth provider\n this.setNonceCookie(res, nonce, cookieConfig);\n\n const state: OAuthState = { nonce, env, origin, redirectUrl, flow };\n\n // If scopes are persisted then we pass them through the state so that we\n // can set the cookie on successful auth\n if (this.options.persistScopes) {\n state.scope = scope;\n }\n const forwardReq = Object.assign(req, { scope, state });\n\n const { url, status } = await this.handlers.start(\n forwardReq as OAuthStartRequest,\n );\n\n res.statusCode = status || 302;\n res.setHeader('Location', url);\n res.setHeader('Content-Length', '0');\n res.end();\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise {\n let appOrigin = this.options.appOrigin;\n\n try {\n const state: OAuthState = readState(req.query.state?.toString() ?? '');\n\n if (state.origin) {\n try {\n appOrigin = new URL(state.origin).origin;\n } catch {\n throw new NotAllowedError('App origin is invalid, failed to parse');\n }\n if (!this.options.isOriginAllowed(appOrigin)) {\n throw new NotAllowedError(`Origin '${appOrigin}' is not allowed`);\n }\n }\n\n // verify nonce cookie and state cookie on callback\n verifyNonce(req, this.options.providerId);\n\n const { response, refreshToken } = await this.handlers.handler(req);\n\n const cookieConfig = this.getCookieConfig(appOrigin);\n\n // Store the scope that we have been granted for this session. This is useful if\n // the provider does not return granted scopes on refresh or if they are normalized.\n if (this.options.persistScopes && state.scope) {\n this.setGrantedScopeCookie(res, state.scope, cookieConfig);\n response.providerInfo.scope = state.scope;\n }\n\n if (refreshToken) {\n // set new refresh token\n this.setRefreshTokenCookie(res, refreshToken, cookieConfig);\n }\n\n const identity = await this.populateIdentity(response.backstageIdentity);\n\n const responseObj: WebMessageResponse = {\n type: 'authorization_response',\n response: { ...response, backstageIdentity: identity },\n };\n\n if (state.flow === 'redirect') {\n if (!state.redirectUrl) {\n throw new InputError(\n 'No redirectUrl provided in request query parameters',\n );\n }\n res.redirect(state.redirectUrl);\n return undefined;\n }\n // post message back to popup if successful\n return postMessageResponse(res, appOrigin, responseObj);\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n // post error message back to popup if failure\n return postMessageResponse(res, appOrigin, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n }\n\n async logout(req: express.Request, res: express.Response): Promise {\n if (!ensuresXRequestedWith(req)) {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (this.handlers.logout) {\n const refreshToken = this.getRefreshTokenFromCookie(req);\n const revokeRequest: OAuthLogoutRequest = Object.assign(req, {\n refreshToken,\n });\n await this.handlers.logout(revokeRequest);\n }\n\n // remove refresh token cookie if it is set\n const origin = req.get('origin');\n const cookieConfig = this.getCookieConfig(origin);\n this.removeRefreshTokenCookie(res, cookieConfig);\n\n res.status(200).end();\n }\n\n async refresh(req: express.Request, res: express.Response): Promise {\n if (!ensuresXRequestedWith(req)) {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (!this.handlers.refresh) {\n throw new InputError(\n `Refresh token is not supported for provider ${this.options.providerId}`,\n );\n }\n\n try {\n const refreshToken = this.getRefreshTokenFromCookie(req);\n\n // throw error if refresh token is missing in the request\n if (!refreshToken) {\n throw new InputError('Missing session cookie');\n }\n\n let scope = req.query.scope?.toString() ?? '';\n if (this.options.persistScopes) {\n scope = this.getGrantedScopeFromCookie(req);\n }\n const forwardReq = Object.assign(req, { scope, refreshToken });\n\n // get new access_token\n const { response, refreshToken: newRefreshToken } =\n await this.handlers.refresh(forwardReq as OAuthRefreshRequest);\n\n const backstageIdentity = await this.populateIdentity(\n response.backstageIdentity,\n );\n\n if (newRefreshToken && newRefreshToken !== refreshToken) {\n const origin = req.get('origin');\n const cookieConfig = this.getCookieConfig(origin);\n this.setRefreshTokenCookie(res, newRefreshToken, cookieConfig);\n }\n\n res.status(200).json({ ...response, backstageIdentity });\n } catch (error) {\n throw new AuthenticationError('Refresh failed', error);\n }\n }\n\n /**\n * If the response from the OAuth provider includes a Backstage identity, we\n * make sure it's populated with all the information we can derive from the user ID.\n */\n private async populateIdentity(\n identity?: BackstageSignInResult,\n ): Promise {\n if (!identity) {\n return undefined;\n }\n if (!identity.token) {\n throw new InputError(`Identity response must return a token`);\n }\n\n return prepareBackstageIdentityResponse(identity);\n }\n\n private setNonceCookie = (\n res: express.Response,\n nonce: string,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-nonce`, nonce, {\n maxAge: TEN_MINUTES_MS,\n ...this.baseCookieOptions,\n ...cookieConfig,\n path: `${cookieConfig.path}/handler`,\n });\n };\n\n private setGrantedScopeCookie = (\n res: express.Response,\n scope: string,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-granted-scope`, scope, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.baseCookieOptions,\n ...cookieConfig,\n });\n };\n\n private getRefreshTokenFromCookie = (req: express.Request) => {\n return req.cookies[`${this.options.providerId}-refresh-token`];\n };\n\n private getGrantedScopeFromCookie = (req: express.Request) => {\n return req.cookies[`${this.options.providerId}-granted-scope`];\n };\n\n private setRefreshTokenCookie = (\n res: express.Response,\n refreshToken: string,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-refresh-token`, refreshToken, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.baseCookieOptions,\n ...cookieConfig,\n });\n };\n\n private removeRefreshTokenCookie = (\n res: express.Response,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-refresh-token`, '', {\n maxAge: 0,\n ...this.baseCookieOptions,\n ...cookieConfig,\n });\n };\n\n private getCookieConfig = (origin?: string) => {\n return this.options.cookieConfigurer({\n providerId: this.options.providerId,\n baseUrl: this.options.baseUrl,\n callbackUrl: this.options.callbackUrl,\n appOrigin: origin ?? this.options.appOrigin,\n });\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport passport from 'passport';\nimport { decodeJwt } from 'jose';\nimport { InternalOAuthError } from 'passport-oauth2';\nimport { ProfileInfo } from '@backstage/plugin-auth-node';\nimport { PassportProfile } from './types';\nimport { OAuthStartResponse } from '../../providers/types';\n\nexport type PassportDoneCallback = (\n err?: Error,\n response?: Res,\n privateInfo?: Private,\n) => void;\n\nexport const makeProfileInfo = (\n profile: PassportProfile,\n idToken?: string,\n): ProfileInfo => {\n let email: string | undefined = undefined;\n if (profile.emails && profile.emails.length > 0) {\n const [firstEmail] = profile.emails;\n email = firstEmail.value;\n }\n\n let picture: string | undefined = undefined;\n if (profile.avatarUrl) {\n picture = profile.avatarUrl;\n } else if (profile.photos && profile.photos.length > 0) {\n const [firstPhoto] = profile.photos;\n picture = firstPhoto.value;\n }\n\n let displayName: string | undefined =\n profile.displayName ?? profile.username ?? profile.id;\n\n if ((!email || !picture || !displayName) && idToken) {\n try {\n const decoded = decodeJwt(idToken) as {\n email?: string;\n name?: string;\n picture?: string;\n };\n if (!email && decoded.email) {\n email = decoded.email;\n }\n if (!picture && decoded.picture) {\n picture = decoded.picture;\n }\n if (!displayName && decoded.name) {\n displayName = decoded.name;\n }\n } catch (e) {\n throw new Error(`Failed to parse id token and get profile info, ${e}`);\n }\n }\n\n return {\n email,\n picture,\n displayName,\n };\n};\n\nexport const executeRedirectStrategy = async (\n req: express.Request,\n providerStrategy: passport.Strategy,\n options: Record,\n): Promise => {\n return new Promise(resolve => {\n const strategy = Object.create(providerStrategy);\n strategy.redirect = (url: string, status?: number) => {\n resolve({ url, status: status ?? undefined });\n };\n\n strategy.authenticate(req, { ...options });\n });\n};\n\nexport const executeFrameHandlerStrategy = async (\n req: express.Request,\n providerStrategy: passport.Strategy,\n options?: Record,\n) => {\n return new Promise<{ result: Result; privateInfo: PrivateInfo }>(\n (resolve, reject) => {\n const strategy = Object.create(providerStrategy);\n strategy.success = (result: any, privateInfo: any) => {\n resolve({ result, privateInfo });\n };\n strategy.fail = (\n info: { type: 'success' | 'error'; message?: string },\n // _status: number,\n ) => {\n reject(new Error(`Authentication rejected, ${info.message ?? ''}`));\n };\n strategy.error = (error: InternalOAuthError) => {\n let message = `Authentication failed, ${error.message}`;\n\n if (error.oauthError?.data) {\n try {\n const errorData = JSON.parse(error.oauthError.data);\n\n if (errorData.message) {\n message += ` - ${errorData.message}`;\n }\n } catch (parseError) {\n message += ` - ${error.oauthError}`;\n }\n }\n\n reject(new Error(message));\n };\n strategy.redirect = () => {\n reject(new Error('Unexpected redirect'));\n };\n strategy.authenticate(req, { ...(options ?? {}) });\n },\n );\n};\n\ntype RefreshTokenResponse = {\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * Optionally, the server can issue a new Refresh Token for the user\n */\n refreshToken?: string;\n params: any;\n};\n\nexport const executeRefreshTokenStrategy = async (\n providerStrategy: passport.Strategy,\n refreshToken: string,\n scope: string,\n): Promise => {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as any;\n const OAuth2 = anyStrategy._oauth2.constructor;\n const oauth2 = new OAuth2(\n anyStrategy._oauth2._clientId,\n anyStrategy._oauth2._clientSecret,\n anyStrategy._oauth2._baseSite,\n anyStrategy._oauth2._authorizeUrl,\n anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,\n anyStrategy._oauth2._customHeaders,\n );\n\n oauth2.getOAuthAccessToken(\n refreshToken,\n {\n scope,\n grant_type: 'refresh_token',\n },\n (\n err: Error | null,\n accessToken: string,\n newRefreshToken: string,\n params: any,\n ) => {\n if (err) {\n reject(new Error(`Failed to refresh access token ${err.toString()}`));\n }\n if (!accessToken) {\n reject(\n new Error(\n `Failed to refresh access token, no access token received`,\n ),\n );\n }\n\n resolve({\n accessToken,\n refreshToken: newRefreshToken,\n params,\n });\n },\n );\n });\n};\n\ntype ProviderStrategy = {\n userProfile(accessToken: string, callback: Function): void;\n};\n\nexport const executeFetchUserProfileStrategy = async (\n providerStrategy: passport.Strategy,\n accessToken: string,\n): Promise => {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as unknown as ProviderStrategy;\n anyStrategy.userProfile(\n accessToken,\n (error: Error, rawProfile: PassportProfile) => {\n if (error) {\n reject(error);\n } else {\n resolve(rawProfile);\n }\n },\n );\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport passport from 'passport';\nimport Auth0Strategy from './strategy';\nimport {\n OAuthAdapter,\n OAuthProviderOptions,\n OAuthHandlers,\n OAuthResponse,\n OAuthEnvironmentHandler,\n OAuthStartRequest,\n encodeState,\n OAuthRefreshRequest,\n OAuthResult,\n} from '../../lib/oauth';\nimport {\n executeFetchUserProfileStrategy,\n executeFrameHandlerStrategy,\n executeRedirectStrategy,\n executeRefreshTokenStrategy,\n makeProfileInfo,\n PassportDoneCallback,\n} from '../../lib/passport';\nimport { OAuthStartResponse, AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { StateStore } from 'passport-oauth2';\nimport {\n AuthResolverContext,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\ntype PrivateInfo = {\n refreshToken: string;\n};\n\nexport type Auth0AuthProviderOptions = OAuthProviderOptions & {\n domain: string;\n signInResolver?: SignInResolver;\n authHandler: AuthHandler;\n resolverContext: AuthResolverContext;\n audience?: string;\n connection?: string;\n connectionScope?: string;\n};\n\nexport class Auth0AuthProvider implements OAuthHandlers {\n private readonly _strategy: Auth0Strategy;\n private readonly signInResolver?: SignInResolver;\n private readonly authHandler: AuthHandler;\n private readonly resolverContext: AuthResolverContext;\n private readonly audience?: string;\n private readonly connection?: string;\n private readonly connectionScope?: string;\n\n /**\n * Due to passport-auth0 forcing options.state = true,\n * passport-oauth2 requires express-session to be installed\n * so that the 'state' parameter of the oauth2 flow can be stored.\n * This implementation of StateStore matches the NullStore found within\n * passport-oauth2, which is the StateStore implementation used when options.state = false,\n * allowing us to avoid using express-session in order to integrate with auth0.\n */\n private store: StateStore = {\n store(_req: express.Request, cb: any) {\n cb(null, null);\n },\n verify(_req: express.Request, _state: string, cb: any) {\n cb(null, true);\n },\n };\n\n constructor(options: Auth0AuthProviderOptions) {\n this.signInResolver = options.signInResolver;\n this.authHandler = options.authHandler;\n this.resolverContext = options.resolverContext;\n this.audience = options.audience;\n this.connection = options.connection;\n this.connectionScope = options.connectionScope;\n this._strategy = new Auth0Strategy(\n {\n clientID: options.clientId,\n clientSecret: options.clientSecret,\n callbackURL: options.callbackUrl,\n domain: options.domain,\n // We need passReqToCallback set to false to get params, but there's\n // no matching type signature for that, so instead behold this beauty\n passReqToCallback: false as true,\n store: this.store,\n },\n (\n accessToken: any,\n refreshToken: any,\n params: any,\n fullProfile: passport.Profile,\n done: PassportDoneCallback,\n ) => {\n done(\n undefined,\n {\n fullProfile,\n accessToken,\n refreshToken,\n params,\n },\n {\n refreshToken,\n },\n );\n },\n );\n }\n\n async start(req: OAuthStartRequest): Promise {\n return await executeRedirectStrategy(req, this._strategy, {\n accessType: 'offline',\n prompt: 'consent',\n scope: req.scope,\n state: encodeState(req.state),\n ...(this.audience ? { audience: this.audience } : {}),\n ...(this.connection ? { connection: this.connection } : {}),\n ...(this.connectionScope\n ? { connection_scope: this.connectionScope }\n : {}),\n });\n }\n\n async handler(req: express.Request) {\n const { result, privateInfo } = await executeFrameHandlerStrategy<\n OAuthResult,\n PrivateInfo\n >(req, this._strategy, {\n ...(this.audience ? { audience: this.audience } : {}),\n ...(this.connection ? { connection: this.connection } : {}),\n ...(this.connectionScope\n ? { connection_scope: this.connectionScope }\n : {}),\n });\n\n return {\n response: await this.handleResult(result),\n refreshToken: privateInfo.refreshToken,\n };\n }\n\n async refresh(req: OAuthRefreshRequest) {\n const { accessToken, refreshToken, params } =\n await executeRefreshTokenStrategy(\n this._strategy,\n req.refreshToken,\n req.scope,\n );\n\n const fullProfile = await executeFetchUserProfileStrategy(\n this._strategy,\n accessToken,\n );\n\n return {\n response: await this.handleResult({\n fullProfile,\n params,\n accessToken,\n }),\n refreshToken,\n };\n }\n\n private async handleResult(result: OAuthResult) {\n const { profile } = await this.authHandler(result, this.resolverContext);\n\n const response: OAuthResponse = {\n providerInfo: {\n idToken: result.params.id_token,\n accessToken: result.accessToken,\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n },\n profile,\n };\n\n if (this.signInResolver) {\n response.backstageIdentity = await this.signInResolver(\n {\n result,\n profile,\n },\n this.resolverContext,\n );\n }\n\n return response;\n }\n}\n\n/**\n * Auth provider integration for auth0 auth\n *\n * @public\n */\nexport const auth0 = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return ({ providerId, globalConfig, config, resolverContext }) =>\n OAuthEnvironmentHandler.mapConfig(config, envConfig => {\n const clientId = envConfig.getString('clientId');\n const clientSecret = envConfig.getString('clientSecret');\n const domain = envConfig.getString('domain');\n const customCallbackUrl = envConfig.getOptionalString('callbackUrl');\n const audience = envConfig.getOptionalString('audience');\n const connection = envConfig.getOptionalString('connection');\n const connectionScope = envConfig.getOptionalString('connectionScope');\n const callbackUrl =\n customCallbackUrl ||\n `${globalConfig.baseUrl}/${providerId}/handler/frame`;\n\n const authHandler: AuthHandler = options?.authHandler\n ? options.authHandler\n : async ({ fullProfile, params }) => ({\n profile: makeProfileInfo(fullProfile, params.id_token),\n });\n\n const signInResolver = options?.signIn?.resolver;\n\n const provider = new Auth0AuthProvider({\n clientId,\n clientSecret,\n callbackUrl,\n domain,\n authHandler,\n signInResolver,\n resolverContext,\n audience,\n connection,\n connectionScope,\n });\n\n return OAuthAdapter.fromConfig(globalConfig, provider, {\n providerId,\n callbackUrl,\n });\n });\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AwsAlbResult,\n awsAlbAuthenticator,\n} from '@backstage/plugin-auth-backend-module-aws-alb-provider';\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\n\n/**\n * Auth provider integration for AWS ALB auth\n *\n * @public\n */\nexport const awsAlb = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth\n * response into the profile that will be presented to the user. The default\n * implementation just provides the authenticated email that the IAP\n * presented.\n */\n authHandler?: AuthHandler;\n /**\n * Configures sign-in for this provider.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: awsAlbAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bitbucketAuthenticator,\n bitbucketSignInResolvers,\n} from '@backstage/plugin-auth-backend-module-bitbucket-provider';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { Profile as PassportProfile } from 'passport';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n adaptOAuthSignInResolverToLegacy,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * @public\n * @deprecated The Bitbucket auth provider was extracted to `@backstage/plugin-auth-backend-module-bitbucket-provider`.\n */\nexport type BitbucketOAuthResult = {\n fullProfile: BitbucketPassportProfile;\n params: {\n id_token?: string;\n scope: string;\n expires_in: number;\n };\n accessToken: string;\n refreshToken?: string;\n};\n\n/**\n * @public\n * @deprecated The Bitbucket auth provider was extracted to `@backstage/plugin-auth-backend-module-bitbucket-provider`.\n */\nexport type BitbucketPassportProfile = PassportProfile & {\n id?: string;\n displayName?: string;\n username?: string;\n avatarUrl?: string;\n _json?: {\n links?: {\n avatar?: {\n href?: string;\n };\n };\n };\n};\n\n/**\n * Auth provider integration for Bitbucket auth\n *\n * @public\n */\nexport const bitbucket = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: bitbucketAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: adaptOAuthSignInResolverToLegacy({\n userIdMatchingUserEntityAnnotation:\n bitbucketSignInResolvers.userIdMatchingUserEntityAnnotation(),\n usernameMatchingUserEntityAnnotation:\n bitbucketSignInResolvers.usernameMatchingUserEntityAnnotation(),\n }),\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CacheClient } from '@backstage/backend-common';\nimport {\n cloudflareAccessSignInResolvers,\n createCloudflareAccessAuthenticator,\n} from '@backstage/plugin-auth-backend-module-cloudflare-access-provider';\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * CloudflareAccessClaims\n *\n * Can be used in externally provided auth handler or sign in resolver to\n * enrich user profile for sign-in user entity\n *\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessClaims = {\n /**\n * `aud` identifies the application to which the JWT is issued.\n */\n aud: string[];\n /**\n * `email` contains the email address of the authenticated user.\n */\n email: string;\n /**\n * iat and exp are the issuance and expiration timestamps.\n */\n exp: number;\n iat: number;\n /**\n * `nonce` is the session identifier.\n */\n nonce: string;\n /**\n * `identity_nonce` is available in the Application Token and can be used to\n * query all group membership for a given user.\n */\n identity_nonce: string;\n /**\n * `sub` contains the identifier of the authenticated user.\n */\n sub: string;\n /**\n * `iss` the issuer is the application’s Cloudflare Access Domain URL.\n */\n iss: string;\n /**\n * `custom` contains SAML attributes in the Application Token specified by an\n * administrator in the identity provider configuration.\n */\n custom: string;\n};\n\n/**\n * CloudflareAccessGroup\n *\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessGroup = {\n /**\n * Group id\n */\n id: string;\n /**\n * Name of group as defined in Cloudflare zero trust dashboard\n */\n name: string;\n /**\n * Access group email address\n */\n email: string;\n};\n\n/**\n * CloudflareAccessIdentityProfile\n *\n * Can be used in externally provided auth handler or sign in resolver to\n * enrich user profile for sign-in user entity\n *\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessIdentityProfile = {\n id: string;\n name: string;\n email: string;\n groups: CloudflareAccessGroup[];\n};\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessResult = {\n claims: CloudflareAccessClaims;\n cfIdentity: CloudflareAccessIdentityProfile;\n expiresInSeconds?: number;\n token: string;\n};\n\n/**\n * Auth provider integration for Cloudflare Access auth\n *\n * @public\n */\nexport const cfAccess = createAuthProviderIntegration({\n create(options: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n\n /**\n * CacheClient object that was configured for the Backstage backend,\n * should be provided via the backend auth plugin.\n */\n cache?: CacheClient;\n }) {\n return createProxyAuthProviderFactory({\n authenticator: createCloudflareAccessAuthenticator({\n cache: options.cache,\n }),\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n signInResolverFactories: cloudflareAccessSignInResolvers,\n });\n },\n resolvers: cloudflareAccessSignInResolvers,\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { gcpIapAuthenticator } from '@backstage/plugin-auth-backend-module-gcp-iap-provider';\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\nimport { GcpIapResult } from './types';\n\n/**\n * Auth provider integration for Google Identity-Aware Proxy auth\n *\n * @public\n */\nexport const gcpIap = createAuthProviderIntegration({\n create(options: {\n /**\n * The profile transformation function used to verify and convert the auth\n * response into the profile that will be presented to the user. The default\n * implementation just provides the authenticated email that the IAP\n * presented.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configures sign-in for this provider.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: gcpIapAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Profile as PassportProfile } from 'passport';\nimport { AuthHandler, StateEncoder } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n createOAuthProviderFactory,\n OAuthAuthenticatorResult,\n ProfileTransform,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\nimport { githubAuthenticator } from '@backstage/plugin-auth-backend-module-github-provider';\n\n/** @public */\nexport type GithubOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n scope: string;\n expires_in?: string;\n refresh_token_expires_in?: string;\n };\n accessToken: string;\n refreshToken?: string;\n};\n\n/**\n * Auth provider integration for GitHub auth\n *\n * @public\n */\nexport const github = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n\n /**\n * The state encoder used to encode the 'state' parameter on the OAuth request.\n *\n * It should return a string that takes the state params (from the request), url encodes the params\n * and finally base64 encodes them.\n *\n * Providing your own stateEncoder will allow you to add addition parameters to the state field.\n *\n * It is typed as follows:\n * `export type StateEncoder = (input: OAuthState) => Promise<{encodedState: string}>;`\n *\n * Note: the stateEncoder must encode a 'nonce' value and an 'env' value. Without this, the OAuth flow will fail\n * (These two values will be set by the req.state by default)\n *\n * For more information, please see the helper module in ../../oauth/helpers #readState\n */\n stateEncoder?: StateEncoder;\n }) {\n const authHandler = options?.authHandler;\n const signInResolver = options?.signIn?.resolver;\n return createOAuthProviderFactory({\n authenticator: githubAuthenticator,\n profileTransform:\n authHandler &&\n ((async (result, ctx) =>\n authHandler!(\n {\n fullProfile: result.fullProfile,\n accessToken: result.session.accessToken,\n params: {\n scope: result.session.scope,\n expires_in: result.session.expiresInSeconds\n ? String(result.session.expiresInSeconds)\n : '',\n refresh_token_expires_in: result.session\n .refreshTokenExpiresInSeconds\n ? String(result.session.refreshTokenExpiresInSeconds)\n : '',\n },\n },\n ctx,\n )) as ProfileTransform>),\n signInResolver:\n signInResolver &&\n ((async ({ profile, result }, ctx) =>\n signInResolver(\n {\n profile: profile,\n result: {\n fullProfile: result.fullProfile,\n accessToken: result.session.accessToken,\n refreshToken: result.session.refreshToken,\n params: {\n scope: result.session.scope,\n expires_in: result.session.expiresInSeconds\n ? String(result.session.expiresInSeconds)\n : '',\n refresh_token_expires_in: result.session\n .refreshTokenExpiresInSeconds\n ? String(result.session.refreshTokenExpiresInSeconds)\n : '',\n },\n },\n },\n ctx,\n )) as SignInResolver>),\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their GitHub username to the entity name.\n */\n usernameMatchingUserEntityName: (): SignInResolver => {\n return async (info, ctx) => {\n const { fullProfile } = info.result;\n\n const userId = fullProfile.username;\n if (!userId) {\n throw new Error(`GitHub user profile does not contain a username`);\n }\n\n return ctx.signInWithCatalogUser({ entityRef: { name: userId } });\n };\n },\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { gitlabAuthenticator } from '@backstage/plugin-auth-backend-module-gitlab-provider';\n\n/**\n * Auth provider integration for GitLab auth\n *\n * @public\n */\nexport const gitlab = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: gitlabAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n googleAuthenticator,\n googleSignInResolvers,\n} from '@backstage/plugin-auth-backend-module-google-provider';\nimport {\n SignInResolver,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n adaptOAuthSignInResolverToLegacy,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * Auth provider integration for Google auth\n *\n * @public\n */\nexport const google = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: googleAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: adaptOAuthSignInResolverToLegacy({\n emailLocalPartMatchingUserEntityName:\n commonSignInResolvers.emailLocalPartMatchingUserEntityName(),\n emailMatchingUserEntityProfileEmail:\n commonSignInResolvers.emailMatchingUserEntityProfileEmail(),\n emailMatchingUserEntityAnnotation:\n googleSignInResolvers.emailMatchingUserEntityAnnotation(),\n }),\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n SignInResolver,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n adaptOAuthSignInResolverToLegacy,\n} from '../../lib/legacy';\nimport {\n microsoftAuthenticator,\n microsoftSignInResolvers,\n} from '@backstage/plugin-auth-backend-module-microsoft-provider';\n\n/**\n * Auth provider integration for Microsoft auth\n *\n * @public\n */\nexport const microsoft = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: microsoftAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: adaptOAuthSignInResolverToLegacy({\n emailLocalPartMatchingUserEntityName:\n commonSignInResolvers.emailLocalPartMatchingUserEntityName(),\n emailMatchingUserEntityProfileEmail:\n commonSignInResolvers.emailMatchingUserEntityProfileEmail(),\n emailMatchingUserEntityAnnotation:\n microsoftSignInResolvers.emailMatchingUserEntityAnnotation(),\n }),\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OAuthResult } from '../../lib/oauth';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { oauth2Authenticator } from '@backstage/plugin-auth-backend-module-oauth2-provider';\n\n/**\n * Auth provider integration for generic OAuth2 auth\n *\n * @public\n */\nexport const oauth2 = createAuthProviderIntegration({\n create(options?: {\n authHandler?: AuthHandler;\n\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: oauth2Authenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n type OAuth2ProxyResult,\n oauth2ProxyAuthenticator,\n} from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider';\n\n/**\n * Auth provider integration for oauth2-proxy auth\n *\n * @public\n */\nexport const oauth2Proxy = createAuthProviderIntegration({\n create(options: {\n /**\n * Configure an auth handler to generate a profile for the user.\n *\n * The default implementation uses the value of the `X-Forwarded-Preferred-Username`\n * header as the display name, falling back to `X-Forwarded-User`, and the value of\n * the `X-Forwarded-Email` header as the email address.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: oauth2ProxyAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SignInResolver } from '@backstage/plugin-auth-node';\n\n/**\n * A common sign-in resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\nexport const commonByEmailLocalPartResolver: SignInResolver = async (\n info,\n ctx,\n) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Login failed, user profile does not contain an email');\n }\n const [localPart] = profile.email.split('@');\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: localPart },\n });\n};\n\n/**\n * A common sign-in resolver that looks up the user using their email address\n * as email of the entity.\n */\nexport const commonByEmailResolver: SignInResolver = async (\n info,\n ctx,\n) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Login failed, user profile does not contain an email');\n }\n\n return ctx.signInWithCatalogUser({\n filter: {\n 'spec.profile.email': profile.email,\n },\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n createOAuthProviderFactory,\n AuthResolverContext,\n BackstageSignInResult,\n OAuthAuthenticatorResult,\n SignInInfo,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\nimport {\n oidcAuthenticator,\n OidcAuthResult,\n} from '@backstage/plugin-auth-backend-module-oidc-provider';\nimport {\n commonByEmailLocalPartResolver,\n commonByEmailResolver,\n} from '../resolvers';\n\n/**\n * Auth provider integration for generic OpenID Connect auth\n *\n * @public\n */\nexport const oidc = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider; convert user profile respones into\n * Backstage identities.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n const authHandler = options?.authHandler;\n const signInResolver = options?.signIn?.resolver;\n return createOAuthProviderFactory({\n authenticator: oidcAuthenticator,\n profileTransform:\n authHandler &&\n ((\n result: OAuthAuthenticatorResult,\n context: AuthResolverContext,\n ) => authHandler(result.fullProfile, context)),\n signInResolver:\n signInResolver &&\n ((\n info: SignInInfo>,\n context: AuthResolverContext,\n ): Promise =>\n signInResolver(\n {\n result: info.result.fullProfile,\n profile: info.profile,\n },\n context,\n )),\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their email local part to the entity name.\n */\n emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,\n /**\n * Looks up the user by matching their email to the entity email.\n */\n emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { OAuthResult } from '../../lib/oauth';\n\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { oktaAuthenticator } from '@backstage/plugin-auth-backend-module-okta-provider';\nimport {\n commonByEmailLocalPartResolver,\n commonByEmailResolver,\n} from '../resolvers';\n\n/**\n * Auth provider integration for Okta auth\n *\n * @public\n */\nexport const okta = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: oktaAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their email local part to the entity name.\n */\n emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,\n /**\n * Looks up the user by matching their email to the entity email.\n */\n emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,\n /**\n * Looks up the user by matching their email to the `okta.com/email` annotation.\n */\n emailMatchingUserEntityAnnotation(): SignInResolver {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Okta profile contained no email');\n }\n\n return ctx.signInWithCatalogUser({\n annotations: {\n 'okta.com/email': profile.email,\n },\n });\n };\n },\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { oneLoginAuthenticator } from '@backstage/plugin-auth-backend-module-onelogin-provider';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * Auth provider integration for OneLogin auth\n *\n * @public\n */\nexport const onelogin = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: oneLoginAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport { SamlConfig, VerifiedCallback } from '@node-saml/passport-saml';\nimport {\n Strategy as SamlStrategy,\n Profile as SamlProfile,\n VerifyWithoutRequest,\n} from '@node-saml/passport-saml';\nimport {\n executeFrameHandlerStrategy,\n executeRedirectStrategy,\n} from '../../lib/passport';\nimport { AuthHandler } from '../types';\nimport { postMessageResponse } from '../../lib/flow';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthenticationError, isError } from '@backstage/errors';\nimport { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\n/** @public */\nexport type SamlAuthResult = {\n fullProfile: any;\n};\n\ntype Options = SamlConfig & {\n signInResolver?: SignInResolver;\n authHandler: AuthHandler;\n resolverContext: AuthResolverContext;\n appUrl: string;\n};\n\nexport class SamlAuthProvider implements AuthProviderRouteHandlers {\n private readonly strategy: SamlStrategy;\n private readonly signInResolver?: SignInResolver;\n private readonly authHandler: AuthHandler;\n private readonly resolverContext: AuthResolverContext;\n private readonly appUrl: string;\n\n constructor(options: Options) {\n this.appUrl = options.appUrl;\n this.signInResolver = options.signInResolver;\n this.authHandler = options.authHandler;\n this.resolverContext = options.resolverContext;\n\n const verifier: VerifyWithoutRequest = (\n profile: SamlProfile | null,\n done: VerifiedCallback,\n ) => {\n // TODO: There's plenty more validation and profile handling to do here,\n // this provider is currently only intended to validate the provider pattern\n // for non-oauth auth flows.\n // TODO: This flow doesn't issue an identity token that can be used to validate\n // the identity of the user in other backends, which we need in some form.\n done(null, { fullProfile: profile });\n };\n this.strategy = new SamlStrategy(options, verifier, verifier);\n }\n\n async start(req: express.Request, res: express.Response): Promise {\n const { url } = await executeRedirectStrategy(req, this.strategy, {});\n res.redirect(url);\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise {\n try {\n const { result } = await executeFrameHandlerStrategy(\n req,\n this.strategy,\n );\n\n const { profile } = await this.authHandler(result, this.resolverContext);\n\n const response: ClientAuthResponse<{}> = {\n profile,\n providerInfo: {},\n };\n\n if (this.signInResolver) {\n const signInResponse = await this.signInResolver(\n {\n result,\n profile,\n },\n this.resolverContext,\n );\n\n response.backstageIdentity =\n prepareBackstageIdentityResponse(signInResponse);\n }\n\n return postMessageResponse(res, this.appUrl, {\n type: 'authorization_response',\n response,\n });\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n return postMessageResponse(res, this.appUrl, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n }\n\n async logout(_req: express.Request, res: express.Response): Promise {\n res.end();\n }\n}\n\ntype SignatureAlgorithm = 'sha1' | 'sha256' | 'sha512';\n\n/**\n * Auth provider integration for SAML auth\n *\n * @public\n */\nexport const saml = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return ({ providerId, globalConfig, config, resolverContext }) => {\n const authHandler: AuthHandler = options?.authHandler\n ? options.authHandler\n : async ({ fullProfile }) => ({\n profile: {\n email: fullProfile.email,\n displayName: fullProfile.displayName,\n },\n });\n\n return new SamlAuthProvider({\n callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,\n entryPoint: config.getString('entryPoint'),\n logoutUrl: config.getOptionalString('logoutUrl'),\n audience: config.getString('audience'),\n issuer: config.getString('issuer'),\n cert: config.getString('cert'),\n privateKey: config.getOptionalString('privateKey'),\n authnContext: config.getOptionalStringArray('authnContext'),\n identifierFormat: config.getOptionalString('identifierFormat'),\n decryptionPvk: config.getOptionalString('decryptionPvk'),\n signatureAlgorithm: config.getOptionalString('signatureAlgorithm') as\n | SignatureAlgorithm\n | undefined,\n digestAlgorithm: config.getOptionalString('digestAlgorithm'),\n acceptedClockSkewMs: config.getOptionalNumber('acceptedClockSkewMs'),\n wantAuthnResponseSigned: config.getOptionalBoolean(\n 'wantAuthnResponseSigned',\n ),\n wantAssertionsSigned: config.getOptionalBoolean('wantAssertionsSigned'),\n appUrl: globalConfig.appUrl,\n authHandler,\n signInResolver: options?.signIn?.resolver,\n resolverContext,\n });\n };\n },\n resolvers: {\n /**\n * Looks up the user by matching their nameID to the entity name.\n */\n nameIdMatchingUserEntityName(): SignInResolver {\n return async (info, ctx) => {\n const id = info.result.fullProfile.nameID;\n\n if (!id) {\n throw new AuthenticationError('No nameID found in SAML response');\n }\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: id },\n });\n };\n },\n },\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n encodeState,\n OAuthAdapter,\n OAuthEnvironmentHandler,\n OAuthHandlers,\n OAuthProviderOptions,\n OAuthRefreshRequest,\n OAuthResponse,\n OAuthStartRequest,\n} from '../../lib/oauth';\nimport { Strategy as OAuth2Strategy, VerifyCallback } from 'passport-oauth2';\nimport {\n executeFetchUserProfileStrategy,\n executeFrameHandlerStrategy,\n executeRedirectStrategy,\n executeRefreshTokenStrategy,\n makeProfileInfo,\n} from '../../lib/passport';\nimport { AuthHandler, OAuthStartResponse } from '../types';\nimport express from 'express';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { Profile as PassportProfile } from 'passport';\nimport { commonByEmailResolver } from '../resolvers';\nimport fetch from 'node-fetch';\nimport {\n AuthResolverContext,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\ntype PrivateInfo = {\n refreshToken: string;\n};\n\n/** @public */\nexport type BitbucketServerOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n scope: string;\n access_token?: string;\n token_type?: string;\n expires_in?: number;\n };\n accessToken: string;\n refreshToken?: string;\n};\n\nexport type BitbucketServerAuthProviderOptions = OAuthProviderOptions & {\n host: string;\n authorizationUrl: string;\n tokenUrl: string;\n authHandler: AuthHandler;\n signInResolver?: SignInResolver;\n resolverContext: AuthResolverContext;\n};\n\nexport class BitbucketServerAuthProvider implements OAuthHandlers {\n private readonly signInResolver?: SignInResolver;\n private readonly authHandler: AuthHandler;\n private readonly resolverContext: AuthResolverContext;\n private readonly strategy: OAuth2Strategy;\n private readonly host: string;\n\n constructor(options: BitbucketServerAuthProviderOptions) {\n this.signInResolver = options.signInResolver;\n this.authHandler = options.authHandler;\n this.resolverContext = options.resolverContext;\n this.strategy = new OAuth2Strategy(\n {\n authorizationURL: options.authorizationUrl,\n tokenURL: options.tokenUrl,\n clientID: options.clientId,\n clientSecret: options.clientSecret,\n callbackURL: options.callbackUrl,\n },\n (\n accessToken: string,\n refreshToken: string,\n params: any,\n fullProfile: PassportProfile,\n done: VerifyCallback,\n ) => {\n done(undefined, { fullProfile, params, accessToken }, { refreshToken });\n },\n );\n this.host = options.host;\n }\n\n async start(req: OAuthStartRequest): Promise {\n return await executeRedirectStrategy(req, this.strategy, {\n accessType: 'offline',\n prompt: 'consent',\n scope: req.scope,\n state: encodeState(req.state),\n });\n }\n\n async handler(\n req: express.Request,\n ): Promise<{ response: OAuthResponse; refreshToken?: string }> {\n const { result, privateInfo } = await executeFrameHandlerStrategy<\n BitbucketServerOAuthResult,\n PrivateInfo\n >(req, this.strategy);\n\n return {\n response: await this.handleResult(result),\n refreshToken: privateInfo.refreshToken,\n };\n }\n\n async refresh(\n req: OAuthRefreshRequest,\n ): Promise<{ response: OAuthResponse; refreshToken?: string }> {\n const { accessToken, refreshToken, params } =\n await executeRefreshTokenStrategy(\n this.strategy,\n req.refreshToken,\n req.scope,\n );\n const fullProfile = await executeFetchUserProfileStrategy(\n this.strategy,\n accessToken,\n );\n return {\n response: await this.handleResult({\n fullProfile,\n params,\n accessToken,\n }),\n refreshToken,\n };\n }\n\n private async handleResult(\n result: BitbucketServerOAuthResult,\n ): Promise {\n // The OAuth2 strategy does not return a user profile -> let's fetch it before calling the auth handler\n result.fullProfile = await this.fetchProfile(result);\n const { profile } = await this.authHandler(result, this.resolverContext);\n\n let backstageIdentity = undefined;\n if (this.signInResolver) {\n backstageIdentity = await this.signInResolver(\n { result, profile },\n this.resolverContext,\n );\n }\n\n return {\n providerInfo: {\n accessToken: result.accessToken,\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n },\n profile,\n backstageIdentity,\n };\n }\n\n private async fetchProfile(\n result: BitbucketServerOAuthResult,\n ): Promise {\n // Get current user name\n let whoAmIResponse;\n try {\n whoAmIResponse = await fetch(\n `https://${this.host}/plugins/servlet/applinks/whoami`,\n {\n headers: {\n Authorization: `Bearer ${result.accessToken}`,\n },\n },\n );\n } catch (e) {\n throw new Error(`Failed to retrieve the username of the logged in user`);\n }\n\n // A response.ok check here would be worthless as the Bitbucket API always returns 200 OK for this call\n const username = whoAmIResponse.headers.get('X-Ausername');\n if (!username) {\n throw new Error(`Failed to retrieve the username of the logged in user`);\n }\n\n let userResponse;\n try {\n userResponse = await fetch(\n `https://${this.host}/rest/api/latest/users/${username}?avatarSize=256`,\n {\n headers: {\n Authorization: `Bearer ${result.accessToken}`,\n },\n },\n );\n } catch (e) {\n throw new Error(`Failed to retrieve the user '${username}'`);\n }\n\n if (!userResponse.ok) {\n throw new Error(`Failed to retrieve the user '${username}'`);\n }\n\n const user = await userResponse.json();\n\n const passportProfile = {\n provider: 'bitbucketServer',\n id: user.id.toString(),\n displayName: user.displayName,\n username: user.name,\n emails: [\n {\n value: user.emailAddress,\n },\n ],\n } as PassportProfile;\n\n if (user.avatarUrl) {\n passportProfile.photos = [\n { value: `https://${this.host}${user.avatarUrl}` },\n ];\n }\n\n return passportProfile;\n }\n}\n\nexport const bitbucketServer = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return ({ providerId, globalConfig, config, resolverContext }) =>\n OAuthEnvironmentHandler.mapConfig(config, envConfig => {\n const clientId = envConfig.getString('clientId');\n const clientSecret = envConfig.getString('clientSecret');\n const host = envConfig.getString('host');\n const customCallbackUrl = envConfig.getOptionalString('callbackUrl');\n const callbackUrl =\n customCallbackUrl ||\n `${globalConfig.baseUrl}/${providerId}/handler/frame`;\n const authorizationUrl = `https://${host}/rest/oauth2/latest/authorize`;\n const tokenUrl = `https://${host}/rest/oauth2/latest/token`;\n\n const authHandler: AuthHandler =\n options?.authHandler\n ? options.authHandler\n : async ({ fullProfile }) => ({\n profile: makeProfileInfo(fullProfile),\n });\n\n const provider = new BitbucketServerAuthProvider({\n callbackUrl,\n clientId,\n clientSecret,\n host,\n authorizationUrl,\n tokenUrl,\n authHandler,\n signInResolver: options?.signIn?.resolver,\n resolverContext,\n });\n\n return OAuthAdapter.fromConfig(globalConfig, provider, {\n providerId,\n callbackUrl,\n });\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their email to the entity email.\n */\n emailMatchingUserEntityProfileEmail:\n (): SignInResolver => commonByEmailResolver,\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n AzureEasyAuthResult,\n azureEasyAuthAuthenticator,\n} from '@backstage/plugin-auth-backend-module-azure-easyauth-provider';\n\nexport type EasyAuthResult = AzureEasyAuthResult;\n\n/**\n * Auth provider integration for Azure EasyAuth\n *\n * @public\n */\nexport const easyAuth = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: azureEasyAuthAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { atlassian } from './atlassian';\nimport { auth0 } from './auth0';\nimport { awsAlb } from './aws-alb';\nimport { bitbucket } from './bitbucket';\nimport { cfAccess } from './cloudflare-access';\nimport { gcpIap } from './gcp-iap';\nimport { github } from './github';\nimport { gitlab } from './gitlab';\nimport { google } from './google';\nimport { microsoft } from './microsoft';\nimport { oauth2 } from './oauth2';\nimport { oauth2Proxy } from './oauth2-proxy';\nimport { oidc } from './oidc';\nimport { okta } from './okta';\nimport { onelogin } from './onelogin';\nimport { saml } from './saml';\nimport { bitbucketServer } from './bitbucketServer';\nimport { easyAuth } from './azure-easyauth';\nimport { AuthProviderFactory } from '@backstage/plugin-auth-node';\n\n/**\n * All built-in auth provider integrations.\n *\n * @public\n */\nexport const providers = Object.freeze({\n atlassian,\n auth0,\n awsAlb,\n bitbucket,\n bitbucketServer,\n cfAccess,\n gcpIap,\n github,\n gitlab,\n google,\n microsoft,\n oauth2,\n oauth2Proxy,\n oidc,\n okta,\n onelogin,\n saml,\n easyAuth,\n});\n\n/**\n * All auth provider factories that are installed by default.\n *\n * @public\n */\nexport const defaultAuthProviderFactories: {\n [providerId: string]: AuthProviderFactory;\n} = {\n google: google.create(),\n github: github.create(),\n gitlab: gitlab.create(),\n saml: saml.create(),\n okta: okta.create(),\n auth0: auth0.create(),\n microsoft: microsoft.create(),\n easyAuth: easyAuth.create(),\n oauth2: oauth2.create(),\n oidc: oidc.create(),\n onelogin: onelogin.create(),\n awsalb: awsAlb.create(),\n bitbucket: bitbucket.create(),\n bitbucketServer: bitbucketServer.create(),\n atlassian: atlassian.create(),\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n RELATION_MEMBER_OF,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport {\n TokenManager,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\n\n/**\n * A catalog client tailored for reading out identity data from the catalog.\n *\n * @public\n */\nexport class CatalogIdentityClient {\n private readonly catalogApi: CatalogApi;\n private readonly auth: AuthService;\n\n constructor(options: {\n catalogApi: CatalogApi;\n tokenManager: TokenManager;\n discovery: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n }) {\n this.catalogApi = options.catalogApi;\n\n const { auth } = createLegacyAuthAdapters({\n auth: options.auth,\n httpAuth: options.httpAuth,\n discovery: options.discovery,\n tokenManager: options.tokenManager,\n });\n\n this.auth = auth;\n }\n\n /**\n * Looks up a single user using a query.\n *\n * Throws a NotFoundError or ConflictError if 0 or multiple users are found.\n */\n async findUser(query: {\n annotations: Record;\n }): Promise {\n const filter: Record = {\n kind: 'user',\n };\n for (const [key, value] of Object.entries(query.annotations)) {\n filter[`metadata.annotations.${key}`] = value;\n }\n\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const { items } = await this.catalogApi.getEntities({ filter }, { token });\n\n if (items.length !== 1) {\n if (items.length > 1) {\n throw new ConflictError('User lookup resulted in multiple matches');\n } else {\n throw new NotFoundError('User not found');\n }\n }\n\n return items[0] as UserEntity;\n }\n\n /**\n * Resolve additional entity claims from the catalog, using the passed-in entity names. Designed\n * to be used within a `signInResolver` where additional entity claims might be provided, but\n * group membership and transient group membership lean on imported catalog relations.\n *\n * Returns a superset of the entity names that can be passed directly to `issueToken` as `ent`.\n */\n async resolveCatalogMembership(query: {\n entityRefs: string[];\n logger?: LoggerService;\n }): Promise {\n const { entityRefs, logger } = query;\n const resolvedEntityRefs = entityRefs\n .map((ref: string) => {\n try {\n const parsedRef = parseEntityRef(ref.toLocaleLowerCase('en-US'), {\n defaultKind: 'user',\n defaultNamespace: 'default',\n });\n return parsedRef;\n } catch {\n logger?.warn(`Failed to parse entityRef from ${ref}, ignoring`);\n return null;\n }\n })\n .filter((ref): ref is CompoundEntityRef => ref !== null);\n\n const filter = resolvedEntityRefs.map(ref => ({\n kind: ref.kind,\n 'metadata.namespace': ref.namespace,\n 'metadata.name': ref.name,\n }));\n\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const entities = await this.catalogApi\n .getEntities({ filter }, { token })\n .then(r => r.items);\n\n if (entityRefs.length !== entities.length) {\n const foundEntityNames = entities.map(stringifyEntityRef);\n const missingEntityNames = resolvedEntityRefs\n .map(stringifyEntityRef)\n .filter(s => !foundEntityNames.includes(s));\n logger?.debug(`Entities not found for refs ${missingEntityNames.join()}`);\n }\n\n const memberOf = entities.flatMap(\n e =>\n e!.relations\n ?.filter(r => r.type === RELATION_MEMBER_OF)\n .map(r => r.targetRef) ?? [],\n );\n\n const newEntityRefs = [\n ...new Set(resolvedEntityRefs.map(stringifyEntityRef).concat(memberOf)),\n ];\n\n logger?.debug(`Found catalog membership: ${newEntityRefs.join()}`);\n return newEntityRefs;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TokenManager } from '@backstage/backend-common';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n DEFAULT_NAMESPACE,\n Entity,\n parseEntityRef,\n RELATION_MEMBER_OF,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { ConflictError, InputError, NotFoundError } from '@backstage/errors';\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { TokenIssuer } from '../../identity/types';\nimport {\n AuthOwnershipResolver,\n AuthResolverCatalogUserQuery,\n AuthResolverContext,\n TokenParams,\n} from '@backstage/plugin-auth-node';\nimport { CatalogIdentityClient } from '../catalog';\n\n/**\n * Uses the default ownership resolution logic to return an array\n * of entity refs that the provided entity claims ownership through.\n *\n * A reference to the entity itself will also be included in the returned array.\n *\n * @public\n */\nexport function getDefaultOwnershipEntityRefs(entity: Entity) {\n const membershipRefs =\n entity.relations\n ?.filter(\n r => r.type === RELATION_MEMBER_OF && r.targetRef.startsWith('group:'),\n )\n .map(r => r.targetRef) ?? [];\n\n return Array.from(new Set([stringifyEntityRef(entity), ...membershipRefs]));\n}\n\n/**\n * @internal\n */\nexport class CatalogAuthResolverContext implements AuthResolverContext {\n static create(options: {\n logger: LoggerService;\n catalogApi: CatalogApi;\n tokenIssuer: TokenIssuer;\n tokenManager: TokenManager;\n discovery: DiscoveryService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n ownershipResolver?: AuthOwnershipResolver;\n }): CatalogAuthResolverContext {\n const catalogIdentityClient = new CatalogIdentityClient({\n catalogApi: options.catalogApi,\n tokenManager: options.tokenManager,\n discovery: options.discovery,\n auth: options.auth,\n httpAuth: options.httpAuth,\n });\n\n return new CatalogAuthResolverContext(\n options.logger,\n options.tokenIssuer,\n catalogIdentityClient,\n options.catalogApi,\n options.auth,\n options.ownershipResolver,\n );\n }\n\n private constructor(\n public readonly logger: LoggerService,\n public readonly tokenIssuer: TokenIssuer,\n public readonly catalogIdentityClient: CatalogIdentityClient,\n private readonly catalogApi: CatalogApi,\n private readonly auth: AuthService,\n private readonly ownershipResolver?: AuthOwnershipResolver,\n ) {}\n\n async issueToken(params: TokenParams) {\n const token = await this.tokenIssuer.issueToken(params);\n return { token };\n }\n\n async findCatalogUser(query: AuthResolverCatalogUserQuery) {\n let result: Entity[] | Entity | undefined = undefined;\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n if ('entityRef' in query) {\n const entityRef = parseEntityRef(query.entityRef, {\n defaultKind: 'User',\n defaultNamespace: DEFAULT_NAMESPACE,\n });\n result = await this.catalogApi.getEntityByRef(entityRef, { token });\n } else if ('annotations' in query) {\n const filter: Record = {\n kind: 'user',\n };\n for (const [key, value] of Object.entries(query.annotations)) {\n filter[`metadata.annotations.${key}`] = value;\n }\n const res = await this.catalogApi.getEntities({ filter }, { token });\n result = res.items;\n } else if ('filter' in query) {\n const filter = [query.filter].flat().map(value => {\n if (\n !Object.keys(value).some(\n key => key.toLocaleLowerCase('en-US') === 'kind',\n )\n ) {\n return {\n ...value,\n kind: 'user',\n };\n }\n return value;\n });\n const res = await this.catalogApi.getEntities(\n { filter: filter },\n { token },\n );\n result = res.items;\n } else {\n throw new InputError('Invalid user lookup query');\n }\n\n if (Array.isArray(result)) {\n if (result.length > 1) {\n throw new ConflictError('User lookup resulted in multiple matches');\n }\n result = result[0];\n }\n if (!result) {\n throw new NotFoundError('User not found');\n }\n\n return { entity: result };\n }\n\n async signInWithCatalogUser(query: AuthResolverCatalogUserQuery) {\n const { entity } = await this.findCatalogUser(query);\n let ent: string[];\n if (this.ownershipResolver) {\n const { ownershipEntityRefs } =\n await this.ownershipResolver.resolveOwnershipEntityRefs(entity);\n ent = ownershipEntityRefs;\n } else {\n ent = getDefaultOwnershipEntityRefs(entity);\n }\n\n const token = await this.tokenIssuer.issueToken({\n claims: {\n sub: stringifyEntityRef(entity),\n ent,\n },\n });\n return { token };\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { CatalogApi, CatalogClient } from '@backstage/catalog-client';\nimport { Config } from '@backstage/config';\nimport { assertError, NotFoundError } from '@backstage/errors';\nimport {\n AuthOwnershipResolver,\n AuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Minimatch } from 'minimatch';\nimport { CatalogAuthResolverContext } from '../lib/resolvers/CatalogAuthResolverContext';\nimport { TokenIssuer } from '../identity/types';\n\n/** @public */\nexport type ProviderFactories = { [s: string]: AuthProviderFactory };\n\nexport function bindProviderRouters(\n targetRouter: express.Router,\n options: {\n providers: ProviderFactories;\n appUrl: string;\n baseUrl: string;\n config: Config;\n logger: LoggerService;\n discovery: PluginEndpointDiscovery;\n auth: AuthService;\n httpAuth: HttpAuthService;\n tokenManager: TokenManager;\n tokenIssuer: TokenIssuer;\n ownershipResolver?: AuthOwnershipResolver;\n catalogApi?: CatalogApi;\n },\n) {\n const {\n providers,\n appUrl,\n baseUrl,\n config,\n logger,\n discovery,\n auth,\n httpAuth,\n tokenManager,\n tokenIssuer,\n catalogApi,\n ownershipResolver,\n } = options;\n\n const providersConfig = config.getOptionalConfig('auth.providers');\n\n const isOriginAllowed = createOriginFilter(config);\n\n for (const [providerId, providerFactory] of Object.entries(providers)) {\n if (providersConfig?.has(providerId)) {\n logger.info(`Configuring auth provider: ${providerId}`);\n try {\n const provider = providerFactory({\n providerId,\n appUrl,\n baseUrl,\n isOriginAllowed,\n globalConfig: {\n baseUrl,\n appUrl,\n isOriginAllowed,\n },\n config: providersConfig.getConfig(providerId),\n logger,\n resolverContext: CatalogAuthResolverContext.create({\n logger,\n catalogApi:\n catalogApi ?? new CatalogClient({ discoveryApi: discovery }),\n tokenIssuer,\n tokenManager,\n discovery,\n auth,\n httpAuth,\n ownershipResolver,\n }),\n });\n\n const r = Router();\n\n r.get('/start', provider.start.bind(provider));\n r.get('/handler/frame', provider.frameHandler.bind(provider));\n r.post('/handler/frame', provider.frameHandler.bind(provider));\n if (provider.logout) {\n r.post('/logout', provider.logout.bind(provider));\n }\n if (provider.refresh) {\n r.get('/refresh', provider.refresh.bind(provider));\n r.post('/refresh', provider.refresh.bind(provider));\n }\n\n targetRouter.use(`/${providerId}`, r);\n } catch (e) {\n assertError(e);\n if (process.env.NODE_ENV !== 'development') {\n throw new Error(\n `Failed to initialize ${providerId} auth provider, ${e.message}`,\n );\n }\n\n logger.warn(`Skipping ${providerId} auth provider, ${e.message}`);\n\n targetRouter.use(`/${providerId}`, () => {\n // If the user added the provider under auth.providers but the clientId and clientSecret etc. were not found.\n throw new NotFoundError(\n `Auth provider registered for '${providerId}' is misconfigured. This could mean the configs under ` +\n `auth.providers.${providerId} are missing or the environment variables used are not defined. ` +\n `Check the auth backend plugin logs when the backend starts to see more details.`,\n );\n });\n }\n } else {\n targetRouter.use(`/${providerId}`, () => {\n throw new NotFoundError(\n `No auth provider registered for '${providerId}'`,\n );\n });\n }\n }\n}\n\n/** @public */\nexport function createOriginFilter(\n config: Config,\n): (origin: string) => boolean {\n const appUrl = config.getString('app.baseUrl');\n const { origin: appOrigin } = new URL(appUrl);\n\n const allowedOrigins = config.getOptionalStringArray(\n 'auth.experimentalExtraAllowedOrigins',\n );\n\n const allowedOriginPatterns =\n allowedOrigins?.map(\n pattern => new Minimatch(pattern, { nocase: true, noglobstar: true }),\n ) ?? [];\n\n return origin => {\n if (origin === appOrigin) {\n return true;\n }\n return allowedOriginPatterns.some(pattern => pattern.match(origin));\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { TokenIssuer } from './types';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { decodeJwt } from 'jose';\nimport { AuthenticationError, InputError } from '@backstage/errors';\nimport { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler';\n\nexport function bindOidcRouter(\n targetRouter: express.Router,\n options: {\n baseUrl: string;\n auth: AuthService;\n tokenIssuer: TokenIssuer;\n userInfoDatabaseHandler: UserInfoDatabaseHandler;\n },\n) {\n const { baseUrl, auth, tokenIssuer, userInfoDatabaseHandler } = options;\n\n const router = Router();\n targetRouter.use(router);\n\n const config = {\n issuer: baseUrl,\n token_endpoint: `${baseUrl}/v1/token`,\n userinfo_endpoint: `${baseUrl}/v1/userinfo`,\n jwks_uri: `${baseUrl}/.well-known/jwks.json`,\n response_types_supported: ['id_token'],\n subject_types_supported: ['public'],\n id_token_signing_alg_values_supported: [\n 'RS256',\n 'RS384',\n 'RS512',\n 'ES256',\n 'ES384',\n 'ES512',\n 'PS256',\n 'PS384',\n 'PS512',\n 'EdDSA',\n ],\n scopes_supported: ['openid'],\n token_endpoint_auth_methods_supported: [],\n claims_supported: ['sub', 'ent'],\n grant_types_supported: [],\n };\n\n router.get('/.well-known/openid-configuration', (_req, res) => {\n res.json(config);\n });\n\n router.get('/.well-known/jwks.json', async (_req, res) => {\n const { keys } = await tokenIssuer.listPublicKeys();\n res.json({ keys });\n });\n\n router.get('/v1/token', (_req, res) => {\n res.status(501).send('Not Implemented');\n });\n\n // This endpoint doesn't use the regular HttpAuthService, since the contract\n // is specifically for the header to be communicated in the Authorization\n // header, regardless of token type\n router.get('/v1/userinfo', async (req, res) => {\n const matches = req.headers.authorization?.match(/^Bearer[ ]+(\\S+)$/i);\n const token = matches?.[1];\n if (!token) {\n throw new AuthenticationError('No token provided');\n }\n\n const credentials = await auth.authenticate(token, {\n allowLimitedAccess: true,\n });\n if (!auth.isPrincipal(credentials, 'user')) {\n throw new InputError(\n 'Userinfo endpoint must be called with a token that represents a user principal',\n );\n }\n\n const { sub: userEntityRef } = decodeJwt(token);\n\n if (typeof userEntityRef !== 'string') {\n throw new Error('Invalid user token, user entity ref must be a string');\n }\n\n const userInfo = await userInfoDatabaseHandler.getUserInfo(userEntityRef);\n if (!userInfo) {\n res.status(404).send('User info not found');\n return;\n }\n\n res.json(userInfo);\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n exportJWK,\n generateKeyPair,\n importJWK,\n JWK,\n SignJWT,\n GeneralSign,\n KeyLike,\n} from 'jose';\nimport { omit } from 'lodash';\nimport { DateTime } from 'luxon';\nimport { v4 as uuid } from 'uuid';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { TokenParams, tokenTypes } from '@backstage/plugin-auth-node';\nimport { AnyJWK, KeyStore, TokenIssuer } from './types';\nimport { JsonValue } from '@backstage/types';\nimport { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler';\n\nconst MS_IN_S = 1000;\nconst MAX_TOKEN_LENGTH = 32768; // At 64 bytes per entity ref this still leaves room for about 500 entities\n\n/**\n * The payload contents of a valid Backstage JWT token\n */\nexport interface BackstageTokenPayload {\n /**\n * The issuer of the token, currently the discovery URL of the auth backend\n */\n iss: string;\n\n /**\n * The entity ref of the user\n */\n sub: string;\n\n /**\n * The entity refs that the user claims ownership througg\n */\n ent: string[];\n\n /**\n * A hard coded audience string\n */\n aud: typeof tokenTypes.user.audClaim;\n\n /**\n * Standard expiry in epoch seconds\n */\n exp: number;\n\n /**\n * Standard issue time in epoch seconds\n */\n iat: number;\n\n /**\n * A separate user identity proof that the auth service can convert to a limited user token\n */\n uip: string;\n\n /**\n * Any other custom claims that the adopter may have added\n */\n [claim: string]: JsonValue;\n}\n\n/**\n * The payload contents of a valid Backstage user identity claim token\n *\n * @internal\n */\ninterface BackstageUserIdentityProofPayload {\n /**\n * The entity ref of the user\n */\n sub: string;\n\n /**\n * Standard expiry in epoch seconds\n */\n exp: number;\n\n /**\n * Standard issue time in epoch seconds\n */\n iat: number;\n}\n\ntype Options = {\n logger: LoggerService;\n /** Value of the issuer claim in issued tokens */\n issuer: string;\n /** Key store used for storing signing keys */\n keyStore: KeyStore;\n /** Expiration time of signing keys in seconds */\n keyDurationSeconds: number;\n /** JWS \"alg\" (Algorithm) Header Parameter value. Defaults to ES256.\n * Must match one of the algorithms defined for IdentityClient.\n * When setting a different algorithm, check if the `key` field\n * of the `signing_keys` table can fit the length of the generated keys.\n * If not, add a knex migration file in the migrations folder.\n * More info on supported algorithms: https://github.com/panva/jose */\n algorithm?: string;\n userInfoDatabaseHandler: UserInfoDatabaseHandler;\n};\n\n/**\n * A token issuer that is able to issue tokens in a distributed system\n * backed by a single database. Tokens are issued using lazily generated\n * signing keys, where each running instance of the auth service uses its own\n * signing key.\n *\n * The public parts of the keys are all stored in the shared key storage,\n * and any of the instances of the auth service will return the full list\n * of public keys that are currently in storage.\n *\n * Signing keys are automatically rotated at the same interval as the token\n * duration. Expired keys are kept in storage until there are no valid tokens\n * in circulation that could have been signed by that key.\n */\nexport class TokenFactory implements TokenIssuer {\n private readonly issuer: string;\n private readonly logger: LoggerService;\n private readonly keyStore: KeyStore;\n private readonly keyDurationSeconds: number;\n private readonly algorithm: string;\n private readonly userInfoDatabaseHandler: UserInfoDatabaseHandler;\n\n private keyExpiry?: Date;\n private privateKeyPromise?: Promise;\n\n constructor(options: Options) {\n this.issuer = options.issuer;\n this.logger = options.logger;\n this.keyStore = options.keyStore;\n this.keyDurationSeconds = options.keyDurationSeconds;\n this.algorithm = options.algorithm ?? 'ES256';\n this.userInfoDatabaseHandler = options.userInfoDatabaseHandler;\n }\n\n async issueToken(params: TokenParams): Promise {\n const key = await this.getKey();\n\n const iss = this.issuer;\n const { sub, ent = [sub], ...additionalClaims } = params.claims;\n const aud = tokenTypes.user.audClaim;\n const iat = Math.floor(Date.now() / MS_IN_S);\n const exp = iat + this.keyDurationSeconds;\n\n try {\n // The subject must be a valid entity ref\n parseEntityRef(sub);\n } catch (error) {\n throw new Error(\n '\"sub\" claim provided by the auth resolver is not a valid EntityRef.',\n );\n }\n\n if (!key.alg) {\n throw new AuthenticationError('No algorithm was provided in the key');\n }\n\n this.logger.info(`Issuing token for ${sub}, with entities ${ent}`);\n\n const signingKey = await importJWK(key);\n\n const uip = await this.createUserIdentityClaim({\n header: {\n typ: tokenTypes.limitedUser.typParam,\n alg: key.alg,\n kid: key.kid,\n },\n payload: { sub, iat, exp },\n key: signingKey,\n });\n\n const claims: BackstageTokenPayload = {\n ...additionalClaims,\n iss,\n sub,\n ent,\n aud,\n iat,\n exp,\n uip,\n };\n\n const token = await new SignJWT(claims)\n .setProtectedHeader({\n typ: tokenTypes.user.typParam,\n alg: key.alg,\n kid: key.kid,\n })\n .sign(signingKey);\n\n if (token.length > MAX_TOKEN_LENGTH) {\n throw new Error(\n `Failed to issue a new user token. The resulting token is excessively large, with either too many ownership claims or too large custom claims. You likely have a bug either in the sign-in resolver or catalog data. The following claims were requested: '${JSON.stringify(\n claims,\n )}'`,\n );\n }\n\n // Store the user info in the database upon successful token\n // issuance so that it can be retrieved later by limited user tokens\n await this.userInfoDatabaseHandler.addUserInfo({\n claims: omit(claims, ['aud', 'iat', 'iss', 'uip']),\n });\n\n return token;\n }\n\n // This will be called by other services that want to verify ID tokens.\n // It is important that it returns a list of all public keys that could\n // have been used to sign tokens that have not yet expired.\n async listPublicKeys(): Promise<{ keys: AnyJWK[] }> {\n const { items: keys } = await this.keyStore.listKeys();\n\n const validKeys = [];\n const expiredKeys = [];\n\n for (const key of keys) {\n // Allow for a grace period of another full key duration before we remove the keys from the database\n const expireAt = DateTime.fromJSDate(key.createdAt).plus({\n seconds: 3 * this.keyDurationSeconds,\n });\n if (expireAt < DateTime.local()) {\n expiredKeys.push(key);\n } else {\n validKeys.push(key);\n }\n }\n\n // Lazily prune expired keys. This may cause duplicate removals if we have concurrent callers, but w/e\n if (expiredKeys.length > 0) {\n const kids = expiredKeys.map(({ key }) => key.kid);\n\n this.logger.info(`Removing expired signing keys, '${kids.join(\"', '\")}'`);\n\n // We don't await this, just let it run in the background\n this.keyStore.removeKeys(kids).catch(error => {\n this.logger.error(`Failed to remove expired keys, ${error}`);\n });\n }\n\n // NOTE: we're currently only storing public keys, but if we start storing private keys we'd have to convert here\n return { keys: validKeys.map(({ key }) => key) };\n }\n\n private async getKey(): Promise {\n // Make sure that we only generate one key at a time\n if (this.privateKeyPromise) {\n if (\n this.keyExpiry &&\n DateTime.fromJSDate(this.keyExpiry) > DateTime.local()\n ) {\n return this.privateKeyPromise;\n }\n this.logger.info(`Signing key has expired, generating new key`);\n delete this.privateKeyPromise;\n }\n\n this.keyExpiry = DateTime.utc()\n .plus({\n seconds: this.keyDurationSeconds,\n })\n .toJSDate();\n const promise = (async () => {\n // This generates a new signing key to be used to sign tokens until the next key rotation\n const key = await generateKeyPair(this.algorithm);\n const publicKey = await exportJWK(key.publicKey);\n const privateKey = await exportJWK(key.privateKey);\n publicKey.kid = privateKey.kid = uuid();\n publicKey.alg = privateKey.alg = this.algorithm;\n\n // We're not allowed to use the key until it has been successfully stored\n // TODO: some token verification implementations aggressively cache the list of keys, and\n // don't attempt to fetch new ones even if they encounter an unknown kid. Therefore we\n // may want to keep using the existing key for some period of time until we switch to\n // the new one. This also needs to be implemented cross-service though, meaning new services\n // that boot up need to be able to grab an existing key to use for signing.\n this.logger.info(`Created new signing key ${publicKey.kid}`);\n await this.keyStore.addKey(publicKey as AnyJWK);\n\n // At this point we are allowed to start using the new key\n return privateKey;\n })();\n\n this.privateKeyPromise = promise;\n\n try {\n // If we fail to generate a new key, we need to clear the state so that\n // the next caller will try to generate another key.\n await promise;\n } catch (error) {\n this.logger.error(`Failed to generate new signing key, ${error}`);\n delete this.keyExpiry;\n delete this.privateKeyPromise;\n }\n\n return promise;\n }\n\n // Creates a string claim that can be used as part of reconstructing a limited\n // user token. The output of this function is only the signature part of a\n // JWS.\n private async createUserIdentityClaim(options: {\n header: {\n typ: string;\n alg: string;\n kid?: string;\n };\n payload: BackstageUserIdentityProofPayload;\n key: KeyLike | Uint8Array;\n }): Promise {\n // NOTE: We reconstruct the header and payload structures carefully to\n // perfectly guarantee ordering. The reason for this is that we store only\n // the signature part of these to reduce duplication within the Backstage\n // token. Anyone who wants to make an actual JWT based on all this must be\n // able to do the EXACT reconstruction of the header and payload parts, to\n // then append the signature.\n\n const header = {\n typ: options.header.typ,\n alg: options.header.alg,\n ...(options.header.kid ? { kid: options.header.kid } : {}),\n };\n\n const payload = {\n sub: options.payload.sub,\n iat: options.payload.iat,\n exp: options.payload.exp,\n };\n\n const jws = await new GeneralSign(\n new TextEncoder().encode(JSON.stringify(payload)),\n )\n .addSignature(options.key)\n .setProtectedHeader(header)\n .done()\n .sign();\n\n return jws.signatures[0].signature;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { AnyJWK, KeyStore, StoredKey } from './types';\n\nconst TABLE = 'signing_keys';\n\ntype Row = {\n created_at: Date; // row.created_at is a string after being returned from the database\n kid: string;\n key: string;\n};\n\nconst parseDate = (date: string | Date) => {\n const parsedDate =\n typeof date === 'string'\n ? DateTime.fromSQL(date, { zone: 'UTC' })\n : DateTime.fromJSDate(date);\n\n if (!parsedDate.isValid) {\n throw new Error(\n `Failed to parse date, reason: ${parsedDate.invalidReason}, explanation: ${parsedDate.invalidExplanation}`,\n );\n }\n\n return parsedDate.toJSDate();\n};\n\nexport class DatabaseKeyStore implements KeyStore {\n constructor(private readonly client: Knex) {}\n\n async addKey(key: AnyJWK): Promise {\n await this.client(TABLE).insert({\n kid: key.kid,\n key: JSON.stringify(key),\n });\n }\n\n async listKeys(): Promise<{ items: StoredKey[] }> {\n const rows = await this.client(TABLE).select();\n\n return {\n items: rows.map(row => ({\n key: JSON.parse(row.key),\n createdAt: parseDate(row.created_at),\n })),\n };\n }\n\n async removeKeys(kids: string[]): Promise {\n await this.client(TABLE).delete().whereIn('kid', kids);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KeyStore, AnyJWK, StoredKey } from './types';\nimport { DateTime } from 'luxon';\n\nexport class MemoryKeyStore implements KeyStore {\n private readonly keys = new Map();\n\n async addKey(key: AnyJWK): Promise {\n this.keys.set(key.kid, {\n createdAt: DateTime.utc().toJSDate(),\n key: JSON.stringify(key),\n });\n }\n\n async removeKeys(kids: string[]): Promise {\n for (const kid of kids) {\n this.keys.delete(kid);\n }\n }\n\n async listKeys(): Promise<{ items: StoredKey[] }> {\n return {\n items: Array.from(this.keys).map(([, { createdAt, key: keyStr }]) => ({\n createdAt,\n key: JSON.parse(keyStr),\n })),\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport {\n DocumentData,\n Firestore,\n QuerySnapshot,\n Settings,\n WriteResult,\n} from '@google-cloud/firestore';\n\nimport { AnyJWK, KeyStore, StoredKey } from './types';\n\nexport type FirestoreKeyStoreSettings = Settings & Options;\n\ntype Options = {\n path?: string;\n timeout?: number;\n};\n\nexport const DEFAULT_TIMEOUT_MS = 10000;\nexport const DEFAULT_DOCUMENT_PATH = 'sessions';\n\nexport class FirestoreKeyStore implements KeyStore {\n static async create(\n settings?: FirestoreKeyStoreSettings,\n ): Promise {\n const { path, timeout, ...firestoreSettings } = settings ?? {};\n const database = new Firestore(firestoreSettings);\n\n return new FirestoreKeyStore(\n database,\n path ?? DEFAULT_DOCUMENT_PATH,\n timeout ?? DEFAULT_TIMEOUT_MS,\n );\n }\n\n private constructor(\n private readonly database: Firestore,\n private readonly path: string,\n private readonly timeout: number,\n ) {}\n\n static async verifyConnection(\n keyStore: FirestoreKeyStore,\n logger?: LoggerService,\n ): Promise {\n try {\n await keyStore.verify();\n } catch (error) {\n if (process.env.NODE_ENV !== 'development') {\n throw new Error(\n `Failed to connect to database: ${(error as Error).message}`,\n );\n }\n logger?.warn(\n `Failed to connect to database: ${(error as Error).message}`,\n );\n }\n }\n\n async addKey(key: AnyJWK): Promise {\n await this.withTimeout(\n this.database\n .collection(this.path)\n .doc(key.kid)\n .set({\n kid: key.kid,\n key: JSON.stringify(key),\n }),\n );\n }\n\n async listKeys(): Promise<{ items: StoredKey[] }> {\n const keys = await this.withTimeout>(\n this.database.collection(this.path).get(),\n );\n\n return {\n items: keys.docs.map(key => ({\n key: key.data() as AnyJWK,\n createdAt: key.createTime.toDate(),\n })),\n };\n }\n\n async removeKeys(kids: string[]): Promise {\n // This is probably really slow, but it's done async in the background\n for (const kid of kids) {\n await this.withTimeout(\n this.database.collection(this.path).doc(kid).delete(),\n );\n }\n\n /**\n * This could be achieved with batching but there's a couple of limitations with that:\n *\n * - A batched write can contain a maximum of 500 operations\n * https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes\n *\n * - The \"in\" operator can combine a maximum of 10 equality clauses\n * https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any\n *\n * Example:\n *\n * const batch = this.database.batch();\n * const docs = await this.database\n * .collection(this.path)\n * .where('kid', 'in', kids)\n * .get();\n * docs.forEach(doc => {\n * batch.delete(doc.ref);\n * });\n * await batch.commit();\n *\n */\n }\n\n /**\n * Helper function to allow us to modify the timeout used when\n * performing Firestore database operations.\n *\n * The reason for this is that it seems that there's no other\n * practical solution to change the default timeout of 10mins\n * that Firestore has.\n *\n */\n private async withTimeout(operation: Promise): Promise {\n const timer = new Promise((_, reject) =>\n setTimeout(() => {\n reject(new Error(`Operation timed out after ${this.timeout}ms`));\n }, this.timeout),\n );\n return Promise.race([operation, timer]);\n }\n\n /**\n * Used to verify that the database is reachable.\n */\n private async verify(): Promise {\n await this.withTimeout(this.database.collection(this.path).limit(1).get());\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { AnyJWK, KeyStore, StoredKey } from './types';\nimport { exportJWK, importPKCS8, importSPKI, JWK } from 'jose';\nimport { KeyLike } from 'jose/dist/types/types';\nimport { promises as fs } from 'fs';\nimport { Config } from '@backstage/config';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey: JWK;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\n/**\n * Key store that loads predefined public/private key pairs from disk\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the StaticKeyStore.create(...) method.\n */\nexport class StaticKeyStore implements KeyStore {\n private readonly keyPairs: KeyPair[];\n private readonly createdAt: Date;\n\n private constructor(keyPairs: KeyPair[]) {\n if (keyPairs.length === 0) {\n throw new Error('Should provide at least one key pair');\n }\n\n this.keyPairs = keyPairs;\n this.createdAt = new Date();\n }\n\n public static async fromConfig(config: Config): Promise {\n const keyConfigs = config\n .getConfigArray('auth.keyStore.static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n return new StaticKeyStore(keyPairs);\n }\n\n addKey(_key: AnyJWK): Promise {\n throw new Error('Cannot add keys to the static key store');\n }\n\n listKeys(): Promise<{ items: StoredKey[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return Promise.resolve({ items: keys });\n }\n\n getPrivateKey(keyId: string): JWK {\n const keyPair = this.keyPairs.find(k => k.publicKey.kid === keyId);\n if (keyPair === undefined) {\n throw new Error(`Could not find key with keyId: ${keyId}`);\n }\n\n return keyPair.privateKey;\n }\n\n removeKeys(_kids: string[]): Promise {\n throw new Error('Cannot remove keys from the static key store');\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): StoredKey {\n const publicKey = {\n ...keyPair.publicKey,\n use: 'sig',\n };\n\n return {\n key: publicKey as AnyJWK,\n createdAt: this.createdAt,\n };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n );\n\n return { publicKey, privateKey };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise,\n ): Promise {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { pickBy } from 'lodash';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nimport { Config } from '@backstage/config';\nimport { AuthDatabase } from '../database/AuthDatabase';\nimport { DatabaseKeyStore } from './DatabaseKeyStore';\nimport { FirestoreKeyStore } from './FirestoreKeyStore';\nimport { MemoryKeyStore } from './MemoryKeyStore';\nimport { KeyStore } from './types';\nimport { StaticKeyStore } from './StaticKeyStore';\n\ntype Options = {\n logger: LoggerService;\n database: AuthDatabase;\n};\n\nexport class KeyStores {\n /**\n * Looks at the `auth.keyStore` section in the application configuration\n * and returns a KeyStore store. Defaults to `database`\n *\n * @returns a KeyStore store\n */\n static async fromConfig(config: Config, options: Options): Promise {\n const { logger, database } = options;\n\n const ks = config.getOptionalConfig('auth.keyStore');\n const provider = ks?.getOptionalString('provider') ?? 'database';\n\n logger.info(`Configuring \"${provider}\" as KeyStore provider`);\n\n if (provider === 'database') {\n return new DatabaseKeyStore(await database.get());\n }\n\n if (provider === 'memory') {\n return new MemoryKeyStore();\n }\n\n if (provider === 'firestore') {\n const settings = ks?.getConfig(provider);\n\n const keyStore = await FirestoreKeyStore.create(\n pickBy(\n {\n projectId: settings?.getOptionalString('projectId'),\n keyFilename: settings?.getOptionalString('keyFilename'),\n host: settings?.getOptionalString('host'),\n port: settings?.getOptionalNumber('port'),\n ssl: settings?.getOptionalBoolean('ssl'),\n path: settings?.getOptionalString('path'),\n timeout: settings?.getOptionalNumber('timeout'),\n },\n value => value !== undefined,\n ),\n );\n await FirestoreKeyStore.verifyConnection(keyStore, logger);\n\n return keyStore;\n }\n\n if (provider === 'static') {\n return await StaticKeyStore.fromConfig(config);\n }\n\n throw new Error(`Unknown KeyStore provider: ${provider}`);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DateTime } from 'luxon';\nimport { Knex } from 'knex';\n\nimport { BackstageTokenPayload } from './TokenFactory';\n\nconst TABLE = 'user_info';\n\ntype Row = {\n user_entity_ref: string;\n user_info: string;\n exp: string;\n};\n\ntype UserInfo = {\n claims: Omit;\n};\n\nexport class UserInfoDatabaseHandler {\n constructor(private readonly client: Knex) {}\n\n async addUserInfo(userInfo: UserInfo): Promise {\n await this.client(TABLE)\n .insert({\n user_entity_ref: userInfo.claims.sub as string,\n user_info: JSON.stringify(userInfo),\n exp: DateTime.fromSeconds(userInfo.claims.exp as number, {\n zone: 'utc',\n }).toSQL({ includeOffset: false }),\n })\n .onConflict('user_entity_ref')\n .merge();\n }\n\n async getUserInfo(userEntityRef: string): Promise {\n const info = await this.client(TABLE)\n .where({ user_entity_ref: userEntityRef })\n .first();\n\n if (!info) {\n return undefined;\n }\n\n const userInfo = JSON.parse(info.user_info);\n return userInfo;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DatabaseManager,\n PluginDatabaseManager,\n} from '@backstage/backend-common';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { ConfigReader } from '@backstage/config';\nimport { Knex } from 'knex';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-auth-backend',\n 'migrations',\n);\n\n/**\n * Ensures that a database connection is established exactly once and only when\n * asked for, and runs migrations.\n */\nexport class AuthDatabase {\n readonly #database: PluginDatabaseManager;\n #promise: Promise | undefined;\n\n static create(database: PluginDatabaseManager): AuthDatabase {\n return new AuthDatabase(database);\n }\n\n /** @internal */\n static forTesting(): AuthDatabase {\n const config = new ConfigReader({\n backend: {\n database: {\n client: 'better-sqlite3',\n connection: ':memory:',\n useNullAsDefault: true,\n },\n },\n });\n const database = DatabaseManager.fromConfig(config).forPlugin('auth');\n return new AuthDatabase(database);\n }\n\n static async runMigrations(knex: Knex): Promise {\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n private constructor(database: PluginDatabaseManager) {\n this.#database = database;\n }\n\n get(): Promise {\n this.#promise ??= this.#database.getClient().then(async client => {\n if (!this.#database.migrations?.skip) {\n await AuthDatabase.runMigrations(client);\n }\n return client;\n });\n\n return this.#promise;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootConfigService } from '@backstage/backend-plugin-api';\nimport { readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nconst TOKEN_EXP_DEFAULT_S = 3600;\nconst TOKEN_EXP_MIN_S = 600;\nconst TOKEN_EXP_MAX_S = 86400;\n\nexport function readBackstageTokenExpiration(config: RootConfigService) {\n const processingIntervalKey = 'auth.backstageTokenExpiration';\n\n if (!config.has(processingIntervalKey)) {\n return TOKEN_EXP_DEFAULT_S;\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const durationS = Math.round(durationToMilliseconds(duration) / 1000);\n\n if (durationS < TOKEN_EXP_MIN_S) {\n return TOKEN_EXP_MIN_S;\n } else if (durationS > TOKEN_EXP_MAX_S) {\n return TOKEN_EXP_MAX_S;\n }\n return durationS;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AnyJWK, TokenIssuer } from './types';\nimport { SignJWT, importJWK, JWK } from 'jose';\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { AuthenticationError } from '@backstage/errors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { StaticKeyStore } from './StaticKeyStore';\nimport { TokenParams } from '@backstage/plugin-auth-node';\n\nconst MS_IN_S = 1000;\n\nexport type Config = {\n publicKeyFile: string;\n privateKeyFile: string;\n keyId: string;\n algorithm?: string;\n};\n\nexport type Options = {\n logger: LoggerService;\n /** Value of the issuer claim in issued tokens */\n issuer: string;\n /** Expiration time of the JWT in seconds */\n sessionExpirationSeconds: number;\n};\n\n/**\n * A token issuer that issues tokens from predefined\n * public/private key pair stored in the static key store.\n */\nexport class StaticTokenIssuer implements TokenIssuer {\n private readonly issuer: string;\n private readonly logger: LoggerService;\n private readonly keyStore: StaticKeyStore;\n private readonly sessionExpirationSeconds: number;\n\n public constructor(options: Options, keyStore: StaticKeyStore) {\n this.issuer = options.issuer;\n this.logger = options.logger;\n this.sessionExpirationSeconds = options.sessionExpirationSeconds;\n this.keyStore = keyStore;\n }\n\n public async issueToken(params: TokenParams): Promise {\n const key = await this.getSigningKey();\n\n // TODO: code shared with TokenFactory.ts\n const iss = this.issuer;\n const { sub, ent, ...additionalClaims } = params.claims;\n const aud = 'backstage';\n const iat = Math.floor(Date.now() / MS_IN_S);\n const exp = iat + this.sessionExpirationSeconds;\n\n // Validate that the subject claim is a valid EntityRef\n try {\n parseEntityRef(sub);\n } catch (error) {\n throw new Error(\n '\"sub\" claim provided by the auth resolver is not a valid EntityRef.',\n );\n }\n\n this.logger.info(`Issuing token for ${sub}, with entities ${ent ?? []}`);\n\n if (!key.alg) {\n throw new AuthenticationError('No algorithm was provided in the key');\n }\n\n return new SignJWT({ ...additionalClaims, iss, sub, ent, aud, iat, exp })\n .setProtectedHeader({ alg: key.alg, kid: key.kid })\n .setIssuer(iss)\n .setAudience(aud)\n .setSubject(sub)\n .setIssuedAt(iat)\n .setExpirationTime(exp)\n .sign(await importJWK(key));\n }\n\n private async getSigningKey(): Promise {\n const { items: keys } = await this.keyStore.listKeys();\n if (keys.length >= 1) {\n return this.keyStore.getPrivateKey(keys[0].key.kid);\n }\n throw new Error('Keystore should hold at least 1 key');\n }\n\n public async listPublicKeys(): Promise<{ keys: AnyJWK[] }> {\n const { items: keys } = await this.keyStore.listKeys();\n return { keys: keys.map(({ key }) => key) };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport cookieParser from 'cookie-parser';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { defaultAuthProviderFactories } from '../providers';\nimport { AuthOwnershipResolver } from '@backstage/plugin-auth-node';\nimport {\n createLegacyAuthAdapters,\n PluginDatabaseManager,\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport { NotFoundError } from '@backstage/errors';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n bindOidcRouter,\n KeyStores,\n TokenFactory,\n UserInfoDatabaseHandler,\n} from '../identity';\nimport session from 'express-session';\nimport connectSessionKnex from 'connect-session-knex';\nimport passport from 'passport';\nimport { AuthDatabase } from '../database/AuthDatabase';\nimport { readBackstageTokenExpiration } from './readBackstageTokenExpiration';\nimport { TokenIssuer } from '../identity/types';\nimport { StaticTokenIssuer } from '../identity/StaticTokenIssuer';\nimport { StaticKeyStore } from '../identity/StaticKeyStore';\nimport { Config } from '@backstage/config';\nimport { bindProviderRouters, ProviderFactories } from '../providers/router';\n\n/** @public */\nexport interface RouterOptions {\n logger: LoggerService;\n database: PluginDatabaseManager;\n config: Config;\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n tokenFactoryAlgorithm?: string;\n providerFactories?: ProviderFactories;\n disableDefaultProviderFactories?: boolean;\n catalogApi?: CatalogApi;\n ownershipResolver?: AuthOwnershipResolver;\n}\n\n/** @public */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const {\n logger,\n config,\n discovery,\n database,\n tokenFactoryAlgorithm,\n providerFactories = {},\n } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters(options);\n\n const router = Router();\n\n const appUrl = config.getString('app.baseUrl');\n const authUrl = await discovery.getExternalBaseUrl('auth');\n const backstageTokenExpiration = readBackstageTokenExpiration(config);\n const authDb = AuthDatabase.create(database);\n\n const keyStore = await KeyStores.fromConfig(config, {\n logger,\n database: authDb,\n });\n\n const userInfoDatabaseHandler = new UserInfoDatabaseHandler(\n await authDb.get(),\n );\n\n let tokenIssuer: TokenIssuer;\n if (keyStore instanceof StaticKeyStore) {\n tokenIssuer = new StaticTokenIssuer(\n {\n logger: logger.child({ component: 'token-factory' }),\n issuer: authUrl,\n sessionExpirationSeconds: backstageTokenExpiration,\n },\n keyStore as StaticKeyStore,\n );\n } else {\n tokenIssuer = new TokenFactory({\n issuer: authUrl,\n keyStore,\n keyDurationSeconds: backstageTokenExpiration,\n logger: logger.child({ component: 'token-factory' }),\n algorithm:\n tokenFactoryAlgorithm ??\n config.getOptionalString('auth.identityTokenAlgorithm'),\n userInfoDatabaseHandler,\n });\n }\n\n const secret = config.getOptionalString('auth.session.secret');\n if (secret) {\n router.use(cookieParser(secret));\n const enforceCookieSSL = authUrl.startsWith('https');\n const KnexSessionStore = connectSessionKnex(session);\n router.use(\n session({\n secret,\n saveUninitialized: false,\n resave: false,\n cookie: { secure: enforceCookieSSL ? 'auto' : false },\n store: new KnexSessionStore({\n createtable: false,\n knex: await authDb.get(),\n }),\n }),\n );\n router.use(passport.initialize());\n router.use(passport.session());\n } else {\n router.use(cookieParser());\n }\n\n router.use(express.urlencoded({ extended: false }));\n router.use(express.json());\n\n const providers = options.disableDefaultProviderFactories\n ? providerFactories\n : {\n ...defaultAuthProviderFactories,\n ...providerFactories,\n };\n\n bindProviderRouters(router, {\n providers,\n appUrl,\n baseUrl: authUrl,\n tokenIssuer,\n ...options,\n auth,\n httpAuth,\n });\n\n bindOidcRouter(router, {\n auth,\n tokenIssuer,\n baseUrl: authUrl,\n userInfoDatabaseHandler,\n });\n\n // Gives a more helpful error message than a plain 404\n router.use('/:provider/', req => {\n const { provider } = req.params;\n throw new NotFoundError(`Unknown auth provider '${provider}'`);\n });\n\n return router;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport {\n authOwnershipResolutionExtensionPoint,\n AuthOwnershipResolver,\n AuthProviderFactory,\n authProvidersExtensionPoint,\n} from '@backstage/plugin-auth-node';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { createRouter } from './service/router';\n\n/**\n * Auth plugin\n *\n * @public\n */\nexport const authPlugin = createBackendPlugin({\n pluginId: 'auth',\n register(reg) {\n const providers = new Map();\n let ownershipResolver: AuthOwnershipResolver | undefined = undefined;\n\n reg.registerExtensionPoint(authProvidersExtensionPoint, {\n registerProvider({ providerId, factory }) {\n if (providers.has(providerId)) {\n throw new Error(\n `Auth provider '${providerId}' was already registered`,\n );\n }\n providers.set(providerId, factory);\n },\n });\n\n reg.registerExtensionPoint(authOwnershipResolutionExtensionPoint, {\n setAuthOwnershipResolver(resolver) {\n if (ownershipResolver) {\n throw new Error('Auth ownership resolver is already set');\n }\n ownershipResolver = resolver;\n },\n });\n\n reg.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n database: coreServices.database,\n discovery: coreServices.discovery,\n tokenManager: coreServices.tokenManager,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n catalogApi: catalogServiceRef,\n },\n async init({\n httpRouter,\n logger,\n config,\n database,\n discovery,\n tokenManager,\n auth,\n httpAuth,\n catalogApi,\n }) {\n const router = await createRouter({\n logger,\n config,\n database,\n discovery,\n tokenManager,\n auth,\n httpAuth,\n catalogApi,\n providerFactories: Object.fromEntries(providers),\n disableDefaultProviderFactories: true,\n ownershipResolver,\n });\n httpRouter.addAuthPolicy({\n path: '/',\n allow: 'unauthenticated',\n });\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createOAuthProviderFactory","atlassianAuthenticator","Auth0InternalStrategy","_OAuthEnvironmentHandler","decodeOAuthState","encodeOAuthState","crypto","_prepareBackstageIdentityResponse","URL","InputError","NotAllowedError","isError","AuthenticationError","decodeJwt","createProxyAuthProviderFactory","awsAlbAuthenticator","bitbucketAuthenticator","bitbucketSignInResolvers","createCloudflareAccessAuthenticator","cloudflareAccessSignInResolvers","gcpIapAuthenticator","githubAuthenticator","gitlabAuthenticator","googleAuthenticator","commonSignInResolvers","googleSignInResolvers","microsoftAuthenticator","microsoftSignInResolvers","oauth2Authenticator","oauth2ProxyAuthenticator","oidcAuthenticator","oktaAuthenticator","oneLoginAuthenticator","SamlStrategy","OAuth2Strategy","fetch","azureEasyAuthAuthenticator","createLegacyAuthAdapters","ConflictError","NotFoundError","parseEntityRef","stringifyEntityRef","RELATION_MEMBER_OF","DEFAULT_NAMESPACE","CatalogClient","Router","assertError","Minimatch","MS_IN_S","tokenTypes","importJWK","SignJWT","omit","DateTime","generateKeyPair","exportJWK","uuid","GeneralSign","TABLE","Firestore","importSPKI","importPKCS8","fs","pickBy","resolvePackagePath","config","ConfigReader","DatabaseManager","readDurationFromConfig","durationToMilliseconds","cookieParser","connectSessionKnex","session","passport","express","createBackendPlugin","authProvidersExtensionPoint","authOwnershipResolutionExtensionPoint","coreServices","catalogServiceRef"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"index.cjs.js","sources":["../src/lib/legacy/adaptLegacyOAuthHandler.ts","../src/lib/legacy/adaptLegacyOAuthSignInResolver.ts","../src/lib/legacy/adaptOAuthSignInResolverToLegacy.ts","../src/providers/createAuthProviderIntegration.ts","../src/providers/atlassian/provider.ts","../src/providers/auth0/strategy.ts","../src/lib/oauth/OAuthEnvironmentHandler.ts","../src/lib/oauth/helpers.ts","../src/lib/flow/authFlowHelpers.ts","../src/providers/prepareBackstageIdentityResponse.ts","../src/lib/oauth/OAuthAdapter.ts","../src/lib/passport/PassportStrategyHelper.ts","../src/providers/auth0/provider.ts","../src/providers/aws-alb/provider.ts","../src/providers/bitbucket/provider.ts","../src/providers/cloudflare-access/provider.ts","../src/providers/gcp-iap/provider.ts","../src/providers/github/provider.ts","../src/providers/gitlab/provider.ts","../src/providers/google/provider.ts","../src/providers/microsoft/provider.ts","../src/providers/oauth2/provider.ts","../src/providers/oauth2-proxy/provider.ts","../src/providers/resolvers.ts","../src/providers/oidc/provider.ts","../src/providers/okta/provider.ts","../src/providers/onelogin/provider.ts","../src/providers/saml/provider.ts","../src/providers/bitbucketServer/provider.ts","../src/providers/azure-easyauth/provider.ts","../src/providers/providers.ts","../src/lib/catalog/CatalogIdentityClient.ts","../src/lib/resolvers/CatalogAuthResolverContext.ts","../src/providers/router.ts","../src/identity/router.ts","../src/identity/TokenFactory.ts","../src/identity/DatabaseKeyStore.ts","../src/identity/MemoryKeyStore.ts","../src/identity/FirestoreKeyStore.ts","../src/identity/StaticKeyStore.ts","../src/identity/KeyStores.ts","../src/identity/UserInfoDatabaseHandler.ts","../src/database/AuthDatabase.ts","../src/service/readBackstageTokenExpiration.ts","../src/identity/StaticTokenIssuer.ts","../src/service/router.ts","../src/authPlugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OAuthAuthenticatorResult,\n ProfileTransform,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../../providers';\nimport { OAuthResult } from '../oauth';\nimport { PassportProfile } from '../passport/types';\n\n/** @internal */\nexport function adaptLegacyOAuthHandler(\n authHandler?: AuthHandler,\n): ProfileTransform> | undefined {\n return (\n authHandler &&\n (async (result, ctx) =>\n authHandler(\n {\n fullProfile: result.fullProfile,\n accessToken: result.session.accessToken,\n params: {\n scope: result.session.scope,\n id_token: result.session.idToken,\n token_type: result.session.tokenType,\n expires_in: result.session.expiresInSeconds!,\n },\n },\n ctx,\n ))\n );\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OAuthAuthenticatorResult,\n PassportProfile,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\nimport { OAuthResult } from '../oauth';\n\n/** @internal */\nexport function adaptLegacyOAuthSignInResolver(\n signInResolver?: SignInResolver,\n): SignInResolver> | undefined {\n return (\n signInResolver &&\n (async (input, ctx) =>\n signInResolver(\n {\n profile: input.profile,\n result: {\n fullProfile: input.result.fullProfile,\n accessToken: input.result.session.accessToken,\n refreshToken: input.result.session.refreshToken,\n params: {\n scope: input.result.session.scope,\n id_token: input.result.session.idToken,\n token_type: input.result.session.tokenType,\n expires_in: input.result.session.expiresInSeconds!,\n },\n },\n },\n ctx,\n ))\n );\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OAuthAuthenticatorResult,\n PassportProfile,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\nimport { OAuthResult } from '../oauth';\n\n/** @internal */\nexport function adaptOAuthSignInResolverToLegacy<\n TKeys extends string,\n>(resolvers: {\n [key in TKeys]: SignInResolver>;\n}): { [key in TKeys]: () => SignInResolver } {\n const legacyResolvers = {} as {\n [key in TKeys]: () => SignInResolver;\n };\n for (const name of Object.keys(resolvers) as TKeys[]) {\n const resolver = resolvers[name];\n legacyResolvers[name] = () => async (input, ctx) =>\n resolver(\n {\n profile: input.profile,\n result: {\n fullProfile: input.result.fullProfile,\n session: {\n accessToken: input.result.accessToken,\n expiresInSeconds: input.result.params.expires_in,\n scope: input.result.params.scope,\n idToken: input.result.params.id_token,\n tokenType: input.result.params.token_type ?? 'bearer',\n refreshToken: input.result.refreshToken,\n },\n },\n },\n ctx,\n );\n }\n return legacyResolvers;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthProviderFactory,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\n/**\n * Creates a standardized representation of an integration with a third-party\n * auth provider.\n *\n * The returned object facilitates the creation of provider instances, and\n * supplies built-in sign-in resolvers for the specific provider.\n *\n * @public\n */\nexport function createAuthProviderIntegration<\n TCreateOptions extends unknown[],\n TResolvers extends\n | {\n [name in string]: (...args: any[]) => SignInResolver;\n },\n>(config: {\n create: (...args: TCreateOptions) => AuthProviderFactory;\n resolvers?: TResolvers;\n}): Readonly<{\n create: (...args: TCreateOptions) => AuthProviderFactory;\n // If no resolvers are defined, this receives the type `never`\n resolvers: Readonly;\n}> {\n return Object.freeze({\n ...config,\n resolvers: Object.freeze(config.resolvers ?? ({} as any)),\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { atlassianAuthenticator } from '@backstage/plugin-auth-backend-module-atlassian-provider';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * Auth provider integration for Atlassian auth\n *\n * @public\n */\nexport const atlassian = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: atlassianAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport Auth0InternalStrategy from 'passport-auth0';\nimport { StateStore } from 'passport-oauth2';\n\nexport interface Auth0StrategyOptionsWithRequest {\n clientID: string;\n clientSecret: string;\n callbackURL: string;\n domain: string;\n passReqToCallback: true;\n store: StateStore;\n}\n\nexport default class Auth0Strategy extends Auth0InternalStrategy {\n constructor(\n options: Auth0StrategyOptionsWithRequest,\n verify: Auth0InternalStrategy.VerifyFunction,\n ) {\n const optionsWithURLs = {\n ...options,\n authorizationURL: `https://${options.domain}/authorize`,\n tokenURL: `https://${options.domain}/oauth/token`,\n userInfoURL: `https://${options.domain}/userinfo`,\n apiUrl: `https://${options.domain}/api`,\n };\n super(optionsWithURLs, verify);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OAuthEnvironmentHandler as _OAuthEnvironmentHandler } from '@backstage/plugin-auth-node';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-auth-node` instead\n */\nexport const OAuthEnvironmentHandler = _OAuthEnvironmentHandler;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport {\n CookieConfigurer,\n OAuthState,\n decodeOAuthState,\n encodeOAuthState,\n} from '@backstage/plugin-auth-node';\n\n/**\n * @public\n * @deprecated Use `decodeOAuthState` from `@backstage/plugin-auth-node` instead\n */\nexport const readState = decodeOAuthState;\n\n/**\n * @public\n * @deprecated Use `encodeOAuthState` from `@backstage/plugin-auth-node` instead\n */\nexport const encodeState = encodeOAuthState;\n\n/**\n * @public\n * @deprecated Use inline logic to make sure the session and state nonce matches instead.\n */\nexport const verifyNonce = (req: express.Request, providerId: string) => {\n const cookieNonce = req.cookies[`${providerId}-nonce`];\n const state: OAuthState = readState(req.query.state?.toString() ?? '');\n const stateNonce = state.nonce;\n\n if (!cookieNonce) {\n throw new Error('Auth response is missing cookie nonce');\n }\n if (stateNonce.length === 0) {\n throw new Error('Auth response is missing state nonce');\n }\n if (cookieNonce !== stateNonce) {\n throw new Error('Invalid nonce');\n }\n};\n\nexport const defaultCookieConfigurer: CookieConfigurer = ({\n callbackUrl,\n providerId,\n appOrigin,\n}) => {\n const { hostname: domain, pathname, protocol } = new URL(callbackUrl);\n const secure = protocol === 'https:';\n\n // For situations where the auth-backend is running on a\n // different domain than the app, we set the SameSite attribute\n // to 'none' to allow third-party access to the cookie, but\n // only if it's in a secure context (https).\n let sameSite: ReturnType['sameSite'] = 'lax';\n if (new URL(appOrigin).hostname !== domain && secure) {\n sameSite = 'none';\n }\n\n // If the provider supports callbackUrls, the pathname will\n // contain the complete path to the frame handler so we need\n // to slice off the trailing part of the path.\n const path = pathname.endsWith(`${providerId}/handler/frame`)\n ? pathname.slice(0, -'/handler/frame'.length)\n : `${pathname}/${providerId}`;\n\n return { domain, path, secure, sameSite };\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport crypto from 'crypto';\nimport { WebMessageResponse } from './types';\n\nexport const safelyEncodeURIComponent = (value: string) => {\n // Note the g at the end of the regex; all occurrences of single quotes must\n // be replaced, which encodeURIComponent does not do itself by default\n return encodeURIComponent(value).replace(/'/g, '%27');\n};\n\n/**\n * @public\n * @deprecated Use `sendWebMessageResponse` from `@backstage/plugin-auth-node` instead\n */\nexport const postMessageResponse = (\n res: express.Response,\n appOrigin: string,\n response: WebMessageResponse,\n) => {\n const jsonData = JSON.stringify(response);\n const base64Data = safelyEncodeURIComponent(jsonData);\n const base64Origin = safelyEncodeURIComponent(appOrigin);\n\n // NOTE: It is absolutely imperative that we use the safe encoder above, to\n // be sure that the js code below does not allow the injection of malicious\n // data.\n\n // TODO: Make target app origin configurable globally\n\n //\n // postMessage fails silently if the targetOrigin is disallowed.\n // So 2 postMessages are sent from the popup to the parent window.\n // First, the origin being used to post the actual authorization response is\n // shared with the parent window with a postMessage with targetOrigin '*'.\n // Second, the actual authorization response is sent with the app origin\n // as the targetOrigin.\n // If the first message was received but the actual auth response was\n // never received, the event listener can conclude that targetOrigin\n // was disallowed, indicating potential misconfiguration.\n //\n const script = `\n var authResponse = decodeURIComponent('${base64Data}');\n var origin = decodeURIComponent('${base64Origin}');\n var originInfo = {'type': 'config_info', 'targetOrigin': origin};\n (window.opener || window.parent).postMessage(originInfo, '*');\n (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin);\n setTimeout(() => {\n window.close();\n }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)\n `;\n const hash = crypto.createHash('sha256').update(script).digest('base64');\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('X-Frame-Options', 'sameorigin');\n res.setHeader('Content-Security-Policy', `script-src 'sha256-${hash}'`);\n res.end(``);\n};\n\n/**\n * @public\n * @deprecated Use inline logic to check that the `X-Requested-With` header is set to `'XMLHttpRequest'` instead.\n */\nexport const ensuresXRequestedWith = (req: express.Request) => {\n const requiredHeader = req.header('X-Requested-With');\n if (!requiredHeader || requiredHeader !== 'XMLHttpRequest') {\n return false;\n }\n return true;\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { prepareBackstageIdentityResponse as _prepareBackstageIdentityResponse } from '@backstage/plugin-auth-node';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-auth-node` instead\n */\nexport const prepareBackstageIdentityResponse =\n _prepareBackstageIdentityResponse;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express, { CookieOptions } from 'express';\nimport crypto from 'crypto';\nimport { URL } from 'url';\nimport {\n AuthProviderConfig,\n AuthProviderRouteHandlers,\n BackstageIdentityResponse,\n BackstageSignInResult,\n CookieConfigurer,\n OAuthState,\n} from '@backstage/plugin-auth-node';\nimport {\n AuthenticationError,\n InputError,\n isError,\n NotAllowedError,\n} from '@backstage/errors';\nimport { defaultCookieConfigurer, readState, verifyNonce } from './helpers';\nimport {\n postMessageResponse,\n ensuresXRequestedWith,\n WebMessageResponse,\n} from '../flow';\nimport {\n OAuthHandlers,\n OAuthStartRequest,\n OAuthRefreshRequest,\n OAuthLogoutRequest,\n} from './types';\nimport { prepareBackstageIdentityResponse } from '../../providers/prepareBackstageIdentityResponse';\n\nexport const THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000;\nexport const TEN_MINUTES_MS = 600 * 1000;\n\n/**\n * @public\n * @deprecated Use `createOAuthRouteHandlers` from `@backstage/plugin-auth-node` instead\n */\nexport type OAuthAdapterOptions = {\n providerId: string;\n persistScopes?: boolean;\n appOrigin: string;\n baseUrl: string;\n cookieConfigurer: CookieConfigurer;\n isOriginAllowed: (origin: string) => boolean;\n callbackUrl: string;\n};\n\n/**\n * @public\n * @deprecated Use `createOAuthRouteHandlers` from `@backstage/plugin-auth-node` instead\n */\nexport class OAuthAdapter implements AuthProviderRouteHandlers {\n static fromConfig(\n config: AuthProviderConfig,\n handlers: OAuthHandlers,\n options: Pick<\n OAuthAdapterOptions,\n 'providerId' | 'persistScopes' | 'callbackUrl'\n >,\n ): OAuthAdapter {\n const { appUrl, baseUrl, isOriginAllowed } = config;\n const { origin: appOrigin } = new URL(appUrl);\n\n const cookieConfigurer = config.cookieConfigurer ?? defaultCookieConfigurer;\n\n return new OAuthAdapter(handlers, {\n ...options,\n appOrigin,\n baseUrl,\n cookieConfigurer,\n isOriginAllowed,\n });\n }\n\n private readonly baseCookieOptions: CookieOptions;\n\n constructor(\n private readonly handlers: OAuthHandlers,\n private readonly options: OAuthAdapterOptions,\n ) {\n this.baseCookieOptions = {\n httpOnly: true,\n sameSite: 'lax',\n };\n }\n\n async start(req: express.Request, res: express.Response): Promise {\n // retrieve scopes from request\n const scope = req.query.scope?.toString() ?? '';\n const env = req.query.env?.toString();\n const origin = req.query.origin?.toString();\n const redirectUrl = req.query.redirectUrl?.toString();\n const flow = req.query.flow?.toString();\n\n if (!env) {\n throw new InputError('No env provided in request query parameters');\n }\n\n const cookieConfig = this.getCookieConfig(origin);\n\n const nonce = crypto.randomBytes(16).toString('base64');\n // set a nonce cookie before redirecting to oauth provider\n this.setNonceCookie(res, nonce, cookieConfig);\n\n const state: OAuthState = { nonce, env, origin, redirectUrl, flow };\n\n // If scopes are persisted then we pass them through the state so that we\n // can set the cookie on successful auth\n if (this.options.persistScopes) {\n state.scope = scope;\n }\n const forwardReq = Object.assign(req, { scope, state });\n\n const { url, status } = await this.handlers.start(\n forwardReq as OAuthStartRequest,\n );\n\n res.statusCode = status || 302;\n res.setHeader('Location', url);\n res.setHeader('Content-Length', '0');\n res.end();\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise {\n let appOrigin = this.options.appOrigin;\n\n try {\n const state: OAuthState = readState(req.query.state?.toString() ?? '');\n\n if (state.origin) {\n try {\n appOrigin = new URL(state.origin).origin;\n } catch {\n throw new NotAllowedError('App origin is invalid, failed to parse');\n }\n if (!this.options.isOriginAllowed(appOrigin)) {\n throw new NotAllowedError(`Origin '${appOrigin}' is not allowed`);\n }\n }\n\n // verify nonce cookie and state cookie on callback\n verifyNonce(req, this.options.providerId);\n\n const { response, refreshToken } = await this.handlers.handler(req);\n\n const cookieConfig = this.getCookieConfig(appOrigin);\n\n // Store the scope that we have been granted for this session. This is useful if\n // the provider does not return granted scopes on refresh or if they are normalized.\n if (this.options.persistScopes && state.scope) {\n this.setGrantedScopeCookie(res, state.scope, cookieConfig);\n response.providerInfo.scope = state.scope;\n }\n\n if (refreshToken) {\n // set new refresh token\n this.setRefreshTokenCookie(res, refreshToken, cookieConfig);\n }\n\n const identity = await this.populateIdentity(response.backstageIdentity);\n\n const responseObj: WebMessageResponse = {\n type: 'authorization_response',\n response: { ...response, backstageIdentity: identity },\n };\n\n if (state.flow === 'redirect') {\n if (!state.redirectUrl) {\n throw new InputError(\n 'No redirectUrl provided in request query parameters',\n );\n }\n res.redirect(state.redirectUrl);\n return undefined;\n }\n // post message back to popup if successful\n return postMessageResponse(res, appOrigin, responseObj);\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n // post error message back to popup if failure\n return postMessageResponse(res, appOrigin, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n }\n\n async logout(req: express.Request, res: express.Response): Promise {\n if (!ensuresXRequestedWith(req)) {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (this.handlers.logout) {\n const refreshToken = this.getRefreshTokenFromCookie(req);\n const revokeRequest: OAuthLogoutRequest = Object.assign(req, {\n refreshToken,\n });\n await this.handlers.logout(revokeRequest);\n }\n\n // remove refresh token cookie if it is set\n const origin = req.get('origin');\n const cookieConfig = this.getCookieConfig(origin);\n this.removeRefreshTokenCookie(res, cookieConfig);\n\n res.status(200).end();\n }\n\n async refresh(req: express.Request, res: express.Response): Promise {\n if (!ensuresXRequestedWith(req)) {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (!this.handlers.refresh) {\n throw new InputError(\n `Refresh token is not supported for provider ${this.options.providerId}`,\n );\n }\n\n try {\n const refreshToken = this.getRefreshTokenFromCookie(req);\n\n // throw error if refresh token is missing in the request\n if (!refreshToken) {\n throw new InputError('Missing session cookie');\n }\n\n let scope = req.query.scope?.toString() ?? '';\n if (this.options.persistScopes) {\n scope = this.getGrantedScopeFromCookie(req);\n }\n const forwardReq = Object.assign(req, { scope, refreshToken });\n\n // get new access_token\n const { response, refreshToken: newRefreshToken } =\n await this.handlers.refresh(forwardReq as OAuthRefreshRequest);\n\n const backstageIdentity = await this.populateIdentity(\n response.backstageIdentity,\n );\n\n if (newRefreshToken && newRefreshToken !== refreshToken) {\n const origin = req.get('origin');\n const cookieConfig = this.getCookieConfig(origin);\n this.setRefreshTokenCookie(res, newRefreshToken, cookieConfig);\n }\n\n res.status(200).json({ ...response, backstageIdentity });\n } catch (error) {\n throw new AuthenticationError('Refresh failed', error);\n }\n }\n\n /**\n * If the response from the OAuth provider includes a Backstage identity, we\n * make sure it's populated with all the information we can derive from the user ID.\n */\n private async populateIdentity(\n identity?: BackstageSignInResult,\n ): Promise {\n if (!identity) {\n return undefined;\n }\n if (!identity.token) {\n throw new InputError(`Identity response must return a token`);\n }\n\n return prepareBackstageIdentityResponse(identity);\n }\n\n private setNonceCookie = (\n res: express.Response,\n nonce: string,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-nonce`, nonce, {\n maxAge: TEN_MINUTES_MS,\n ...this.baseCookieOptions,\n ...cookieConfig,\n path: `${cookieConfig.path}/handler`,\n });\n };\n\n private setGrantedScopeCookie = (\n res: express.Response,\n scope: string,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-granted-scope`, scope, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.baseCookieOptions,\n ...cookieConfig,\n });\n };\n\n private getRefreshTokenFromCookie = (req: express.Request) => {\n return req.cookies[`${this.options.providerId}-refresh-token`];\n };\n\n private getGrantedScopeFromCookie = (req: express.Request) => {\n return req.cookies[`${this.options.providerId}-granted-scope`];\n };\n\n private setRefreshTokenCookie = (\n res: express.Response,\n refreshToken: string,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-refresh-token`, refreshToken, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.baseCookieOptions,\n ...cookieConfig,\n });\n };\n\n private removeRefreshTokenCookie = (\n res: express.Response,\n cookieConfig: ReturnType,\n ) => {\n res.cookie(`${this.options.providerId}-refresh-token`, '', {\n maxAge: 0,\n ...this.baseCookieOptions,\n ...cookieConfig,\n });\n };\n\n private getCookieConfig = (origin?: string) => {\n return this.options.cookieConfigurer({\n providerId: this.options.providerId,\n baseUrl: this.options.baseUrl,\n callbackUrl: this.options.callbackUrl,\n appOrigin: origin ?? this.options.appOrigin,\n });\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport passport from 'passport';\nimport { decodeJwt } from 'jose';\nimport { InternalOAuthError } from 'passport-oauth2';\nimport { ProfileInfo } from '@backstage/plugin-auth-node';\nimport { PassportProfile } from './types';\nimport { OAuthStartResponse } from '../../providers/types';\n\nexport type PassportDoneCallback = (\n err?: Error,\n response?: Res,\n privateInfo?: Private,\n) => void;\n\nexport const makeProfileInfo = (\n profile: PassportProfile,\n idToken?: string,\n): ProfileInfo => {\n let email: string | undefined = undefined;\n if (profile.emails && profile.emails.length > 0) {\n const [firstEmail] = profile.emails;\n email = firstEmail.value;\n }\n\n let picture: string | undefined = undefined;\n if (profile.avatarUrl) {\n picture = profile.avatarUrl;\n } else if (profile.photos && profile.photos.length > 0) {\n const [firstPhoto] = profile.photos;\n picture = firstPhoto.value;\n }\n\n let displayName: string | undefined =\n profile.displayName ?? profile.username ?? profile.id;\n\n if ((!email || !picture || !displayName) && idToken) {\n try {\n const decoded = decodeJwt(idToken) as {\n email?: string;\n name?: string;\n picture?: string;\n };\n if (!email && decoded.email) {\n email = decoded.email;\n }\n if (!picture && decoded.picture) {\n picture = decoded.picture;\n }\n if (!displayName && decoded.name) {\n displayName = decoded.name;\n }\n } catch (e) {\n throw new Error(`Failed to parse id token and get profile info, ${e}`);\n }\n }\n\n return {\n email,\n picture,\n displayName,\n };\n};\n\nexport const executeRedirectStrategy = async (\n req: express.Request,\n providerStrategy: passport.Strategy,\n options: Record,\n): Promise => {\n return new Promise(resolve => {\n const strategy = Object.create(providerStrategy);\n strategy.redirect = (url: string, status?: number) => {\n resolve({ url, status: status ?? undefined });\n };\n\n strategy.authenticate(req, { ...options });\n });\n};\n\nexport const executeFrameHandlerStrategy = async (\n req: express.Request,\n providerStrategy: passport.Strategy,\n options?: Record,\n) => {\n return new Promise<{ result: Result; privateInfo: PrivateInfo }>(\n (resolve, reject) => {\n const strategy = Object.create(providerStrategy);\n strategy.success = (result: any, privateInfo: any) => {\n resolve({ result, privateInfo });\n };\n strategy.fail = (\n info: { type: 'success' | 'error'; message?: string },\n // _status: number,\n ) => {\n reject(new Error(`Authentication rejected, ${info.message ?? ''}`));\n };\n strategy.error = (error: InternalOAuthError) => {\n let message = `Authentication failed, ${error.message}`;\n\n if (error.oauthError?.data) {\n try {\n const errorData = JSON.parse(error.oauthError.data);\n\n if (errorData.message) {\n message += ` - ${errorData.message}`;\n }\n } catch (parseError) {\n message += ` - ${error.oauthError}`;\n }\n }\n\n reject(new Error(message));\n };\n strategy.redirect = () => {\n reject(new Error('Unexpected redirect'));\n };\n strategy.authenticate(req, { ...(options ?? {}) });\n },\n );\n};\n\ntype RefreshTokenResponse = {\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * Optionally, the server can issue a new Refresh Token for the user\n */\n refreshToken?: string;\n params: any;\n};\n\nexport const executeRefreshTokenStrategy = async (\n providerStrategy: passport.Strategy,\n refreshToken: string,\n scope: string,\n): Promise => {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as any;\n const OAuth2 = anyStrategy._oauth2.constructor;\n const oauth2 = new OAuth2(\n anyStrategy._oauth2._clientId,\n anyStrategy._oauth2._clientSecret,\n anyStrategy._oauth2._baseSite,\n anyStrategy._oauth2._authorizeUrl,\n anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,\n anyStrategy._oauth2._customHeaders,\n );\n\n oauth2.getOAuthAccessToken(\n refreshToken,\n {\n scope,\n grant_type: 'refresh_token',\n },\n (\n err: Error | null,\n accessToken: string,\n newRefreshToken: string,\n params: any,\n ) => {\n if (err) {\n reject(new Error(`Failed to refresh access token ${err.toString()}`));\n }\n if (!accessToken) {\n reject(\n new Error(\n `Failed to refresh access token, no access token received`,\n ),\n );\n }\n\n resolve({\n accessToken,\n refreshToken: newRefreshToken,\n params,\n });\n },\n );\n });\n};\n\ntype ProviderStrategy = {\n userProfile(accessToken: string, callback: Function): void;\n};\n\nexport const executeFetchUserProfileStrategy = async (\n providerStrategy: passport.Strategy,\n accessToken: string,\n): Promise => {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as unknown as ProviderStrategy;\n anyStrategy.userProfile(\n accessToken,\n (error: Error, rawProfile: PassportProfile) => {\n if (error) {\n reject(error);\n } else {\n resolve(rawProfile);\n }\n },\n );\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport passport from 'passport';\nimport Auth0Strategy from './strategy';\nimport {\n OAuthAdapter,\n OAuthProviderOptions,\n OAuthHandlers,\n OAuthResponse,\n OAuthEnvironmentHandler,\n OAuthStartRequest,\n encodeState,\n OAuthRefreshRequest,\n OAuthResult,\n} from '../../lib/oauth';\nimport {\n executeFetchUserProfileStrategy,\n executeFrameHandlerStrategy,\n executeRedirectStrategy,\n executeRefreshTokenStrategy,\n makeProfileInfo,\n PassportDoneCallback,\n} from '../../lib/passport';\nimport { OAuthStartResponse, AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { StateStore } from 'passport-oauth2';\nimport {\n AuthResolverContext,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\ntype PrivateInfo = {\n refreshToken: string;\n};\n\nexport type Auth0AuthProviderOptions = OAuthProviderOptions & {\n domain: string;\n signInResolver?: SignInResolver;\n authHandler: AuthHandler;\n resolverContext: AuthResolverContext;\n audience?: string;\n connection?: string;\n connectionScope?: string;\n};\n\nexport class Auth0AuthProvider implements OAuthHandlers {\n private readonly _strategy: Auth0Strategy;\n private readonly signInResolver?: SignInResolver;\n private readonly authHandler: AuthHandler;\n private readonly resolverContext: AuthResolverContext;\n private readonly audience?: string;\n private readonly connection?: string;\n private readonly connectionScope?: string;\n\n /**\n * Due to passport-auth0 forcing options.state = true,\n * passport-oauth2 requires express-session to be installed\n * so that the 'state' parameter of the oauth2 flow can be stored.\n * This implementation of StateStore matches the NullStore found within\n * passport-oauth2, which is the StateStore implementation used when options.state = false,\n * allowing us to avoid using express-session in order to integrate with auth0.\n */\n private store: StateStore = {\n store(_req: express.Request, cb: any) {\n cb(null, null);\n },\n verify(_req: express.Request, _state: string, cb: any) {\n cb(null, true);\n },\n };\n\n constructor(options: Auth0AuthProviderOptions) {\n this.signInResolver = options.signInResolver;\n this.authHandler = options.authHandler;\n this.resolverContext = options.resolverContext;\n this.audience = options.audience;\n this.connection = options.connection;\n this.connectionScope = options.connectionScope;\n this._strategy = new Auth0Strategy(\n {\n clientID: options.clientId,\n clientSecret: options.clientSecret,\n callbackURL: options.callbackUrl,\n domain: options.domain,\n // We need passReqToCallback set to false to get params, but there's\n // no matching type signature for that, so instead behold this beauty\n passReqToCallback: false as true,\n store: this.store,\n },\n (\n accessToken: any,\n refreshToken: any,\n params: any,\n fullProfile: passport.Profile,\n done: PassportDoneCallback,\n ) => {\n done(\n undefined,\n {\n fullProfile,\n accessToken,\n refreshToken,\n params,\n },\n {\n refreshToken,\n },\n );\n },\n );\n }\n\n async start(req: OAuthStartRequest): Promise {\n return await executeRedirectStrategy(req, this._strategy, {\n accessType: 'offline',\n prompt: 'consent',\n scope: req.scope,\n state: encodeState(req.state),\n ...(this.audience ? { audience: this.audience } : {}),\n ...(this.connection ? { connection: this.connection } : {}),\n ...(this.connectionScope\n ? { connection_scope: this.connectionScope }\n : {}),\n });\n }\n\n async handler(req: express.Request) {\n const { result, privateInfo } = await executeFrameHandlerStrategy<\n OAuthResult,\n PrivateInfo\n >(req, this._strategy, {\n ...(this.audience ? { audience: this.audience } : {}),\n ...(this.connection ? { connection: this.connection } : {}),\n ...(this.connectionScope\n ? { connection_scope: this.connectionScope }\n : {}),\n });\n\n return {\n response: await this.handleResult(result),\n refreshToken: privateInfo.refreshToken,\n };\n }\n\n async refresh(req: OAuthRefreshRequest) {\n const { accessToken, refreshToken, params } =\n await executeRefreshTokenStrategy(\n this._strategy,\n req.refreshToken,\n req.scope,\n );\n\n const fullProfile = await executeFetchUserProfileStrategy(\n this._strategy,\n accessToken,\n );\n\n return {\n response: await this.handleResult({\n fullProfile,\n params,\n accessToken,\n }),\n refreshToken,\n };\n }\n\n private async handleResult(result: OAuthResult) {\n const { profile } = await this.authHandler(result, this.resolverContext);\n\n const response: OAuthResponse = {\n providerInfo: {\n idToken: result.params.id_token,\n accessToken: result.accessToken,\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n },\n profile,\n };\n\n if (this.signInResolver) {\n response.backstageIdentity = await this.signInResolver(\n {\n result,\n profile,\n },\n this.resolverContext,\n );\n }\n\n return response;\n }\n}\n\n/**\n * Auth provider integration for auth0 auth\n *\n * @public\n */\nexport const auth0 = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return ({ providerId, globalConfig, config, resolverContext }) =>\n OAuthEnvironmentHandler.mapConfig(config, envConfig => {\n const clientId = envConfig.getString('clientId');\n const clientSecret = envConfig.getString('clientSecret');\n const domain = envConfig.getString('domain');\n const customCallbackUrl = envConfig.getOptionalString('callbackUrl');\n const audience = envConfig.getOptionalString('audience');\n const connection = envConfig.getOptionalString('connection');\n const connectionScope = envConfig.getOptionalString('connectionScope');\n const callbackUrl =\n customCallbackUrl ||\n `${globalConfig.baseUrl}/${providerId}/handler/frame`;\n\n const authHandler: AuthHandler = options?.authHandler\n ? options.authHandler\n : async ({ fullProfile, params }) => ({\n profile: makeProfileInfo(fullProfile, params.id_token),\n });\n\n const signInResolver = options?.signIn?.resolver;\n\n const provider = new Auth0AuthProvider({\n clientId,\n clientSecret,\n callbackUrl,\n domain,\n authHandler,\n signInResolver,\n resolverContext,\n audience,\n connection,\n connectionScope,\n });\n\n return OAuthAdapter.fromConfig(globalConfig, provider, {\n providerId,\n callbackUrl,\n });\n });\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AwsAlbResult,\n awsAlbAuthenticator,\n} from '@backstage/plugin-auth-backend-module-aws-alb-provider';\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\n\n/**\n * Auth provider integration for AWS ALB auth\n *\n * @public\n */\nexport const awsAlb = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth\n * response into the profile that will be presented to the user. The default\n * implementation just provides the authenticated email that the IAP\n * presented.\n */\n authHandler?: AuthHandler;\n /**\n * Configures sign-in for this provider.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: awsAlbAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bitbucketAuthenticator,\n bitbucketSignInResolvers,\n} from '@backstage/plugin-auth-backend-module-bitbucket-provider';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { Profile as PassportProfile } from 'passport';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n adaptOAuthSignInResolverToLegacy,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * @public\n * @deprecated The Bitbucket auth provider was extracted to `@backstage/plugin-auth-backend-module-bitbucket-provider`.\n */\nexport type BitbucketOAuthResult = {\n fullProfile: BitbucketPassportProfile;\n params: {\n id_token?: string;\n scope: string;\n expires_in: number;\n };\n accessToken: string;\n refreshToken?: string;\n};\n\n/**\n * @public\n * @deprecated The Bitbucket auth provider was extracted to `@backstage/plugin-auth-backend-module-bitbucket-provider`.\n */\nexport type BitbucketPassportProfile = PassportProfile & {\n id?: string;\n displayName?: string;\n username?: string;\n avatarUrl?: string;\n _json?: {\n links?: {\n avatar?: {\n href?: string;\n };\n };\n };\n};\n\n/**\n * Auth provider integration for Bitbucket auth\n *\n * @public\n */\nexport const bitbucket = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: bitbucketAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: adaptOAuthSignInResolverToLegacy({\n userIdMatchingUserEntityAnnotation:\n bitbucketSignInResolvers.userIdMatchingUserEntityAnnotation(),\n usernameMatchingUserEntityAnnotation:\n bitbucketSignInResolvers.usernameMatchingUserEntityAnnotation(),\n }),\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CacheClient } from '@backstage/backend-common';\nimport {\n cloudflareAccessSignInResolvers,\n createCloudflareAccessAuthenticator,\n} from '@backstage/plugin-auth-backend-module-cloudflare-access-provider';\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * CloudflareAccessClaims\n *\n * Can be used in externally provided auth handler or sign in resolver to\n * enrich user profile for sign-in user entity\n *\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessClaims = {\n /**\n * `aud` identifies the application to which the JWT is issued.\n */\n aud: string[];\n /**\n * `email` contains the email address of the authenticated user.\n */\n email: string;\n /**\n * iat and exp are the issuance and expiration timestamps.\n */\n exp: number;\n iat: number;\n /**\n * `nonce` is the session identifier.\n */\n nonce: string;\n /**\n * `identity_nonce` is available in the Application Token and can be used to\n * query all group membership for a given user.\n */\n identity_nonce: string;\n /**\n * `sub` contains the identifier of the authenticated user.\n */\n sub: string;\n /**\n * `iss` the issuer is the application’s Cloudflare Access Domain URL.\n */\n iss: string;\n /**\n * `custom` contains SAML attributes in the Application Token specified by an\n * administrator in the identity provider configuration.\n */\n custom: string;\n};\n\n/**\n * CloudflareAccessGroup\n *\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessGroup = {\n /**\n * Group id\n */\n id: string;\n /**\n * Name of group as defined in Cloudflare zero trust dashboard\n */\n name: string;\n /**\n * Access group email address\n */\n email: string;\n};\n\n/**\n * CloudflareAccessIdentityProfile\n *\n * Can be used in externally provided auth handler or sign in resolver to\n * enrich user profile for sign-in user entity\n *\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessIdentityProfile = {\n id: string;\n name: string;\n email: string;\n groups: CloudflareAccessGroup[];\n};\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-auth-backend-module-cloudflare-access-provider` instead\n */\nexport type CloudflareAccessResult = {\n claims: CloudflareAccessClaims;\n cfIdentity: CloudflareAccessIdentityProfile;\n expiresInSeconds?: number;\n token: string;\n};\n\n/**\n * Auth provider integration for Cloudflare Access auth\n *\n * @public\n */\nexport const cfAccess = createAuthProviderIntegration({\n create(options: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n\n /**\n * CacheClient object that was configured for the Backstage backend,\n * should be provided via the backend auth plugin.\n */\n cache?: CacheClient;\n }) {\n return createProxyAuthProviderFactory({\n authenticator: createCloudflareAccessAuthenticator({\n cache: options.cache,\n }),\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n signInResolverFactories: cloudflareAccessSignInResolvers,\n });\n },\n resolvers: cloudflareAccessSignInResolvers,\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { gcpIapAuthenticator } from '@backstage/plugin-auth-backend-module-gcp-iap-provider';\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\nimport { GcpIapResult } from './types';\n\n/**\n * Auth provider integration for Google Identity-Aware Proxy auth\n *\n * @public\n */\nexport const gcpIap = createAuthProviderIntegration({\n create(options: {\n /**\n * The profile transformation function used to verify and convert the auth\n * response into the profile that will be presented to the user. The default\n * implementation just provides the authenticated email that the IAP\n * presented.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configures sign-in for this provider.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: gcpIapAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Profile as PassportProfile } from 'passport';\nimport { AuthHandler, StateEncoder } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n createOAuthProviderFactory,\n OAuthAuthenticatorResult,\n ProfileTransform,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\nimport { githubAuthenticator } from '@backstage/plugin-auth-backend-module-github-provider';\n\n/** @public */\nexport type GithubOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n scope: string;\n expires_in?: string;\n refresh_token_expires_in?: string;\n };\n accessToken: string;\n refreshToken?: string;\n};\n\n/**\n * Auth provider integration for GitHub auth\n *\n * @public\n */\nexport const github = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n\n /**\n * The state encoder used to encode the 'state' parameter on the OAuth request.\n *\n * It should return a string that takes the state params (from the request), url encodes the params\n * and finally base64 encodes them.\n *\n * Providing your own stateEncoder will allow you to add addition parameters to the state field.\n *\n * It is typed as follows:\n * `export type StateEncoder = (input: OAuthState) => Promise<{encodedState: string}>;`\n *\n * Note: the stateEncoder must encode a 'nonce' value and an 'env' value. Without this, the OAuth flow will fail\n * (These two values will be set by the req.state by default)\n *\n * For more information, please see the helper module in ../../oauth/helpers #readState\n */\n stateEncoder?: StateEncoder;\n }) {\n const authHandler = options?.authHandler;\n const signInResolver = options?.signIn?.resolver;\n return createOAuthProviderFactory({\n authenticator: githubAuthenticator,\n profileTransform:\n authHandler &&\n ((async (result, ctx) =>\n authHandler!(\n {\n fullProfile: result.fullProfile,\n accessToken: result.session.accessToken,\n params: {\n scope: result.session.scope,\n expires_in: result.session.expiresInSeconds\n ? String(result.session.expiresInSeconds)\n : '',\n refresh_token_expires_in: result.session\n .refreshTokenExpiresInSeconds\n ? String(result.session.refreshTokenExpiresInSeconds)\n : '',\n },\n },\n ctx,\n )) as ProfileTransform>),\n signInResolver:\n signInResolver &&\n ((async ({ profile, result }, ctx) =>\n signInResolver(\n {\n profile: profile,\n result: {\n fullProfile: result.fullProfile,\n accessToken: result.session.accessToken,\n refreshToken: result.session.refreshToken,\n params: {\n scope: result.session.scope,\n expires_in: result.session.expiresInSeconds\n ? String(result.session.expiresInSeconds)\n : '',\n refresh_token_expires_in: result.session\n .refreshTokenExpiresInSeconds\n ? String(result.session.refreshTokenExpiresInSeconds)\n : '',\n },\n },\n },\n ctx,\n )) as SignInResolver>),\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their GitHub username to the entity name.\n */\n usernameMatchingUserEntityName: (): SignInResolver => {\n return async (info, ctx) => {\n const { fullProfile } = info.result;\n\n const userId = fullProfile.username;\n if (!userId) {\n throw new Error(`GitHub user profile does not contain a username`);\n }\n\n return ctx.signInWithCatalogUser({ entityRef: { name: userId } });\n };\n },\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { gitlabAuthenticator } from '@backstage/plugin-auth-backend-module-gitlab-provider';\n\n/**\n * Auth provider integration for GitLab auth\n *\n * @public\n */\nexport const gitlab = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: gitlabAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n googleAuthenticator,\n googleSignInResolvers,\n} from '@backstage/plugin-auth-backend-module-google-provider';\nimport {\n SignInResolver,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n adaptOAuthSignInResolverToLegacy,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * Auth provider integration for Google auth\n *\n * @public\n */\nexport const google = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: googleAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: adaptOAuthSignInResolverToLegacy({\n emailLocalPartMatchingUserEntityName:\n commonSignInResolvers.emailLocalPartMatchingUserEntityName(),\n emailMatchingUserEntityProfileEmail:\n commonSignInResolvers.emailMatchingUserEntityProfileEmail(),\n emailMatchingUserEntityAnnotation:\n googleSignInResolvers.emailMatchingUserEntityAnnotation(),\n }),\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n SignInResolver,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n adaptOAuthSignInResolverToLegacy,\n} from '../../lib/legacy';\nimport {\n microsoftAuthenticator,\n microsoftSignInResolvers,\n} from '@backstage/plugin-auth-backend-module-microsoft-provider';\n\n/**\n * Auth provider integration for Microsoft auth\n *\n * @public\n */\nexport const microsoft = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: microsoftAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: adaptOAuthSignInResolverToLegacy({\n emailLocalPartMatchingUserEntityName:\n commonSignInResolvers.emailLocalPartMatchingUserEntityName(),\n emailMatchingUserEntityProfileEmail:\n commonSignInResolvers.emailMatchingUserEntityProfileEmail(),\n emailMatchingUserEntityAnnotation:\n microsoftSignInResolvers.emailMatchingUserEntityAnnotation(),\n userIdMatchingUserEntityAnnotation:\n microsoftSignInResolvers.userIdMatchingUserEntityAnnotation(),\n }),\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OAuthResult } from '../../lib/oauth';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { oauth2Authenticator } from '@backstage/plugin-auth-backend-module-oauth2-provider';\n\n/**\n * Auth provider integration for generic OAuth2 auth\n *\n * @public\n */\nexport const oauth2 = createAuthProviderIntegration({\n create(options?: {\n authHandler?: AuthHandler;\n\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: oauth2Authenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n type OAuth2ProxyResult,\n oauth2ProxyAuthenticator,\n} from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider';\n\n/**\n * Auth provider integration for oauth2-proxy auth\n *\n * @public\n */\nexport const oauth2Proxy = createAuthProviderIntegration({\n create(options: {\n /**\n * Configure an auth handler to generate a profile for the user.\n *\n * The default implementation uses the value of the `X-Forwarded-Preferred-Username`\n * header as the display name, falling back to `X-Forwarded-User`, and the value of\n * the `X-Forwarded-Email` header as the email address.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: oauth2ProxyAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SignInResolver } from '@backstage/plugin-auth-node';\n\n/**\n * A common sign-in resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\nexport const commonByEmailLocalPartResolver: SignInResolver = async (\n info,\n ctx,\n) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Login failed, user profile does not contain an email');\n }\n const [localPart] = profile.email.split('@');\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: localPart },\n });\n};\n\n/**\n * A common sign-in resolver that looks up the user using their email address\n * as email of the entity.\n */\nexport const commonByEmailResolver: SignInResolver = async (\n info,\n ctx,\n) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Login failed, user profile does not contain an email');\n }\n\n return ctx.signInWithCatalogUser({\n filter: {\n 'spec.profile.email': profile.email,\n },\n });\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n createOAuthProviderFactory,\n AuthResolverContext,\n BackstageSignInResult,\n OAuthAuthenticatorResult,\n SignInInfo,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\nimport {\n oidcAuthenticator,\n OidcAuthResult,\n} from '@backstage/plugin-auth-backend-module-oidc-provider';\nimport {\n commonByEmailLocalPartResolver,\n commonByEmailResolver,\n} from '../resolvers';\n\n/**\n * Auth provider integration for generic OpenID Connect auth\n *\n * @public\n */\nexport const oidc = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider; convert user profile respones into\n * Backstage identities.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n const authHandler = options?.authHandler;\n const signInResolver = options?.signIn?.resolver;\n return createOAuthProviderFactory({\n authenticator: oidcAuthenticator,\n profileTransform:\n authHandler &&\n ((\n result: OAuthAuthenticatorResult,\n context: AuthResolverContext,\n ) => authHandler(result.fullProfile, context)),\n signInResolver:\n signInResolver &&\n ((\n info: SignInInfo>,\n context: AuthResolverContext,\n ): Promise =>\n signInResolver(\n {\n result: info.result.fullProfile,\n profile: info.profile,\n },\n context,\n )),\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their email local part to the entity name.\n */\n emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,\n /**\n * Looks up the user by matching their email to the entity email.\n */\n emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthHandler } from '../types';\nimport { OAuthResult } from '../../lib/oauth';\n\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { oktaAuthenticator } from '@backstage/plugin-auth-backend-module-okta-provider';\nimport {\n commonByEmailLocalPartResolver,\n commonByEmailResolver,\n} from '../resolvers';\n\n/**\n * Auth provider integration for Okta auth\n *\n * @public\n */\nexport const okta = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: oktaAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their email local part to the entity name.\n */\n emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,\n /**\n * Looks up the user by matching their email to the entity email.\n */\n emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,\n /**\n * Looks up the user by matching their email to the `okta.com/email` annotation.\n */\n emailMatchingUserEntityAnnotation(): SignInResolver {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Okta profile contained no email');\n }\n\n return ctx.signInWithCatalogUser({\n annotations: {\n 'okta.com/email': profile.email,\n },\n });\n };\n },\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { oneLoginAuthenticator } from '@backstage/plugin-auth-backend-module-onelogin-provider';\nimport {\n SignInResolver,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport {\n adaptLegacyOAuthHandler,\n adaptLegacyOAuthSignInResolver,\n} from '../../lib/legacy';\nimport { OAuthResult } from '../../lib/oauth';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthHandler } from '../types';\n\n/**\n * Auth provider integration for OneLogin auth\n *\n * @public\n */\nexport const onelogin = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createOAuthProviderFactory({\n authenticator: oneLoginAuthenticator,\n profileTransform: adaptLegacyOAuthHandler(options?.authHandler),\n signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver),\n });\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport { SamlConfig, VerifiedCallback } from '@node-saml/passport-saml';\nimport {\n Strategy as SamlStrategy,\n Profile as SamlProfile,\n VerifyWithoutRequest,\n} from '@node-saml/passport-saml';\nimport {\n executeFrameHandlerStrategy,\n executeRedirectStrategy,\n} from '../../lib/passport';\nimport { AuthHandler } from '../types';\nimport { postMessageResponse } from '../../lib/flow';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { AuthenticationError, isError } from '@backstage/errors';\nimport { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\n/** @public */\nexport type SamlAuthResult = {\n fullProfile: any;\n};\n\ntype Options = SamlConfig & {\n signInResolver?: SignInResolver;\n authHandler: AuthHandler;\n resolverContext: AuthResolverContext;\n appUrl: string;\n};\n\nexport class SamlAuthProvider implements AuthProviderRouteHandlers {\n private readonly strategy: SamlStrategy;\n private readonly signInResolver?: SignInResolver;\n private readonly authHandler: AuthHandler;\n private readonly resolverContext: AuthResolverContext;\n private readonly appUrl: string;\n\n constructor(options: Options) {\n this.appUrl = options.appUrl;\n this.signInResolver = options.signInResolver;\n this.authHandler = options.authHandler;\n this.resolverContext = options.resolverContext;\n\n const verifier: VerifyWithoutRequest = (\n profile: SamlProfile | null,\n done: VerifiedCallback,\n ) => {\n // TODO: There's plenty more validation and profile handling to do here,\n // this provider is currently only intended to validate the provider pattern\n // for non-oauth auth flows.\n // TODO: This flow doesn't issue an identity token that can be used to validate\n // the identity of the user in other backends, which we need in some form.\n done(null, { fullProfile: profile });\n };\n this.strategy = new SamlStrategy(options, verifier, verifier);\n }\n\n async start(req: express.Request, res: express.Response): Promise {\n const { url } = await executeRedirectStrategy(req, this.strategy, {});\n res.redirect(url);\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise {\n try {\n const { result } = await executeFrameHandlerStrategy(\n req,\n this.strategy,\n );\n\n const { profile } = await this.authHandler(result, this.resolverContext);\n\n const response: ClientAuthResponse<{}> = {\n profile,\n providerInfo: {},\n };\n\n if (this.signInResolver) {\n const signInResponse = await this.signInResolver(\n {\n result,\n profile,\n },\n this.resolverContext,\n );\n\n response.backstageIdentity =\n prepareBackstageIdentityResponse(signInResponse);\n }\n\n return postMessageResponse(res, this.appUrl, {\n type: 'authorization_response',\n response,\n });\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n return postMessageResponse(res, this.appUrl, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n }\n\n async logout(_req: express.Request, res: express.Response): Promise {\n res.end();\n }\n}\n\ntype SignatureAlgorithm = 'sha1' | 'sha256' | 'sha512';\n\n/**\n * Auth provider integration for SAML auth\n *\n * @public\n */\nexport const saml = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return ({ providerId, globalConfig, config, resolverContext }) => {\n const authHandler: AuthHandler = options?.authHandler\n ? options.authHandler\n : async ({ fullProfile }) => ({\n profile: {\n email: fullProfile.email,\n displayName: fullProfile.displayName,\n },\n });\n\n return new SamlAuthProvider({\n callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,\n entryPoint: config.getString('entryPoint'),\n logoutUrl: config.getOptionalString('logoutUrl'),\n audience: config.getString('audience'),\n issuer: config.getString('issuer'),\n cert: config.getString('cert'),\n privateKey: config.getOptionalString('privateKey'),\n authnContext: config.getOptionalStringArray('authnContext'),\n identifierFormat: config.getOptionalString('identifierFormat'),\n decryptionPvk: config.getOptionalString('decryptionPvk'),\n signatureAlgorithm: config.getOptionalString('signatureAlgorithm') as\n | SignatureAlgorithm\n | undefined,\n digestAlgorithm: config.getOptionalString('digestAlgorithm'),\n acceptedClockSkewMs: config.getOptionalNumber('acceptedClockSkewMs'),\n wantAuthnResponseSigned: config.getOptionalBoolean(\n 'wantAuthnResponseSigned',\n ),\n wantAssertionsSigned: config.getOptionalBoolean('wantAssertionsSigned'),\n appUrl: globalConfig.appUrl,\n authHandler,\n signInResolver: options?.signIn?.resolver,\n resolverContext,\n });\n };\n },\n resolvers: {\n /**\n * Looks up the user by matching their nameID to the entity name.\n */\n nameIdMatchingUserEntityName(): SignInResolver {\n return async (info, ctx) => {\n const id = info.result.fullProfile.nameID;\n\n if (!id) {\n throw new AuthenticationError('No nameID found in SAML response');\n }\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: id },\n });\n };\n },\n },\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n encodeState,\n OAuthAdapter,\n OAuthEnvironmentHandler,\n OAuthHandlers,\n OAuthProviderOptions,\n OAuthRefreshRequest,\n OAuthResponse,\n OAuthStartRequest,\n} from '../../lib/oauth';\nimport { Strategy as OAuth2Strategy, VerifyCallback } from 'passport-oauth2';\nimport {\n executeFetchUserProfileStrategy,\n executeFrameHandlerStrategy,\n executeRedirectStrategy,\n executeRefreshTokenStrategy,\n makeProfileInfo,\n} from '../../lib/passport';\nimport { AuthHandler, OAuthStartResponse } from '../types';\nimport express from 'express';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport { Profile as PassportProfile } from 'passport';\nimport { commonByEmailResolver } from '../resolvers';\nimport fetch from 'node-fetch';\nimport {\n AuthResolverContext,\n SignInResolver,\n} from '@backstage/plugin-auth-node';\n\ntype PrivateInfo = {\n refreshToken: string;\n};\n\n/** @public */\nexport type BitbucketServerOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n scope: string;\n access_token?: string;\n token_type?: string;\n expires_in?: number;\n };\n accessToken: string;\n refreshToken?: string;\n};\n\nexport type BitbucketServerAuthProviderOptions = OAuthProviderOptions & {\n host: string;\n authorizationUrl: string;\n tokenUrl: string;\n authHandler: AuthHandler;\n signInResolver?: SignInResolver;\n resolverContext: AuthResolverContext;\n};\n\nexport class BitbucketServerAuthProvider implements OAuthHandlers {\n private readonly signInResolver?: SignInResolver;\n private readonly authHandler: AuthHandler;\n private readonly resolverContext: AuthResolverContext;\n private readonly strategy: OAuth2Strategy;\n private readonly host: string;\n\n constructor(options: BitbucketServerAuthProviderOptions) {\n this.signInResolver = options.signInResolver;\n this.authHandler = options.authHandler;\n this.resolverContext = options.resolverContext;\n this.strategy = new OAuth2Strategy(\n {\n authorizationURL: options.authorizationUrl,\n tokenURL: options.tokenUrl,\n clientID: options.clientId,\n clientSecret: options.clientSecret,\n callbackURL: options.callbackUrl,\n },\n (\n accessToken: string,\n refreshToken: string,\n params: any,\n fullProfile: PassportProfile,\n done: VerifyCallback,\n ) => {\n done(undefined, { fullProfile, params, accessToken }, { refreshToken });\n },\n );\n this.host = options.host;\n }\n\n async start(req: OAuthStartRequest): Promise {\n return await executeRedirectStrategy(req, this.strategy, {\n accessType: 'offline',\n prompt: 'consent',\n scope: req.scope,\n state: encodeState(req.state),\n });\n }\n\n async handler(\n req: express.Request,\n ): Promise<{ response: OAuthResponse; refreshToken?: string }> {\n const { result, privateInfo } = await executeFrameHandlerStrategy<\n BitbucketServerOAuthResult,\n PrivateInfo\n >(req, this.strategy);\n\n return {\n response: await this.handleResult(result),\n refreshToken: privateInfo.refreshToken,\n };\n }\n\n async refresh(\n req: OAuthRefreshRequest,\n ): Promise<{ response: OAuthResponse; refreshToken?: string }> {\n const { accessToken, refreshToken, params } =\n await executeRefreshTokenStrategy(\n this.strategy,\n req.refreshToken,\n req.scope,\n );\n const fullProfile = await executeFetchUserProfileStrategy(\n this.strategy,\n accessToken,\n );\n return {\n response: await this.handleResult({\n fullProfile,\n params,\n accessToken,\n }),\n refreshToken,\n };\n }\n\n private async handleResult(\n result: BitbucketServerOAuthResult,\n ): Promise {\n // The OAuth2 strategy does not return a user profile -> let's fetch it before calling the auth handler\n result.fullProfile = await this.fetchProfile(result);\n const { profile } = await this.authHandler(result, this.resolverContext);\n\n let backstageIdentity = undefined;\n if (this.signInResolver) {\n backstageIdentity = await this.signInResolver(\n { result, profile },\n this.resolverContext,\n );\n }\n\n return {\n providerInfo: {\n accessToken: result.accessToken,\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n },\n profile,\n backstageIdentity,\n };\n }\n\n private async fetchProfile(\n result: BitbucketServerOAuthResult,\n ): Promise {\n // Get current user name\n let whoAmIResponse;\n try {\n whoAmIResponse = await fetch(\n `https://${this.host}/plugins/servlet/applinks/whoami`,\n {\n headers: {\n Authorization: `Bearer ${result.accessToken}`,\n },\n },\n );\n } catch (e) {\n throw new Error(`Failed to retrieve the username of the logged in user`);\n }\n\n // A response.ok check here would be worthless as the Bitbucket API always returns 200 OK for this call\n const username = whoAmIResponse.headers.get('X-Ausername');\n if (!username) {\n throw new Error(`Failed to retrieve the username of the logged in user`);\n }\n\n let userResponse;\n try {\n userResponse = await fetch(\n `https://${this.host}/rest/api/latest/users/${username}?avatarSize=256`,\n {\n headers: {\n Authorization: `Bearer ${result.accessToken}`,\n },\n },\n );\n } catch (e) {\n throw new Error(`Failed to retrieve the user '${username}'`);\n }\n\n if (!userResponse.ok) {\n throw new Error(`Failed to retrieve the user '${username}'`);\n }\n\n const user = await userResponse.json();\n\n const passportProfile = {\n provider: 'bitbucketServer',\n id: user.id.toString(),\n displayName: user.displayName,\n username: user.name,\n emails: [\n {\n value: user.emailAddress,\n },\n ],\n } as PassportProfile;\n\n if (user.avatarUrl) {\n passportProfile.photos = [\n { value: `https://${this.host}${user.avatarUrl}` },\n ];\n }\n\n return passportProfile;\n }\n}\n\nexport const bitbucketServer = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn?: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return ({ providerId, globalConfig, config, resolverContext }) =>\n OAuthEnvironmentHandler.mapConfig(config, envConfig => {\n const clientId = envConfig.getString('clientId');\n const clientSecret = envConfig.getString('clientSecret');\n const host = envConfig.getString('host');\n const customCallbackUrl = envConfig.getOptionalString('callbackUrl');\n const callbackUrl =\n customCallbackUrl ||\n `${globalConfig.baseUrl}/${providerId}/handler/frame`;\n const authorizationUrl = `https://${host}/rest/oauth2/latest/authorize`;\n const tokenUrl = `https://${host}/rest/oauth2/latest/token`;\n\n const authHandler: AuthHandler =\n options?.authHandler\n ? options.authHandler\n : async ({ fullProfile }) => ({\n profile: makeProfileInfo(fullProfile),\n });\n\n const provider = new BitbucketServerAuthProvider({\n callbackUrl,\n clientId,\n clientSecret,\n host,\n authorizationUrl,\n tokenUrl,\n authHandler,\n signInResolver: options?.signIn?.resolver,\n resolverContext,\n });\n\n return OAuthAdapter.fromConfig(globalConfig, provider, {\n providerId,\n callbackUrl,\n });\n });\n },\n resolvers: {\n /**\n * Looks up the user by matching their email to the entity email.\n */\n emailMatchingUserEntityProfileEmail:\n (): SignInResolver => commonByEmailResolver,\n },\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SignInResolver,\n createProxyAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { AuthHandler } from '../types';\nimport { createAuthProviderIntegration } from '../createAuthProviderIntegration';\nimport {\n AzureEasyAuthResult,\n azureEasyAuthAuthenticator,\n} from '@backstage/plugin-auth-backend-module-azure-easyauth-provider';\n\nexport type EasyAuthResult = AzureEasyAuthResult;\n\n/**\n * Auth provider integration for Azure EasyAuth\n *\n * @public\n */\nexport const easyAuth = createAuthProviderIntegration({\n create(options?: {\n /**\n * The profile transformation function used to verify and convert the auth response\n * into the profile that will be presented to the user.\n */\n authHandler?: AuthHandler;\n\n /**\n * Configure sign-in for this provider, without it the provider can not be used to sign users in.\n */\n signIn: {\n /**\n * Maps an auth result to a Backstage identity for the user.\n */\n resolver: SignInResolver;\n };\n }) {\n return createProxyAuthProviderFactory({\n authenticator: azureEasyAuthAuthenticator,\n profileTransform: options?.authHandler,\n signInResolver: options?.signIn?.resolver,\n });\n },\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { atlassian } from './atlassian';\nimport { auth0 } from './auth0';\nimport { awsAlb } from './aws-alb';\nimport { bitbucket } from './bitbucket';\nimport { cfAccess } from './cloudflare-access';\nimport { gcpIap } from './gcp-iap';\nimport { github } from './github';\nimport { gitlab } from './gitlab';\nimport { google } from './google';\nimport { microsoft } from './microsoft';\nimport { oauth2 } from './oauth2';\nimport { oauth2Proxy } from './oauth2-proxy';\nimport { oidc } from './oidc';\nimport { okta } from './okta';\nimport { onelogin } from './onelogin';\nimport { saml } from './saml';\nimport { bitbucketServer } from './bitbucketServer';\nimport { easyAuth } from './azure-easyauth';\nimport { AuthProviderFactory } from '@backstage/plugin-auth-node';\n\n/**\n * All built-in auth provider integrations.\n *\n * @public\n */\nexport const providers = Object.freeze({\n atlassian,\n auth0,\n awsAlb,\n bitbucket,\n bitbucketServer,\n cfAccess,\n gcpIap,\n github,\n gitlab,\n google,\n microsoft,\n oauth2,\n oauth2Proxy,\n oidc,\n okta,\n onelogin,\n saml,\n easyAuth,\n});\n\n/**\n * All auth provider factories that are installed by default.\n *\n * @public\n */\nexport const defaultAuthProviderFactories: {\n [providerId: string]: AuthProviderFactory;\n} = {\n google: google.create(),\n github: github.create(),\n gitlab: gitlab.create(),\n saml: saml.create(),\n okta: okta.create(),\n auth0: auth0.create(),\n microsoft: microsoft.create(),\n easyAuth: easyAuth.create(),\n oauth2: oauth2.create(),\n oidc: oidc.create(),\n onelogin: onelogin.create(),\n awsalb: awsAlb.create(),\n bitbucket: bitbucket.create(),\n bitbucketServer: bitbucketServer.create(),\n atlassian: atlassian.create(),\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n RELATION_MEMBER_OF,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport {\n TokenManager,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\n\n/**\n * A catalog client tailored for reading out identity data from the catalog.\n *\n * @public\n */\nexport class CatalogIdentityClient {\n private readonly catalogApi: CatalogApi;\n private readonly auth: AuthService;\n\n constructor(options: {\n catalogApi: CatalogApi;\n tokenManager: TokenManager;\n discovery: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n }) {\n this.catalogApi = options.catalogApi;\n\n const { auth } = createLegacyAuthAdapters({\n auth: options.auth,\n httpAuth: options.httpAuth,\n discovery: options.discovery,\n tokenManager: options.tokenManager,\n });\n\n this.auth = auth;\n }\n\n /**\n * Looks up a single user using a query.\n *\n * Throws a NotFoundError or ConflictError if 0 or multiple users are found.\n */\n async findUser(query: {\n annotations: Record;\n }): Promise {\n const filter: Record = {\n kind: 'user',\n };\n for (const [key, value] of Object.entries(query.annotations)) {\n filter[`metadata.annotations.${key}`] = value;\n }\n\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const { items } = await this.catalogApi.getEntities({ filter }, { token });\n\n if (items.length !== 1) {\n if (items.length > 1) {\n throw new ConflictError('User lookup resulted in multiple matches');\n } else {\n throw new NotFoundError('User not found');\n }\n }\n\n return items[0] as UserEntity;\n }\n\n /**\n * Resolve additional entity claims from the catalog, using the passed-in entity names. Designed\n * to be used within a `signInResolver` where additional entity claims might be provided, but\n * group membership and transient group membership lean on imported catalog relations.\n *\n * Returns a superset of the entity names that can be passed directly to `issueToken` as `ent`.\n */\n async resolveCatalogMembership(query: {\n entityRefs: string[];\n logger?: LoggerService;\n }): Promise {\n const { entityRefs, logger } = query;\n const resolvedEntityRefs = entityRefs\n .map((ref: string) => {\n try {\n const parsedRef = parseEntityRef(ref.toLocaleLowerCase('en-US'), {\n defaultKind: 'user',\n defaultNamespace: 'default',\n });\n return parsedRef;\n } catch {\n logger?.warn(`Failed to parse entityRef from ${ref}, ignoring`);\n return null;\n }\n })\n .filter((ref): ref is CompoundEntityRef => ref !== null);\n\n const filter = resolvedEntityRefs.map(ref => ({\n kind: ref.kind,\n 'metadata.namespace': ref.namespace,\n 'metadata.name': ref.name,\n }));\n\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const entities = await this.catalogApi\n .getEntities({ filter }, { token })\n .then(r => r.items);\n\n if (entityRefs.length !== entities.length) {\n const foundEntityNames = entities.map(stringifyEntityRef);\n const missingEntityNames = resolvedEntityRefs\n .map(stringifyEntityRef)\n .filter(s => !foundEntityNames.includes(s));\n logger?.debug(`Entities not found for refs ${missingEntityNames.join()}`);\n }\n\n const memberOf = entities.flatMap(\n e =>\n e!.relations\n ?.filter(r => r.type === RELATION_MEMBER_OF)\n .map(r => r.targetRef) ?? [],\n );\n\n const newEntityRefs = [\n ...new Set(resolvedEntityRefs.map(stringifyEntityRef).concat(memberOf)),\n ];\n\n logger?.debug(`Found catalog membership: ${newEntityRefs.join()}`);\n return newEntityRefs;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TokenManager } from '@backstage/backend-common';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n DEFAULT_NAMESPACE,\n Entity,\n parseEntityRef,\n RELATION_MEMBER_OF,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { ConflictError, InputError, NotFoundError } from '@backstage/errors';\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { TokenIssuer } from '../../identity/types';\nimport {\n AuthOwnershipResolver,\n AuthResolverCatalogUserQuery,\n AuthResolverContext,\n TokenParams,\n} from '@backstage/plugin-auth-node';\nimport { CatalogIdentityClient } from '../catalog';\n\n/**\n * Uses the default ownership resolution logic to return an array\n * of entity refs that the provided entity claims ownership through.\n *\n * A reference to the entity itself will also be included in the returned array.\n *\n * @public\n */\nexport function getDefaultOwnershipEntityRefs(entity: Entity) {\n const membershipRefs =\n entity.relations\n ?.filter(\n r => r.type === RELATION_MEMBER_OF && r.targetRef.startsWith('group:'),\n )\n .map(r => r.targetRef) ?? [];\n\n return Array.from(new Set([stringifyEntityRef(entity), ...membershipRefs]));\n}\n\n/**\n * @internal\n */\nexport class CatalogAuthResolverContext implements AuthResolverContext {\n static create(options: {\n logger: LoggerService;\n catalogApi: CatalogApi;\n tokenIssuer: TokenIssuer;\n tokenManager: TokenManager;\n discovery: DiscoveryService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n ownershipResolver?: AuthOwnershipResolver;\n }): CatalogAuthResolverContext {\n const catalogIdentityClient = new CatalogIdentityClient({\n catalogApi: options.catalogApi,\n tokenManager: options.tokenManager,\n discovery: options.discovery,\n auth: options.auth,\n httpAuth: options.httpAuth,\n });\n\n return new CatalogAuthResolverContext(\n options.logger,\n options.tokenIssuer,\n catalogIdentityClient,\n options.catalogApi,\n options.auth,\n options.ownershipResolver,\n );\n }\n\n private constructor(\n public readonly logger: LoggerService,\n public readonly tokenIssuer: TokenIssuer,\n public readonly catalogIdentityClient: CatalogIdentityClient,\n private readonly catalogApi: CatalogApi,\n private readonly auth: AuthService,\n private readonly ownershipResolver?: AuthOwnershipResolver,\n ) {}\n\n async issueToken(params: TokenParams) {\n const token = await this.tokenIssuer.issueToken(params);\n return { token };\n }\n\n async findCatalogUser(query: AuthResolverCatalogUserQuery) {\n let result: Entity[] | Entity | undefined = undefined;\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n if ('entityRef' in query) {\n const entityRef = parseEntityRef(query.entityRef, {\n defaultKind: 'User',\n defaultNamespace: DEFAULT_NAMESPACE,\n });\n result = await this.catalogApi.getEntityByRef(entityRef, { token });\n } else if ('annotations' in query) {\n const filter: Record = {\n kind: 'user',\n };\n for (const [key, value] of Object.entries(query.annotations)) {\n filter[`metadata.annotations.${key}`] = value;\n }\n const res = await this.catalogApi.getEntities({ filter }, { token });\n result = res.items;\n } else if ('filter' in query) {\n const filter = [query.filter].flat().map(value => {\n if (\n !Object.keys(value).some(\n key => key.toLocaleLowerCase('en-US') === 'kind',\n )\n ) {\n return {\n ...value,\n kind: 'user',\n };\n }\n return value;\n });\n const res = await this.catalogApi.getEntities(\n { filter: filter },\n { token },\n );\n result = res.items;\n } else {\n throw new InputError('Invalid user lookup query');\n }\n\n if (Array.isArray(result)) {\n if (result.length > 1) {\n throw new ConflictError('User lookup resulted in multiple matches');\n }\n result = result[0];\n }\n if (!result) {\n throw new NotFoundError('User not found');\n }\n\n return { entity: result };\n }\n\n async signInWithCatalogUser(query: AuthResolverCatalogUserQuery) {\n const { entity } = await this.findCatalogUser(query);\n let ent: string[];\n if (this.ownershipResolver) {\n const { ownershipEntityRefs } =\n await this.ownershipResolver.resolveOwnershipEntityRefs(entity);\n ent = ownershipEntityRefs;\n } else {\n ent = getDefaultOwnershipEntityRefs(entity);\n }\n\n const token = await this.tokenIssuer.issueToken({\n claims: {\n sub: stringifyEntityRef(entity),\n ent,\n },\n });\n return { token };\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { CatalogApi, CatalogClient } from '@backstage/catalog-client';\nimport { Config } from '@backstage/config';\nimport { assertError, NotFoundError } from '@backstage/errors';\nimport {\n AuthOwnershipResolver,\n AuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Minimatch } from 'minimatch';\nimport { CatalogAuthResolverContext } from '../lib/resolvers/CatalogAuthResolverContext';\nimport { TokenIssuer } from '../identity/types';\n\n/** @public */\nexport type ProviderFactories = { [s: string]: AuthProviderFactory };\n\nexport function bindProviderRouters(\n targetRouter: express.Router,\n options: {\n providers: ProviderFactories;\n appUrl: string;\n baseUrl: string;\n config: Config;\n logger: LoggerService;\n discovery: PluginEndpointDiscovery;\n auth: AuthService;\n httpAuth: HttpAuthService;\n tokenManager: TokenManager;\n tokenIssuer: TokenIssuer;\n ownershipResolver?: AuthOwnershipResolver;\n catalogApi?: CatalogApi;\n },\n) {\n const {\n providers,\n appUrl,\n baseUrl,\n config,\n logger,\n discovery,\n auth,\n httpAuth,\n tokenManager,\n tokenIssuer,\n catalogApi,\n ownershipResolver,\n } = options;\n\n const providersConfig = config.getOptionalConfig('auth.providers');\n\n const isOriginAllowed = createOriginFilter(config);\n\n for (const [providerId, providerFactory] of Object.entries(providers)) {\n if (providersConfig?.has(providerId)) {\n logger.info(`Configuring auth provider: ${providerId}`);\n try {\n const provider = providerFactory({\n providerId,\n appUrl,\n baseUrl,\n isOriginAllowed,\n globalConfig: {\n baseUrl,\n appUrl,\n isOriginAllowed,\n },\n config: providersConfig.getConfig(providerId),\n logger,\n resolverContext: CatalogAuthResolverContext.create({\n logger,\n catalogApi:\n catalogApi ?? new CatalogClient({ discoveryApi: discovery }),\n tokenIssuer,\n tokenManager,\n discovery,\n auth,\n httpAuth,\n ownershipResolver,\n }),\n });\n\n const r = Router();\n\n r.get('/start', provider.start.bind(provider));\n r.get('/handler/frame', provider.frameHandler.bind(provider));\n r.post('/handler/frame', provider.frameHandler.bind(provider));\n if (provider.logout) {\n r.post('/logout', provider.logout.bind(provider));\n }\n if (provider.refresh) {\n r.get('/refresh', provider.refresh.bind(provider));\n r.post('/refresh', provider.refresh.bind(provider));\n }\n\n targetRouter.use(`/${providerId}`, r);\n } catch (e) {\n assertError(e);\n if (process.env.NODE_ENV !== 'development') {\n throw new Error(\n `Failed to initialize ${providerId} auth provider, ${e.message}`,\n );\n }\n\n logger.warn(`Skipping ${providerId} auth provider, ${e.message}`);\n\n targetRouter.use(`/${providerId}`, () => {\n // If the user added the provider under auth.providers but the clientId and clientSecret etc. were not found.\n throw new NotFoundError(\n `Auth provider registered for '${providerId}' is misconfigured. This could mean the configs under ` +\n `auth.providers.${providerId} are missing or the environment variables used are not defined. ` +\n `Check the auth backend plugin logs when the backend starts to see more details.`,\n );\n });\n }\n } else {\n targetRouter.use(`/${providerId}`, () => {\n throw new NotFoundError(\n `No auth provider registered for '${providerId}'`,\n );\n });\n }\n }\n}\n\n/** @public */\nexport function createOriginFilter(\n config: Config,\n): (origin: string) => boolean {\n const appUrl = config.getString('app.baseUrl');\n const { origin: appOrigin } = new URL(appUrl);\n\n const allowedOrigins = config.getOptionalStringArray(\n 'auth.experimentalExtraAllowedOrigins',\n );\n\n const allowedOriginPatterns =\n allowedOrigins?.map(\n pattern => new Minimatch(pattern, { nocase: true, noglobstar: true }),\n ) ?? [];\n\n return origin => {\n if (origin === appOrigin) {\n return true;\n }\n return allowedOriginPatterns.some(pattern => pattern.match(origin));\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { TokenIssuer } from './types';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { decodeJwt } from 'jose';\nimport { AuthenticationError, InputError } from '@backstage/errors';\nimport { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler';\n\nexport function bindOidcRouter(\n targetRouter: express.Router,\n options: {\n baseUrl: string;\n auth: AuthService;\n tokenIssuer: TokenIssuer;\n userInfoDatabaseHandler: UserInfoDatabaseHandler;\n },\n) {\n const { baseUrl, auth, tokenIssuer, userInfoDatabaseHandler } = options;\n\n const router = Router();\n targetRouter.use(router);\n\n const config = {\n issuer: baseUrl,\n token_endpoint: `${baseUrl}/v1/token`,\n userinfo_endpoint: `${baseUrl}/v1/userinfo`,\n jwks_uri: `${baseUrl}/.well-known/jwks.json`,\n response_types_supported: ['id_token'],\n subject_types_supported: ['public'],\n id_token_signing_alg_values_supported: [\n 'RS256',\n 'RS384',\n 'RS512',\n 'ES256',\n 'ES384',\n 'ES512',\n 'PS256',\n 'PS384',\n 'PS512',\n 'EdDSA',\n ],\n scopes_supported: ['openid'],\n token_endpoint_auth_methods_supported: [],\n claims_supported: ['sub', 'ent'],\n grant_types_supported: [],\n };\n\n router.get('/.well-known/openid-configuration', (_req, res) => {\n res.json(config);\n });\n\n router.get('/.well-known/jwks.json', async (_req, res) => {\n const { keys } = await tokenIssuer.listPublicKeys();\n res.json({ keys });\n });\n\n router.get('/v1/token', (_req, res) => {\n res.status(501).send('Not Implemented');\n });\n\n // This endpoint doesn't use the regular HttpAuthService, since the contract\n // is specifically for the header to be communicated in the Authorization\n // header, regardless of token type\n router.get('/v1/userinfo', async (req, res) => {\n const matches = req.headers.authorization?.match(/^Bearer[ ]+(\\S+)$/i);\n const token = matches?.[1];\n if (!token) {\n throw new AuthenticationError('No token provided');\n }\n\n const credentials = await auth.authenticate(token, {\n allowLimitedAccess: true,\n });\n if (!auth.isPrincipal(credentials, 'user')) {\n throw new InputError(\n 'Userinfo endpoint must be called with a token that represents a user principal',\n );\n }\n\n const { sub: userEntityRef } = decodeJwt(token);\n\n if (typeof userEntityRef !== 'string') {\n throw new Error('Invalid user token, user entity ref must be a string');\n }\n\n const userInfo = await userInfoDatabaseHandler.getUserInfo(userEntityRef);\n if (!userInfo) {\n res.status(404).send('User info not found');\n return;\n }\n\n res.json(userInfo);\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n exportJWK,\n generateKeyPair,\n importJWK,\n JWK,\n SignJWT,\n GeneralSign,\n KeyLike,\n} from 'jose';\nimport { omit } from 'lodash';\nimport { DateTime } from 'luxon';\nimport { v4 as uuid } from 'uuid';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { TokenParams, tokenTypes } from '@backstage/plugin-auth-node';\nimport { AnyJWK, KeyStore, TokenIssuer } from './types';\nimport { JsonValue } from '@backstage/types';\nimport { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler';\n\nconst MS_IN_S = 1000;\nconst MAX_TOKEN_LENGTH = 32768; // At 64 bytes per entity ref this still leaves room for about 500 entities\n\n/**\n * The payload contents of a valid Backstage JWT token\n */\nexport interface BackstageTokenPayload {\n /**\n * The issuer of the token, currently the discovery URL of the auth backend\n */\n iss: string;\n\n /**\n * The entity ref of the user\n */\n sub: string;\n\n /**\n * The entity refs that the user claims ownership througg\n */\n ent: string[];\n\n /**\n * A hard coded audience string\n */\n aud: typeof tokenTypes.user.audClaim;\n\n /**\n * Standard expiry in epoch seconds\n */\n exp: number;\n\n /**\n * Standard issue time in epoch seconds\n */\n iat: number;\n\n /**\n * A separate user identity proof that the auth service can convert to a limited user token\n */\n uip: string;\n\n /**\n * Any other custom claims that the adopter may have added\n */\n [claim: string]: JsonValue;\n}\n\n/**\n * The payload contents of a valid Backstage user identity claim token\n *\n * @internal\n */\ninterface BackstageUserIdentityProofPayload {\n /**\n * The entity ref of the user\n */\n sub: string;\n\n /**\n * Standard expiry in epoch seconds\n */\n exp: number;\n\n /**\n * Standard issue time in epoch seconds\n */\n iat: number;\n}\n\ntype Options = {\n logger: LoggerService;\n /** Value of the issuer claim in issued tokens */\n issuer: string;\n /** Key store used for storing signing keys */\n keyStore: KeyStore;\n /** Expiration time of signing keys in seconds */\n keyDurationSeconds: number;\n /** JWS \"alg\" (Algorithm) Header Parameter value. Defaults to ES256.\n * Must match one of the algorithms defined for IdentityClient.\n * When setting a different algorithm, check if the `key` field\n * of the `signing_keys` table can fit the length of the generated keys.\n * If not, add a knex migration file in the migrations folder.\n * More info on supported algorithms: https://github.com/panva/jose */\n algorithm?: string;\n userInfoDatabaseHandler: UserInfoDatabaseHandler;\n};\n\n/**\n * A token issuer that is able to issue tokens in a distributed system\n * backed by a single database. Tokens are issued using lazily generated\n * signing keys, where each running instance of the auth service uses its own\n * signing key.\n *\n * The public parts of the keys are all stored in the shared key storage,\n * and any of the instances of the auth service will return the full list\n * of public keys that are currently in storage.\n *\n * Signing keys are automatically rotated at the same interval as the token\n * duration. Expired keys are kept in storage until there are no valid tokens\n * in circulation that could have been signed by that key.\n */\nexport class TokenFactory implements TokenIssuer {\n private readonly issuer: string;\n private readonly logger: LoggerService;\n private readonly keyStore: KeyStore;\n private readonly keyDurationSeconds: number;\n private readonly algorithm: string;\n private readonly userInfoDatabaseHandler: UserInfoDatabaseHandler;\n\n private keyExpiry?: Date;\n private privateKeyPromise?: Promise;\n\n constructor(options: Options) {\n this.issuer = options.issuer;\n this.logger = options.logger;\n this.keyStore = options.keyStore;\n this.keyDurationSeconds = options.keyDurationSeconds;\n this.algorithm = options.algorithm ?? 'ES256';\n this.userInfoDatabaseHandler = options.userInfoDatabaseHandler;\n }\n\n async issueToken(params: TokenParams): Promise {\n const key = await this.getKey();\n\n const iss = this.issuer;\n const { sub, ent = [sub], ...additionalClaims } = params.claims;\n const aud = tokenTypes.user.audClaim;\n const iat = Math.floor(Date.now() / MS_IN_S);\n const exp = iat + this.keyDurationSeconds;\n\n try {\n // The subject must be a valid entity ref\n parseEntityRef(sub);\n } catch (error) {\n throw new Error(\n '\"sub\" claim provided by the auth resolver is not a valid EntityRef.',\n );\n }\n\n if (!key.alg) {\n throw new AuthenticationError('No algorithm was provided in the key');\n }\n\n this.logger.info(`Issuing token for ${sub}, with entities ${ent}`);\n\n const signingKey = await importJWK(key);\n\n const uip = await this.createUserIdentityClaim({\n header: {\n typ: tokenTypes.limitedUser.typParam,\n alg: key.alg,\n kid: key.kid,\n },\n payload: { sub, iat, exp },\n key: signingKey,\n });\n\n const claims: BackstageTokenPayload = {\n ...additionalClaims,\n iss,\n sub,\n ent,\n aud,\n iat,\n exp,\n uip,\n };\n\n const token = await new SignJWT(claims)\n .setProtectedHeader({\n typ: tokenTypes.user.typParam,\n alg: key.alg,\n kid: key.kid,\n })\n .sign(signingKey);\n\n if (token.length > MAX_TOKEN_LENGTH) {\n throw new Error(\n `Failed to issue a new user token. The resulting token is excessively large, with either too many ownership claims or too large custom claims. You likely have a bug either in the sign-in resolver or catalog data. The following claims were requested: '${JSON.stringify(\n claims,\n )}'`,\n );\n }\n\n // Store the user info in the database upon successful token\n // issuance so that it can be retrieved later by limited user tokens\n await this.userInfoDatabaseHandler.addUserInfo({\n claims: omit(claims, ['aud', 'iat', 'iss', 'uip']),\n });\n\n return token;\n }\n\n // This will be called by other services that want to verify ID tokens.\n // It is important that it returns a list of all public keys that could\n // have been used to sign tokens that have not yet expired.\n async listPublicKeys(): Promise<{ keys: AnyJWK[] }> {\n const { items: keys } = await this.keyStore.listKeys();\n\n const validKeys = [];\n const expiredKeys = [];\n\n for (const key of keys) {\n // Allow for a grace period of another full key duration before we remove the keys from the database\n const expireAt = DateTime.fromJSDate(key.createdAt).plus({\n seconds: 3 * this.keyDurationSeconds,\n });\n if (expireAt < DateTime.local()) {\n expiredKeys.push(key);\n } else {\n validKeys.push(key);\n }\n }\n\n // Lazily prune expired keys. This may cause duplicate removals if we have concurrent callers, but w/e\n if (expiredKeys.length > 0) {\n const kids = expiredKeys.map(({ key }) => key.kid);\n\n this.logger.info(`Removing expired signing keys, '${kids.join(\"', '\")}'`);\n\n // We don't await this, just let it run in the background\n this.keyStore.removeKeys(kids).catch(error => {\n this.logger.error(`Failed to remove expired keys, ${error}`);\n });\n }\n\n // NOTE: we're currently only storing public keys, but if we start storing private keys we'd have to convert here\n return { keys: validKeys.map(({ key }) => key) };\n }\n\n private async getKey(): Promise {\n // Make sure that we only generate one key at a time\n if (this.privateKeyPromise) {\n if (\n this.keyExpiry &&\n DateTime.fromJSDate(this.keyExpiry) > DateTime.local()\n ) {\n return this.privateKeyPromise;\n }\n this.logger.info(`Signing key has expired, generating new key`);\n delete this.privateKeyPromise;\n }\n\n this.keyExpiry = DateTime.utc()\n .plus({\n seconds: this.keyDurationSeconds,\n })\n .toJSDate();\n const promise = (async () => {\n // This generates a new signing key to be used to sign tokens until the next key rotation\n const key = await generateKeyPair(this.algorithm);\n const publicKey = await exportJWK(key.publicKey);\n const privateKey = await exportJWK(key.privateKey);\n publicKey.kid = privateKey.kid = uuid();\n publicKey.alg = privateKey.alg = this.algorithm;\n\n // We're not allowed to use the key until it has been successfully stored\n // TODO: some token verification implementations aggressively cache the list of keys, and\n // don't attempt to fetch new ones even if they encounter an unknown kid. Therefore we\n // may want to keep using the existing key for some period of time until we switch to\n // the new one. This also needs to be implemented cross-service though, meaning new services\n // that boot up need to be able to grab an existing key to use for signing.\n this.logger.info(`Created new signing key ${publicKey.kid}`);\n await this.keyStore.addKey(publicKey as AnyJWK);\n\n // At this point we are allowed to start using the new key\n return privateKey;\n })();\n\n this.privateKeyPromise = promise;\n\n try {\n // If we fail to generate a new key, we need to clear the state so that\n // the next caller will try to generate another key.\n await promise;\n } catch (error) {\n this.logger.error(`Failed to generate new signing key, ${error}`);\n delete this.keyExpiry;\n delete this.privateKeyPromise;\n }\n\n return promise;\n }\n\n // Creates a string claim that can be used as part of reconstructing a limited\n // user token. The output of this function is only the signature part of a\n // JWS.\n private async createUserIdentityClaim(options: {\n header: {\n typ: string;\n alg: string;\n kid?: string;\n };\n payload: BackstageUserIdentityProofPayload;\n key: KeyLike | Uint8Array;\n }): Promise {\n // NOTE: We reconstruct the header and payload structures carefully to\n // perfectly guarantee ordering. The reason for this is that we store only\n // the signature part of these to reduce duplication within the Backstage\n // token. Anyone who wants to make an actual JWT based on all this must be\n // able to do the EXACT reconstruction of the header and payload parts, to\n // then append the signature.\n\n const header = {\n typ: options.header.typ,\n alg: options.header.alg,\n ...(options.header.kid ? { kid: options.header.kid } : {}),\n };\n\n const payload = {\n sub: options.payload.sub,\n iat: options.payload.iat,\n exp: options.payload.exp,\n };\n\n const jws = await new GeneralSign(\n new TextEncoder().encode(JSON.stringify(payload)),\n )\n .addSignature(options.key)\n .setProtectedHeader(header)\n .done()\n .sign();\n\n return jws.signatures[0].signature;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { AnyJWK, KeyStore, StoredKey } from './types';\n\nconst TABLE = 'signing_keys';\n\ntype Row = {\n created_at: Date; // row.created_at is a string after being returned from the database\n kid: string;\n key: string;\n};\n\nconst parseDate = (date: string | Date) => {\n const parsedDate =\n typeof date === 'string'\n ? DateTime.fromSQL(date, { zone: 'UTC' })\n : DateTime.fromJSDate(date);\n\n if (!parsedDate.isValid) {\n throw new Error(\n `Failed to parse date, reason: ${parsedDate.invalidReason}, explanation: ${parsedDate.invalidExplanation}`,\n );\n }\n\n return parsedDate.toJSDate();\n};\n\nexport class DatabaseKeyStore implements KeyStore {\n constructor(private readonly client: Knex) {}\n\n async addKey(key: AnyJWK): Promise {\n await this.client(TABLE).insert({\n kid: key.kid,\n key: JSON.stringify(key),\n });\n }\n\n async listKeys(): Promise<{ items: StoredKey[] }> {\n const rows = await this.client(TABLE).select();\n\n return {\n items: rows.map(row => ({\n key: JSON.parse(row.key),\n createdAt: parseDate(row.created_at),\n })),\n };\n }\n\n async removeKeys(kids: string[]): Promise {\n await this.client(TABLE).delete().whereIn('kid', kids);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { KeyStore, AnyJWK, StoredKey } from './types';\nimport { DateTime } from 'luxon';\n\nexport class MemoryKeyStore implements KeyStore {\n private readonly keys = new Map();\n\n async addKey(key: AnyJWK): Promise {\n this.keys.set(key.kid, {\n createdAt: DateTime.utc().toJSDate(),\n key: JSON.stringify(key),\n });\n }\n\n async removeKeys(kids: string[]): Promise {\n for (const kid of kids) {\n this.keys.delete(kid);\n }\n }\n\n async listKeys(): Promise<{ items: StoredKey[] }> {\n return {\n items: Array.from(this.keys).map(([, { createdAt, key: keyStr }]) => ({\n createdAt,\n key: JSON.parse(keyStr),\n })),\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport {\n DocumentData,\n Firestore,\n QuerySnapshot,\n Settings,\n WriteResult,\n} from '@google-cloud/firestore';\n\nimport { AnyJWK, KeyStore, StoredKey } from './types';\n\nexport type FirestoreKeyStoreSettings = Settings & Options;\n\ntype Options = {\n path?: string;\n timeout?: number;\n};\n\nexport const DEFAULT_TIMEOUT_MS = 10000;\nexport const DEFAULT_DOCUMENT_PATH = 'sessions';\n\nexport class FirestoreKeyStore implements KeyStore {\n static async create(\n settings?: FirestoreKeyStoreSettings,\n ): Promise {\n const { path, timeout, ...firestoreSettings } = settings ?? {};\n const database = new Firestore(firestoreSettings);\n\n return new FirestoreKeyStore(\n database,\n path ?? DEFAULT_DOCUMENT_PATH,\n timeout ?? DEFAULT_TIMEOUT_MS,\n );\n }\n\n private constructor(\n private readonly database: Firestore,\n private readonly path: string,\n private readonly timeout: number,\n ) {}\n\n static async verifyConnection(\n keyStore: FirestoreKeyStore,\n logger?: LoggerService,\n ): Promise {\n try {\n await keyStore.verify();\n } catch (error) {\n if (process.env.NODE_ENV !== 'development') {\n throw new Error(\n `Failed to connect to database: ${(error as Error).message}`,\n );\n }\n logger?.warn(\n `Failed to connect to database: ${(error as Error).message}`,\n );\n }\n }\n\n async addKey(key: AnyJWK): Promise {\n await this.withTimeout(\n this.database\n .collection(this.path)\n .doc(key.kid)\n .set({\n kid: key.kid,\n key: JSON.stringify(key),\n }),\n );\n }\n\n async listKeys(): Promise<{ items: StoredKey[] }> {\n const keys = await this.withTimeout>(\n this.database.collection(this.path).get(),\n );\n\n return {\n items: keys.docs.map(key => ({\n key: key.data() as AnyJWK,\n createdAt: key.createTime.toDate(),\n })),\n };\n }\n\n async removeKeys(kids: string[]): Promise {\n // This is probably really slow, but it's done async in the background\n for (const kid of kids) {\n await this.withTimeout(\n this.database.collection(this.path).doc(kid).delete(),\n );\n }\n\n /**\n * This could be achieved with batching but there's a couple of limitations with that:\n *\n * - A batched write can contain a maximum of 500 operations\n * https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes\n *\n * - The \"in\" operator can combine a maximum of 10 equality clauses\n * https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any\n *\n * Example:\n *\n * const batch = this.database.batch();\n * const docs = await this.database\n * .collection(this.path)\n * .where('kid', 'in', kids)\n * .get();\n * docs.forEach(doc => {\n * batch.delete(doc.ref);\n * });\n * await batch.commit();\n *\n */\n }\n\n /**\n * Helper function to allow us to modify the timeout used when\n * performing Firestore database operations.\n *\n * The reason for this is that it seems that there's no other\n * practical solution to change the default timeout of 10mins\n * that Firestore has.\n *\n */\n private async withTimeout(operation: Promise): Promise {\n const timer = new Promise((_, reject) =>\n setTimeout(() => {\n reject(new Error(`Operation timed out after ${this.timeout}ms`));\n }, this.timeout),\n );\n return Promise.race([operation, timer]);\n }\n\n /**\n * Used to verify that the database is reachable.\n */\n private async verify(): Promise {\n await this.withTimeout(this.database.collection(this.path).limit(1).get());\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { AnyJWK, KeyStore, StoredKey } from './types';\nimport { exportJWK, importPKCS8, importSPKI, JWK } from 'jose';\nimport { KeyLike } from 'jose/dist/types/types';\nimport { promises as fs } from 'fs';\nimport { Config } from '@backstage/config';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey: JWK;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\n/**\n * Key store that loads predefined public/private key pairs from disk\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the StaticKeyStore.create(...) method.\n */\nexport class StaticKeyStore implements KeyStore {\n private readonly keyPairs: KeyPair[];\n private readonly createdAt: Date;\n\n private constructor(keyPairs: KeyPair[]) {\n if (keyPairs.length === 0) {\n throw new Error('Should provide at least one key pair');\n }\n\n this.keyPairs = keyPairs;\n this.createdAt = new Date();\n }\n\n public static async fromConfig(config: Config): Promise {\n const keyConfigs = config\n .getConfigArray('auth.keyStore.static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n return new StaticKeyStore(keyPairs);\n }\n\n addKey(_key: AnyJWK): Promise {\n throw new Error('Cannot add keys to the static key store');\n }\n\n listKeys(): Promise<{ items: StoredKey[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return Promise.resolve({ items: keys });\n }\n\n getPrivateKey(keyId: string): JWK {\n const keyPair = this.keyPairs.find(k => k.publicKey.kid === keyId);\n if (keyPair === undefined) {\n throw new Error(`Could not find key with keyId: ${keyId}`);\n }\n\n return keyPair.privateKey;\n }\n\n removeKeys(_kids: string[]): Promise {\n throw new Error('Cannot remove keys from the static key store');\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): StoredKey {\n const publicKey = {\n ...keyPair.publicKey,\n use: 'sig',\n };\n\n return {\n key: publicKey as AnyJWK,\n createdAt: this.createdAt,\n };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n );\n\n return { publicKey, privateKey };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise,\n ): Promise {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { pickBy } from 'lodash';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nimport { Config } from '@backstage/config';\nimport { AuthDatabase } from '../database/AuthDatabase';\nimport { DatabaseKeyStore } from './DatabaseKeyStore';\nimport { FirestoreKeyStore } from './FirestoreKeyStore';\nimport { MemoryKeyStore } from './MemoryKeyStore';\nimport { KeyStore } from './types';\nimport { StaticKeyStore } from './StaticKeyStore';\n\ntype Options = {\n logger: LoggerService;\n database: AuthDatabase;\n};\n\nexport class KeyStores {\n /**\n * Looks at the `auth.keyStore` section in the application configuration\n * and returns a KeyStore store. Defaults to `database`\n *\n * @returns a KeyStore store\n */\n static async fromConfig(config: Config, options: Options): Promise {\n const { logger, database } = options;\n\n const ks = config.getOptionalConfig('auth.keyStore');\n const provider = ks?.getOptionalString('provider') ?? 'database';\n\n logger.info(`Configuring \"${provider}\" as KeyStore provider`);\n\n if (provider === 'database') {\n return new DatabaseKeyStore(await database.get());\n }\n\n if (provider === 'memory') {\n return new MemoryKeyStore();\n }\n\n if (provider === 'firestore') {\n const settings = ks?.getConfig(provider);\n\n const keyStore = await FirestoreKeyStore.create(\n pickBy(\n {\n projectId: settings?.getOptionalString('projectId'),\n keyFilename: settings?.getOptionalString('keyFilename'),\n host: settings?.getOptionalString('host'),\n port: settings?.getOptionalNumber('port'),\n ssl: settings?.getOptionalBoolean('ssl'),\n path: settings?.getOptionalString('path'),\n timeout: settings?.getOptionalNumber('timeout'),\n },\n value => value !== undefined,\n ),\n );\n await FirestoreKeyStore.verifyConnection(keyStore, logger);\n\n return keyStore;\n }\n\n if (provider === 'static') {\n return await StaticKeyStore.fromConfig(config);\n }\n\n throw new Error(`Unknown KeyStore provider: ${provider}`);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DateTime } from 'luxon';\nimport { Knex } from 'knex';\n\nimport { BackstageTokenPayload } from './TokenFactory';\n\nconst TABLE = 'user_info';\n\ntype Row = {\n user_entity_ref: string;\n user_info: string;\n exp: string;\n};\n\ntype UserInfo = {\n claims: Omit;\n};\n\nexport class UserInfoDatabaseHandler {\n constructor(private readonly client: Knex) {}\n\n async addUserInfo(userInfo: UserInfo): Promise {\n await this.client(TABLE)\n .insert({\n user_entity_ref: userInfo.claims.sub as string,\n user_info: JSON.stringify(userInfo),\n exp: DateTime.fromSeconds(userInfo.claims.exp as number, {\n zone: 'utc',\n }).toSQL({ includeOffset: false }),\n })\n .onConflict('user_entity_ref')\n .merge();\n }\n\n async getUserInfo(userEntityRef: string): Promise {\n const info = await this.client(TABLE)\n .where({ user_entity_ref: userEntityRef })\n .first();\n\n if (!info) {\n return undefined;\n }\n\n const userInfo = JSON.parse(info.user_info);\n return userInfo;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DatabaseManager,\n PluginDatabaseManager,\n} from '@backstage/backend-common';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { ConfigReader } from '@backstage/config';\nimport { Knex } from 'knex';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-auth-backend',\n 'migrations',\n);\n\n/**\n * Ensures that a database connection is established exactly once and only when\n * asked for, and runs migrations.\n */\nexport class AuthDatabase {\n readonly #database: PluginDatabaseManager;\n #promise: Promise | undefined;\n\n static create(database: PluginDatabaseManager): AuthDatabase {\n return new AuthDatabase(database);\n }\n\n /** @internal */\n static forTesting(): AuthDatabase {\n const config = new ConfigReader({\n backend: {\n database: {\n client: 'better-sqlite3',\n connection: ':memory:',\n useNullAsDefault: true,\n },\n },\n });\n const database = DatabaseManager.fromConfig(config).forPlugin('auth');\n return new AuthDatabase(database);\n }\n\n static async runMigrations(knex: Knex): Promise {\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n private constructor(database: PluginDatabaseManager) {\n this.#database = database;\n }\n\n get(): Promise {\n this.#promise ??= this.#database.getClient().then(async client => {\n if (!this.#database.migrations?.skip) {\n await AuthDatabase.runMigrations(client);\n }\n return client;\n });\n\n return this.#promise;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootConfigService } from '@backstage/backend-plugin-api';\nimport { readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nconst TOKEN_EXP_DEFAULT_S = 3600;\nconst TOKEN_EXP_MIN_S = 600;\nconst TOKEN_EXP_MAX_S = 86400;\n\nexport function readBackstageTokenExpiration(config: RootConfigService) {\n const processingIntervalKey = 'auth.backstageTokenExpiration';\n\n if (!config.has(processingIntervalKey)) {\n return TOKEN_EXP_DEFAULT_S;\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const durationS = Math.round(durationToMilliseconds(duration) / 1000);\n\n if (durationS < TOKEN_EXP_MIN_S) {\n return TOKEN_EXP_MIN_S;\n } else if (durationS > TOKEN_EXP_MAX_S) {\n return TOKEN_EXP_MAX_S;\n }\n return durationS;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AnyJWK, TokenIssuer } from './types';\nimport { SignJWT, importJWK, JWK } from 'jose';\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { AuthenticationError } from '@backstage/errors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { StaticKeyStore } from './StaticKeyStore';\nimport { TokenParams } from '@backstage/plugin-auth-node';\n\nconst MS_IN_S = 1000;\n\nexport type Config = {\n publicKeyFile: string;\n privateKeyFile: string;\n keyId: string;\n algorithm?: string;\n};\n\nexport type Options = {\n logger: LoggerService;\n /** Value of the issuer claim in issued tokens */\n issuer: string;\n /** Expiration time of the JWT in seconds */\n sessionExpirationSeconds: number;\n};\n\n/**\n * A token issuer that issues tokens from predefined\n * public/private key pair stored in the static key store.\n */\nexport class StaticTokenIssuer implements TokenIssuer {\n private readonly issuer: string;\n private readonly logger: LoggerService;\n private readonly keyStore: StaticKeyStore;\n private readonly sessionExpirationSeconds: number;\n\n public constructor(options: Options, keyStore: StaticKeyStore) {\n this.issuer = options.issuer;\n this.logger = options.logger;\n this.sessionExpirationSeconds = options.sessionExpirationSeconds;\n this.keyStore = keyStore;\n }\n\n public async issueToken(params: TokenParams): Promise {\n const key = await this.getSigningKey();\n\n // TODO: code shared with TokenFactory.ts\n const iss = this.issuer;\n const { sub, ent, ...additionalClaims } = params.claims;\n const aud = 'backstage';\n const iat = Math.floor(Date.now() / MS_IN_S);\n const exp = iat + this.sessionExpirationSeconds;\n\n // Validate that the subject claim is a valid EntityRef\n try {\n parseEntityRef(sub);\n } catch (error) {\n throw new Error(\n '\"sub\" claim provided by the auth resolver is not a valid EntityRef.',\n );\n }\n\n this.logger.info(`Issuing token for ${sub}, with entities ${ent ?? []}`);\n\n if (!key.alg) {\n throw new AuthenticationError('No algorithm was provided in the key');\n }\n\n return new SignJWT({ ...additionalClaims, iss, sub, ent, aud, iat, exp })\n .setProtectedHeader({ alg: key.alg, kid: key.kid })\n .setIssuer(iss)\n .setAudience(aud)\n .setSubject(sub)\n .setIssuedAt(iat)\n .setExpirationTime(exp)\n .sign(await importJWK(key));\n }\n\n private async getSigningKey(): Promise {\n const { items: keys } = await this.keyStore.listKeys();\n if (keys.length >= 1) {\n return this.keyStore.getPrivateKey(keys[0].key.kid);\n }\n throw new Error('Keystore should hold at least 1 key');\n }\n\n public async listPublicKeys(): Promise<{ keys: AnyJWK[] }> {\n const { items: keys } = await this.keyStore.listKeys();\n return { keys: keys.map(({ key }) => key) };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport cookieParser from 'cookie-parser';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { defaultAuthProviderFactories } from '../providers';\nimport { AuthOwnershipResolver } from '@backstage/plugin-auth-node';\nimport {\n createLegacyAuthAdapters,\n PluginDatabaseManager,\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport { NotFoundError } from '@backstage/errors';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n bindOidcRouter,\n KeyStores,\n TokenFactory,\n UserInfoDatabaseHandler,\n} from '../identity';\nimport session from 'express-session';\nimport connectSessionKnex from 'connect-session-knex';\nimport passport from 'passport';\nimport { AuthDatabase } from '../database/AuthDatabase';\nimport { readBackstageTokenExpiration } from './readBackstageTokenExpiration';\nimport { TokenIssuer } from '../identity/types';\nimport { StaticTokenIssuer } from '../identity/StaticTokenIssuer';\nimport { StaticKeyStore } from '../identity/StaticKeyStore';\nimport { Config } from '@backstage/config';\nimport { bindProviderRouters, ProviderFactories } from '../providers/router';\n\n/** @public */\nexport interface RouterOptions {\n logger: LoggerService;\n database: PluginDatabaseManager;\n config: Config;\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n tokenFactoryAlgorithm?: string;\n providerFactories?: ProviderFactories;\n disableDefaultProviderFactories?: boolean;\n catalogApi?: CatalogApi;\n ownershipResolver?: AuthOwnershipResolver;\n}\n\n/** @public */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const {\n logger,\n config,\n discovery,\n database,\n tokenFactoryAlgorithm,\n providerFactories = {},\n } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters(options);\n\n const router = Router();\n\n const appUrl = config.getString('app.baseUrl');\n const authUrl = await discovery.getExternalBaseUrl('auth');\n const backstageTokenExpiration = readBackstageTokenExpiration(config);\n const authDb = AuthDatabase.create(database);\n\n const keyStore = await KeyStores.fromConfig(config, {\n logger,\n database: authDb,\n });\n\n const userInfoDatabaseHandler = new UserInfoDatabaseHandler(\n await authDb.get(),\n );\n\n let tokenIssuer: TokenIssuer;\n if (keyStore instanceof StaticKeyStore) {\n tokenIssuer = new StaticTokenIssuer(\n {\n logger: logger.child({ component: 'token-factory' }),\n issuer: authUrl,\n sessionExpirationSeconds: backstageTokenExpiration,\n },\n keyStore as StaticKeyStore,\n );\n } else {\n tokenIssuer = new TokenFactory({\n issuer: authUrl,\n keyStore,\n keyDurationSeconds: backstageTokenExpiration,\n logger: logger.child({ component: 'token-factory' }),\n algorithm:\n tokenFactoryAlgorithm ??\n config.getOptionalString('auth.identityTokenAlgorithm'),\n userInfoDatabaseHandler,\n });\n }\n\n const secret = config.getOptionalString('auth.session.secret');\n if (secret) {\n router.use(cookieParser(secret));\n const enforceCookieSSL = authUrl.startsWith('https');\n const KnexSessionStore = connectSessionKnex(session);\n router.use(\n session({\n secret,\n saveUninitialized: false,\n resave: false,\n cookie: { secure: enforceCookieSSL ? 'auto' : false },\n store: new KnexSessionStore({\n createtable: false,\n knex: await authDb.get(),\n }),\n }),\n );\n router.use(passport.initialize());\n router.use(passport.session());\n } else {\n router.use(cookieParser());\n }\n\n router.use(express.urlencoded({ extended: false }));\n router.use(express.json());\n\n const providers = options.disableDefaultProviderFactories\n ? providerFactories\n : {\n ...defaultAuthProviderFactories,\n ...providerFactories,\n };\n\n bindProviderRouters(router, {\n providers,\n appUrl,\n baseUrl: authUrl,\n tokenIssuer,\n ...options,\n auth,\n httpAuth,\n });\n\n bindOidcRouter(router, {\n auth,\n tokenIssuer,\n baseUrl: authUrl,\n userInfoDatabaseHandler,\n });\n\n // Gives a more helpful error message than a plain 404\n router.use('/:provider/', req => {\n const { provider } = req.params;\n throw new NotFoundError(`Unknown auth provider '${provider}'`);\n });\n\n return router;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport {\n authOwnershipResolutionExtensionPoint,\n AuthOwnershipResolver,\n AuthProviderFactory,\n authProvidersExtensionPoint,\n} from '@backstage/plugin-auth-node';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { createRouter } from './service/router';\n\n/**\n * Auth plugin\n *\n * @public\n */\nexport const authPlugin = createBackendPlugin({\n pluginId: 'auth',\n register(reg) {\n const providers = new Map();\n let ownershipResolver: AuthOwnershipResolver | undefined = undefined;\n\n reg.registerExtensionPoint(authProvidersExtensionPoint, {\n registerProvider({ providerId, factory }) {\n if (providers.has(providerId)) {\n throw new Error(\n `Auth provider '${providerId}' was already registered`,\n );\n }\n providers.set(providerId, factory);\n },\n });\n\n reg.registerExtensionPoint(authOwnershipResolutionExtensionPoint, {\n setAuthOwnershipResolver(resolver) {\n if (ownershipResolver) {\n throw new Error('Auth ownership resolver is already set');\n }\n ownershipResolver = resolver;\n },\n });\n\n reg.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n database: coreServices.database,\n discovery: coreServices.discovery,\n tokenManager: coreServices.tokenManager,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n catalogApi: catalogServiceRef,\n },\n async init({\n httpRouter,\n logger,\n config,\n database,\n discovery,\n tokenManager,\n auth,\n httpAuth,\n catalogApi,\n }) {\n const router = await createRouter({\n logger,\n config,\n database,\n discovery,\n tokenManager,\n auth,\n httpAuth,\n catalogApi,\n providerFactories: Object.fromEntries(providers),\n disableDefaultProviderFactories: true,\n ownershipResolver,\n });\n httpRouter.addAuthPolicy({\n path: '/',\n allow: 'unauthenticated',\n });\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createOAuthProviderFactory","atlassianAuthenticator","Auth0InternalStrategy","_OAuthEnvironmentHandler","decodeOAuthState","encodeOAuthState","crypto","_prepareBackstageIdentityResponse","URL","InputError","NotAllowedError","isError","AuthenticationError","decodeJwt","createProxyAuthProviderFactory","awsAlbAuthenticator","bitbucketAuthenticator","bitbucketSignInResolvers","createCloudflareAccessAuthenticator","cloudflareAccessSignInResolvers","gcpIapAuthenticator","githubAuthenticator","gitlabAuthenticator","googleAuthenticator","commonSignInResolvers","googleSignInResolvers","microsoftAuthenticator","microsoftSignInResolvers","oauth2Authenticator","oauth2ProxyAuthenticator","oidcAuthenticator","oktaAuthenticator","oneLoginAuthenticator","SamlStrategy","OAuth2Strategy","fetch","azureEasyAuthAuthenticator","createLegacyAuthAdapters","ConflictError","NotFoundError","parseEntityRef","stringifyEntityRef","RELATION_MEMBER_OF","DEFAULT_NAMESPACE","CatalogClient","Router","assertError","Minimatch","MS_IN_S","tokenTypes","importJWK","SignJWT","omit","DateTime","generateKeyPair","exportJWK","uuid","GeneralSign","TABLE","Firestore","importSPKI","importPKCS8","fs","pickBy","resolvePackagePath","config","ConfigReader","DatabaseManager","readDurationFromConfig","durationToMilliseconds","cookieParser","connectSessionKnex","session","passport","express","createBackendPlugin","authProvidersExtensionPoint","authOwnershipResolutionExtensionPoint","coreServices","catalogServiceRef"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBO,SAAS,wBACd,WACyE,EAAA;AACzE,EACE,OAAA,WAAA,KACC,OAAO,MAAA,EAAQ,GACd,KAAA,WAAA;AAAA,IACE;AAAA,MACE,aAAa,MAAO,CAAA,WAAA;AAAA,MACpB,WAAA,EAAa,OAAO,OAAQ,CAAA,WAAA;AAAA,MAC5B,MAAQ,EAAA;AAAA,QACN,KAAA,EAAO,OAAO,OAAQ,CAAA,KAAA;AAAA,QACtB,QAAA,EAAU,OAAO,OAAQ,CAAA,OAAA;AAAA,QACzB,UAAA,EAAY,OAAO,OAAQ,CAAA,SAAA;AAAA,QAC3B,UAAA,EAAY,OAAO,OAAQ,CAAA,gBAAA;AAAA,OAC7B;AAAA,KACF;AAAA,IACA,GAAA;AAAA,GACF,CAAA,CAAA;AAEN;;ACrBO,SAAS,+BACd,cACuE,EAAA;AACvE,EACE,OAAA,cAAA,KACC,OAAO,KAAA,EAAO,GACb,KAAA,cAAA;AAAA,IACE;AAAA,MACE,SAAS,KAAM,CAAA,OAAA;AAAA,MACf,MAAQ,EAAA;AAAA,QACN,WAAA,EAAa,MAAM,MAAO,CAAA,WAAA;AAAA,QAC1B,WAAA,EAAa,KAAM,CAAA,MAAA,CAAO,OAAQ,CAAA,WAAA;AAAA,QAClC,YAAA,EAAc,KAAM,CAAA,MAAA,CAAO,OAAQ,CAAA,YAAA;AAAA,QACnC,MAAQ,EAAA;AAAA,UACN,KAAA,EAAO,KAAM,CAAA,MAAA,CAAO,OAAQ,CAAA,KAAA;AAAA,UAC5B,QAAA,EAAU,KAAM,CAAA,MAAA,CAAO,OAAQ,CAAA,OAAA;AAAA,UAC/B,UAAA,EAAY,KAAM,CAAA,MAAA,CAAO,OAAQ,CAAA,SAAA;AAAA,UACjC,UAAA,EAAY,KAAM,CAAA,MAAA,CAAO,OAAQ,CAAA,gBAAA;AAAA,SACnC;AAAA,OACF;AAAA,KACF;AAAA,IACA,GAAA;AAAA,GACF,CAAA,CAAA;AAEN;;ACxBO,SAAS,iCAEd,SAEwD,EAAA;AACxD,EAAA,MAAM,kBAAkB,EAAC,CAAA;AAGzB,EAAA,KAAA,MAAW,IAAQ,IAAA,MAAA,CAAO,IAAK,CAAA,SAAS,CAAc,EAAA;AACpD,IAAM,MAAA,QAAA,GAAW,UAAU,IAAI,CAAA,CAAA;AAC/B,IAAA,eAAA,CAAgB,IAAI,CAAA,GAAI,MAAM,OAAO,OAAO,GAC1C,KAAA,QAAA;AAAA,MACE;AAAA,QACE,SAAS,KAAM,CAAA,OAAA;AAAA,QACf,MAAQ,EAAA;AAAA,UACN,WAAA,EAAa,MAAM,MAAO,CAAA,WAAA;AAAA,UAC1B,OAAS,EAAA;AAAA,YACP,WAAA,EAAa,MAAM,MAAO,CAAA,WAAA;AAAA,YAC1B,gBAAA,EAAkB,KAAM,CAAA,MAAA,CAAO,MAAO,CAAA,UAAA;AAAA,YACtC,KAAA,EAAO,KAAM,CAAA,MAAA,CAAO,MAAO,CAAA,KAAA;AAAA,YAC3B,OAAA,EAAS,KAAM,CAAA,MAAA,CAAO,MAAO,CAAA,QAAA;AAAA,YAC7B,SAAW,EAAA,KAAA,CAAM,MAAO,CAAA,MAAA,CAAO,UAAc,IAAA,QAAA;AAAA,YAC7C,YAAA,EAAc,MAAM,MAAO,CAAA,YAAA;AAAA,WAC7B;AAAA,SACF;AAAA,OACF;AAAA,MACA,GAAA;AAAA,KACF,CAAA;AAAA,GACJ;AACA,EAAO,OAAA,eAAA,CAAA;AACT;;ACxBO,SAAS,8BAMd,MAOC,EAAA;AACD,EAAA,OAAO,OAAO,MAAO,CAAA;AAAA,IACnB,GAAG,MAAA;AAAA,IACH,WAAW,MAAO,CAAA,MAAA,CAAO,MAAO,CAAA,SAAA,IAAc,EAAU,CAAA;AAAA,GACzD,CAAA,CAAA;AACH;;ACdO,MAAM,YAAY,6BAA8B,CAAA;AAAA,EACrD,OAAO,OAaJ,EAAA;AACD,IAAA,OAAOA,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAAC,+DAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;AC5BD,MAAqB,sBAAsBC,sCAAsB,CAAA;AAAA,EAC/D,WAAA,CACE,SACA,MACA,EAAA;AACA,IAAA,MAAM,eAAkB,GAAA;AAAA,MACtB,GAAG,OAAA;AAAA,MACH,gBAAA,EAAkB,CAAW,QAAA,EAAA,OAAA,CAAQ,MAAM,CAAA,UAAA,CAAA;AAAA,MAC3C,QAAA,EAAU,CAAW,QAAA,EAAA,OAAA,CAAQ,MAAM,CAAA,YAAA,CAAA;AAAA,MACnC,WAAA,EAAa,CAAW,QAAA,EAAA,OAAA,CAAQ,MAAM,CAAA,SAAA,CAAA;AAAA,MACtC,MAAA,EAAQ,CAAW,QAAA,EAAA,OAAA,CAAQ,MAAM,CAAA,IAAA,CAAA;AAAA,KACnC,CAAA;AACA,IAAA,KAAA,CAAM,iBAAiB,MAAM,CAAA,CAAA;AAAA,GAC/B;AACF;;ACnBO,MAAM,uBAA0B,GAAAC;;ACMhC,MAAM,SAAY,GAAAC,gCAAA;AAMlB,MAAM,WAAc,GAAAC,gCAAA;AAMd,MAAA,WAAA,GAAc,CAAC,GAAA,EAAsB,UAAuB,KAAA;AACvE,EAAA,MAAM,WAAc,GAAA,GAAA,CAAI,OAAQ,CAAA,CAAA,EAAG,UAAU,CAAQ,MAAA,CAAA,CAAA,CAAA;AACrD,EAAA,MAAM,QAAoB,SAAU,CAAA,GAAA,CAAI,MAAM,KAAO,EAAA,QAAA,MAAc,EAAE,CAAA,CAAA;AACrE,EAAA,MAAM,aAAa,KAAM,CAAA,KAAA,CAAA;AAEzB,EAAA,IAAI,CAAC,WAAa,EAAA;AAChB,IAAM,MAAA,IAAI,MAAM,uCAAuC,CAAA,CAAA;AAAA,GACzD;AACA,EAAI,IAAA,UAAA,CAAW,WAAW,CAAG,EAAA;AAC3B,IAAM,MAAA,IAAI,MAAM,sCAAsC,CAAA,CAAA;AAAA,GACxD;AACA,EAAA,IAAI,gBAAgB,UAAY,EAAA;AAC9B,IAAM,MAAA,IAAI,MAAM,eAAe,CAAA,CAAA;AAAA,GACjC;AACF,EAAA;AAEO,MAAM,0BAA4C,CAAC;AAAA,EACxD,WAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AACF,CAAM,KAAA;AACJ,EAAM,MAAA,EAAE,UAAU,MAAQ,EAAA,QAAA,EAAU,UAAa,GAAA,IAAI,IAAI,WAAW,CAAA,CAAA;AACpE,EAAA,MAAM,SAAS,QAAa,KAAA,QAAA,CAAA;AAM5B,EAAA,IAAI,QAAqD,GAAA,KAAA,CAAA;AACzD,EAAA,IAAI,IAAI,GAAI,CAAA,SAAS,CAAE,CAAA,QAAA,KAAa,UAAU,MAAQ,EAAA;AACpD,IAAW,QAAA,GAAA,MAAA,CAAA;AAAA,GACb;AAKA,EAAA,MAAM,OAAO,QAAS,CAAA,QAAA,CAAS,CAAG,EAAA,UAAU,gBAAgB,CACxD,GAAA,QAAA,CAAS,KAAM,CAAA,CAAA,EAAG,CAAC,gBAAiB,CAAA,MAAM,IAC1C,CAAG,EAAA,QAAQ,IAAI,UAAU,CAAA,CAAA,CAAA;AAE7B,EAAA,OAAO,EAAE,MAAA,EAAQ,IAAM,EAAA,MAAA,EAAQ,QAAS,EAAA,CAAA;AAC1C,CAAA;;AC7Da,MAAA,wBAAA,GAA2B,CAAC,KAAkB,KAAA;AAGzD,EAAA,OAAO,kBAAmB,CAAA,KAAK,CAAE,CAAA,OAAA,CAAQ,MAAM,KAAK,CAAA,CAAA;AACtD,CAAA,CAAA;AAMO,MAAM,mBAAsB,GAAA,CACjC,GACA,EAAA,SAAA,EACA,QACG,KAAA;AACH,EAAM,MAAA,QAAA,GAAW,IAAK,CAAA,SAAA,CAAU,QAAQ,CAAA,CAAA;AACxC,EAAM,MAAA,UAAA,GAAa,yBAAyB,QAAQ,CAAA,CAAA;AACpD,EAAM,MAAA,YAAA,GAAe,yBAAyB,SAAS,CAAA,CAAA;AAmBvD,EAAA,MAAM,MAAS,GAAA,CAAA;AAAA,2CAAA,EAC4B,UAAU,CAAA;AAAA,qCAAA,EAChB,YAAY,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA,CAAA;AAQjD,EAAM,MAAA,IAAA,GAAOC,wBAAO,UAAW,CAAA,QAAQ,EAAE,MAAO,CAAA,MAAM,CAAE,CAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAEvE,EAAI,GAAA,CAAA,SAAA,CAAU,gBAAgB,WAAW,CAAA,CAAA;AACzC,EAAI,GAAA,CAAA,SAAA,CAAU,mBAAmB,YAAY,CAAA,CAAA;AAC7C,EAAA,GAAA,CAAI,SAAU,CAAA,yBAAA,EAA2B,CAAsB,mBAAA,EAAA,IAAI,CAAG,CAAA,CAAA,CAAA,CAAA;AACtE,EAAI,GAAA,CAAA,GAAA,CAAI,CAAuB,oBAAA,EAAA,MAAM,CAAyB,wBAAA,CAAA,CAAA,CAAA;AAChE,EAAA;AAMa,MAAA,qBAAA,GAAwB,CAAC,GAAyB,KAAA;AAC7D,EAAM,MAAA,cAAA,GAAiB,GAAI,CAAA,MAAA,CAAO,kBAAkB,CAAA,CAAA;AACpD,EAAI,IAAA,CAAC,cAAkB,IAAA,cAAA,KAAmB,gBAAkB,EAAA;AAC1D,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AACA,EAAO,OAAA,IAAA,CAAA;AACT;;AC9DO,MAAM,gCACX,GAAAC;;ACwBK,MAAM,gBAAmB,GAAA,GAAA,GAAO,EAAK,GAAA,EAAA,GAAK,EAAK,GAAA,GAAA,CAAA;AAC/C,MAAM,iBAAiB,GAAM,GAAA,GAAA,CAAA;AAoB7B,MAAM,YAAkD,CAAA;AAAA,EAyB7D,WAAA,CACmB,UACA,OACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AAEjB,IAAA,IAAA,CAAK,iBAAoB,GAAA;AAAA,MACvB,QAAU,EAAA,IAAA;AAAA,MACV,QAAU,EAAA,KAAA;AAAA,KACZ,CAAA;AAAA,GACF;AAAA,EAhCA,OAAO,UAAA,CACL,MACA,EAAA,QAAA,EACA,OAIc,EAAA;AACd,IAAA,MAAM,EAAE,MAAA,EAAQ,OAAS,EAAA,eAAA,EAAoB,GAAA,MAAA,CAAA;AAC7C,IAAA,MAAM,EAAE,MAAQ,EAAA,SAAA,EAAc,GAAA,IAAIC,QAAI,MAAM,CAAA,CAAA;AAE5C,IAAM,MAAA,gBAAA,GAAmB,OAAO,gBAAoB,IAAA,uBAAA,CAAA;AAEpD,IAAO,OAAA,IAAI,aAAa,QAAU,EAAA;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,SAAA;AAAA,MACA,OAAA;AAAA,MACA,gBAAA;AAAA,MACA,eAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEiB,iBAAA,CAAA;AAAA,EAYjB,MAAM,KAAM,CAAA,GAAA,EAAsB,GAAsC,EAAA;AAEtE,IAAA,MAAM,KAAQ,GAAA,GAAA,CAAI,KAAM,CAAA,KAAA,EAAO,UAAc,IAAA,EAAA,CAAA;AAC7C,IAAA,MAAM,GAAM,GAAA,GAAA,CAAI,KAAM,CAAA,GAAA,EAAK,QAAS,EAAA,CAAA;AACpC,IAAA,MAAM,MAAS,GAAA,GAAA,CAAI,KAAM,CAAA,MAAA,EAAQ,QAAS,EAAA,CAAA;AAC1C,IAAA,MAAM,WAAc,GAAA,GAAA,CAAI,KAAM,CAAA,WAAA,EAAa,QAAS,EAAA,CAAA;AACpD,IAAA,MAAM,IAAO,GAAA,GAAA,CAAI,KAAM,CAAA,IAAA,EAAM,QAAS,EAAA,CAAA;AAEtC,IAAA,IAAI,CAAC,GAAK,EAAA;AACR,MAAM,MAAA,IAAIC,kBAAW,6CAA6C,CAAA,CAAA;AAAA,KACpE;AAEA,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,eAAA,CAAgB,MAAM,CAAA,CAAA;AAEhD,IAAA,MAAM,QAAQH,uBAAO,CAAA,WAAA,CAAY,EAAE,CAAA,CAAE,SAAS,QAAQ,CAAA,CAAA;AAEtD,IAAK,IAAA,CAAA,cAAA,CAAe,GAAK,EAAA,KAAA,EAAO,YAAY,CAAA,CAAA;AAE5C,IAAA,MAAM,QAAoB,EAAE,KAAA,EAAO,GAAK,EAAA,MAAA,EAAQ,aAAa,IAAK,EAAA,CAAA;AAIlE,IAAI,IAAA,IAAA,CAAK,QAAQ,aAAe,EAAA;AAC9B,MAAA,KAAA,CAAM,KAAQ,GAAA,KAAA,CAAA;AAAA,KAChB;AACA,IAAA,MAAM,aAAa,MAAO,CAAA,MAAA,CAAO,KAAK,EAAE,KAAA,EAAO,OAAO,CAAA,CAAA;AAEtD,IAAA,MAAM,EAAE,GAAK,EAAA,MAAA,EAAW,GAAA,MAAM,KAAK,QAAS,CAAA,KAAA;AAAA,MAC1C,UAAA;AAAA,KACF,CAAA;AAEA,IAAA,GAAA,CAAI,aAAa,MAAU,IAAA,GAAA,CAAA;AAC3B,IAAI,GAAA,CAAA,SAAA,CAAU,YAAY,GAAG,CAAA,CAAA;AAC7B,IAAI,GAAA,CAAA,SAAA,CAAU,kBAAkB,GAAG,CAAA,CAAA;AACnC,IAAA,GAAA,CAAI,GAAI,EAAA,CAAA;AAAA,GACV;AAAA,EAEA,MAAM,YACJ,CAAA,GAAA,EACA,GACe,EAAA;AACf,IAAI,IAAA,SAAA,GAAY,KAAK,OAAQ,CAAA,SAAA,CAAA;AAE7B,IAAI,IAAA;AACF,MAAA,MAAM,QAAoB,SAAU,CAAA,GAAA,CAAI,MAAM,KAAO,EAAA,QAAA,MAAc,EAAE,CAAA,CAAA;AAErE,MAAA,IAAI,MAAM,MAAQ,EAAA;AAChB,QAAI,IAAA;AACF,UAAA,SAAA,GAAY,IAAIE,OAAA,CAAI,KAAM,CAAA,MAAM,CAAE,CAAA,MAAA,CAAA;AAAA,SAC5B,CAAA,MAAA;AACN,UAAM,MAAA,IAAIE,uBAAgB,wCAAwC,CAAA,CAAA;AAAA,SACpE;AACA,QAAA,IAAI,CAAC,IAAA,CAAK,OAAQ,CAAA,eAAA,CAAgB,SAAS,CAAG,EAAA;AAC5C,UAAA,MAAM,IAAIA,sBAAA,CAAgB,CAAW,QAAA,EAAA,SAAS,CAAkB,gBAAA,CAAA,CAAA,CAAA;AAAA,SAClE;AAAA,OACF;AAGA,MAAY,WAAA,CAAA,GAAA,EAAK,IAAK,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAExC,MAAM,MAAA,EAAE,UAAU,YAAa,EAAA,GAAI,MAAM,IAAK,CAAA,QAAA,CAAS,QAAQ,GAAG,CAAA,CAAA;AAElE,MAAM,MAAA,YAAA,GAAe,IAAK,CAAA,eAAA,CAAgB,SAAS,CAAA,CAAA;AAInD,MAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,aAAiB,IAAA,KAAA,CAAM,KAAO,EAAA;AAC7C,QAAA,IAAA,CAAK,qBAAsB,CAAA,GAAA,EAAK,KAAM,CAAA,KAAA,EAAO,YAAY,CAAA,CAAA;AACzD,QAAS,QAAA,CAAA,YAAA,CAAa,QAAQ,KAAM,CAAA,KAAA,CAAA;AAAA,OACtC;AAEA,MAAA,IAAI,YAAc,EAAA;AAEhB,QAAK,IAAA,CAAA,qBAAA,CAAsB,GAAK,EAAA,YAAA,EAAc,YAAY,CAAA,CAAA;AAAA,OAC5D;AAEA,MAAA,MAAM,QAAW,GAAA,MAAM,IAAK,CAAA,gBAAA,CAAiB,SAAS,iBAAiB,CAAA,CAAA;AAEvE,MAAA,MAAM,WAAkC,GAAA;AAAA,QACtC,IAAM,EAAA,wBAAA;AAAA,QACN,QAAU,EAAA,EAAE,GAAG,QAAA,EAAU,mBAAmB,QAAS,EAAA;AAAA,OACvD,CAAA;AAEA,MAAI,IAAA,KAAA,CAAM,SAAS,UAAY,EAAA;AAC7B,QAAI,IAAA,CAAC,MAAM,WAAa,EAAA;AACtB,UAAA,MAAM,IAAID,iBAAA;AAAA,YACR,qDAAA;AAAA,WACF,CAAA;AAAA,SACF;AACA,QAAI,GAAA,CAAA,QAAA,CAAS,MAAM,WAAW,CAAA,CAAA;AAC9B,QAAO,OAAA,KAAA,CAAA,CAAA;AAAA,OACT;AAEA,MAAO,OAAA,mBAAA,CAAoB,GAAK,EAAA,SAAA,EAAW,WAAW,CAAA,CAAA;AAAA,aAC/C,KAAO,EAAA;AACd,MAAM,MAAA,EAAE,IAAM,EAAA,OAAA,EAAY,GAAAE,cAAA,CAAQ,KAAK,CACnC,GAAA,KAAA,GACA,IAAI,KAAA,CAAM,2BAA2B,CAAA,CAAA;AAEzC,MAAO,OAAA,mBAAA,CAAoB,KAAK,SAAW,EAAA;AAAA,QACzC,IAAM,EAAA,wBAAA;AAAA,QACN,KAAA,EAAO,EAAE,IAAA,EAAM,OAAQ,EAAA;AAAA,OACxB,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AAAA,EAEA,MAAM,MAAO,CAAA,GAAA,EAAsB,GAAsC,EAAA;AACvE,IAAI,IAAA,CAAC,qBAAsB,CAAA,GAAG,CAAG,EAAA;AAC/B,MAAM,MAAA,IAAIC,2BAAoB,iCAAiC,CAAA,CAAA;AAAA,KACjE;AAEA,IAAI,IAAA,IAAA,CAAK,SAAS,MAAQ,EAAA;AACxB,MAAM,MAAA,YAAA,GAAe,IAAK,CAAA,yBAAA,CAA0B,GAAG,CAAA,CAAA;AACvD,MAAM,MAAA,aAAA,GAAoC,MAAO,CAAA,MAAA,CAAO,GAAK,EAAA;AAAA,QAC3D,YAAA;AAAA,OACD,CAAA,CAAA;AACD,MAAM,MAAA,IAAA,CAAK,QAAS,CAAA,MAAA,CAAO,aAAa,CAAA,CAAA;AAAA,KAC1C;AAGA,IAAM,MAAA,MAAA,GAAS,GAAI,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAC/B,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,eAAA,CAAgB,MAAM,CAAA,CAAA;AAChD,IAAK,IAAA,CAAA,wBAAA,CAAyB,KAAK,YAAY,CAAA,CAAA;AAE/C,IAAI,GAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,GAAI,EAAA,CAAA;AAAA,GACtB;AAAA,EAEA,MAAM,OAAQ,CAAA,GAAA,EAAsB,GAAsC,EAAA;AACxE,IAAI,IAAA,CAAC,qBAAsB,CAAA,GAAG,CAAG,EAAA;AAC/B,MAAM,MAAA,IAAIA,2BAAoB,iCAAiC,CAAA,CAAA;AAAA,KACjE;AAEA,IAAI,IAAA,CAAC,IAAK,CAAA,QAAA,CAAS,OAAS,EAAA;AAC1B,MAAA,MAAM,IAAIH,iBAAA;AAAA,QACR,CAAA,4CAAA,EAA+C,IAAK,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,OACxE,CAAA;AAAA,KACF;AAEA,IAAI,IAAA;AACF,MAAM,MAAA,YAAA,GAAe,IAAK,CAAA,yBAAA,CAA0B,GAAG,CAAA,CAAA;AAGvD,MAAA,IAAI,CAAC,YAAc,EAAA;AACjB,QAAM,MAAA,IAAIA,kBAAW,wBAAwB,CAAA,CAAA;AAAA,OAC/C;AAEA,MAAA,IAAI,KAAQ,GAAA,GAAA,CAAI,KAAM,CAAA,KAAA,EAAO,UAAc,IAAA,EAAA,CAAA;AAC3C,MAAI,IAAA,IAAA,CAAK,QAAQ,aAAe,EAAA;AAC9B,QAAQ,KAAA,GAAA,IAAA,CAAK,0BAA0B,GAAG,CAAA,CAAA;AAAA,OAC5C;AACA,MAAA,MAAM,aAAa,MAAO,CAAA,MAAA,CAAO,KAAK,EAAE,KAAA,EAAO,cAAc,CAAA,CAAA;AAG7D,MAAM,MAAA,EAAE,UAAU,YAAc,EAAA,eAAA,KAC9B,MAAM,IAAA,CAAK,QAAS,CAAA,OAAA,CAAQ,UAAiC,CAAA,CAAA;AAE/D,MAAM,MAAA,iBAAA,GAAoB,MAAM,IAAK,CAAA,gBAAA;AAAA,QACnC,QAAS,CAAA,iBAAA;AAAA,OACX,CAAA;AAEA,MAAI,IAAA,eAAA,IAAmB,oBAAoB,YAAc,EAAA;AACvD,QAAM,MAAA,MAAA,GAAS,GAAI,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAC/B,QAAM,MAAA,YAAA,GAAe,IAAK,CAAA,eAAA,CAAgB,MAAM,CAAA,CAAA;AAChD,QAAK,IAAA,CAAA,qBAAA,CAAsB,GAAK,EAAA,eAAA,EAAiB,YAAY,CAAA,CAAA;AAAA,OAC/D;AAEA,MAAI,GAAA,CAAA,MAAA,CAAO,GAAG,CAAE,CAAA,IAAA,CAAK,EAAE,GAAG,QAAA,EAAU,mBAAmB,CAAA,CAAA;AAAA,aAChD,KAAO,EAAA;AACd,MAAM,MAAA,IAAIG,0BAAoB,CAAA,gBAAA,EAAkB,KAAK,CAAA,CAAA;AAAA,KACvD;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBACZ,QACgD,EAAA;AAChD,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACT;AACA,IAAI,IAAA,CAAC,SAAS,KAAO,EAAA;AACnB,MAAM,MAAA,IAAIH,kBAAW,CAAuC,qCAAA,CAAA,CAAA,CAAA;AAAA,KAC9D;AAEA,IAAA,OAAO,iCAAiC,QAAQ,CAAA,CAAA;AAAA,GAClD;AAAA,EAEQ,cAAiB,GAAA,CACvB,GACA,EAAA,KAAA,EACA,YACG,KAAA;AACH,IAAA,GAAA,CAAI,OAAO,CAAG,EAAA,IAAA,CAAK,OAAQ,CAAA,UAAU,UAAU,KAAO,EAAA;AAAA,MACpD,MAAQ,EAAA,cAAA;AAAA,MACR,GAAG,IAAK,CAAA,iBAAA;AAAA,MACR,GAAG,YAAA;AAAA,MACH,IAAA,EAAM,CAAG,EAAA,YAAA,CAAa,IAAI,CAAA,QAAA,CAAA;AAAA,KAC3B,CAAA,CAAA;AAAA,GACH,CAAA;AAAA,EAEQ,qBAAwB,GAAA,CAC9B,GACA,EAAA,KAAA,EACA,YACG,KAAA;AACH,IAAA,GAAA,CAAI,OAAO,CAAG,EAAA,IAAA,CAAK,OAAQ,CAAA,UAAU,kBAAkB,KAAO,EAAA;AAAA,MAC5D,MAAQ,EAAA,gBAAA;AAAA,MACR,GAAG,IAAK,CAAA,iBAAA;AAAA,MACR,GAAG,YAAA;AAAA,KACJ,CAAA,CAAA;AAAA,GACH,CAAA;AAAA,EAEQ,yBAAA,GAA4B,CAAC,GAAyB,KAAA;AAC5D,IAAA,OAAO,IAAI,OAAQ,CAAA,CAAA,EAAG,IAAK,CAAA,OAAA,CAAQ,UAAU,CAAgB,cAAA,CAAA,CAAA,CAAA;AAAA,GAC/D,CAAA;AAAA,EAEQ,yBAAA,GAA4B,CAAC,GAAyB,KAAA;AAC5D,IAAA,OAAO,IAAI,OAAQ,CAAA,CAAA,EAAG,IAAK,CAAA,OAAA,CAAQ,UAAU,CAAgB,cAAA,CAAA,CAAA,CAAA;AAAA,GAC/D,CAAA;AAAA,EAEQ,qBAAwB,GAAA,CAC9B,GACA,EAAA,YAAA,EACA,YACG,KAAA;AACH,IAAA,GAAA,CAAI,OAAO,CAAG,EAAA,IAAA,CAAK,OAAQ,CAAA,UAAU,kBAAkB,YAAc,EAAA;AAAA,MACnE,MAAQ,EAAA,gBAAA;AAAA,MACR,GAAG,IAAK,CAAA,iBAAA;AAAA,MACR,GAAG,YAAA;AAAA,KACJ,CAAA,CAAA;AAAA,GACH,CAAA;AAAA,EAEQ,wBAAA,GAA2B,CACjC,GAAA,EACA,YACG,KAAA;AACH,IAAA,GAAA,CAAI,OAAO,CAAG,EAAA,IAAA,CAAK,OAAQ,CAAA,UAAU,kBAAkB,EAAI,EAAA;AAAA,MACzD,MAAQ,EAAA,CAAA;AAAA,MACR,GAAG,IAAK,CAAA,iBAAA;AAAA,MACR,GAAG,YAAA;AAAA,KACJ,CAAA,CAAA;AAAA,GACH,CAAA;AAAA,EAEQ,eAAA,GAAkB,CAAC,MAAoB,KAAA;AAC7C,IAAO,OAAA,IAAA,CAAK,QAAQ,gBAAiB,CAAA;AAAA,MACnC,UAAA,EAAY,KAAK,OAAQ,CAAA,UAAA;AAAA,MACzB,OAAA,EAAS,KAAK,OAAQ,CAAA,OAAA;AAAA,MACtB,WAAA,EAAa,KAAK,OAAQ,CAAA,WAAA;AAAA,MAC1B,SAAA,EAAW,MAAU,IAAA,IAAA,CAAK,OAAQ,CAAA,SAAA;AAAA,KACnC,CAAA,CAAA;AAAA,GACH,CAAA;AACF;;ACtUa,MAAA,eAAA,GAAkB,CAC7B,OAAA,EACA,OACgB,KAAA;AAChB,EAAA,IAAI,KAA4B,GAAA,KAAA,CAAA,CAAA;AAChC,EAAA,IAAI,OAAQ,CAAA,MAAA,IAAU,OAAQ,CAAA,MAAA,CAAO,SAAS,CAAG,EAAA;AAC/C,IAAM,MAAA,CAAC,UAAU,CAAA,GAAI,OAAQ,CAAA,MAAA,CAAA;AAC7B,IAAA,KAAA,GAAQ,UAAW,CAAA,KAAA,CAAA;AAAA,GACrB;AAEA,EAAA,IAAI,OAA8B,GAAA,KAAA,CAAA,CAAA;AAClC,EAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,IAAA,OAAA,GAAU,OAAQ,CAAA,SAAA,CAAA;AAAA,aACT,OAAQ,CAAA,MAAA,IAAU,OAAQ,CAAA,MAAA,CAAO,SAAS,CAAG,EAAA;AACtD,IAAM,MAAA,CAAC,UAAU,CAAA,GAAI,OAAQ,CAAA,MAAA,CAAA;AAC7B,IAAA,OAAA,GAAU,UAAW,CAAA,KAAA,CAAA;AAAA,GACvB;AAEA,EAAA,IAAI,WACF,GAAA,OAAA,CAAQ,WAAe,IAAA,OAAA,CAAQ,YAAY,OAAQ,CAAA,EAAA,CAAA;AAErD,EAAA,IAAA,CAAK,CAAC,KAAS,IAAA,CAAC,OAAW,IAAA,CAAC,gBAAgB,OAAS,EAAA;AACnD,IAAI,IAAA;AACF,MAAM,MAAA,OAAA,GAAUI,eAAU,OAAO,CAAA,CAAA;AAKjC,MAAI,IAAA,CAAC,KAAS,IAAA,OAAA,CAAQ,KAAO,EAAA;AAC3B,QAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAA;AAAA,OAClB;AACA,MAAI,IAAA,CAAC,OAAW,IAAA,OAAA,CAAQ,OAAS,EAAA;AAC/B,QAAA,OAAA,GAAU,OAAQ,CAAA,OAAA,CAAA;AAAA,OACpB;AACA,MAAI,IAAA,CAAC,WAAe,IAAA,OAAA,CAAQ,IAAM,EAAA;AAChC,QAAA,WAAA,GAAc,OAAQ,CAAA,IAAA,CAAA;AAAA,OACxB;AAAA,aACO,CAAG,EAAA;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAkD,+CAAA,EAAA,CAAC,CAAE,CAAA,CAAA,CAAA;AAAA,KACvE;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,KAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,GACF,CAAA;AACF,CAAA,CAAA;AAEO,MAAM,uBAA0B,GAAA,OACrC,GACA,EAAA,gBAAA,EACA,OACgC,KAAA;AAChC,EAAO,OAAA,IAAI,QAAQ,CAAW,OAAA,KAAA;AAC5B,IAAM,MAAA,QAAA,GAAW,MAAO,CAAA,MAAA,CAAO,gBAAgB,CAAA,CAAA;AAC/C,IAAS,QAAA,CAAA,QAAA,GAAW,CAAC,GAAA,EAAa,MAAoB,KAAA;AACpD,MAAA,OAAA,CAAQ,EAAE,GAAA,EAAK,MAAQ,EAAA,MAAA,IAAU,QAAW,CAAA,CAAA;AAAA,KAC9C,CAAA;AAEA,IAAA,QAAA,CAAS,YAAa,CAAA,GAAA,EAAK,EAAE,GAAG,SAAS,CAAA,CAAA;AAAA,GAC1C,CAAA,CAAA;AACH,CAAA,CAAA;AAEO,MAAM,2BAA8B,GAAA,OACzC,GACA,EAAA,gBAAA,EACA,OACG,KAAA;AACH,EAAA,OAAO,IAAI,OAAA;AAAA,IACT,CAAC,SAAS,MAAW,KAAA;AACnB,MAAM,MAAA,QAAA,GAAW,MAAO,CAAA,MAAA,CAAO,gBAAgB,CAAA,CAAA;AAC/C,MAAS,QAAA,CAAA,OAAA,GAAU,CAAC,MAAA,EAAa,WAAqB,KAAA;AACpD,QAAQ,OAAA,CAAA,EAAE,MAAQ,EAAA,WAAA,EAAa,CAAA,CAAA;AAAA,OACjC,CAAA;AACA,MAAS,QAAA,CAAA,IAAA,GAAO,CACd,IAEG,KAAA;AACH,QAAA,MAAA,CAAO,IAAI,KAAM,CAAA,CAAA,yBAAA,EAA4B,KAAK,OAAW,IAAA,EAAE,EAAE,CAAC,CAAA,CAAA;AAAA,OACpE,CAAA;AACA,MAAS,QAAA,CAAA,KAAA,GAAQ,CAAC,KAA8B,KAAA;AAC9C,QAAI,IAAA,OAAA,GAAU,CAA0B,uBAAA,EAAA,KAAA,CAAM,OAAO,CAAA,CAAA,CAAA;AAErD,QAAI,IAAA,KAAA,CAAM,YAAY,IAAM,EAAA;AAC1B,UAAI,IAAA;AACF,YAAA,MAAM,SAAY,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,WAAW,IAAI,CAAA,CAAA;AAElD,YAAA,IAAI,UAAU,OAAS,EAAA;AACrB,cAAW,OAAA,IAAA,CAAA,GAAA,EAAM,UAAU,OAAO,CAAA,CAAA,CAAA;AAAA,aACpC;AAAA,mBACO,UAAY,EAAA;AACnB,YAAW,OAAA,IAAA,CAAA,GAAA,EAAM,MAAM,UAAU,CAAA,CAAA,CAAA;AAAA,WACnC;AAAA,SACF;AAEA,QAAO,MAAA,CAAA,IAAI,KAAM,CAAA,OAAO,CAAC,CAAA,CAAA;AAAA,OAC3B,CAAA;AACA,MAAA,QAAA,CAAS,WAAW,MAAM;AACxB,QAAO,MAAA,CAAA,IAAI,KAAM,CAAA,qBAAqB,CAAC,CAAA,CAAA;AAAA,OACzC,CAAA;AACA,MAAA,QAAA,CAAS,aAAa,GAAK,EAAA,EAAE,GAAI,OAAW,IAAA,IAAK,CAAA,CAAA;AAAA,KACnD;AAAA,GACF,CAAA;AACF,CAAA,CAAA;AAcO,MAAM,2BAA8B,GAAA,OACzC,gBACA,EAAA,YAAA,EACA,KACkC,KAAA;AAClC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAW,KAAA;AACtC,IAAA,MAAM,WAAc,GAAA,gBAAA,CAAA;AACpB,IAAM,MAAA,MAAA,GAAS,YAAY,OAAQ,CAAA,WAAA,CAAA;AACnC,IAAA,MAAM,SAAS,IAAI,MAAA;AAAA,MACjB,YAAY,OAAQ,CAAA,SAAA;AAAA,MACpB,YAAY,OAAQ,CAAA,aAAA;AAAA,MACpB,YAAY,OAAQ,CAAA,SAAA;AAAA,MACpB,YAAY,OAAQ,CAAA,aAAA;AAAA,MACpB,WAAA,CAAY,WAAe,IAAA,WAAA,CAAY,OAAQ,CAAA,eAAA;AAAA,MAC/C,YAAY,OAAQ,CAAA,cAAA;AAAA,KACtB,CAAA;AAEA,IAAO,MAAA,CAAA,mBAAA;AAAA,MACL,YAAA;AAAA,MACA;AAAA,QACE,KAAA;AAAA,QACA,UAAY,EAAA,eAAA;AAAA,OACd;AAAA,MACA,CACE,GAAA,EACA,WACA,EAAA,eAAA,EACA,MACG,KAAA;AACH,QAAA,IAAI,GAAK,EAAA;AACP,UAAA,MAAA,CAAO,IAAI,KAAM,CAAA,CAAA,+BAAA,EAAkC,IAAI,QAAS,EAAC,EAAE,CAAC,CAAA,CAAA;AAAA,SACtE;AACA,QAAA,IAAI,CAAC,WAAa,EAAA;AAChB,UAAA,MAAA;AAAA,YACE,IAAI,KAAA;AAAA,cACF,CAAA,wDAAA,CAAA;AAAA,aACF;AAAA,WACF,CAAA;AAAA,SACF;AAEA,QAAQ,OAAA,CAAA;AAAA,UACN,WAAA;AAAA,UACA,YAAc,EAAA,eAAA;AAAA,UACd,MAAA;AAAA,SACD,CAAA,CAAA;AAAA,OACH;AAAA,KACF,CAAA;AAAA,GACD,CAAA,CAAA;AACH,CAAA,CAAA;AAMa,MAAA,+BAAA,GAAkC,OAC7C,gBAAA,EACA,WAC6B,KAAA;AAC7B,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAW,KAAA;AACtC,IAAA,MAAM,WAAc,GAAA,gBAAA,CAAA;AACpB,IAAY,WAAA,CAAA,WAAA;AAAA,MACV,WAAA;AAAA,MACA,CAAC,OAAc,UAAgC,KAAA;AAC7C,QAAA,IAAI,KAAO,EAAA;AACT,UAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AAAA,SACP,MAAA;AACL,UAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,SACpB;AAAA,OACF;AAAA,KACF,CAAA;AAAA,GACD,CAAA,CAAA;AACH,CAAA;;AC/JO,MAAM,iBAA2C,CAAA;AAAA,EACrC,SAAA,CAAA;AAAA,EACA,cAAA,CAAA;AAAA,EACA,WAAA,CAAA;AAAA,EACA,eAAA,CAAA;AAAA,EACA,QAAA,CAAA;AAAA,EACA,UAAA,CAAA;AAAA,EACA,eAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUT,KAAoB,GAAA;AAAA,IAC1B,KAAA,CAAM,MAAuB,EAAS,EAAA;AACpC,MAAA,EAAA,CAAG,MAAM,IAAI,CAAA,CAAA;AAAA,KACf;AAAA,IACA,MAAA,CAAO,IAAuB,EAAA,MAAA,EAAgB,EAAS,EAAA;AACrD,MAAA,EAAA,CAAG,MAAM,IAAI,CAAA,CAAA;AAAA,KACf;AAAA,GACF,CAAA;AAAA,EAEA,YAAY,OAAmC,EAAA;AAC7C,IAAA,IAAA,CAAK,iBAAiB,OAAQ,CAAA,cAAA,CAAA;AAC9B,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,kBAAkB,OAAQ,CAAA,eAAA,CAAA;AAC/B,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA,CAAA;AACxB,IAAA,IAAA,CAAK,aAAa,OAAQ,CAAA,UAAA,CAAA;AAC1B,IAAA,IAAA,CAAK,kBAAkB,OAAQ,CAAA,eAAA,CAAA;AAC/B,IAAA,IAAA,CAAK,YAAY,IAAI,aAAA;AAAA,MACnB;AAAA,QACE,UAAU,OAAQ,CAAA,QAAA;AAAA,QAClB,cAAc,OAAQ,CAAA,YAAA;AAAA,QACtB,aAAa,OAAQ,CAAA,WAAA;AAAA,QACrB,QAAQ,OAAQ,CAAA,MAAA;AAAA;AAAA;AAAA,QAGhB,iBAAmB,EAAA,KAAA;AAAA,QACnB,OAAO,IAAK,CAAA,KAAA;AAAA,OACd;AAAA,MACA,CACE,WAAA,EACA,YACA,EAAA,MAAA,EACA,aACA,IACG,KAAA;AACH,QAAA,IAAA;AAAA,UACE,KAAA,CAAA;AAAA,UACA;AAAA,YACE,WAAA;AAAA,YACA,WAAA;AAAA,YACA,YAAA;AAAA,YACA,MAAA;AAAA,WACF;AAAA,UACA;AAAA,YACE,YAAA;AAAA,WACF;AAAA,SACF,CAAA;AAAA,OACF;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,MAAM,GAAqD,EAAA;AAC/D,IAAA,OAAO,MAAM,uBAAA,CAAwB,GAAK,EAAA,IAAA,CAAK,SAAW,EAAA;AAAA,MACxD,UAAY,EAAA,SAAA;AAAA,MACZ,MAAQ,EAAA,SAAA;AAAA,MACR,OAAO,GAAI,CAAA,KAAA;AAAA,MACX,KAAA,EAAO,WAAY,CAAA,GAAA,CAAI,KAAK,CAAA;AAAA,MAC5B,GAAI,KAAK,QAAW,GAAA,EAAE,UAAU,IAAK,CAAA,QAAA,KAAa,EAAC;AAAA,MACnD,GAAI,KAAK,UAAa,GAAA,EAAE,YAAY,IAAK,CAAA,UAAA,KAAe,EAAC;AAAA,MACzD,GAAI,KAAK,eACL,GAAA,EAAE,kBAAkB,IAAK,CAAA,eAAA,KACzB,EAAC;AAAA,KACN,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,QAAQ,GAAsB,EAAA;AAClC,IAAM,MAAA,EAAE,QAAQ,WAAY,EAAA,GAAI,MAAM,2BAGpC,CAAA,GAAA,EAAK,KAAK,SAAW,EAAA;AAAA,MACrB,GAAI,KAAK,QAAW,GAAA,EAAE,UAAU,IAAK,CAAA,QAAA,KAAa,EAAC;AAAA,MACnD,GAAI,KAAK,UAAa,GAAA,EAAE,YAAY,IAAK,CAAA,UAAA,KAAe,EAAC;AAAA,MACzD,GAAI,KAAK,eACL,GAAA,EAAE,kBAAkB,IAAK,CAAA,eAAA,KACzB,EAAC;AAAA,KACN,CAAA,CAAA;AAED,IAAO,OAAA;AAAA,MACL,QAAU,EAAA,MAAM,IAAK,CAAA,YAAA,CAAa,MAAM,CAAA;AAAA,MACxC,cAAc,WAAY,CAAA,YAAA;AAAA,KAC5B,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,QAAQ,GAA0B,EAAA;AACtC,IAAA,MAAM,EAAE,WAAA,EAAa,YAAc,EAAA,MAAA,KACjC,MAAM,2BAAA;AAAA,MACJ,IAAK,CAAA,SAAA;AAAA,MACL,GAAI,CAAA,YAAA;AAAA,MACJ,GAAI,CAAA,KAAA;AAAA,KACN,CAAA;AAEF,IAAA,MAAM,cAAc,MAAM,+BAAA;AAAA,MACxB,IAAK,CAAA,SAAA;AAAA,MACL,WAAA;AAAA,KACF,CAAA;AAEA,IAAO,OAAA;AAAA,MACL,QAAA,EAAU,MAAM,IAAA,CAAK,YAAa,CAAA;AAAA,QAChC,WAAA;AAAA,QACA,MAAA;AAAA,QACA,WAAA;AAAA,OACD,CAAA;AAAA,MACD,YAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,MAAc,aAAa,MAAqB,EAAA;AAC9C,IAAM,MAAA,EAAE,SAAY,GAAA,MAAM,KAAK,WAAY,CAAA,MAAA,EAAQ,KAAK,eAAe,CAAA,CAAA;AAEvE,IAAA,MAAM,QAA0B,GAAA;AAAA,MAC9B,YAAc,EAAA;AAAA,QACZ,OAAA,EAAS,OAAO,MAAO,CAAA,QAAA;AAAA,QACvB,aAAa,MAAO,CAAA,WAAA;AAAA,QACpB,KAAA,EAAO,OAAO,MAAO,CAAA,KAAA;AAAA,QACrB,gBAAA,EAAkB,OAAO,MAAO,CAAA,UAAA;AAAA,OAClC;AAAA,MACA,OAAA;AAAA,KACF,CAAA;AAEA,IAAA,IAAI,KAAK,cAAgB,EAAA;AACvB,MAAS,QAAA,CAAA,iBAAA,GAAoB,MAAM,IAAK,CAAA,cAAA;AAAA,QACtC;AAAA,UACE,MAAA;AAAA,UACA,OAAA;AAAA,SACF;AAAA,QACA,IAAK,CAAA,eAAA;AAAA,OACP,CAAA;AAAA,KACF;AAEA,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AACF,CAAA;AAOO,MAAM,QAAQ,6BAA8B,CAAA;AAAA,EACjD,OAAO,OAgBJ,EAAA;AACD,IAAO,OAAA,CAAC,EAAE,UAAA,EAAY,YAAc,EAAA,MAAA,EAAQ,iBAC1C,KAAA,uBAAA,CAAwB,SAAU,CAAA,MAAA,EAAQ,CAAa,SAAA,KAAA;AACrD,MAAM,MAAA,QAAA,GAAW,SAAU,CAAA,SAAA,CAAU,UAAU,CAAA,CAAA;AAC/C,MAAM,MAAA,YAAA,GAAe,SAAU,CAAA,SAAA,CAAU,cAAc,CAAA,CAAA;AACvD,MAAM,MAAA,MAAA,GAAS,SAAU,CAAA,SAAA,CAAU,QAAQ,CAAA,CAAA;AAC3C,MAAM,MAAA,iBAAA,GAAoB,SAAU,CAAA,iBAAA,CAAkB,aAAa,CAAA,CAAA;AACnE,MAAM,MAAA,QAAA,GAAW,SAAU,CAAA,iBAAA,CAAkB,UAAU,CAAA,CAAA;AACvD,MAAM,MAAA,UAAA,GAAa,SAAU,CAAA,iBAAA,CAAkB,YAAY,CAAA,CAAA;AAC3D,MAAM,MAAA,eAAA,GAAkB,SAAU,CAAA,iBAAA,CAAkB,iBAAiB,CAAA,CAAA;AACrE,MAAA,MAAM,cACJ,iBACA,IAAA,CAAA,EAAG,YAAa,CAAA,OAAO,IAAI,UAAU,CAAA,cAAA,CAAA,CAAA;AAEvC,MAAM,MAAA,WAAA,GAAwC,SAAS,WACnD,GAAA,OAAA,CAAQ,cACR,OAAO,EAAE,WAAa,EAAA,MAAA,EAAc,MAAA;AAAA,QAClC,OAAS,EAAA,eAAA,CAAgB,WAAa,EAAA,MAAA,CAAO,QAAQ,CAAA;AAAA,OACvD,CAAA,CAAA;AAEJ,MAAM,MAAA,cAAA,GAAiB,SAAS,MAAQ,EAAA,QAAA,CAAA;AAExC,MAAM,MAAA,QAAA,GAAW,IAAI,iBAAkB,CAAA;AAAA,QACrC,QAAA;AAAA,QACA,YAAA;AAAA,QACA,WAAA;AAAA,QACA,MAAA;AAAA,QACA,WAAA;AAAA,QACA,cAAA;AAAA,QACA,eAAA;AAAA,QACA,QAAA;AAAA,QACA,UAAA;AAAA,QACA,eAAA;AAAA,OACD,CAAA,CAAA;AAED,MAAO,OAAA,YAAA,CAAa,UAAW,CAAA,YAAA,EAAc,QAAU,EAAA;AAAA,QACrD,UAAA;AAAA,QACA,WAAA;AAAA,OACD,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACL;AACF,CAAC,CAAA;;AChPM,MAAM,SAAS,6BAA8B,CAAA;AAAA,EAClD,OAAO,OAiBJ,EAAA;AACD,IAAA,OAAOC,6CAA+B,CAAA;AAAA,MACpC,aAAe,EAAAC,yDAAA;AAAA,MACf,kBAAkB,OAAS,EAAA,WAAA;AAAA,MAC3B,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,KAClC,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;ACeM,MAAM,YAAY,6BAA8B,CAAA;AAAA,EACrD,OAAO,OAaJ,EAAA;AACD,IAAA,OAAOf,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAAgB,+DAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AAAA,EACA,WAAW,gCAAiC,CAAA;AAAA,IAC1C,kCAAA,EACEC,kEAAyB,kCAAmC,EAAA;AAAA,IAC9D,oCAAA,EACEA,kEAAyB,oCAAqC,EAAA;AAAA,GACjE,CAAA;AACH,CAAC,CAAA;;AC6BM,MAAM,WAAW,6BAA8B,CAAA;AAAA,EACpD,OAAO,OAsBJ,EAAA;AACD,IAAA,OAAOH,6CAA+B,CAAA;AAAA,MACpC,eAAeI,mFAAoC,CAAA;AAAA,QACjD,OAAO,OAAQ,CAAA,KAAA;AAAA,OAChB,CAAA;AAAA,MACD,kBAAkB,OAAS,EAAA,WAAA;AAAA,MAC3B,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,MACjC,uBAAyB,EAAAC,+EAAA;AAAA,KAC1B,CAAA,CAAA;AAAA,GACH;AAAA,EACA,SAAW,EAAAA,+EAAA;AACb,CAAC,CAAA;;ACpIM,MAAM,SAAS,6BAA8B,CAAA;AAAA,EAClD,OAAO,OAkBJ,EAAA;AACD,IAAA,OAAOL,6CAA+B,CAAA;AAAA,MACpC,aAAe,EAAAM,yDAAA;AAAA,MACf,kBAAkB,OAAS,EAAA,WAAA;AAAA,MAC3B,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,KAClC,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;ACZM,MAAM,SAAS,6BAA8B,CAAA;AAAA,EAClD,OAAO,OAkCJ,EAAA;AACD,IAAA,MAAM,cAAc,OAAS,EAAA,WAAA,CAAA;AAC7B,IAAM,MAAA,cAAA,GAAiB,SAAS,MAAQ,EAAA,QAAA,CAAA;AACxC,IAAA,OAAOpB,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAAqB,yDAAA;AAAA,MACf,gBACE,EAAA,WAAA,KACE,OAAO,MAAA,EAAQ,GACf,KAAA,WAAA;AAAA,QACE;AAAA,UACE,aAAa,MAAO,CAAA,WAAA;AAAA,UACpB,WAAA,EAAa,OAAO,OAAQ,CAAA,WAAA;AAAA,UAC5B,MAAQ,EAAA;AAAA,YACN,KAAA,EAAO,OAAO,OAAQ,CAAA,KAAA;AAAA,YACtB,UAAA,EAAY,OAAO,OAAQ,CAAA,gBAAA,GACvB,OAAO,MAAO,CAAA,OAAA,CAAQ,gBAAgB,CACtC,GAAA,EAAA;AAAA,YACJ,wBAAA,EAA0B,OAAO,OAC9B,CAAA,4BAAA,GACC,OAAO,MAAO,CAAA,OAAA,CAAQ,4BAA4B,CAClD,GAAA,EAAA;AAAA,WACN;AAAA,SACF;AAAA,QACA,GAAA;AAAA,OACF,CAAA;AAAA,MACJ,gBACE,cACE,KAAA,OAAO,EAAE,OAAS,EAAA,MAAA,IAAU,GAC5B,KAAA,cAAA;AAAA,QACE;AAAA,UACE,OAAA;AAAA,UACA,MAAQ,EAAA;AAAA,YACN,aAAa,MAAO,CAAA,WAAA;AAAA,YACpB,WAAA,EAAa,OAAO,OAAQ,CAAA,WAAA;AAAA,YAC5B,YAAA,EAAc,OAAO,OAAQ,CAAA,YAAA;AAAA,YAC7B,MAAQ,EAAA;AAAA,cACN,KAAA,EAAO,OAAO,OAAQ,CAAA,KAAA;AAAA,cACtB,UAAA,EAAY,OAAO,OAAQ,CAAA,gBAAA,GACvB,OAAO,MAAO,CAAA,OAAA,CAAQ,gBAAgB,CACtC,GAAA,EAAA;AAAA,cACJ,wBAAA,EAA0B,OAAO,OAC9B,CAAA,4BAAA,GACC,OAAO,MAAO,CAAA,OAAA,CAAQ,4BAA4B,CAClD,GAAA,EAAA;AAAA,aACN;AAAA,WACF;AAAA,SACF;AAAA,QACA,GAAA;AAAA,OACF,CAAA;AAAA,KACL,CAAA,CAAA;AAAA,GACH;AAAA,EACA,SAAW,EAAA;AAAA;AAAA;AAAA;AAAA,IAIT,gCAAgC,MAAyC;AACvE,MAAO,OAAA,OAAO,MAAM,GAAQ,KAAA;AAC1B,QAAM,MAAA,EAAE,WAAY,EAAA,GAAI,IAAK,CAAA,MAAA,CAAA;AAE7B,QAAA,MAAM,SAAS,WAAY,CAAA,QAAA,CAAA;AAC3B,QAAA,IAAI,CAAC,MAAQ,EAAA;AACX,UAAM,MAAA,IAAI,MAAM,CAAiD,+CAAA,CAAA,CAAA,CAAA;AAAA,SACnE;AAEA,QAAO,OAAA,GAAA,CAAI,sBAAsB,EAAE,SAAA,EAAW,EAAE,IAAM,EAAA,MAAA,IAAU,CAAA,CAAA;AAAA,OAClE,CAAA;AAAA,KACF;AAAA,GACF;AACF,CAAC,CAAA;;ACjHM,MAAM,SAAS,6BAA8B,CAAA;AAAA,EAClD,OAAO,OAaJ,EAAA;AACD,IAAA,OAAOrB,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAAsB,yDAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;AChBM,MAAM,SAAS,6BAA8B,CAAA;AAAA,EAClD,OAAO,OAgBJ,EAAA;AACD,IAAA,OAAOtB,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAAuB,yDAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AAAA,EACA,WAAW,gCAAiC,CAAA;AAAA,IAC1C,oCAAA,EACEC,qCAAsB,oCAAqC,EAAA;AAAA,IAC7D,mCAAA,EACEA,qCAAsB,mCAAoC,EAAA;AAAA,IAC5D,iCAAA,EACEC,4DAAsB,iCAAkC,EAAA;AAAA,GAC3D,CAAA;AACH,CAAC,CAAA;;AChCM,MAAM,YAAY,6BAA8B,CAAA;AAAA,EACrD,OAAO,OAaJ,EAAA;AACD,IAAA,OAAOzB,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAA0B,+DAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AAAA,EACA,WAAW,gCAAiC,CAAA;AAAA,IAC1C,oCAAA,EACEF,qCAAsB,oCAAqC,EAAA;AAAA,IAC7D,mCAAA,EACEA,qCAAsB,mCAAoC,EAAA;AAAA,IAC5D,iCAAA,EACEG,kEAAyB,iCAAkC,EAAA;AAAA,IAC7D,kCAAA,EACEA,kEAAyB,kCAAmC,EAAA;AAAA,GAC/D,CAAA;AACH,CAAC,CAAA;;ACpCM,MAAM,SAAS,6BAA8B,CAAA;AAAA,EAClD,OAAO,OAMJ,EAAA;AACD,IAAA,OAAO3B,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAA4B,yDAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;AChBM,MAAM,cAAc,6BAA8B,CAAA;AAAA,EACvD,OAAO,OAmBJ,EAAA;AACD,IAAA,OAAOd,6CAA+B,CAAA;AAAA,MACpC,aAAe,EAAAe,mEAAA;AAAA,MACf,kBAAkB,OAAS,EAAA,WAAA;AAAA,MAC3B,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,KAClC,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;ACrCY,MAAA,8BAAA,GAA0D,OACrE,IAAA,EACA,GACG,KAAA;AACH,EAAM,MAAA,EAAE,SAAY,GAAA,IAAA,CAAA;AAEpB,EAAI,IAAA,CAAC,QAAQ,KAAO,EAAA;AAClB,IAAM,MAAA,IAAI,MAAM,sDAAsD,CAAA,CAAA;AAAA,GACxE;AACA,EAAA,MAAM,CAAC,SAAS,CAAA,GAAI,OAAQ,CAAA,KAAA,CAAM,MAAM,GAAG,CAAA,CAAA;AAE3C,EAAA,OAAO,IAAI,qBAAsB,CAAA;AAAA,IAC/B,SAAA,EAAW,EAAE,IAAA,EAAM,SAAU,EAAA;AAAA,GAC9B,CAAA,CAAA;AACH,CAAA,CAAA;AAMa,MAAA,qBAAA,GAAiD,OAC5D,IAAA,EACA,GACG,KAAA;AACH,EAAM,MAAA,EAAE,SAAY,GAAA,IAAA,CAAA;AAEpB,EAAI,IAAA,CAAC,QAAQ,KAAO,EAAA;AAClB,IAAM,MAAA,IAAI,MAAM,sDAAsD,CAAA,CAAA;AAAA,GACxE;AAEA,EAAA,OAAO,IAAI,qBAAsB,CAAA;AAAA,IAC/B,MAAQ,EAAA;AAAA,MACN,sBAAsB,OAAQ,CAAA,KAAA;AAAA,KAChC;AAAA,GACD,CAAA,CAAA;AACH,CAAA;;ACjBO,MAAM,OAAO,6BAA8B,CAAA;AAAA,EAChD,OAAO,OAcJ,EAAA;AACD,IAAA,MAAM,cAAc,OAAS,EAAA,WAAA,CAAA;AAC7B,IAAM,MAAA,cAAA,GAAiB,SAAS,MAAQ,EAAA,QAAA,CAAA;AACxC,IAAA,OAAO7B,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAA8B,qDAAA;AAAA,MACf,gBAAA,EACE,gBACC,CACC,MAAA,EACA,YACG,WAAY,CAAA,MAAA,CAAO,aAAa,OAAO,CAAA,CAAA;AAAA,MAC9C,cACE,EAAA,cAAA,KACC,CACC,IAAA,EACA,OAEA,KAAA,cAAA;AAAA,QACE;AAAA,UACE,MAAA,EAAQ,KAAK,MAAO,CAAA,WAAA;AAAA,UACpB,SAAS,IAAK,CAAA,OAAA;AAAA,SAChB;AAAA,QACA,OAAA;AAAA,OACF,CAAA;AAAA,KACL,CAAA,CAAA;AAAA,GACH;AAAA,EACA,SAAW,EAAA;AAAA;AAAA;AAAA;AAAA,IAIT,sCAAsC,MAAM,8BAAA;AAAA;AAAA;AAAA;AAAA,IAI5C,qCAAqC,MAAM,qBAAA;AAAA,GAC7C;AACF,CAAC,CAAA;;ACpDM,MAAM,OAAO,6BAA8B,CAAA;AAAA,EAChD,OAAO,OAYJ,EAAA;AACD,IAAA,OAAO9B,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAA+B,qDAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AAAA,EACA,SAAW,EAAA;AAAA;AAAA;AAAA;AAAA,IAIT,sCAAsC,MAAM,8BAAA;AAAA;AAAA;AAAA;AAAA,IAI5C,qCAAqC,MAAM,qBAAA;AAAA;AAAA;AAAA;AAAA,IAI3C,iCAAiE,GAAA;AAC/D,MAAO,OAAA,OAAO,MAAM,GAAQ,KAAA;AAC1B,QAAM,MAAA,EAAE,SAAY,GAAA,IAAA,CAAA;AAEpB,QAAI,IAAA,CAAC,QAAQ,KAAO,EAAA;AAClB,UAAM,MAAA,IAAI,MAAM,iCAAiC,CAAA,CAAA;AAAA,SACnD;AAEA,QAAA,OAAO,IAAI,qBAAsB,CAAA;AAAA,UAC/B,WAAa,EAAA;AAAA,YACX,kBAAkB,OAAQ,CAAA,KAAA;AAAA,WAC5B;AAAA,SACD,CAAA,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAAA,GACF;AACF,CAAC,CAAA;;ACrDM,MAAM,WAAW,6BAA8B,CAAA;AAAA,EACpD,OAAO,OAgBJ,EAAA;AACD,IAAA,OAAO/B,yCAA2B,CAAA;AAAA,MAChC,aAAe,EAAAgC,6DAAA;AAAA,MACf,gBAAA,EAAkB,uBAAwB,CAAA,OAAA,EAAS,WAAW,CAAA;AAAA,MAC9D,cAAgB,EAAA,8BAAA,CAA+B,OAAS,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,KACzE,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;ACPM,MAAM,gBAAsD,CAAA;AAAA,EAChD,QAAA,CAAA;AAAA,EACA,cAAA,CAAA;AAAA,EACA,WAAA,CAAA;AAAA,EACA,eAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EAEjB,YAAY,OAAkB,EAAA;AAC5B,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAA,IAAA,CAAK,iBAAiB,OAAQ,CAAA,cAAA,CAAA;AAC9B,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,kBAAkB,OAAQ,CAAA,eAAA,CAAA;AAE/B,IAAM,MAAA,QAAA,GAAiC,CACrC,OAAA,EACA,IACG,KAAA;AAMH,MAAA,IAAA,CAAK,IAAM,EAAA,EAAE,WAAa,EAAA,OAAA,EAAS,CAAA,CAAA;AAAA,KACrC,CAAA;AACA,IAAA,IAAA,CAAK,QAAW,GAAA,IAAIC,qBAAa,CAAA,OAAA,EAAS,UAAU,QAAQ,CAAA,CAAA;AAAA,GAC9D;AAAA,EAEA,MAAM,KAAM,CAAA,GAAA,EAAsB,GAAsC,EAAA;AACtE,IAAM,MAAA,EAAE,KAAQ,GAAA,MAAM,wBAAwB,GAAK,EAAA,IAAA,CAAK,QAAU,EAAA,EAAE,CAAA,CAAA;AACpE,IAAA,GAAA,CAAI,SAAS,GAAG,CAAA,CAAA;AAAA,GAClB;AAAA,EAEA,MAAM,YACJ,CAAA,GAAA,EACA,GACe,EAAA;AACf,IAAI,IAAA;AACF,MAAM,MAAA,EAAE,MAAO,EAAA,GAAI,MAAM,2BAAA;AAAA,QACvB,GAAA;AAAA,QACA,IAAK,CAAA,QAAA;AAAA,OACP,CAAA;AAEA,MAAM,MAAA,EAAE,SAAY,GAAA,MAAM,KAAK,WAAY,CAAA,MAAA,EAAQ,KAAK,eAAe,CAAA,CAAA;AAEvE,MAAA,MAAM,QAAmC,GAAA;AAAA,QACvC,OAAA;AAAA,QACA,cAAc,EAAC;AAAA,OACjB,CAAA;AAEA,MAAA,IAAI,KAAK,cAAgB,EAAA;AACvB,QAAM,MAAA,cAAA,GAAiB,MAAM,IAAK,CAAA,cAAA;AAAA,UAChC;AAAA,YACE,MAAA;AAAA,YACA,OAAA;AAAA,WACF;AAAA,UACA,IAAK,CAAA,eAAA;AAAA,SACP,CAAA;AAEA,QAAS,QAAA,CAAA,iBAAA,GACP,iCAAiC,cAAc,CAAA,CAAA;AAAA,OACnD;AAEA,MAAO,OAAA,mBAAA,CAAoB,GAAK,EAAA,IAAA,CAAK,MAAQ,EAAA;AAAA,QAC3C,IAAM,EAAA,wBAAA;AAAA,QACN,QAAA;AAAA,OACD,CAAA,CAAA;AAAA,aACM,KAAO,EAAA;AACd,MAAM,MAAA,EAAE,IAAM,EAAA,OAAA,EAAY,GAAAtB,cAAA,CAAQ,KAAK,CACnC,GAAA,KAAA,GACA,IAAI,KAAA,CAAM,2BAA2B,CAAA,CAAA;AACzC,MAAO,OAAA,mBAAA,CAAoB,GAAK,EAAA,IAAA,CAAK,MAAQ,EAAA;AAAA,QAC3C,IAAM,EAAA,wBAAA;AAAA,QACN,KAAA,EAAO,EAAE,IAAA,EAAM,OAAQ,EAAA;AAAA,OACxB,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AAAA,EAEA,MAAM,MAAO,CAAA,IAAA,EAAuB,GAAsC,EAAA;AACxE,IAAA,GAAA,CAAI,GAAI,EAAA,CAAA;AAAA,GACV;AACF,CAAA;AASO,MAAM,OAAO,6BAA8B,CAAA;AAAA,EAChD,OAAO,OAgBJ,EAAA;AACD,IAAA,OAAO,CAAC,EAAE,UAAA,EAAY,YAAc,EAAA,MAAA,EAAQ,iBAAsB,KAAA;AAChE,MAAM,MAAA,WAAA,GAA2C,SAAS,WACtD,GAAA,OAAA,CAAQ,cACR,OAAO,EAAE,aAAmB,MAAA;AAAA,QAC1B,OAAS,EAAA;AAAA,UACP,OAAO,WAAY,CAAA,KAAA;AAAA,UACnB,aAAa,WAAY,CAAA,WAAA;AAAA,SAC3B;AAAA,OACF,CAAA,CAAA;AAEJ,MAAA,OAAO,IAAI,gBAAiB,CAAA;AAAA,QAC1B,WAAa,EAAA,CAAA,EAAG,YAAa,CAAA,OAAO,IAAI,UAAU,CAAA,cAAA,CAAA;AAAA,QAClD,UAAA,EAAY,MAAO,CAAA,SAAA,CAAU,YAAY,CAAA;AAAA,QACzC,SAAA,EAAW,MAAO,CAAA,iBAAA,CAAkB,WAAW,CAAA;AAAA,QAC/C,QAAA,EAAU,MAAO,CAAA,SAAA,CAAU,UAAU,CAAA;AAAA,QACrC,MAAA,EAAQ,MAAO,CAAA,SAAA,CAAU,QAAQ,CAAA;AAAA,QACjC,IAAA,EAAM,MAAO,CAAA,SAAA,CAAU,MAAM,CAAA;AAAA,QAC7B,UAAA,EAAY,MAAO,CAAA,iBAAA,CAAkB,YAAY,CAAA;AAAA,QACjD,YAAA,EAAc,MAAO,CAAA,sBAAA,CAAuB,cAAc,CAAA;AAAA,QAC1D,gBAAA,EAAkB,MAAO,CAAA,iBAAA,CAAkB,kBAAkB,CAAA;AAAA,QAC7D,aAAA,EAAe,MAAO,CAAA,iBAAA,CAAkB,eAAe,CAAA;AAAA,QACvD,kBAAA,EAAoB,MAAO,CAAA,iBAAA,CAAkB,oBAAoB,CAAA;AAAA,QAGjE,eAAA,EAAiB,MAAO,CAAA,iBAAA,CAAkB,iBAAiB,CAAA;AAAA,QAC3D,mBAAA,EAAqB,MAAO,CAAA,iBAAA,CAAkB,qBAAqB,CAAA;AAAA,QACnE,yBAAyB,MAAO,CAAA,kBAAA;AAAA,UAC9B,yBAAA;AAAA,SACF;AAAA,QACA,oBAAA,EAAsB,MAAO,CAAA,kBAAA,CAAmB,sBAAsB,CAAA;AAAA,QACtE,QAAQ,YAAa,CAAA,MAAA;AAAA,QACrB,WAAA;AAAA,QACA,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,QACjC,eAAA;AAAA,OACD,CAAA,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AAAA,EACA,SAAW,EAAA;AAAA;AAAA;AAAA;AAAA,IAIT,4BAA+D,GAAA;AAC7D,MAAO,OAAA,OAAO,MAAM,GAAQ,KAAA;AAC1B,QAAM,MAAA,EAAA,GAAK,IAAK,CAAA,MAAA,CAAO,WAAY,CAAA,MAAA,CAAA;AAEnC,QAAA,IAAI,CAAC,EAAI,EAAA;AACP,UAAM,MAAA,IAAIC,2BAAoB,kCAAkC,CAAA,CAAA;AAAA,SAClE;AAEA,QAAA,OAAO,IAAI,qBAAsB,CAAA;AAAA,UAC/B,SAAA,EAAW,EAAE,IAAA,EAAM,EAAG,EAAA;AAAA,SACvB,CAAA,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAAA,GACF;AACF,CAAC,CAAA;;AC9IM,MAAM,2BAAqD,CAAA;AAAA,EAC/C,cAAA,CAAA;AAAA,EACA,WAAA,CAAA;AAAA,EACA,eAAA,CAAA;AAAA,EACA,QAAA,CAAA;AAAA,EACA,IAAA,CAAA;AAAA,EAEjB,YAAY,OAA6C,EAAA;AACvD,IAAA,IAAA,CAAK,iBAAiB,OAAQ,CAAA,cAAA,CAAA;AAC9B,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,kBAAkB,OAAQ,CAAA,eAAA,CAAA;AAC/B,IAAA,IAAA,CAAK,WAAW,IAAIsB,uBAAA;AAAA,MAClB;AAAA,QACE,kBAAkB,OAAQ,CAAA,gBAAA;AAAA,QAC1B,UAAU,OAAQ,CAAA,QAAA;AAAA,QAClB,UAAU,OAAQ,CAAA,QAAA;AAAA,QAClB,cAAc,OAAQ,CAAA,YAAA;AAAA,QACtB,aAAa,OAAQ,CAAA,WAAA;AAAA,OACvB;AAAA,MACA,CACE,WAAA,EACA,YACA,EAAA,MAAA,EACA,aACA,IACG,KAAA;AACH,QAAK,IAAA,CAAA,KAAA,CAAA,EAAW,EAAE,WAAa,EAAA,MAAA,EAAQ,aAAe,EAAA,EAAE,cAAc,CAAA,CAAA;AAAA,OACxE;AAAA,KACF,CAAA;AACA,IAAA,IAAA,CAAK,OAAO,OAAQ,CAAA,IAAA,CAAA;AAAA,GACtB;AAAA,EAEA,MAAM,MAAM,GAAqD,EAAA;AAC/D,IAAA,OAAO,MAAM,uBAAA,CAAwB,GAAK,EAAA,IAAA,CAAK,QAAU,EAAA;AAAA,MACvD,UAAY,EAAA,SAAA;AAAA,MACZ,MAAQ,EAAA,SAAA;AAAA,MACR,OAAO,GAAI,CAAA,KAAA;AAAA,MACX,KAAA,EAAO,WAAY,CAAA,GAAA,CAAI,KAAK,CAAA;AAAA,KAC7B,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,QACJ,GAC6D,EAAA;AAC7D,IAAM,MAAA,EAAE,QAAQ,WAAY,EAAA,GAAI,MAAM,2BAGpC,CAAA,GAAA,EAAK,KAAK,QAAQ,CAAA,CAAA;AAEpB,IAAO,OAAA;AAAA,MACL,QAAU,EAAA,MAAM,IAAK,CAAA,YAAA,CAAa,MAAM,CAAA;AAAA,MACxC,cAAc,WAAY,CAAA,YAAA;AAAA,KAC5B,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,QACJ,GAC6D,EAAA;AAC7D,IAAA,MAAM,EAAE,WAAA,EAAa,YAAc,EAAA,MAAA,KACjC,MAAM,2BAAA;AAAA,MACJ,IAAK,CAAA,QAAA;AAAA,MACL,GAAI,CAAA,YAAA;AAAA,MACJ,GAAI,CAAA,KAAA;AAAA,KACN,CAAA;AACF,IAAA,MAAM,cAAc,MAAM,+BAAA;AAAA,MACxB,IAAK,CAAA,QAAA;AAAA,MACL,WAAA;AAAA,KACF,CAAA;AACA,IAAO,OAAA;AAAA,MACL,QAAA,EAAU,MAAM,IAAA,CAAK,YAAa,CAAA;AAAA,QAChC,WAAA;AAAA,QACA,MAAA;AAAA,QACA,WAAA;AAAA,OACD,CAAA;AAAA,MACD,YAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,MAAc,aACZ,MACwB,EAAA;AAExB,IAAA,MAAA,CAAO,WAAc,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,MAAM,CAAA,CAAA;AACnD,IAAM,MAAA,EAAE,SAAY,GAAA,MAAM,KAAK,WAAY,CAAA,MAAA,EAAQ,KAAK,eAAe,CAAA,CAAA;AAEvE,IAAA,IAAI,iBAAoB,GAAA,KAAA,CAAA,CAAA;AACxB,IAAA,IAAI,KAAK,cAAgB,EAAA;AACvB,MAAA,iBAAA,GAAoB,MAAM,IAAK,CAAA,cAAA;AAAA,QAC7B,EAAE,QAAQ,OAAQ,EAAA;AAAA,QAClB,IAAK,CAAA,eAAA;AAAA,OACP,CAAA;AAAA,KACF;AAEA,IAAO,OAAA;AAAA,MACL,YAAc,EAAA;AAAA,QACZ,aAAa,MAAO,CAAA,WAAA;AAAA,QACpB,KAAA,EAAO,OAAO,MAAO,CAAA,KAAA;AAAA,QACrB,gBAAA,EAAkB,OAAO,MAAO,CAAA,UAAA;AAAA,OAClC;AAAA,MACA,OAAA;AAAA,MACA,iBAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,MAAc,aACZ,MAC0B,EAAA;AAE1B,IAAI,IAAA,cAAA,CAAA;AACJ,IAAI,IAAA;AACF,MAAA,cAAA,GAAiB,MAAMC,sBAAA;AAAA,QACrB,CAAA,QAAA,EAAW,KAAK,IAAI,CAAA,gCAAA,CAAA;AAAA,QACpB;AAAA,UACE,OAAS,EAAA;AAAA,YACP,aAAA,EAAe,CAAU,OAAA,EAAA,MAAA,CAAO,WAAW,CAAA,CAAA;AAAA,WAC7C;AAAA,SACF;AAAA,OACF,CAAA;AAAA,aACO,CAAG,EAAA;AACV,MAAM,MAAA,IAAI,MAAM,CAAuD,qDAAA,CAAA,CAAA,CAAA;AAAA,KACzE;AAGA,IAAA,MAAM,QAAW,GAAA,cAAA,CAAe,OAAQ,CAAA,GAAA,CAAI,aAAa,CAAA,CAAA;AACzD,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAM,MAAA,IAAI,MAAM,CAAuD,qDAAA,CAAA,CAAA,CAAA;AAAA,KACzE;AAEA,IAAI,IAAA,YAAA,CAAA;AACJ,IAAI,IAAA;AACF,MAAA,YAAA,GAAe,MAAMA,sBAAA;AAAA,QACnB,CAAW,QAAA,EAAA,IAAA,CAAK,IAAI,CAAA,uBAAA,EAA0B,QAAQ,CAAA,eAAA,CAAA;AAAA,QACtD;AAAA,UACE,OAAS,EAAA;AAAA,YACP,aAAA,EAAe,CAAU,OAAA,EAAA,MAAA,CAAO,WAAW,CAAA,CAAA;AAAA,WAC7C;AAAA,SACF;AAAA,OACF,CAAA;AAAA,aACO,CAAG,EAAA;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAgC,6BAAA,EAAA,QAAQ,CAAG,CAAA,CAAA,CAAA,CAAA;AAAA,KAC7D;AAEA,IAAI,IAAA,CAAC,aAAa,EAAI,EAAA;AACpB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAgC,6BAAA,EAAA,QAAQ,CAAG,CAAA,CAAA,CAAA,CAAA;AAAA,KAC7D;AAEA,IAAM,MAAA,IAAA,GAAO,MAAM,YAAA,CAAa,IAAK,EAAA,CAAA;AAErC,IAAA,MAAM,eAAkB,GAAA;AAAA,MACtB,QAAU,EAAA,iBAAA;AAAA,MACV,EAAA,EAAI,IAAK,CAAA,EAAA,CAAG,QAAS,EAAA;AAAA,MACrB,aAAa,IAAK,CAAA,WAAA;AAAA,MAClB,UAAU,IAAK,CAAA,IAAA;AAAA,MACf,MAAQ,EAAA;AAAA,QACN;AAAA,UACE,OAAO,IAAK,CAAA,YAAA;AAAA,SACd;AAAA,OACF;AAAA,KACF,CAAA;AAEA,IAAA,IAAI,KAAK,SAAW,EAAA;AAClB,MAAA,eAAA,CAAgB,MAAS,GAAA;AAAA,QACvB,EAAE,OAAO,CAAW,QAAA,EAAA,IAAA,CAAK,IAAI,CAAG,EAAA,IAAA,CAAK,SAAS,CAAG,CAAA,EAAA;AAAA,OACnD,CAAA;AAAA,KACF;AAEA,IAAO,OAAA,eAAA,CAAA;AAAA,GACT;AACF,CAAA;AAEO,MAAM,kBAAkB,6BAA8B,CAAA;AAAA,EAC3D,OAAO,OAgBJ,EAAA;AACD,IAAO,OAAA,CAAC,EAAE,UAAA,EAAY,YAAc,EAAA,MAAA,EAAQ,iBAC1C,KAAA,uBAAA,CAAwB,SAAU,CAAA,MAAA,EAAQ,CAAa,SAAA,KAAA;AACrD,MAAM,MAAA,QAAA,GAAW,SAAU,CAAA,SAAA,CAAU,UAAU,CAAA,CAAA;AAC/C,MAAM,MAAA,YAAA,GAAe,SAAU,CAAA,SAAA,CAAU,cAAc,CAAA,CAAA;AACvD,MAAM,MAAA,IAAA,GAAO,SAAU,CAAA,SAAA,CAAU,MAAM,CAAA,CAAA;AACvC,MAAM,MAAA,iBAAA,GAAoB,SAAU,CAAA,iBAAA,CAAkB,aAAa,CAAA,CAAA;AACnE,MAAA,MAAM,cACJ,iBACA,IAAA,CAAA,EAAG,YAAa,CAAA,OAAO,IAAI,UAAU,CAAA,cAAA,CAAA,CAAA;AACvC,MAAM,MAAA,gBAAA,GAAmB,WAAW,IAAI,CAAA,6BAAA,CAAA,CAAA;AACxC,MAAM,MAAA,QAAA,GAAW,WAAW,IAAI,CAAA,yBAAA,CAAA,CAAA;AAEhC,MAAM,MAAA,WAAA,GACJ,SAAS,WACL,GAAA,OAAA,CAAQ,cACR,OAAO,EAAE,aAAmB,MAAA;AAAA,QAC1B,OAAA,EAAS,gBAAgB,WAAW,CAAA;AAAA,OACtC,CAAA,CAAA;AAEN,MAAM,MAAA,QAAA,GAAW,IAAI,2BAA4B,CAAA;AAAA,QAC/C,WAAA;AAAA,QACA,QAAA;AAAA,QACA,YAAA;AAAA,QACA,IAAA;AAAA,QACA,gBAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,QACjC,eAAA;AAAA,OACD,CAAA,CAAA;AAED,MAAO,OAAA,YAAA,CAAa,UAAW,CAAA,YAAA,EAAc,QAAU,EAAA;AAAA,QACrD,UAAA;AAAA,QACA,WAAA;AAAA,OACD,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACL;AAAA,EACA,SAAW,EAAA;AAAA;AAAA;AAAA;AAAA,IAIT,qCACE,MAAkD,qBAAA;AAAA,GACtD;AACF,CAAC,CAAA;;AC7QM,MAAM,WAAW,6BAA8B,CAAA;AAAA,EACpD,OAAO,OAgBJ,EAAA;AACD,IAAA,OAAOrB,6CAA+B,CAAA;AAAA,MACpC,aAAe,EAAAsB,uEAAA;AAAA,MACf,kBAAkB,OAAS,EAAA,WAAA;AAAA,MAC3B,cAAA,EAAgB,SAAS,MAAQ,EAAA,QAAA;AAAA,KAClC,CAAA,CAAA;AAAA,GACH;AACF,CAAC,CAAA;;ACjBY,MAAA,SAAA,GAAY,OAAO,MAAO,CAAA;AAAA,EACrC,SAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,eAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AACF,CAAC,EAAA;AAOM,MAAM,4BAET,GAAA;AAAA,EACF,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,EACtB,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,EACtB,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,EACtB,IAAA,EAAM,KAAK,MAAO,EAAA;AAAA,EAClB,IAAA,EAAM,KAAK,MAAO,EAAA;AAAA,EAClB,KAAA,EAAO,MAAM,MAAO,EAAA;AAAA,EACpB,SAAA,EAAW,UAAU,MAAO,EAAA;AAAA,EAC5B,QAAA,EAAU,SAAS,MAAO,EAAA;AAAA,EAC1B,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,EACtB,IAAA,EAAM,KAAK,MAAO,EAAA;AAAA,EAClB,QAAA,EAAU,SAAS,MAAO,EAAA;AAAA,EAC1B,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,EACtB,SAAA,EAAW,UAAU,MAAO,EAAA;AAAA,EAC5B,eAAA,EAAiB,gBAAgB,MAAO,EAAA;AAAA,EACxC,SAAA,EAAW,UAAU,MAAO,EAAA;AAC9B;;AC5CO,MAAM,qBAAsB,CAAA;AAAA,EAChB,UAAA,CAAA;AAAA,EACA,IAAA,CAAA;AAAA,EAEjB,YAAY,OAMT,EAAA;AACD,IAAA,IAAA,CAAK,aAAa,OAAQ,CAAA,UAAA,CAAA;AAE1B,IAAM,MAAA,EAAE,IAAK,EAAA,GAAIC,sCAAyB,CAAA;AAAA,MACxC,MAAM,OAAQ,CAAA,IAAA;AAAA,MACd,UAAU,OAAQ,CAAA,QAAA;AAAA,MAClB,WAAW,OAAQ,CAAA,SAAA;AAAA,MACnB,cAAc,OAAQ,CAAA,YAAA;AAAA,KACvB,CAAA,CAAA;AAED,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AAAA,GACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,KAES,EAAA;AACtB,IAAA,MAAM,MAAiC,GAAA;AAAA,MACrC,IAAM,EAAA,MAAA;AAAA,KACR,CAAA;AACA,IAAW,KAAA,MAAA,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAQ,CAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AAC5D,MAAO,MAAA,CAAA,CAAA,qBAAA,EAAwB,GAAG,CAAA,CAAE,CAAI,GAAA,KAAA,CAAA;AAAA,KAC1C;AAEA,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,KAAK,qBAAsB,CAAA;AAAA,MACtD,UAAY,EAAA,MAAM,IAAK,CAAA,IAAA,CAAK,wBAAyB,EAAA;AAAA,MACrD,cAAgB,EAAA,SAAA;AAAA,KACjB,CAAA,CAAA;AAED,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,IAAK,CAAA,UAAA,CAAW,WAAY,CAAA,EAAE,MAAO,EAAA,EAAG,EAAE,KAAA,EAAO,CAAA,CAAA;AAEzE,IAAI,IAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AACtB,MAAI,IAAA,KAAA,CAAM,SAAS,CAAG,EAAA;AACpB,QAAM,MAAA,IAAIC,qBAAc,0CAA0C,CAAA,CAAA;AAAA,OAC7D,MAAA;AACL,QAAM,MAAA,IAAIC,qBAAc,gBAAgB,CAAA,CAAA;AAAA,OAC1C;AAAA,KACF;AAEA,IAAA,OAAO,MAAM,CAAC,CAAA,CAAA;AAAA,GAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,yBAAyB,KAGT,EAAA;AACpB,IAAM,MAAA,EAAE,UAAY,EAAA,MAAA,EAAW,GAAA,KAAA,CAAA;AAC/B,IAAA,MAAM,kBAAqB,GAAA,UAAA,CACxB,GAAI,CAAA,CAAC,GAAgB,KAAA;AACpB,MAAI,IAAA;AACF,QAAA,MAAM,SAAY,GAAAC,2BAAA,CAAe,GAAI,CAAA,iBAAA,CAAkB,OAAO,CAAG,EAAA;AAAA,UAC/D,WAAa,EAAA,MAAA;AAAA,UACb,gBAAkB,EAAA,SAAA;AAAA,SACnB,CAAA,CAAA;AACD,QAAO,OAAA,SAAA,CAAA;AAAA,OACD,CAAA,MAAA;AACN,QAAQ,MAAA,EAAA,IAAA,CAAK,CAAkC,+BAAA,EAAA,GAAG,CAAY,UAAA,CAAA,CAAA,CAAA;AAC9D,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,KACD,CACA,CAAA,MAAA,CAAO,CAAC,GAAA,KAAkC,QAAQ,IAAI,CAAA,CAAA;AAEzD,IAAM,MAAA,MAAA,GAAS,kBAAmB,CAAA,GAAA,CAAI,CAAQ,GAAA,MAAA;AAAA,MAC5C,MAAM,GAAI,CAAA,IAAA;AAAA,MACV,sBAAsB,GAAI,CAAA,SAAA;AAAA,MAC1B,iBAAiB,GAAI,CAAA,IAAA;AAAA,KACrB,CAAA,CAAA,CAAA;AAEF,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,KAAK,qBAAsB,CAAA;AAAA,MACtD,UAAY,EAAA,MAAM,IAAK,CAAA,IAAA,CAAK,wBAAyB,EAAA;AAAA,MACrD,cAAgB,EAAA,SAAA;AAAA,KACjB,CAAA,CAAA;AAED,IAAA,MAAM,QAAW,GAAA,MAAM,IAAK,CAAA,UAAA,CACzB,YAAY,EAAE,MAAA,EAAU,EAAA,EAAE,OAAO,CAAA,CACjC,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,KAAK,CAAA,CAAA;AAEpB,IAAI,IAAA,UAAA,CAAW,MAAW,KAAA,QAAA,CAAS,MAAQ,EAAA;AACzC,MAAM,MAAA,gBAAA,GAAmB,QAAS,CAAA,GAAA,CAAIC,+BAAkB,CAAA,CAAA;AACxD,MAAM,MAAA,kBAAA,GAAqB,kBACxB,CAAA,GAAA,CAAIA,+BAAkB,CAAA,CACtB,MAAO,CAAA,CAAA,CAAA,KAAK,CAAC,gBAAA,CAAiB,QAAS,CAAA,CAAC,CAAC,CAAA,CAAA;AAC5C,MAAA,MAAA,EAAQ,KAAM,CAAA,CAAA,4BAAA,EAA+B,kBAAmB,CAAA,IAAA,EAAM,CAAE,CAAA,CAAA,CAAA;AAAA,KAC1E;AAEA,IAAA,MAAM,WAAW,QAAS,CAAA,OAAA;AAAA,MACxB,CACE,CAAA,KAAA,CAAA,CAAG,SACC,EAAA,MAAA,CAAO,OAAK,CAAE,CAAA,IAAA,KAASC,+BAAkB,CAAA,CAC1C,GAAI,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,SAAS,KAAK,EAAC;AAAA,KACjC,CAAA;AAEA,IAAA,MAAM,aAAgB,GAAA;AAAA,MACpB,GAAG,IAAI,GAAI,CAAA,kBAAA,CAAmB,IAAID,+BAAkB,CAAA,CAAE,MAAO,CAAA,QAAQ,CAAC,CAAA;AAAA,KACxE,CAAA;AAEA,IAAA,MAAA,EAAQ,KAAM,CAAA,CAAA,0BAAA,EAA6B,aAAc,CAAA,IAAA,EAAM,CAAE,CAAA,CAAA,CAAA;AACjE,IAAO,OAAA,aAAA,CAAA;AAAA,GACT;AACF;;AChHO,SAAS,8BAA8B,MAAgB,EAAA;AAC5D,EAAM,MAAA,cAAA,GACJ,OAAO,SACH,EAAA,MAAA;AAAA,IACA,OAAK,CAAE,CAAA,IAAA,KAASC,mCAAsB,CAAE,CAAA,SAAA,CAAU,WAAW,QAAQ,CAAA;AAAA,IAEtE,GAAI,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,SAAS,KAAK,EAAC,CAAA;AAE/B,EAAO,OAAA,KAAA,CAAM,IAAK,iBAAA,IAAI,GAAI,CAAA,CAACD,+BAAmB,CAAA,MAAM,CAAG,EAAA,GAAG,cAAc,CAAC,CAAC,CAAA,CAAA;AAC5E,CAAA;AAKO,MAAM,0BAA0D,CAAA;AAAA,EA6B7D,YACU,MACA,EAAA,WAAA,EACA,qBACC,EAAA,UAAA,EACA,MACA,iBACjB,EAAA;AANgB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,qBAAA,GAAA,qBAAA,CAAA;AACC,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,iBAAA,GAAA,iBAAA,CAAA;AAAA,GAChB;AAAA,EAnCH,OAAO,OAAO,OASiB,EAAA;AAC7B,IAAM,MAAA,qBAAA,GAAwB,IAAI,qBAAsB,CAAA;AAAA,MACtD,YAAY,OAAQ,CAAA,UAAA;AAAA,MACpB,cAAc,OAAQ,CAAA,YAAA;AAAA,MACtB,WAAW,OAAQ,CAAA,SAAA;AAAA,MACnB,MAAM,OAAQ,CAAA,IAAA;AAAA,MACd,UAAU,OAAQ,CAAA,QAAA;AAAA,KACnB,CAAA,CAAA;AAED,IAAA,OAAO,IAAI,0BAAA;AAAA,MACT,OAAQ,CAAA,MAAA;AAAA,MACR,OAAQ,CAAA,WAAA;AAAA,MACR,qBAAA;AAAA,MACA,OAAQ,CAAA,UAAA;AAAA,MACR,OAAQ,CAAA,IAAA;AAAA,MACR,OAAQ,CAAA,iBAAA;AAAA,KACV,CAAA;AAAA,GACF;AAAA,EAWA,MAAM,WAAW,MAAqB,EAAA;AACpC,IAAA,MAAM,KAAQ,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,WAAW,MAAM,CAAA,CAAA;AACtD,IAAA,OAAO,EAAE,KAAM,EAAA,CAAA;AAAA,GACjB;AAAA,EAEA,MAAM,gBAAgB,KAAqC,EAAA;AACzD,IAAA,IAAI,MAAwC,GAAA,KAAA,CAAA,CAAA;AAC5C,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,KAAK,qBAAsB,CAAA;AAAA,MACtD,UAAY,EAAA,MAAM,IAAK,CAAA,IAAA,CAAK,wBAAyB,EAAA;AAAA,MACrD,cAAgB,EAAA,SAAA;AAAA,KACjB,CAAA,CAAA;AAED,IAAA,IAAI,eAAe,KAAO,EAAA;AACxB,MAAM,MAAA,SAAA,GAAYD,2BAAe,CAAA,KAAA,CAAM,SAAW,EAAA;AAAA,QAChD,WAAa,EAAA,MAAA;AAAA,QACb,gBAAkB,EAAAG,8BAAA;AAAA,OACnB,CAAA,CAAA;AACD,MAAA,MAAA,GAAS,MAAM,IAAK,CAAA,UAAA,CAAW,eAAe,SAAW,EAAA,EAAE,OAAO,CAAA,CAAA;AAAA,KACpE,MAAA,IAAW,iBAAiB,KAAO,EAAA;AACjC,MAAA,MAAM,MAAiC,GAAA;AAAA,QACrC,IAAM,EAAA,MAAA;AAAA,OACR,CAAA;AACA,MAAW,KAAA,MAAA,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAQ,CAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AAC5D,QAAO,MAAA,CAAA,CAAA,qBAAA,EAAwB,GAAG,CAAA,CAAE,CAAI,GAAA,KAAA,CAAA;AAAA,OAC1C;AACA,MAAM,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,UAAW,CAAA,WAAA,CAAY,EAAE,MAAO,EAAA,EAAG,EAAE,KAAA,EAAO,CAAA,CAAA;AACnE,MAAA,MAAA,GAAS,GAAI,CAAA,KAAA,CAAA;AAAA,KACf,MAAA,IAAW,YAAY,KAAO,EAAA;AAC5B,MAAM,MAAA,MAAA,GAAS,CAAC,KAAM,CAAA,MAAM,EAAE,IAAK,EAAA,CAAE,IAAI,CAAS,KAAA,KAAA;AAChD,QAAA,IACE,CAAC,MAAA,CAAO,IAAK,CAAA,KAAK,CAAE,CAAA,IAAA;AAAA,UAClB,CAAO,GAAA,KAAA,GAAA,CAAI,iBAAkB,CAAA,OAAO,CAAM,KAAA,MAAA;AAAA,SAE5C,EAAA;AACA,UAAO,OAAA;AAAA,YACL,GAAG,KAAA;AAAA,YACH,IAAM,EAAA,MAAA;AAAA,WACR,CAAA;AAAA,SACF;AACA,QAAO,OAAA,KAAA,CAAA;AAAA,OACR,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,UAAW,CAAA,WAAA;AAAA,QAChC,EAAE,MAAe,EAAA;AAAA,QACjB,EAAE,KAAM,EAAA;AAAA,OACV,CAAA;AACA,MAAA,MAAA,GAAS,GAAI,CAAA,KAAA,CAAA;AAAA,KACR,MAAA;AACL,MAAM,MAAA,IAAIlC,kBAAW,2BAA2B,CAAA,CAAA;AAAA,KAClD;AAEA,IAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,MAAM,CAAG,EAAA;AACzB,MAAI,IAAA,MAAA,CAAO,SAAS,CAAG,EAAA;AACrB,QAAM,MAAA,IAAI6B,qBAAc,0CAA0C,CAAA,CAAA;AAAA,OACpE;AACA,MAAA,MAAA,GAAS,OAAO,CAAC,CAAA,CAAA;AAAA,KACnB;AACA,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAM,MAAA,IAAIC,qBAAc,gBAAgB,CAAA,CAAA;AAAA,KAC1C;AAEA,IAAO,OAAA,EAAE,QAAQ,MAAO,EAAA,CAAA;AAAA,GAC1B;AAAA,EAEA,MAAM,sBAAsB,KAAqC,EAAA;AAC/D,IAAA,MAAM,EAAE,MAAO,EAAA,GAAI,MAAM,IAAA,CAAK,gBAAgB,KAAK,CAAA,CAAA;AACnD,IAAI,IAAA,GAAA,CAAA;AACJ,IAAA,IAAI,KAAK,iBAAmB,EAAA;AAC1B,MAAA,MAAM,EAAE,mBAAoB,EAAA,GAC1B,MAAM,IAAK,CAAA,iBAAA,CAAkB,2BAA2B,MAAM,CAAA,CAAA;AAChE,MAAM,GAAA,GAAA,mBAAA,CAAA;AAAA,KACD,MAAA;AACL,MAAA,GAAA,GAAM,8BAA8B,MAAM,CAAA,CAAA;AAAA,KAC5C;AAEA,IAAA,MAAM,KAAQ,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,UAAW,CAAA;AAAA,MAC9C,MAAQ,EAAA;AAAA,QACN,GAAA,EAAKE,gCAAmB,MAAM,CAAA;AAAA,QAC9B,GAAA;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AACD,IAAA,OAAO,EAAE,KAAM,EAAA,CAAA;AAAA,GACjB;AACF;;AC9IgB,SAAA,mBAAA,CACd,cACA,OAcA,EAAA;AACA,EAAM,MAAA;AAAA,IACJ,SAAA;AAAA,IACA,MAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,IAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,iBAAA;AAAA,GACE,GAAA,OAAA,CAAA;AAEJ,EAAM,MAAA,eAAA,GAAkB,MAAO,CAAA,iBAAA,CAAkB,gBAAgB,CAAA,CAAA;AAEjE,EAAM,MAAA,eAAA,GAAkB,mBAAmB,MAAM,CAAA,CAAA;AAEjD,EAAA,KAAA,MAAW,CAAC,UAAY,EAAA,eAAe,KAAK,MAAO,CAAA,OAAA,CAAQ,SAAS,CAAG,EAAA;AACrE,IAAI,IAAA,eAAA,EAAiB,GAAI,CAAA,UAAU,CAAG,EAAA;AACpC,MAAO,MAAA,CAAA,IAAA,CAAK,CAA8B,2BAAA,EAAA,UAAU,CAAE,CAAA,CAAA,CAAA;AACtD,MAAI,IAAA;AACF,QAAA,MAAM,WAAW,eAAgB,CAAA;AAAA,UAC/B,UAAA;AAAA,UACA,MAAA;AAAA,UACA,OAAA;AAAA,UACA,eAAA;AAAA,UACA,YAAc,EAAA;AAAA,YACZ,OAAA;AAAA,YACA,MAAA;AAAA,YACA,eAAA;AAAA,WACF;AAAA,UACA,MAAA,EAAQ,eAAgB,CAAA,SAAA,CAAU,UAAU,CAAA;AAAA,UAC5C,MAAA;AAAA,UACA,eAAA,EAAiB,2BAA2B,MAAO,CAAA;AAAA,YACjD,MAAA;AAAA,YACA,YACE,UAAc,IAAA,IAAIG,4BAAc,EAAE,YAAA,EAAc,WAAW,CAAA;AAAA,YAC7D,WAAA;AAAA,YACA,YAAA;AAAA,YACA,SAAA;AAAA,YACA,IAAA;AAAA,YACA,QAAA;AAAA,YACA,iBAAA;AAAA,WACD,CAAA;AAAA,SACF,CAAA,CAAA;AAED,QAAA,MAAM,IAAIC,uBAAO,EAAA,CAAA;AAEjB,QAAA,CAAA,CAAE,IAAI,QAAU,EAAA,QAAA,CAAS,KAAM,CAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA;AAC7C,QAAA,CAAA,CAAE,IAAI,gBAAkB,EAAA,QAAA,CAAS,YAAa,CAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA;AAC5D,QAAA,CAAA,CAAE,KAAK,gBAAkB,EAAA,QAAA,CAAS,YAAa,CAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA;AAC7D,QAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,UAAA,CAAA,CAAE,KAAK,SAAW,EAAA,QAAA,CAAS,MAAO,CAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA;AAAA,SAClD;AACA,QAAA,IAAI,SAAS,OAAS,EAAA;AACpB,UAAA,CAAA,CAAE,IAAI,UAAY,EAAA,QAAA,CAAS,OAAQ,CAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA;AACjD,UAAA,CAAA,CAAE,KAAK,UAAY,EAAA,QAAA,CAAS,OAAQ,CAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA;AAAA,SACpD;AAEA,QAAA,YAAA,CAAa,GAAI,CAAA,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AAAA,eAC7B,CAAG,EAAA;AACV,QAAAC,kBAAA,CAAY,CAAC,CAAA,CAAA;AACb,QAAI,IAAA,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,aAAe,EAAA;AAC1C,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAwB,qBAAA,EAAA,UAAU,CAAmB,gBAAA,EAAA,CAAA,CAAE,OAAO,CAAA,CAAA;AAAA,WAChE,CAAA;AAAA,SACF;AAEA,QAAA,MAAA,CAAO,KAAK,CAAY,SAAA,EAAA,UAAU,CAAmB,gBAAA,EAAA,CAAA,CAAE,OAAO,CAAE,CAAA,CAAA,CAAA;AAEhE,QAAA,YAAA,CAAa,GAAI,CAAA,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,EAAI,MAAM;AAEvC,UAAA,MAAM,IAAIP,oBAAA;AAAA,YACR,CAAA,8BAAA,EAAiC,UAAU,CAAA,qEAAA,EACvB,UAAU,CAAA,+IAAA,CAAA;AAAA,WAEhC,CAAA;AAAA,SACD,CAAA,CAAA;AAAA,OACH;AAAA,KACK,MAAA;AACL,MAAA,YAAA,CAAa,GAAI,CAAA,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,EAAI,MAAM;AACvC,QAAA,MAAM,IAAIA,oBAAA;AAAA,UACR,oCAAoC,UAAU,CAAA,CAAA,CAAA;AAAA,SAChD,CAAA;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AACF,CAAA;AAGO,SAAS,mBACd,MAC6B,EAAA;AAC7B,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,SAAA,CAAU,aAAa,CAAA,CAAA;AAC7C,EAAA,MAAM,EAAE,MAAQ,EAAA,SAAA,EAAc,GAAA,IAAI,IAAI,MAAM,CAAA,CAAA;AAE5C,EAAA,MAAM,iBAAiB,MAAO,CAAA,sBAAA;AAAA,IAC5B,sCAAA;AAAA,GACF,CAAA;AAEA,EAAA,MAAM,wBACJ,cAAgB,EAAA,GAAA;AAAA,IACd,CAAA,OAAA,KAAW,IAAIQ,mBAAU,CAAA,OAAA,EAAS,EAAE,MAAQ,EAAA,IAAA,EAAM,UAAY,EAAA,IAAA,EAAM,CAAA;AAAA,OACjE,EAAC,CAAA;AAER,EAAA,OAAO,CAAU,MAAA,KAAA;AACf,IAAA,IAAI,WAAW,SAAW,EAAA;AACxB,MAAO,OAAA,IAAA,CAAA;AAAA,KACT;AACA,IAAA,OAAO,sBAAsB,IAAK,CAAA,CAAA,OAAA,KAAW,OAAQ,CAAA,KAAA,CAAM,MAAM,CAAC,CAAA,CAAA;AAAA,GACpE,CAAA;AACF;;ACnJgB,SAAA,cAAA,CACd,cACA,OAMA,EAAA;AACA,EAAA,MAAM,EAAE,OAAA,EAAS,IAAM,EAAA,WAAA,EAAa,yBAA4B,GAAA,OAAA,CAAA;AAEhE,EAAA,MAAM,SAASF,uBAAO,EAAA,CAAA;AACtB,EAAA,YAAA,CAAa,IAAI,MAAM,CAAA,CAAA;AAEvB,EAAA,MAAM,MAAS,GAAA;AAAA,IACb,MAAQ,EAAA,OAAA;AAAA,IACR,cAAA,EAAgB,GAAG,OAAO,CAAA,SAAA,CAAA;AAAA,IAC1B,iBAAA,EAAmB,GAAG,OAAO,CAAA,YAAA,CAAA;AAAA,IAC7B,QAAA,EAAU,GAAG,OAAO,CAAA,sBAAA,CAAA;AAAA,IACpB,wBAAA,EAA0B,CAAC,UAAU,CAAA;AAAA,IACrC,uBAAA,EAAyB,CAAC,QAAQ,CAAA;AAAA,IAClC,qCAAuC,EAAA;AAAA,MACrC,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,KACF;AAAA,IACA,gBAAA,EAAkB,CAAC,QAAQ,CAAA;AAAA,IAC3B,uCAAuC,EAAC;AAAA,IACxC,gBAAA,EAAkB,CAAC,KAAA,EAAO,KAAK,CAAA;AAAA,IAC/B,uBAAuB,EAAC;AAAA,GAC1B,CAAA;AAEA,EAAA,MAAA,CAAO,GAAI,CAAA,mCAAA,EAAqC,CAAC,IAAA,EAAM,GAAQ,KAAA;AAC7D,IAAA,GAAA,CAAI,KAAK,MAAM,CAAA,CAAA;AAAA,GAChB,CAAA,CAAA;AAED,EAAA,MAAA,CAAO,GAAI,CAAA,wBAAA,EAA0B,OAAO,IAAA,EAAM,GAAQ,KAAA;AACxD,IAAA,MAAM,EAAE,IAAA,EAAS,GAAA,MAAM,YAAY,cAAe,EAAA,CAAA;AAClD,IAAI,GAAA,CAAA,IAAA,CAAK,EAAE,IAAA,EAAM,CAAA,CAAA;AAAA,GAClB,CAAA,CAAA;AAED,EAAA,MAAA,CAAO,GAAI,CAAA,WAAA,EAAa,CAAC,IAAA,EAAM,GAAQ,KAAA;AACrC,IAAA,GAAA,CAAI,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,iBAAiB,CAAA,CAAA;AAAA,GACvC,CAAA,CAAA;AAKD,EAAA,MAAA,CAAO,GAAI,CAAA,cAAA,EAAgB,OAAO,GAAA,EAAK,GAAQ,KAAA;AAC7C,IAAA,MAAM,OAAU,GAAA,GAAA,CAAI,OAAQ,CAAA,aAAA,EAAe,MAAM,oBAAoB,CAAA,CAAA;AACrE,IAAM,MAAA,KAAA,GAAQ,UAAU,CAAC,CAAA,CAAA;AACzB,IAAA,IAAI,CAAC,KAAO,EAAA;AACV,MAAM,MAAA,IAAIjC,2BAAoB,mBAAmB,CAAA,CAAA;AAAA,KACnD;AAEA,IAAA,MAAM,WAAc,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,KAAO,EAAA;AAAA,MACjD,kBAAoB,EAAA,IAAA;AAAA,KACrB,CAAA,CAAA;AACD,IAAA,IAAI,CAAC,IAAA,CAAK,WAAY,CAAA,WAAA,EAAa,MAAM,CAAG,EAAA;AAC1C,MAAA,MAAM,IAAIH,iBAAA;AAAA,QACR,gFAAA;AAAA,OACF,CAAA;AAAA,KACF;AAEA,IAAA,MAAM,EAAE,GAAA,EAAK,aAAc,EAAA,GAAII,eAAU,KAAK,CAAA,CAAA;AAE9C,IAAI,IAAA,OAAO,kBAAkB,QAAU,EAAA;AACrC,MAAM,MAAA,IAAI,MAAM,sDAAsD,CAAA,CAAA;AAAA,KACxE;AAEA,IAAA,MAAM,QAAW,GAAA,MAAM,uBAAwB,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AACxE,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAA,GAAA,CAAI,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,qBAAqB,CAAA,CAAA;AAC1C,MAAA,OAAA;AAAA,KACF;AAEA,IAAA,GAAA,CAAI,KAAK,QAAQ,CAAA,CAAA;AAAA,GAClB,CAAA,CAAA;AACH;;ACzEA,MAAMmC,SAAU,GAAA,GAAA,CAAA;AAChB,MAAM,gBAAmB,GAAA,KAAA,CAAA;AAqGlB,MAAM,YAAoC,CAAA;AAAA,EAC9B,MAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EACA,QAAA,CAAA;AAAA,EACA,kBAAA,CAAA;AAAA,EACA,SAAA,CAAA;AAAA,EACA,uBAAA,CAAA;AAAA,EAET,SAAA,CAAA;AAAA,EACA,iBAAA,CAAA;AAAA,EAER,YAAY,OAAkB,EAAA;AAC5B,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA,CAAA;AACxB,IAAA,IAAA,CAAK,qBAAqB,OAAQ,CAAA,kBAAA,CAAA;AAClC,IAAK,IAAA,CAAA,SAAA,GAAY,QAAQ,SAAa,IAAA,OAAA,CAAA;AACtC,IAAA,IAAA,CAAK,0BAA0B,OAAQ,CAAA,uBAAA,CAAA;AAAA,GACzC;AAAA,EAEA,MAAM,WAAW,MAAsC,EAAA;AACrD,IAAM,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,MAAO,EAAA,CAAA;AAE9B,IAAA,MAAM,MAAM,IAAK,CAAA,MAAA,CAAA;AACjB,IAAM,MAAA,EAAE,KAAK,GAAM,GAAA,CAAC,GAAG,CAAG,EAAA,GAAG,gBAAiB,EAAA,GAAI,MAAO,CAAA,MAAA,CAAA;AACzD,IAAM,MAAA,GAAA,GAAMC,0BAAW,IAAK,CAAA,QAAA,CAAA;AAC5B,IAAA,MAAM,MAAM,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,KAAQD,SAAO,CAAA,CAAA;AAC3C,IAAM,MAAA,GAAA,GAAM,MAAM,IAAK,CAAA,kBAAA,CAAA;AAEvB,IAAI,IAAA;AAEF,MAAAR,2BAAA,CAAe,GAAG,CAAA,CAAA;AAAA,aACX,KAAO,EAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,qEAAA;AAAA,OACF,CAAA;AAAA,KACF;AAEA,IAAI,IAAA,CAAC,IAAI,GAAK,EAAA;AACZ,MAAM,MAAA,IAAI5B,2BAAoB,sCAAsC,CAAA,CAAA;AAAA,KACtE;AAEA,IAAA,IAAA,CAAK,OAAO,IAAK,CAAA,CAAA,kBAAA,EAAqB,GAAG,CAAA,gBAAA,EAAmB,GAAG,CAAE,CAAA,CAAA,CAAA;AAEjE,IAAM,MAAA,UAAA,GAAa,MAAMsC,cAAA,CAAU,GAAG,CAAA,CAAA;AAEtC,IAAM,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,uBAAwB,CAAA;AAAA,MAC7C,MAAQ,EAAA;AAAA,QACN,GAAA,EAAKD,0BAAW,WAAY,CAAA,QAAA;AAAA,QAC5B,KAAK,GAAI,CAAA,GAAA;AAAA,QACT,KAAK,GAAI,CAAA,GAAA;AAAA,OACX;AAAA,MACA,OAAS,EAAA,EAAE,GAAK,EAAA,GAAA,EAAK,GAAI,EAAA;AAAA,MACzB,GAAK,EAAA,UAAA;AAAA,KACN,CAAA,CAAA;AAED,IAAA,MAAM,MAAgC,GAAA;AAAA,MACpC,GAAG,gBAAA;AAAA,MACH,GAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAA;AAAA,KACF,CAAA;AAEA,IAAA,MAAM,QAAQ,MAAM,IAAIE,YAAQ,CAAA,MAAM,EACnC,kBAAmB,CAAA;AAAA,MAClB,GAAA,EAAKF,0BAAW,IAAK,CAAA,QAAA;AAAA,MACrB,KAAK,GAAI,CAAA,GAAA;AAAA,MACT,KAAK,GAAI,CAAA,GAAA;AAAA,KACV,CACA,CAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAElB,IAAI,IAAA,KAAA,CAAM,SAAS,gBAAkB,EAAA;AACnC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,6PAA6P,IAAK,CAAA,SAAA;AAAA,UAChQ,MAAA;AAAA,SACD,CAAA,CAAA,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAIA,IAAM,MAAA,IAAA,CAAK,wBAAwB,WAAY,CAAA;AAAA,MAC7C,MAAA,EAAQG,YAAK,MAAQ,EAAA,CAAC,OAAO,KAAO,EAAA,KAAA,EAAO,KAAK,CAAC,CAAA;AAAA,KAClD,CAAA,CAAA;AAED,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAA8C,GAAA;AAClD,IAAA,MAAM,EAAE,KAAO,EAAA,IAAA,KAAS,MAAM,IAAA,CAAK,SAAS,QAAS,EAAA,CAAA;AAErD,IAAA,MAAM,YAAY,EAAC,CAAA;AACnB,IAAA,MAAM,cAAc,EAAC,CAAA;AAErB,IAAA,KAAA,MAAW,OAAO,IAAM,EAAA;AAEtB,MAAA,MAAM,WAAWC,cAAS,CAAA,UAAA,CAAW,GAAI,CAAA,SAAS,EAAE,IAAK,CAAA;AAAA,QACvD,OAAA,EAAS,IAAI,IAAK,CAAA,kBAAA;AAAA,OACnB,CAAA,CAAA;AACD,MAAI,IAAA,QAAA,GAAWA,cAAS,CAAA,KAAA,EAAS,EAAA;AAC/B,QAAA,WAAA,CAAY,KAAK,GAAG,CAAA,CAAA;AAAA,OACf,MAAA;AACL,QAAA,SAAA,CAAU,KAAK,GAAG,CAAA,CAAA;AAAA,OACpB;AAAA,KACF;AAGA,IAAI,IAAA,WAAA,CAAY,SAAS,CAAG,EAAA;AAC1B,MAAM,MAAA,IAAA,GAAO,YAAY,GAAI,CAAA,CAAC,EAAE,GAAI,EAAA,KAAM,IAAI,GAAG,CAAA,CAAA;AAEjD,MAAA,IAAA,CAAK,OAAO,IAAK,CAAA,CAAA,gCAAA,EAAmC,KAAK,IAAK,CAAA,MAAM,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA;AAGxE,MAAA,IAAA,CAAK,QAAS,CAAA,UAAA,CAAW,IAAI,CAAA,CAAE,MAAM,CAAS,KAAA,KAAA;AAC5C,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,CAAkC,+BAAA,EAAA,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,OAC5D,CAAA,CAAA;AAAA,KACH;AAGA,IAAO,OAAA,EAAE,MAAM,SAAU,CAAA,GAAA,CAAI,CAAC,EAAE,GAAA,EAAU,KAAA,GAAG,CAAE,EAAA,CAAA;AAAA,GACjD;AAAA,EAEA,MAAc,MAAuB,GAAA;AAEnC,IAAA,IAAI,KAAK,iBAAmB,EAAA;AAC1B,MACE,IAAA,IAAA,CAAK,aACLA,cAAS,CAAA,UAAA,CAAW,KAAK,SAAS,CAAA,GAAIA,cAAS,CAAA,KAAA,EAC/C,EAAA;AACA,QAAA,OAAO,IAAK,CAAA,iBAAA,CAAA;AAAA,OACd;AACA,MAAK,IAAA,CAAA,MAAA,CAAO,KAAK,CAA6C,2CAAA,CAAA,CAAA,CAAA;AAC9D,MAAA,OAAO,IAAK,CAAA,iBAAA,CAAA;AAAA,KACd;AAEA,IAAA,IAAA,CAAK,SAAY,GAAAA,cAAA,CAAS,GAAI,EAAA,CAC3B,IAAK,CAAA;AAAA,MACJ,SAAS,IAAK,CAAA,kBAAA;AAAA,KACf,EACA,QAAS,EAAA,CAAA;AACZ,IAAA,MAAM,WAAW,YAAY;AAE3B,MAAA,MAAM,GAAM,GAAA,MAAMC,oBAAgB,CAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAChD,MAAA,MAAM,SAAY,GAAA,MAAMC,cAAU,CAAA,GAAA,CAAI,SAAS,CAAA,CAAA;AAC/C,MAAA,MAAM,UAAa,GAAA,MAAMA,cAAU,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AACjD,MAAU,SAAA,CAAA,GAAA,GAAM,UAAW,CAAA,GAAA,GAAMC,OAAK,EAAA,CAAA;AACtC,MAAU,SAAA,CAAA,GAAA,GAAM,UAAW,CAAA,GAAA,GAAM,IAAK,CAAA,SAAA,CAAA;AAQtC,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAA2B,wBAAA,EAAA,SAAA,CAAU,GAAG,CAAE,CAAA,CAAA,CAAA;AAC3D,MAAM,MAAA,IAAA,CAAK,QAAS,CAAA,MAAA,CAAO,SAAmB,CAAA,CAAA;AAG9C,MAAO,OAAA,UAAA,CAAA;AAAA,KACN,GAAA,CAAA;AAEH,IAAA,IAAA,CAAK,iBAAoB,GAAA,OAAA,CAAA;AAEzB,IAAI,IAAA;AAGF,MAAM,MAAA,OAAA,CAAA;AAAA,aACC,KAAO,EAAA;AACd,MAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,CAAuC,oCAAA,EAAA,KAAK,CAAE,CAAA,CAAA,CAAA;AAChE,MAAA,OAAO,IAAK,CAAA,SAAA,CAAA;AACZ,MAAA,OAAO,IAAK,CAAA,iBAAA,CAAA;AAAA,KACd;AAEA,IAAO,OAAA,OAAA,CAAA;AAAA,GACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBAAwB,OAQlB,EAAA;AAQlB,IAAA,MAAM,MAAS,GAAA;AAAA,MACb,GAAA,EAAK,QAAQ,MAAO,CAAA,GAAA;AAAA,MACpB,GAAA,EAAK,QAAQ,MAAO,CAAA,GAAA;AAAA,MACpB,GAAI,OAAQ,CAAA,MAAA,CAAO,GAAM,GAAA,EAAE,KAAK,OAAQ,CAAA,MAAA,CAAO,GAAI,EAAA,GAAI,EAAC;AAAA,KAC1D,CAAA;AAEA,IAAA,MAAM,OAAU,GAAA;AAAA,MACd,GAAA,EAAK,QAAQ,OAAQ,CAAA,GAAA;AAAA,MACrB,GAAA,EAAK,QAAQ,OAAQ,CAAA,GAAA;AAAA,MACrB,GAAA,EAAK,QAAQ,OAAQ,CAAA,GAAA;AAAA,KACvB,CAAA;AAEA,IAAM,MAAA,GAAA,GAAM,MAAM,IAAIC,gBAAA;AAAA,MACpB,IAAI,WAAY,EAAA,CAAE,OAAO,IAAK,CAAA,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,KAClD,CACG,YAAa,CAAA,OAAA,CAAQ,GAAG,CAAA,CACxB,mBAAmB,MAAM,CAAA,CACzB,IAAK,EAAA,CACL,IAAK,EAAA,CAAA;AAER,IAAO,OAAA,GAAA,CAAI,UAAW,CAAA,CAAC,CAAE,CAAA,SAAA,CAAA;AAAA,GAC3B;AACF;;ACtVA,MAAMC,OAAQ,GAAA,cAAA,CAAA;AAQd,MAAM,SAAA,GAAY,CAAC,IAAwB,KAAA;AACzC,EAAA,MAAM,UACJ,GAAA,OAAO,IAAS,KAAA,QAAA,GACZL,eAAS,OAAQ,CAAA,IAAA,EAAM,EAAE,IAAA,EAAM,KAAM,EAAC,CACtC,GAAAA,cAAA,CAAS,WAAW,IAAI,CAAA,CAAA;AAE9B,EAAI,IAAA,CAAC,WAAW,OAAS,EAAA;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAiC,8BAAA,EAAA,UAAA,CAAW,aAAa,CAAA,eAAA,EAAkB,WAAW,kBAAkB,CAAA,CAAA;AAAA,KAC1G,CAAA;AAAA,GACF;AAEA,EAAA,OAAO,WAAW,QAAS,EAAA,CAAA;AAC7B,CAAA,CAAA;AAEO,MAAM,gBAAqC,CAAA;AAAA,EAChD,YAA6B,MAAc,EAAA;AAAd,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAAe;AAAA,EAE5C,MAAM,OAAO,GAA4B,EAAA;AACvC,IAAA,MAAM,IAAK,CAAA,MAAA,CAAYK,OAAK,CAAA,CAAE,MAAO,CAAA;AAAA,MACnC,KAAK,GAAI,CAAA,GAAA;AAAA,MACT,GAAA,EAAK,IAAK,CAAA,SAAA,CAAU,GAAG,CAAA;AAAA,KACxB,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,QAA4C,GAAA;AAChD,IAAA,MAAM,OAAO,MAAM,IAAA,CAAK,MAAY,CAAAA,OAAK,EAAE,MAAO,EAAA,CAAA;AAElD,IAAO,OAAA;AAAA,MACL,KAAA,EAAO,IAAK,CAAA,GAAA,CAAI,CAAQ,GAAA,MAAA;AAAA,QACtB,GAAK,EAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAI,GAAG,CAAA;AAAA,QACvB,SAAA,EAAW,SAAU,CAAA,GAAA,CAAI,UAAU,CAAA;AAAA,OACnC,CAAA,CAAA;AAAA,KACJ,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,WAAW,IAA+B,EAAA;AAC9C,IAAM,MAAA,IAAA,CAAK,OAAOA,OAAK,CAAA,CAAE,QAAS,CAAA,OAAA,CAAQ,OAAO,IAAI,CAAA,CAAA;AAAA,GACvD;AACF;;AChDO,MAAM,cAAmC,CAAA;AAAA,EAC7B,IAAA,uBAAW,GAA8C,EAAA,CAAA;AAAA,EAE1E,MAAM,OAAO,GAA4B,EAAA;AACvC,IAAK,IAAA,CAAA,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,GAAK,EAAA;AAAA,MACrB,SAAW,EAAAL,cAAA,CAAS,GAAI,EAAA,CAAE,QAAS,EAAA;AAAA,MACnC,GAAA,EAAK,IAAK,CAAA,SAAA,CAAU,GAAG,CAAA;AAAA,KACxB,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,WAAW,IAA+B,EAAA;AAC9C,IAAA,KAAA,MAAW,OAAO,IAAM,EAAA;AACtB,MAAK,IAAA,CAAA,IAAA,CAAK,OAAO,GAAG,CAAA,CAAA;AAAA,KACtB;AAAA,GACF;AAAA,EAEA,MAAM,QAA4C,GAAA;AAChD,IAAO,OAAA;AAAA,MACL,KAAO,EAAA,KAAA,CAAM,IAAK,CAAA,IAAA,CAAK,IAAI,CAAE,CAAA,GAAA,CAAI,CAAC,GAAG,EAAE,SAAA,EAAW,GAAK,EAAA,MAAA,EAAQ,CAAO,MAAA;AAAA,QACpE,SAAA;AAAA,QACA,GAAA,EAAK,IAAK,CAAA,KAAA,CAAM,MAAM,CAAA;AAAA,OACtB,CAAA,CAAA;AAAA,KACJ,CAAA;AAAA,GACF;AACF;;ACTO,MAAM,kBAAqB,GAAA,GAAA,CAAA;AAC3B,MAAM,qBAAwB,GAAA,UAAA,CAAA;AAE9B,MAAM,iBAAsC,CAAA;AAAA,EAczC,WAAA,CACW,QACA,EAAA,IAAA,EACA,OACjB,EAAA;AAHiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AAAA,GAChB;AAAA,EAjBH,aAAa,OACX,QAC4B,EAAA;AAC5B,IAAA,MAAM,EAAE,IAAM,EAAA,OAAA,EAAS,GAAG,iBAAkB,EAAA,GAAI,YAAY,EAAC,CAAA;AAC7D,IAAM,MAAA,QAAA,GAAW,IAAIM,mBAAA,CAAU,iBAAiB,CAAA,CAAA;AAEhD,IAAA,OAAO,IAAI,iBAAA;AAAA,MACT,QAAA;AAAA,MACA,IAAQ,IAAA,qBAAA;AAAA,MACR,OAAW,IAAA,kBAAA;AAAA,KACb,CAAA;AAAA,GACF;AAAA,EAQA,aAAa,gBACX,CAAA,QAAA,EACA,MACe,EAAA;AACf,IAAI,IAAA;AACF,MAAA,MAAM,SAAS,MAAO,EAAA,CAAA;AAAA,aACf,KAAO,EAAA;AACd,MAAI,IAAA,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,aAAe,EAAA;AAC1C,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,+BAAA,EAAmC,MAAgB,OAAO,CAAA,CAAA;AAAA,SAC5D,CAAA;AAAA,OACF;AACA,MAAQ,MAAA,EAAA,IAAA;AAAA,QACN,CAAA,+BAAA,EAAmC,MAAgB,OAAO,CAAA,CAAA;AAAA,OAC5D,CAAA;AAAA,KACF;AAAA,GACF;AAAA,EAEA,MAAM,OAAO,GAA4B,EAAA;AACvC,IAAA,MAAM,IAAK,CAAA,WAAA;AAAA,MACT,IAAA,CAAK,QACF,CAAA,UAAA,CAAW,IAAK,CAAA,IAAI,EACpB,GAAI,CAAA,GAAA,CAAI,GAAG,CAAA,CACX,GAAI,CAAA;AAAA,QACH,KAAK,GAAI,CAAA,GAAA;AAAA,QACT,GAAA,EAAK,IAAK,CAAA,SAAA,CAAU,GAAG,CAAA;AAAA,OACxB,CAAA;AAAA,KACL,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,QAA4C,GAAA;AAChD,IAAM,MAAA,IAAA,GAAO,MAAM,IAAK,CAAA,WAAA;AAAA,MACtB,KAAK,QAAS,CAAA,UAAA,CAAW,IAAK,CAAA,IAAI,EAAE,GAAI,EAAA;AAAA,KAC1C,CAAA;AAEA,IAAO,OAAA;AAAA,MACL,KAAO,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,CAAQ,GAAA,MAAA;AAAA,QAC3B,GAAA,EAAK,IAAI,IAAK,EAAA;AAAA,QACd,SAAA,EAAW,GAAI,CAAA,UAAA,CAAW,MAAO,EAAA;AAAA,OACjC,CAAA,CAAA;AAAA,KACJ,CAAA;AAAA,GACF;AAAA,EAEA,MAAM,WAAW,IAA+B,EAAA;AAE9C,IAAA,KAAA,MAAW,OAAO,IAAM,EAAA;AACtB,MAAA,MAAM,IAAK,CAAA,WAAA;AAAA,QACT,IAAA,CAAK,SAAS,UAAW,CAAA,IAAA,CAAK,IAAI,CAAE,CAAA,GAAA,CAAI,GAAG,CAAA,CAAE,MAAO,EAAA;AAAA,OACtD,CAAA;AAAA,KACF;AAAA,GAwBF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,YAAe,SAAmC,EAAA;AAC9D,IAAA,MAAM,QAAQ,IAAI,OAAA;AAAA,MAAe,CAAC,CAAA,EAAG,MACnC,KAAA,UAAA,CAAW,MAAM;AACf,QAAA,MAAA,CAAO,IAAI,KAAM,CAAA,CAAA,0BAAA,EAA6B,IAAK,CAAA,OAAO,IAAI,CAAC,CAAA,CAAA;AAAA,OACjE,EAAG,KAAK,OAAO,CAAA;AAAA,KACjB,CAAA;AACA,IAAA,OAAO,OAAQ,CAAA,IAAA,CAAQ,CAAC,SAAA,EAAW,KAAK,CAAC,CAAA,CAAA;AAAA,GAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,MAAwB,GAAA;AACpC,IAAA,MAAM,IAAK,CAAA,WAAA,CAAY,IAAK,CAAA,QAAA,CAAS,UAAW,CAAA,IAAA,CAAK,IAAI,CAAA,CAAE,KAAM,CAAA,CAAC,CAAE,CAAA,GAAA,EAAK,CAAA,CAAA;AAAA,GAC3E;AACF;;AC3HA,MAAM,iBAAoB,GAAA,OAAA,CAAA;AA6BnB,MAAM,cAAmC,CAAA;AAAA,EAC7B,QAAA,CAAA;AAAA,EACA,SAAA,CAAA;AAAA,EAET,YAAY,QAAqB,EAAA;AACvC,IAAI,IAAA,QAAA,CAAS,WAAW,CAAG,EAAA;AACzB,MAAM,MAAA,IAAI,MAAM,sCAAsC,CAAA,CAAA;AAAA,KACxD;AAEA,IAAA,IAAA,CAAK,QAAW,GAAA,QAAA,CAAA;AAChB,IAAK,IAAA,CAAA,SAAA,uBAAgB,IAAK,EAAA,CAAA;AAAA,GAC5B;AAAA,EAEA,aAAoB,WAAW,MAAyC,EAAA;AACtE,IAAA,MAAM,aAAa,MAChB,CAAA,cAAA,CAAe,2BAA2B,CAAA,CAC1C,IAAI,CAAK,CAAA,KAAA;AACR,MAAA,MAAM,eAAmC,GAAA;AAAA,QACvC,aAAA,EAAe,CAAE,CAAA,SAAA,CAAU,eAAe,CAAA;AAAA,QAC1C,cAAA,EAAgB,CAAE,CAAA,SAAA,CAAU,gBAAgB,CAAA;AAAA,QAC5C,KAAA,EAAO,CAAE,CAAA,SAAA,CAAU,OAAO,CAAA;AAAA,QAC1B,SAAW,EAAA,CAAA,CAAE,iBAAkB,CAAA,WAAW,CAAK,IAAA,iBAAA;AAAA,OACjD,CAAA;AAEA,MAAO,OAAA,eAAA,CAAA;AAAA,KACR,CAAA,CAAA;AAEH,IAAM,MAAA,QAAA,GAAW,MAAM,OAAQ,CAAA,GAAA;AAAA,MAC7B,UAAA,CAAW,IAAI,OAAM,CAAA,KAAK,MAAM,IAAK,CAAA,WAAA,CAAY,CAAC,CAAC,CAAA;AAAA,KACrD,CAAA;AAEA,IAAO,OAAA,IAAI,eAAe,QAAQ,CAAA,CAAA;AAAA,GACpC;AAAA,EAEA,OAAO,IAA6B,EAAA;AAClC,IAAM,MAAA,IAAI,MAAM,yCAAyC,CAAA,CAAA;AAAA,GAC3D;AAAA,EAEA,QAA4C,GAAA;AAC1C,IAAM,MAAA,IAAA,GAAO,KAAK,QAAS,CAAA,GAAA,CAAI,OAAK,IAAK,CAAA,kBAAA,CAAmB,CAAC,CAAC,CAAA,CAAA;AAC9D,IAAA,OAAO,OAAQ,CAAA,OAAA,CAAQ,EAAE,KAAA,EAAO,MAAM,CAAA,CAAA;AAAA,GACxC;AAAA,EAEA,cAAc,KAAoB,EAAA;AAChC,IAAM,MAAA,OAAA,GAAU,KAAK,QAAS,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,SAAA,CAAU,QAAQ,KAAK,CAAA,CAAA;AACjE,IAAA,IAAI,YAAY,KAAW,CAAA,EAAA;AACzB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAkC,+BAAA,EAAA,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,KAC3D;AAEA,IAAA,OAAO,OAAQ,CAAA,UAAA,CAAA;AAAA,GACjB;AAAA,EAEA,WAAW,KAAgC,EAAA;AACzC,IAAM,MAAA,IAAI,MAAM,8CAA8C,CAAA,CAAA;AAAA,GAChE;AAAA,EAEQ,mBAAmB,OAA6B,EAAA;AACtD,IAAA,MAAM,SAAY,GAAA;AAAA,MAChB,GAAG,OAAQ,CAAA,SAAA;AAAA,MACX,GAAK,EAAA,KAAA;AAAA,KACP,CAAA;AAEA,IAAO,OAAA;AAAA,MACL,GAAK,EAAA,SAAA;AAAA,MACL,WAAW,IAAK,CAAA,SAAA;AAAA,KAClB,CAAA;AAAA,GACF;AAAA,EAEA,aAAqB,YAAY,OAA4C,EAAA;AAC3E,IAAA,MAAM,YAAY,OAAQ,CAAA,SAAA,CAAA;AAC1B,IAAA,MAAM,QAAQ,OAAQ,CAAA,KAAA,CAAA;AACtB,IAAM,MAAA,SAAA,GAAY,MAAM,IAAK,CAAA,qBAAA;AAAA,MAC3B,OAAQ,CAAA,aAAA;AAAA,MACR,KAAA;AAAA,MACA,SAAA;AAAA,KACF,CAAA;AACA,IAAM,MAAA,UAAA,GAAa,MAAM,IAAK,CAAA,sBAAA;AAAA,MAC5B,OAAQ,CAAA,cAAA;AAAA,MACR,KAAA;AAAA,MACA,SAAA;AAAA,KACF,CAAA;AAEA,IAAO,OAAA,EAAE,WAAW,UAAW,EAAA,CAAA;AAAA,GACjC;AAAA,EAEA,aAAqB,qBAAA,CACnB,IACA,EAAA,KAAA,EACA,SACc,EAAA;AACd,IAAA,OAAO,IAAK,CAAA,eAAA,CAAgB,IAAM,EAAA,KAAA,EAAO,WAAWC,eAAU,CAAA,CAAA;AAAA,GAChE;AAAA,EAEA,aAAqB,sBAAA,CACnB,IACA,EAAA,KAAA,EACA,SACc,EAAA;AACd,IAAA,OAAO,IAAK,CAAA,eAAA,CAAgB,IAAM,EAAA,KAAA,EAAO,WAAWC,gBAAW,CAAA,CAAA;AAAA,GACjE;AAAA,EAEA,aAAqB,eAAA,CACnB,IACA,EAAA,KAAA,EACA,WACA,QACc,EAAA;AACd,IAAM,MAAA,OAAA,GAAU,MAAMC,WAAA,CAAG,QAAS,CAAA,IAAA,EAAM,EAAE,QAAU,EAAA,MAAA,EAAQ,IAAM,EAAA,GAAA,EAAK,CAAA,CAAA;AACvE,IAAA,MAAM,GAAM,GAAA,MAAM,QAAS,CAAA,OAAA,EAAS,SAAS,CAAA,CAAA;AAC7C,IAAM,MAAA,GAAA,GAAM,MAAMP,cAAA,CAAU,GAAG,CAAA,CAAA;AAC/B,IAAA,GAAA,CAAI,GAAM,GAAA,KAAA,CAAA;AACV,IAAA,GAAA,CAAI,GAAM,GAAA,SAAA,CAAA;AAEV,IAAO,OAAA,GAAA,CAAA;AAAA,GACT;AACF;;ACjJO,MAAM,SAAU,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,aAAa,UAAW,CAAA,MAAA,EAAgB,OAAqC,EAAA;AAC3E,IAAM,MAAA,EAAE,MAAQ,EAAA,QAAA,EAAa,GAAA,OAAA,CAAA;AAE7B,IAAM,MAAA,EAAA,GAAK,MAAO,CAAA,iBAAA,CAAkB,eAAe,CAAA,CAAA;AACnD,IAAA,MAAM,QAAW,GAAA,EAAA,EAAI,iBAAkB,CAAA,UAAU,CAAK,IAAA,UAAA,CAAA;AAEtD,IAAO,MAAA,CAAA,IAAA,CAAK,CAAgB,aAAA,EAAA,QAAQ,CAAwB,sBAAA,CAAA,CAAA,CAAA;AAE5D,IAAA,IAAI,aAAa,UAAY,EAAA;AAC3B,MAAA,OAAO,IAAI,gBAAA,CAAiB,MAAM,QAAA,CAAS,KAAK,CAAA,CAAA;AAAA,KAClD;AAEA,IAAA,IAAI,aAAa,QAAU,EAAA;AACzB,MAAA,OAAO,IAAI,cAAe,EAAA,CAAA;AAAA,KAC5B;AAEA,IAAA,IAAI,aAAa,WAAa,EAAA;AAC5B,MAAM,MAAA,QAAA,GAAW,EAAI,EAAA,SAAA,CAAU,QAAQ,CAAA,CAAA;AAEvC,MAAM,MAAA,QAAA,GAAW,MAAM,iBAAkB,CAAA,MAAA;AAAA,QACvCQ,aAAA;AAAA,UACE;AAAA,YACE,SAAA,EAAW,QAAU,EAAA,iBAAA,CAAkB,WAAW,CAAA;AAAA,YAClD,WAAA,EAAa,QAAU,EAAA,iBAAA,CAAkB,aAAa,CAAA;AAAA,YACtD,IAAA,EAAM,QAAU,EAAA,iBAAA,CAAkB,MAAM,CAAA;AAAA,YACxC,IAAA,EAAM,QAAU,EAAA,iBAAA,CAAkB,MAAM,CAAA;AAAA,YACxC,GAAA,EAAK,QAAU,EAAA,kBAAA,CAAmB,KAAK,CAAA;AAAA,YACvC,IAAA,EAAM,QAAU,EAAA,iBAAA,CAAkB,MAAM,CAAA;AAAA,YACxC,OAAA,EAAS,QAAU,EAAA,iBAAA,CAAkB,SAAS,CAAA;AAAA,WAChD;AAAA,UACA,WAAS,KAAU,KAAA,KAAA,CAAA;AAAA,SACrB;AAAA,OACF,CAAA;AACA,MAAM,MAAA,iBAAA,CAAkB,gBAAiB,CAAA,QAAA,EAAU,MAAM,CAAA,CAAA;AAEzD,MAAO,OAAA,QAAA,CAAA;AAAA,KACT;AAEA,IAAA,IAAI,aAAa,QAAU,EAAA;AACzB,MAAO,OAAA,MAAM,cAAe,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AAAA,KAC/C;AAEA,IAAA,MAAM,IAAI,KAAA,CAAM,CAA8B,2BAAA,EAAA,QAAQ,CAAE,CAAA,CAAA,CAAA;AAAA,GAC1D;AACF;;AC9DA,MAAM,KAAQ,GAAA,WAAA,CAAA;AAYP,MAAM,uBAAwB,CAAA;AAAA,EACnC,YAA6B,MAAc,EAAA;AAAd,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAAe;AAAA,EAE5C,MAAM,YAAY,QAAmC,EAAA;AACnD,IAAA,MAAM,IAAK,CAAA,MAAA,CAAY,KAAK,CAAA,CACzB,MAAO,CAAA;AAAA,MACN,eAAA,EAAiB,SAAS,MAAO,CAAA,GAAA;AAAA,MACjC,SAAA,EAAW,IAAK,CAAA,SAAA,CAAU,QAAQ,CAAA;AAAA,MAClC,GAAK,EAAAV,cAAA,CAAS,WAAY,CAAA,QAAA,CAAS,OAAO,GAAe,EAAA;AAAA,QACvD,IAAM,EAAA,KAAA;AAAA,OACP,CAAE,CAAA,KAAA,CAAM,EAAE,aAAA,EAAe,OAAO,CAAA;AAAA,KAClC,CAAA,CACA,UAAW,CAAA,iBAAiB,EAC5B,KAAM,EAAA,CAAA;AAAA,GACX;AAAA,EAEA,MAAM,YAAY,aAAsD,EAAA;AACtE,IAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,MAAA,CAAY,KAAK,CAAA,CACtC,KAAM,CAAA,EAAE,eAAiB,EAAA,aAAA,EAAe,CAAA,CACxC,KAAM,EAAA,CAAA;AAET,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACT;AAEA,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,KAAM,CAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAC1C,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AACF;;ACrCA,MAAM,aAAgB,GAAAW,mCAAA;AAAA,EACpB,gCAAA;AAAA,EACA,YAAA;AACF,CAAA,CAAA;AAMO,MAAM,YAAa,CAAA;AAAA,EACf,SAAA,CAAA;AAAA,EACT,QAAA,CAAA;AAAA,EAEA,OAAO,OAAO,QAA+C,EAAA;AAC3D,IAAO,OAAA,IAAI,aAAa,QAAQ,CAAA,CAAA;AAAA,GAClC;AAAA;AAAA,EAGA,OAAO,UAA2B,GAAA;AAChC,IAAM,MAAAC,QAAA,GAAS,IAAIC,mBAAa,CAAA;AAAA,MAC9B,OAAS,EAAA;AAAA,QACP,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,gBAAA;AAAA,UACR,UAAY,EAAA,UAAA;AAAA,UACZ,gBAAkB,EAAA,IAAA;AAAA,SACpB;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AACD,IAAA,MAAM,WAAWC,6BAAgB,CAAA,UAAA,CAAWF,QAAM,CAAA,CAAE,UAAU,MAAM,CAAA,CAAA;AACpE,IAAO,OAAA,IAAI,aAAa,QAAQ,CAAA,CAAA;AAAA,GAClC;AAAA,EAEA,aAAa,cAAc,IAA2B,EAAA;AACpD,IAAM,MAAA,IAAA,CAAK,QAAQ,MAAO,CAAA;AAAA,MACxB,SAAW,EAAA,aAAA;AAAA,KACZ,CAAA,CAAA;AAAA,GACH;AAAA,EAEQ,YAAY,QAAiC,EAAA;AACnD,IAAA,IAAA,CAAK,SAAY,GAAA,QAAA,CAAA;AAAA,GACnB;AAAA,EAEA,GAAqB,GAAA;AACnB,IAAA,IAAA,CAAK,aAAa,IAAK,CAAA,SAAA,CAAU,WAAY,CAAA,IAAA,CAAK,OAAM,MAAU,KAAA;AAChE,MAAA,IAAI,CAAC,IAAA,CAAK,SAAU,CAAA,UAAA,EAAY,IAAM,EAAA;AACpC,QAAM,MAAA,YAAA,CAAa,cAAc,MAAM,CAAA,CAAA;AAAA,OACzC;AACA,MAAO,OAAA,MAAA,CAAA;AAAA,KACR,CAAA,CAAA;AAED,IAAA,OAAO,IAAK,CAAA,QAAA,CAAA;AAAA,GACd;AACF;;ACxDA,MAAM,mBAAsB,GAAA,IAAA,CAAA;AAC5B,MAAM,eAAkB,GAAA,GAAA,CAAA;AACxB,MAAM,eAAkB,GAAA,KAAA,CAAA;AAEjB,SAAS,6BAA6BA,QAA2B,EAAA;AACtE,EAAA,MAAM,qBAAwB,GAAA,+BAAA,CAAA;AAE9B,EAAA,IAAI,CAACA,QAAA,CAAO,GAAI,CAAA,qBAAqB,CAAG,EAAA;AACtC,IAAO,OAAA,mBAAA,CAAA;AAAA,GACT;AAEA,EAAM,MAAA,QAAA,GAAWG,8BAAuBH,QAAQ,EAAA;AAAA,IAC9C,GAAK,EAAA,qBAAA;AAAA,GACN,CAAA,CAAA;AAED,EAAA,MAAM,YAAY,IAAK,CAAA,KAAA,CAAMI,4BAAuB,CAAA,QAAQ,IAAI,GAAI,CAAA,CAAA;AAEpE,EAAA,IAAI,YAAY,eAAiB,EAAA;AAC/B,IAAO,OAAA,eAAA,CAAA;AAAA,GACT,MAAA,IAAW,YAAY,eAAiB,EAAA;AACtC,IAAO,OAAA,eAAA,CAAA;AAAA,GACT;AACA,EAAO,OAAA,SAAA,CAAA;AACT;;ACnBA,MAAM,OAAU,GAAA,GAAA,CAAA;AAqBT,MAAM,iBAAyC,CAAA;AAAA,EACnC,MAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EACA,QAAA,CAAA;AAAA,EACA,wBAAA,CAAA;AAAA,EAEV,WAAA,CAAY,SAAkB,QAA0B,EAAA;AAC7D,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAA,IAAA,CAAK,2BAA2B,OAAQ,CAAA,wBAAA,CAAA;AACxC,IAAA,IAAA,CAAK,QAAW,GAAA,QAAA,CAAA;AAAA,GAClB;AAAA,EAEA,MAAa,WAAW,MAAsC,EAAA;AAC5D,IAAM,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,aAAc,EAAA,CAAA;AAGrC,IAAA,MAAM,MAAM,IAAK,CAAA,MAAA,CAAA;AACjB,IAAA,MAAM,EAAE,GAAK,EAAA,GAAA,EAAK,GAAG,gBAAA,KAAqB,MAAO,CAAA,MAAA,CAAA;AACjD,IAAA,MAAM,GAAM,GAAA,WAAA,CAAA;AACZ,IAAA,MAAM,MAAM,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,KAAQ,OAAO,CAAA,CAAA;AAC3C,IAAM,MAAA,GAAA,GAAM,MAAM,IAAK,CAAA,wBAAA,CAAA;AAGvB,IAAI,IAAA;AACF,MAAA7B,2BAAA,CAAe,GAAG,CAAA,CAAA;AAAA,aACX,KAAO,EAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,qEAAA;AAAA,OACF,CAAA;AAAA,KACF;AAEA,IAAK,IAAA,CAAA,MAAA,CAAO,KAAK,CAAqB,kBAAA,EAAA,GAAG,mBAAmB,GAAO,IAAA,EAAE,CAAE,CAAA,CAAA,CAAA;AAEvE,IAAI,IAAA,CAAC,IAAI,GAAK,EAAA;AACZ,MAAM,MAAA,IAAI5B,2BAAoB,sCAAsC,CAAA,CAAA;AAAA,KACtE;AAEA,IAAA,OAAO,IAAIuC,YAAQ,CAAA,EAAE,GAAG,gBAAkB,EAAA,GAAA,EAAK,KAAK,GAAK,EAAA,GAAA,EAAK,KAAK,GAAI,EAAC,EACrE,kBAAmB,CAAA,EAAE,KAAK,GAAI,CAAA,GAAA,EAAK,KAAK,GAAI,CAAA,GAAA,EAAK,CAAA,CACjD,UAAU,GAAG,CAAA,CACb,YAAY,GAAG,CAAA,CACf,WAAW,GAAG,CAAA,CACd,YAAY,GAAG,CAAA,CACf,kBAAkB,GAAG,CAAA,CACrB,KAAK,MAAMD,cAAA,CAAU,GAAG,CAAC,CAAA,CAAA;AAAA,GAC9B;AAAA,EAEA,MAAc,aAA8B,GAAA;AAC1C,IAAA,MAAM,EAAE,KAAO,EAAA,IAAA,KAAS,MAAM,IAAA,CAAK,SAAS,QAAS,EAAA,CAAA;AACrD,IAAI,IAAA,IAAA,CAAK,UAAU,CAAG,EAAA;AACpB,MAAA,OAAO,KAAK,QAAS,CAAA,aAAA,CAAc,KAAK,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA,CAAA;AAAA,KACpD;AACA,IAAM,MAAA,IAAI,MAAM,qCAAqC,CAAA,CAAA;AAAA,GACvD;AAAA,EAEA,MAAa,cAA8C,GAAA;AACzD,IAAA,MAAM,EAAE,KAAO,EAAA,IAAA,KAAS,MAAM,IAAA,CAAK,SAAS,QAAS,EAAA,CAAA;AACrD,IAAO,OAAA,EAAE,MAAM,IAAK,CAAA,GAAA,CAAI,CAAC,EAAE,GAAA,EAAU,KAAA,GAAG,CAAE,EAAA,CAAA;AAAA,GAC5C;AACF;;ACrCA,eAAsB,aACpB,OACyB,EAAA;AACzB,EAAM,MAAA;AAAA,IACJ,MAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,qBAAA;AAAA,IACA,oBAAoB,EAAC;AAAA,GACnB,GAAA,OAAA,CAAA;AAEJ,EAAA,MAAM,EAAE,IAAA,EAAM,QAAS,EAAA,GAAIb,uCAAyB,OAAO,CAAA,CAAA;AAE3D,EAAA,MAAM,SAASQ,uBAAO,EAAA,CAAA;AAEtB,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,SAAA,CAAU,aAAa,CAAA,CAAA;AAC7C,EAAA,MAAM,OAAU,GAAA,MAAM,SAAU,CAAA,kBAAA,CAAmB,MAAM,CAAA,CAAA;AACzD,EAAM,MAAA,wBAAA,GAA2B,6BAA6B,MAAM,CAAA,CAAA;AACpE,EAAM,MAAA,MAAA,GAAS,YAAa,CAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAE3C,EAAA,MAAM,QAAW,GAAA,MAAM,SAAU,CAAA,UAAA,CAAW,MAAQ,EAAA;AAAA,IAClD,MAAA;AAAA,IACA,QAAU,EAAA,MAAA;AAAA,GACX,CAAA,CAAA;AAED,EAAA,MAAM,0BAA0B,IAAI,uBAAA;AAAA,IAClC,MAAM,OAAO,GAAI,EAAA;AAAA,GACnB,CAAA;AAEA,EAAI,IAAA,WAAA,CAAA;AACJ,EAAA,IAAI,oBAAoB,cAAgB,EAAA;AACtC,IAAA,WAAA,GAAc,IAAI,iBAAA;AAAA,MAChB;AAAA,QACE,QAAQ,MAAO,CAAA,KAAA,CAAM,EAAE,SAAA,EAAW,iBAAiB,CAAA;AAAA,QACnD,MAAQ,EAAA,OAAA;AAAA,QACR,wBAA0B,EAAA,wBAAA;AAAA,OAC5B;AAAA,MACA,QAAA;AAAA,KACF,CAAA;AAAA,GACK,MAAA;AACL,IAAA,WAAA,GAAc,IAAI,YAAa,CAAA;AAAA,MAC7B,MAAQ,EAAA,OAAA;AAAA,MACR,QAAA;AAAA,MACA,kBAAoB,EAAA,wBAAA;AAAA,MACpB,QAAQ,MAAO,CAAA,KAAA,CAAM,EAAE,SAAA,EAAW,iBAAiB,CAAA;AAAA,MACnD,SACE,EAAA,qBAAA,IACA,MAAO,CAAA,iBAAA,CAAkB,6BAA6B,CAAA;AAAA,MACxD,uBAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAEA,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,iBAAA,CAAkB,qBAAqB,CAAA,CAAA;AAC7D,EAAA,IAAI,MAAQ,EAAA;AACV,IAAO,MAAA,CAAA,GAAA,CAAIyB,6BAAa,CAAA,MAAM,CAAC,CAAA,CAAA;AAC/B,IAAM,MAAA,gBAAA,GAAmB,OAAQ,CAAA,UAAA,CAAW,OAAO,CAAA,CAAA;AACnD,IAAM,MAAA,gBAAA,GAAmBC,oCAAmBC,wBAAO,CAAA,CAAA;AACnD,IAAO,MAAA,CAAA,GAAA;AAAA,MACLA,wBAAQ,CAAA;AAAA,QACN,MAAA;AAAA,QACA,iBAAmB,EAAA,KAAA;AAAA,QACnB,MAAQ,EAAA,KAAA;AAAA,QACR,MAAQ,EAAA,EAAE,MAAQ,EAAA,gBAAA,GAAmB,SAAS,KAAM,EAAA;AAAA,QACpD,KAAA,EAAO,IAAI,gBAAiB,CAAA;AAAA,UAC1B,WAAa,EAAA,KAAA;AAAA,UACb,IAAA,EAAM,MAAM,MAAA,CAAO,GAAI,EAAA;AAAA,SACxB,CAAA;AAAA,OACF,CAAA;AAAA,KACH,CAAA;AACA,IAAO,MAAA,CAAA,GAAA,CAAIC,yBAAS,CAAA,UAAA,EAAY,CAAA,CAAA;AAChC,IAAO,MAAA,CAAA,GAAA,CAAIA,yBAAS,CAAA,OAAA,EAAS,CAAA,CAAA;AAAA,GACxB,MAAA;AACL,IAAO,MAAA,CAAA,GAAA,CAAIH,+BAAc,CAAA,CAAA;AAAA,GAC3B;AAEA,EAAA,MAAA,CAAO,IAAII,wBAAQ,CAAA,UAAA,CAAW,EAAE,QAAU,EAAA,KAAA,EAAO,CAAC,CAAA,CAAA;AAClD,EAAO,MAAA,CAAA,GAAA,CAAIA,wBAAQ,CAAA,IAAA,EAAM,CAAA,CAAA;AAEzB,EAAM,MAAA,SAAA,GAAY,OAAQ,CAAA,+BAAA,GACtB,iBACA,GAAA;AAAA,IACE,GAAG,4BAAA;AAAA,IACH,GAAG,iBAAA;AAAA,GACL,CAAA;AAEJ,EAAA,mBAAA,CAAoB,MAAQ,EAAA;AAAA,IAC1B,SAAA;AAAA,IACA,MAAA;AAAA,IACA,OAAS,EAAA,OAAA;AAAA,IACT,WAAA;AAAA,IACA,GAAG,OAAA;AAAA,IACH,IAAA;AAAA,IACA,QAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,cAAA,CAAe,MAAQ,EAAA;AAAA,IACrB,IAAA;AAAA,IACA,WAAA;AAAA,IACA,OAAS,EAAA,OAAA;AAAA,IACT,uBAAA;AAAA,GACD,CAAA,CAAA;AAGD,EAAO,MAAA,CAAA,GAAA,CAAI,eAAe,CAAO,GAAA,KAAA;AAC/B,IAAM,MAAA,EAAE,QAAS,EAAA,GAAI,GAAI,CAAA,MAAA,CAAA;AACzB,IAAA,MAAM,IAAInC,oBAAA,CAAc,CAA0B,uBAAA,EAAA,QAAQ,CAAG,CAAA,CAAA,CAAA,CAAA;AAAA,GAC9D,CAAA,CAAA;AAED,EAAO,OAAA,MAAA,CAAA;AACT;;AChJO,MAAM,aAAaoC,oCAAoB,CAAA;AAAA,EAC5C,QAAU,EAAA,MAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAM,MAAA,SAAA,uBAAgB,GAAiC,EAAA,CAAA;AACvD,IAAA,IAAI,iBAAuD,GAAA,KAAA,CAAA,CAAA;AAE3D,IAAA,GAAA,CAAI,uBAAuBC,0CAA6B,EAAA;AAAA,MACtD,gBAAiB,CAAA,EAAE,UAAY,EAAA,OAAA,EAAW,EAAA;AACxC,QAAI,IAAA,SAAA,CAAU,GAAI,CAAA,UAAU,CAAG,EAAA;AAC7B,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,kBAAkB,UAAU,CAAA,wBAAA,CAAA;AAAA,WAC9B,CAAA;AAAA,SACF;AACA,QAAU,SAAA,CAAA,GAAA,CAAI,YAAY,OAAO,CAAA,CAAA;AAAA,OACnC;AAAA,KACD,CAAA,CAAA;AAED,IAAA,GAAA,CAAI,uBAAuBC,oDAAuC,EAAA;AAAA,MAChE,yBAAyB,QAAU,EAAA;AACjC,QAAA,IAAI,iBAAmB,EAAA;AACrB,UAAM,MAAA,IAAI,MAAM,wCAAwC,CAAA,CAAA;AAAA,SAC1D;AACA,QAAoB,iBAAA,GAAA,QAAA,CAAA;AAAA,OACtB;AAAA,KACD,CAAA,CAAA;AAED,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,YAAYC,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,cAAcA,6BAAa,CAAA,YAAA;AAAA,QAC3B,MAAMA,6BAAa,CAAA,IAAA;AAAA,QACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,UAAY,EAAAC,uBAAA;AAAA,OACd;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,UAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA;AAAA,QACA,IAAA;AAAA,QACA,QAAA;AAAA,QACA,UAAA;AAAA,OACC,EAAA;AACD,QAAM,MAAA,MAAA,GAAS,MAAM,YAAa,CAAA;AAAA,UAChC,MAAA;AAAA,UACA,MAAA;AAAA,UACA,QAAA;AAAA,UACA,SAAA;AAAA,UACA,YAAA;AAAA,UACA,IAAA;AAAA,UACA,QAAA;AAAA,UACA,UAAA;AAAA,UACA,iBAAA,EAAmB,MAAO,CAAA,WAAA,CAAY,SAAS,CAAA;AAAA,UAC/C,+BAAiC,EAAA,IAAA;AAAA,UACjC,iBAAA;AAAA,SACD,CAAA,CAAA;AACD,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,GAAA;AAAA,UACN,KAAO,EAAA,iBAAA;AAAA,SACR,CAAA,CAAA;AACD,QAAA,UAAA,CAAW,IAAI,MAAM,CAAA,CAAA;AAAA,OACvB;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;;;;;;;;;;;;;;;;"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-auth-backend/dist/index.d.ts b/node_modules/@backstage/plugin-auth-backend/dist/index.d.ts -index 261f40c..e27a219 100644 ---- a/node_modules/@backstage/plugin-auth-backend/dist/index.d.ts -+++ b/node_modules/@backstage/plugin-auth-backend/dist/index.d.ts -@@ -657,6 +657,7 @@ declare const providers: Readonly<{ - resolvers: Readonly<{ - emailMatchingUserEntityProfileEmail: () => _backstage_plugin_auth_node.SignInResolver; - emailLocalPartMatchingUserEntityName: () => _backstage_plugin_auth_node.SignInResolver; -+ userIdMatchingUserEntityAnnotation: () => _backstage_plugin_auth_node.SignInResolver; - emailMatchingUserEntityAnnotation: () => _backstage_plugin_auth_node.SignInResolver; - }>; - }>; diff --git a/patches/@backstage+plugin-auth-backend-module-microsoft-provider+0.1.17.patch b/patches/@backstage+plugin-auth-backend-module-microsoft-provider+0.1.17.patch deleted file mode 100644 index d7e16cb66e..0000000000 --- a/patches/@backstage+plugin-auth-backend-module-microsoft-provider+0.1.17.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff --git a/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js b/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js -index 1d39e52..7210676 100644 ---- a/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js -+++ b/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js -@@ -142,6 +142,24 @@ exports.microsoftSignInResolvers = void 0; - }; - } - }); -+ microsoftSignInResolvers2.userIdMatchingUserEntityAnnotation = pluginAuthNode.createSignInResolverFactory( -+ { -+ create() { -+ return async (info, ctx) => { -+ const { result } = info; -+ const id = result.fullProfile.id; -+ if (!id) { -+ throw new Error("Microsoft profile contained no id"); -+ } -+ return ctx.signInWithCatalogUser({ -+ annotations: { -+ "graph.microsoft.com/user-id": id -+ } -+ }); -+ }; -+ } -+ } -+ ); - })(exports.microsoftSignInResolvers || (exports.microsoftSignInResolvers = {})); - - const authModuleMicrosoftProvider$1 = backendPluginApi.createBackendModule({ -diff --git a/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js.map b/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js.map -index 7c1083a..58849d7 100644 ---- a/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js.map -+++ b/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"index.cjs.js","sources":["../src/strategy.ts","../src/authenticator.ts","../src/resolvers.ts","../src/module.ts","../src/deprecated.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PassportProfile } from '@backstage/plugin-auth-node';\nimport { decodeJwt } from 'jose';\nimport fetch from 'node-fetch';\nimport { Strategy as MicrosoftStrategy } from 'passport-microsoft';\n\nexport class ExtendedMicrosoftStrategy extends MicrosoftStrategy {\n userProfile(\n accessToken: string,\n done: (err?: unknown, profile?: PassportProfile) => void,\n ): void {\n if (this.skipUserProfile(accessToken)) {\n done(null, undefined);\n return;\n }\n\n super.userProfile(\n accessToken,\n (err?: unknown, profile?: PassportProfile) => {\n if (!profile || profile.photos) {\n done(err, profile);\n return;\n }\n\n this.getProfilePhotos(accessToken).then(photos => {\n profile.photos = photos;\n done(err, profile);\n });\n },\n );\n }\n\n private hasGraphReadScope(accessToken: string): boolean {\n const { aud, scp } = decodeJwt(accessToken);\n return (\n aud === '00000003-0000-0000-c000-000000000000' &&\n !!scp &&\n (scp as string)\n .split(' ')\n .map(s => s.toLocaleLowerCase('en-US'))\n .some(s =>\n [\n 'https://graph.microsoft.com/user.read',\n 'https://graph.microsoft.com/user.read.all',\n 'user.read',\n 'user.read.all',\n ].includes(s),\n )\n );\n }\n\n private skipUserProfile(accessToken: string): boolean {\n try {\n return !this.hasGraphReadScope(accessToken);\n } catch {\n // If there is any error with checking the scope\n // we fall back to not skipping the user profile\n // which may still result in an auth failure\n // e.g. due to a foreign scope.\n return false;\n }\n }\n\n private async getProfilePhotos(\n accessToken: string,\n ): Promise | undefined> {\n return this.getCurrentUserPhoto(accessToken, '96x96').then(photo =>\n photo ? [{ value: photo }] : undefined,\n );\n }\n\n private async getCurrentUserPhoto(\n accessToken: string,\n size: string,\n ): Promise {\n try {\n const res = await fetch(\n `https://graph.microsoft.com/v1.0/me/photos/${size}/$value`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n },\n );\n const data = await res.buffer();\n\n return `data:image/jpeg;base64,${data.toString('base64')}`;\n } catch (error) {\n return undefined;\n }\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createOAuthAuthenticator,\n PassportOAuthAuthenticatorHelper,\n PassportOAuthDoneCallback,\n PassportProfile,\n} from '@backstage/plugin-auth-node';\nimport { ExtendedMicrosoftStrategy } from './strategy';\nimport { union } from 'lodash';\n\n/** @public */\nexport const microsoftAuthenticator = createOAuthAuthenticator({\n defaultProfileTransform:\n PassportOAuthAuthenticatorHelper.defaultProfileTransform,\n initialize({ callbackUrl, config }) {\n const clientId = config.getString('clientId');\n const clientSecret = config.getString('clientSecret');\n const tenantId = config.getString('tenantId');\n const domainHint = config.getOptionalString('domainHint');\n const scope = union(\n ['user.read'],\n config.getOptionalStringArray('additionalScopes'),\n );\n\n const helper = PassportOAuthAuthenticatorHelper.from(\n new ExtendedMicrosoftStrategy(\n {\n clientID: clientId,\n clientSecret: clientSecret,\n callbackURL: callbackUrl,\n tenant: tenantId,\n scope: scope,\n },\n (\n accessToken: string,\n refreshToken: string,\n params: any,\n fullProfile: PassportProfile,\n done: PassportOAuthDoneCallback,\n ) => {\n done(\n undefined,\n { fullProfile, params, accessToken },\n { refreshToken },\n );\n },\n ),\n );\n\n return {\n helper,\n domainHint,\n };\n },\n\n async start(input, ctx) {\n const options: Record = {\n accessType: 'offline',\n };\n\n if (ctx.domainHint !== undefined) {\n options.domain_hint = ctx.domainHint;\n }\n\n return ctx.helper.start(input, options);\n },\n\n async authenticate(input, ctx) {\n return ctx.helper.authenticate(input);\n },\n\n async refresh(input, ctx) {\n return ctx.helper.refresh(input);\n },\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OAuthAuthenticatorResult,\n createSignInResolverFactory,\n PassportProfile,\n SignInInfo,\n} from '@backstage/plugin-auth-node';\n\n/**\n * Available sign-in resolvers for the Microsoft auth provider.\n *\n * @public\n */\nexport namespace microsoftSignInResolvers {\n /**\n * Looks up the user by matching their Microsoft username to the entity name.\n */\n export const emailMatchingUserEntityAnnotation = createSignInResolverFactory({\n create() {\n return async (\n info: SignInInfo>,\n ctx,\n ) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Microsoft profile contained no email');\n }\n\n return ctx.signInWithCatalogUser({\n annotations: {\n 'microsoft.com/email': profile.email,\n },\n });\n };\n },\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createBackendModule } from '@backstage/backend-plugin-api';\nimport {\n authProvidersExtensionPoint,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { microsoftAuthenticator } from './authenticator';\nimport { microsoftSignInResolvers } from './resolvers';\n\n/** @public */\nexport const authModuleMicrosoftProvider = createBackendModule({\n pluginId: 'auth',\n moduleId: 'microsoft-provider',\n register(reg) {\n reg.registerInit({\n deps: {\n providers: authProvidersExtensionPoint,\n },\n async init({ providers }) {\n providers.registerProvider({\n providerId: 'microsoft',\n factory: createOAuthProviderFactory({\n authenticator: microsoftAuthenticator,\n signInResolverFactories: {\n ...microsoftSignInResolvers,\n ...commonSignInResolvers,\n },\n }),\n });\n },\n });\n },\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { authModuleMicrosoftProvider as deprecatedAuthModuleMicrosoftProvider } from './module';\n\n/**\n * @public\n * @deprecated Use default import instead\n */\nexport const authModuleMicrosoftProvider =\n deprecatedAuthModuleMicrosoftProvider;\n"],"names":["MicrosoftStrategy","decodeJwt","fetch","createOAuthAuthenticator","PassportOAuthAuthenticatorHelper","union","microsoftSignInResolvers","createSignInResolverFactory","authModuleMicrosoftProvider","createBackendModule","authProvidersExtensionPoint","createOAuthProviderFactory","commonSignInResolvers","deprecatedAuthModuleMicrosoftProvider"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"index.cjs.js","sources":["../src/strategy.ts","../src/authenticator.ts","../src/resolvers.ts","../src/module.ts","../src/deprecated.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PassportProfile } from '@backstage/plugin-auth-node';\nimport { decodeJwt } from 'jose';\nimport fetch from 'node-fetch';\nimport { Strategy as MicrosoftStrategy } from 'passport-microsoft';\n\nexport class ExtendedMicrosoftStrategy extends MicrosoftStrategy {\n userProfile(\n accessToken: string,\n done: (err?: unknown, profile?: PassportProfile) => void,\n ): void {\n if (this.skipUserProfile(accessToken)) {\n done(null, undefined);\n return;\n }\n\n super.userProfile(\n accessToken,\n (err?: unknown, profile?: PassportProfile) => {\n if (!profile || profile.photos) {\n done(err, profile);\n return;\n }\n\n this.getProfilePhotos(accessToken).then(photos => {\n profile.photos = photos;\n done(err, profile);\n });\n },\n );\n }\n\n private hasGraphReadScope(accessToken: string): boolean {\n const { aud, scp } = decodeJwt(accessToken);\n return (\n aud === '00000003-0000-0000-c000-000000000000' &&\n !!scp &&\n (scp as string)\n .split(' ')\n .map(s => s.toLocaleLowerCase('en-US'))\n .some(s =>\n [\n 'https://graph.microsoft.com/user.read',\n 'https://graph.microsoft.com/user.read.all',\n 'user.read',\n 'user.read.all',\n ].includes(s),\n )\n );\n }\n\n private skipUserProfile(accessToken: string): boolean {\n try {\n return !this.hasGraphReadScope(accessToken);\n } catch {\n // If there is any error with checking the scope\n // we fall back to not skipping the user profile\n // which may still result in an auth failure\n // e.g. due to a foreign scope.\n return false;\n }\n }\n\n private async getProfilePhotos(\n accessToken: string,\n ): Promise | undefined> {\n return this.getCurrentUserPhoto(accessToken, '96x96').then(photo =>\n photo ? [{ value: photo }] : undefined,\n );\n }\n\n private async getCurrentUserPhoto(\n accessToken: string,\n size: string,\n ): Promise {\n try {\n const res = await fetch(\n `https://graph.microsoft.com/v1.0/me/photos/${size}/$value`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n },\n );\n const data = await res.buffer();\n\n return `data:image/jpeg;base64,${data.toString('base64')}`;\n } catch (error) {\n return undefined;\n }\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createOAuthAuthenticator,\n PassportOAuthAuthenticatorHelper,\n PassportOAuthDoneCallback,\n PassportProfile,\n} from '@backstage/plugin-auth-node';\nimport { ExtendedMicrosoftStrategy } from './strategy';\nimport { union } from 'lodash';\n\n/** @public */\nexport const microsoftAuthenticator = createOAuthAuthenticator({\n defaultProfileTransform:\n PassportOAuthAuthenticatorHelper.defaultProfileTransform,\n initialize({ callbackUrl, config }) {\n const clientId = config.getString('clientId');\n const clientSecret = config.getString('clientSecret');\n const tenantId = config.getString('tenantId');\n const domainHint = config.getOptionalString('domainHint');\n const scope = union(\n ['user.read'],\n config.getOptionalStringArray('additionalScopes'),\n );\n\n const helper = PassportOAuthAuthenticatorHelper.from(\n new ExtendedMicrosoftStrategy(\n {\n clientID: clientId,\n clientSecret: clientSecret,\n callbackURL: callbackUrl,\n tenant: tenantId,\n scope: scope,\n },\n (\n accessToken: string,\n refreshToken: string,\n params: any,\n fullProfile: PassportProfile,\n done: PassportOAuthDoneCallback,\n ) => {\n done(\n undefined,\n { fullProfile, params, accessToken },\n { refreshToken },\n );\n },\n ),\n );\n\n return {\n helper,\n domainHint,\n };\n },\n\n async start(input, ctx) {\n const options: Record = {\n accessType: 'offline',\n };\n\n if (ctx.domainHint !== undefined) {\n options.domain_hint = ctx.domainHint;\n }\n\n return ctx.helper.start(input, options);\n },\n\n async authenticate(input, ctx) {\n return ctx.helper.authenticate(input);\n },\n\n async refresh(input, ctx) {\n return ctx.helper.refresh(input);\n },\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OAuthAuthenticatorResult,\n createSignInResolverFactory,\n PassportProfile,\n SignInInfo,\n} from '@backstage/plugin-auth-node';\n\n/**\n * Available sign-in resolvers for the Microsoft auth provider.\n *\n * @public\n */\nexport namespace microsoftSignInResolvers {\n /**\n * Looks up the user by matching their Microsoft email to the email entity annotation.\n */\n export const emailMatchingUserEntityAnnotation = createSignInResolverFactory({\n create() {\n return async (\n info: SignInInfo>,\n ctx,\n ) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error('Microsoft profile contained no email');\n }\n\n return ctx.signInWithCatalogUser({\n annotations: {\n 'microsoft.com/email': profile.email,\n },\n });\n };\n },\n });\n /**\n * Looks up the user by matching their Microsoft user id to the user id entity annotation.\n */\n export const userIdMatchingUserEntityAnnotation = createSignInResolverFactory(\n {\n create() {\n return async (\n info: SignInInfo>,\n ctx,\n ) => {\n const { result } = info;\n\n const id = result.fullProfile.id;\n\n if (!id) {\n throw new Error('Microsoft profile contained no id');\n }\n\n return ctx.signInWithCatalogUser({\n annotations: {\n 'graph.microsoft.com/user-id': id,\n },\n });\n };\n },\n },\n );\n}","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createBackendModule } from '@backstage/backend-plugin-api';\nimport {\n authProvidersExtensionPoint,\n commonSignInResolvers,\n createOAuthProviderFactory,\n} from '@backstage/plugin-auth-node';\nimport { microsoftAuthenticator } from './authenticator';\nimport { microsoftSignInResolvers } from './resolvers';\n\n/** @public */\nexport const authModuleMicrosoftProvider = createBackendModule({\n pluginId: 'auth',\n moduleId: 'microsoft-provider',\n register(reg) {\n reg.registerInit({\n deps: {\n providers: authProvidersExtensionPoint,\n },\n async init({ providers }) {\n providers.registerProvider({\n providerId: 'microsoft',\n factory: createOAuthProviderFactory({\n authenticator: microsoftAuthenticator,\n signInResolverFactories: {\n ...microsoftSignInResolvers,\n ...commonSignInResolvers,\n },\n }),\n });\n },\n });\n },\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { authModuleMicrosoftProvider as deprecatedAuthModuleMicrosoftProvider } from './module';\n\n/**\n * @public\n * @deprecated Use default import instead\n */\nexport const authModuleMicrosoftProvider =\n deprecatedAuthModuleMicrosoftProvider;\n"],"names":["MicrosoftStrategy","decodeJwt","fetch","createOAuthAuthenticator","PassportOAuthAuthenticatorHelper","union","microsoftSignInResolvers","createSignInResolverFactory","authModuleMicrosoftProvider","createBackendModule","authProvidersExtensionPoint","createOAuthProviderFactory","commonSignInResolvers","deprecatedAuthModuleMicrosoftProvider"],"mappings":"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"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.d.ts b/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.d.ts -index 4efdcf1..05263c1 100644 ---- a/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.d.ts -+++ b/node_modules/@backstage/plugin-auth-backend-module-microsoft-provider/dist/index.d.ts -@@ -18,9 +18,13 @@ declare const authModuleMicrosoftProvider$1: _backstage_backend_plugin_api.Backe - */ - declare namespace microsoftSignInResolvers { - /** -- * Looks up the user by matching their Microsoft username to the entity name. -+ * Looks up the user by matching their Microsoft email to the email entity annotation. - */ - const emailMatchingUserEntityAnnotation: _backstage_plugin_auth_node.SignInResolverFactory, unknown>; -+ /** -+ * Looks up the user by matching their Microsoft user id to the user id entity annotation. -+ */ -+ const userIdMatchingUserEntityAnnotation: _backstage_plugin_auth_node.SignInResolverFactory, unknown>; - } - - /** diff --git a/patches/@backstage+plugin-auth-node+0.4.17.patch b/patches/@backstage+plugin-auth-node+0.4.17.patch deleted file mode 100644 index eb4592cef1..0000000000 --- a/patches/@backstage+plugin-auth-node+0.4.17.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js b/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js -index 5283385..b3bc327 100644 ---- a/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js -+++ b/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js -@@ -929,10 +929,10 @@ exports.commonSignInResolvers = void 0; - function createOAuthProviderFactory(options) { - return (ctx) => { - return OAuthEnvironmentHandler.mapConfig(ctx.config, (envConfig) => { -- const signInResolver = options.signInResolver ?? readDeclarativeSignInResolver({ -+ const signInResolver = readDeclarativeSignInResolver({ - config: envConfig, - signInResolverFactories: options.signInResolverFactories ?? {} -- }); -+ }) ?? options.signInResolver; - return createOAuthRouteHandlers({ - authenticator: options.authenticator, - appUrl: ctx.appUrl, -diff --git a/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js.map b/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js.map -index 5500da2..899ab31 100644 ---- a/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js.map -+++ b/node_modules/@backstage/plugin-auth-node/dist/index.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"index.cjs.js","sources":["../src/extensions/AuthProvidersExtensionPoint.ts","../src/extensions/AuthOwnershipResolutionExtensionPoint.ts","../src/flow/sendWebMessageResponse.ts","../src/identity/prepareBackstageIdentityResponse.ts","../src/identity/getBearerTokenFromAuthorizationHeader.ts","../src/identity/DefaultIdentityClient.ts","../src/identity/IdentityClient.ts","../src/oauth/state.ts","../src/oauth/OAuthCookieManager.ts","../src/oauth/CookieScopeManager.ts","../src/oauth/createOAuthRouteHandlers.ts","../src/passport/PassportHelpers.ts","../src/oauth/PassportOAuthAuthenticatorHelper.ts","../src/oauth/OAuthEnvironmentHandler.ts","../src/sign-in/createSignInResolverFactory.ts","../src/sign-in/readDeclarativeSignInResolver.ts","../src/sign-in/commonSignInResolvers.ts","../src/oauth/createOAuthProviderFactory.ts","../src/oauth/types.ts","../src/proxy/types.ts","../src/proxy/createProxyRouteHandlers.ts","../src/proxy/createProxyAuthProviderFactory.ts","../src/types.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { AuthProviderFactory } from '../types';\n\n/** @public */\nexport interface AuthProviderRegistrationOptions {\n providerId: string;\n factory: AuthProviderFactory;\n}\n\n/** @public */\nexport interface AuthProvidersExtensionPoint {\n registerProvider(options: AuthProviderRegistrationOptions): void;\n}\n\n/** @public */\nexport const authProvidersExtensionPoint =\n createExtensionPoint({\n id: 'auth.providers',\n });\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { AuthOwnershipResolver } from '../types';\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\n\n/** @public */\nexport interface AuthOwnershipResolutionExtensionPoint {\n setAuthOwnershipResolver(ownershipResolver: AuthOwnershipResolver): void;\n}\n\n/** @public */\nexport const authOwnershipResolutionExtensionPoint =\n createExtensionPoint({\n id: 'auth.ownershipResolution',\n });\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Response } from 'express';\nimport crypto from 'crypto';\nimport { ClientAuthResponse } from '../types';\nimport { serializeError } from '@backstage/errors';\n\n/**\n * Payload sent as a post message after the auth request is complete.\n * If successful then has a valid payload with Auth information else contains an error.\n *\n * @public\n */\nexport type WebMessageResponse =\n | {\n type: 'authorization_response';\n response: ClientAuthResponse;\n }\n | {\n type: 'authorization_response';\n error: Error;\n };\n\n/** @internal */\nexport function safelyEncodeURIComponent(value: string): string {\n // Note the g at the end of the regex; all occurrences of single quotes must\n // be replaced, which encodeURIComponent does not do itself by default\n return encodeURIComponent(value).replace(/'/g, '%27');\n}\n\n/** @public */\nexport function sendWebMessageResponse(\n res: Response,\n appOrigin: string,\n response: WebMessageResponse,\n): void {\n const jsonData = JSON.stringify(response, (_, value) => {\n if (value instanceof Error) {\n return serializeError(value);\n }\n return value;\n });\n const base64Data = safelyEncodeURIComponent(jsonData);\n const base64Origin = safelyEncodeURIComponent(appOrigin);\n\n // NOTE: It is absolutely imperative that we use the safe encoder above, to\n // be sure that the js code below does not allow the injection of malicious\n // data.\n\n // TODO: Make target app origin configurable globally\n\n //\n // postMessage fails silently if the targetOrigin is disallowed.\n // So 2 postMessages are sent from the popup to the parent window.\n // First, the origin being used to post the actual authorization response is\n // shared with the parent window with a postMessage with targetOrigin '*'.\n // Second, the actual authorization response is sent with the app origin\n // as the targetOrigin.\n // If the first message was received but the actual auth response was\n // never received, the event listener can conclude that targetOrigin\n // was disallowed, indicating potential misconfiguration.\n //\n const script = `\n var authResponse = decodeURIComponent('${base64Data}');\n var origin = decodeURIComponent('${base64Origin}');\n var originInfo = {'type': 'config_info', 'targetOrigin': origin};\n (window.opener || window.parent).postMessage(originInfo, '*');\n (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin);\n setTimeout(() => {\n window.close();\n }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)\n `;\n const hash = crypto.createHash('sha256').update(script).digest('base64');\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('X-Frame-Options', 'sameorigin');\n res.setHeader('Content-Security-Policy', `script-src 'sha256-${hash}'`);\n res.end(``);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport {\n BackstageIdentityResponse,\n BackstageSignInResult,\n} from '@backstage/plugin-auth-node';\n\nfunction parseJwtPayload(token: string) {\n const [_header, payload, _signature] = token.split('.');\n return JSON.parse(Buffer.from(payload, 'base64').toString());\n}\n\n/**\n * Parses a Backstage-issued token and decorates the\n * {@link @backstage/plugin-auth-node#BackstageIdentityResponse} with identity information sourced from the\n * token.\n *\n * @public\n */\nexport function prepareBackstageIdentityResponse(\n result: BackstageSignInResult,\n): BackstageIdentityResponse {\n if (!result.token) {\n throw new InputError(`Identity response must return a token`);\n }\n\n const { sub, ent = [], exp: expStr } = parseJwtPayload(result.token);\n if (!sub) {\n throw new InputError(\n `Identity response must return a token with subject claim`,\n );\n }\n\n const expAt = Number(expStr);\n\n // Default to 1 hour if no expiration is set, in particular to make testing simpler\n const exp = expAt ? Math.round(expAt - Date.now() / 1000) : undefined;\n if (exp && exp < 0) {\n throw new InputError(`Identity response must not return an expired token`);\n }\n\n return {\n ...result,\n expiresInSeconds: exp,\n identity: {\n type: 'user',\n userEntityRef: sub,\n ownershipEntityRefs: ent,\n },\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Parses the given authorization header and returns the bearer token, or\n * undefined if no bearer token is given.\n *\n * @remarks\n *\n * This function is explicitly built to tolerate bad inputs safely, so you may\n * call it directly with e.g. the output of `req.header('authorization')`\n * without first checking that it exists.\n *\n * @deprecated Use the `credentials` method of `HttpAuthService` from `@backstage/backend-plugin-api` instead\n * @public\n */\nexport function getBearerTokenFromAuthorizationHeader(\n authorizationHeader: unknown,\n): string | undefined {\n if (typeof authorizationHeader !== 'string') {\n return undefined;\n }\n const matches = authorizationHeader.match(/^Bearer[ ]+(\\S+)$/i);\n return matches?.[1];\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n jwtVerify,\n} from 'jose';\nimport { GetKeyFunction } from 'jose/dist/types/types';\nimport { getBearerTokenFromAuthorizationHeader } from './getBearerTokenFromAuthorizationHeader';\nimport { IdentityApi, IdentityApiGetIdentityRequest } from './IdentityApi';\nimport { BackstageIdentityResponse } from '../types';\n\nconst CLOCK_MARGIN_S = 10;\n\n/**\n * An identity client options object which allows extra configurations\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport type IdentityClientOptions = {\n discovery: PluginEndpointDiscovery;\n issuer?: string;\n\n /** JWS \"alg\" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.\n * More info on supported algorithms: https://github.com/panva/jose */\n algorithms?: string[];\n};\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport class DefaultIdentityClient implements IdentityApi {\n private readonly discovery: PluginEndpointDiscovery;\n private readonly issuer?: string;\n private readonly algorithms?: string[];\n private keyStore?: GetKeyFunction;\n private keyStoreUpdated: number = 0;\n\n /**\n * Create a new {@link DefaultIdentityClient} instance.\n */\n static create(options: IdentityClientOptions): DefaultIdentityClient {\n return new DefaultIdentityClient(options);\n }\n\n private constructor(options: IdentityClientOptions) {\n this.discovery = options.discovery;\n this.issuer = options.issuer;\n this.algorithms = options.hasOwnProperty('algorithms')\n ? options.algorithms\n : ['ES256'];\n }\n\n async getIdentity(options: IdentityApiGetIdentityRequest) {\n const {\n request: { headers },\n } = options;\n if (!headers.authorization) {\n return undefined;\n }\n try {\n return await this.authenticate(\n getBearerTokenFromAuthorizationHeader(headers.authorization),\n );\n } catch (e) {\n throw new AuthenticationError(e.message);\n }\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use getIdentity instead of authenticate to retrieve the user\n * identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise {\n // Extract token from header\n if (!token) {\n throw new AuthenticationError('No token specified');\n }\n\n // Verify token claims and signature\n // Note: Claims must match those set by TokenFactory when issuing tokens\n // Note: verify throws if verification fails\n // Check if the keystore needs to be updated\n await this.refreshKeyStore(token);\n if (!this.keyStore) {\n throw new AuthenticationError('No keystore exists');\n }\n const decoded = await jwtVerify(token, this.keyStore, {\n algorithms: this.algorithms,\n audience: 'backstage',\n issuer: this.issuer,\n });\n // Verified, return the matching user as BackstageIdentity\n // TODO: Settle internal user format/properties\n if (!decoded.payload.sub) {\n throw new AuthenticationError('No user sub found in token');\n }\n\n const user: BackstageIdentityResponse = {\n token,\n identity: {\n type: 'user',\n userEntityRef: decoded.payload.sub,\n ownershipEntityRefs: decoded.payload.ent\n ? (decoded.payload.ent as string[])\n : [],\n },\n };\n return user;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n private async refreshKeyStore(rawJwtToken: string): Promise {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const url = await this.discovery.getBaseUrl('auth');\n const endpoint = new URL(`${url}/.well-known/jwks.json`);\n this.keyStore = createRemoteJWKSet(endpoint);\n this.keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DefaultIdentityClient,\n IdentityClientOptions,\n} from './DefaultIdentityClient';\nimport { BackstageIdentityResponse } from '../types';\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @public\n * @experimental This is not a stable API yet\n * @deprecated Please migrate to the DefaultIdentityClient.\n */\nexport class IdentityClient {\n private readonly defaultIdentityClient: DefaultIdentityClient;\n static create(options: IdentityClientOptions): IdentityClient {\n return new IdentityClient(DefaultIdentityClient.create(options));\n }\n\n private constructor(defaultIdentityClient: DefaultIdentityClient) {\n this.defaultIdentityClient = defaultIdentityClient;\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use IdentityApi#getIdentity instead of authenticate\n * to retrieve the user identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise {\n return await this.defaultIdentityClient.authenticate(token);\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport pickBy from 'lodash/pickBy';\nimport { Request } from 'express';\nimport { NotAllowedError } from '@backstage/errors';\n\n/**\n * A type for the serialized value in the `state` parameter of the OAuth authorization flow\n * @public\n */\nexport type OAuthState = {\n nonce: string;\n env: string;\n origin?: string;\n scope?: string;\n redirectUrl?: string;\n flow?: string;\n audience?: string;\n};\n\n/** @public */\nexport type OAuthStateTransform = (\n state: OAuthState,\n context: { req: Request },\n) => Promise<{ state: OAuthState }>;\n\n/** @public */\nexport function encodeOAuthState(state: OAuthState): string {\n const stateString = new URLSearchParams(\n pickBy(state, value => value !== undefined),\n ).toString();\n\n return Buffer.from(stateString, 'utf-8').toString('hex');\n}\n\n/** @public */\nexport function decodeOAuthState(encodedState: string): OAuthState {\n const state = Object.fromEntries(\n new URLSearchParams(Buffer.from(encodedState, 'hex').toString('utf-8')),\n );\n if (!state.env || state.env?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing env');\n }\n if (!state.nonce || state.nonce?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing nonce');\n }\n\n return state as OAuthState;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { CookieConfigurer } from '../types';\n\nconst THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000;\nconst TEN_MINUTES_MS = 600 * 1000;\n\nconst defaultCookieConfigurer: CookieConfigurer = ({\n callbackUrl,\n providerId,\n appOrigin,\n}) => {\n const { hostname: domain, pathname, protocol } = new URL(callbackUrl);\n const secure = protocol === 'https:';\n\n // For situations where the auth-backend is running on a\n // different domain than the app, we set the SameSite attribute\n // to 'none' to allow third-party access to the cookie, but\n // only if it's in a secure context (https).\n let sameSite: ReturnType['sameSite'] = 'lax';\n if (new URL(appOrigin).hostname !== domain && secure) {\n sameSite = 'none';\n }\n\n // If the provider supports callbackUrls, the pathname will\n // contain the complete path to the frame handler so we need\n // to slice off the trailing part of the path.\n const path = pathname.endsWith(`${providerId}/handler/frame`)\n ? pathname.slice(0, -'/handler/frame'.length)\n : `${pathname}/${providerId}`;\n\n return { domain, path, secure, sameSite };\n};\n\n/** @internal */\nexport class OAuthCookieManager {\n private readonly cookieConfigurer: CookieConfigurer;\n private readonly nonceCookie: string;\n private readonly refreshTokenCookie: string;\n private readonly grantedScopeCookie: string;\n\n constructor(\n private readonly options: {\n providerId: string;\n defaultAppOrigin: string;\n baseUrl: string;\n callbackUrl: string;\n cookieConfigurer?: CookieConfigurer;\n },\n ) {\n this.cookieConfigurer = options.cookieConfigurer ?? defaultCookieConfigurer;\n\n this.nonceCookie = `${options.providerId}-nonce`;\n this.refreshTokenCookie = `${options.providerId}-refresh-token`;\n this.grantedScopeCookie = `${options.providerId}-granted-scope`;\n }\n\n private getConfig(origin?: string, pathSuffix: string = '') {\n const cookieConfig = this.cookieConfigurer({\n providerId: this.options.providerId,\n baseUrl: this.options.baseUrl,\n callbackUrl: this.options.callbackUrl,\n appOrigin: origin ?? this.options.defaultAppOrigin,\n });\n return {\n httpOnly: true,\n sameSite: 'lax' as const,\n ...cookieConfig,\n path: cookieConfig.path + pathSuffix,\n };\n }\n\n setNonce(res: Response, nonce: string, origin?: string) {\n res.cookie(this.nonceCookie, nonce, {\n maxAge: TEN_MINUTES_MS,\n ...this.getConfig(origin, '/handler'),\n });\n }\n\n setRefreshToken(res: Response, refreshToken: string, origin?: string) {\n res.cookie(this.refreshTokenCookie, refreshToken, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n removeRefreshToken(res: Response, origin?: string) {\n res.cookie(this.refreshTokenCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n removeGrantedScopes(res: Response, origin?: string) {\n res.cookie(this.grantedScopeCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n setGrantedScopes(res: Response, scope: string, origin?: string) {\n res.cookie(this.grantedScopeCookie, scope, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n getNonce(req: Request): string | undefined {\n return req.cookies[this.nonceCookie];\n }\n\n getRefreshToken(req: Request): string | undefined {\n return req.cookies[this.refreshTokenCookie];\n }\n\n getGrantedScopes(req: Request): string | undefined {\n return req.cookies[this.grantedScopeCookie];\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport {\n OAuthAuthenticator,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorScopeOptions,\n} from './types';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport { OAuthState } from './state';\nimport { AuthenticationError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\n\nfunction reqRes(req: express.Request): express.Response {\n const res = req.res;\n if (!res) {\n throw new Error('No response object found in request');\n }\n return res;\n}\n\nconst defaultTransform: Required['transform'] =\n ({ requested, granted, required, additional }) => {\n return [...requested, ...granted, ...required, ...additional];\n };\n\nfunction splitScope(scope?: string): Iterable {\n if (!scope) {\n return [];\n }\n\n return scope.split(/[\\s|,]/).filter(Boolean);\n}\n\nexport class CookieScopeManager {\n static create(options: {\n config?: Config;\n additionalScopes?: string[];\n authenticator: OAuthAuthenticator;\n cookieManager: OAuthCookieManager;\n }) {\n const { authenticator, config } = options;\n\n const shouldPersistScopes =\n authenticator.scopes?.persist ??\n authenticator.shouldPersistScopes ??\n false;\n\n const configScopes =\n typeof config?.getOptional('additionalScopes') === 'string'\n ? splitScope(config.getString('additionalScopes'))\n : config?.getOptionalStringArray('additionalScopes') ?? [];\n\n const transform = authenticator?.scopes?.transform ?? defaultTransform;\n const additional = [...configScopes, ...(options.additionalScopes ?? [])];\n const required = authenticator?.scopes?.required ?? [];\n\n return new CookieScopeManager(\n (requested, granted) =>\n Array.from(\n new Set(transform({ required, additional, requested, granted })),\n ).join(' '),\n shouldPersistScopes ? options.cookieManager : undefined,\n );\n }\n\n private constructor(\n private readonly scopeTransform: (\n requested: Iterable,\n granted: Iterable,\n ) => string,\n private readonly cookieManager?: OAuthCookieManager,\n ) {}\n\n async start(\n req: express.Request,\n ): Promise<{ scopeState?: Partial; scope: string }> {\n const requestScope = splitScope(req.query.scope?.toString());\n const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));\n\n const scope = this.scopeTransform(requestScope, grantedScope);\n\n if (this.cookieManager) {\n // If scopes are persisted then we pass them through the state so that we\n // can set the cookie on successful auth\n return {\n scope,\n scopeState: { scope },\n };\n }\n return { scope };\n }\n\n async handleCallback(\n req: express.Request,\n ctx: {\n result: OAuthAuthenticatorResult;\n state: OAuthState;\n origin?: string;\n },\n ): Promise {\n // If we are not persisting scopes we can forward the scope from the result\n if (!this.cookieManager) {\n return Array.from(splitScope(ctx.result.session.scope)).join(' ');\n }\n\n const scope = ctx.state.scope;\n if (scope === undefined) {\n throw new AuthenticationError('No scope found in OAuth state');\n }\n\n // Store the scope that we have been granted for this session. This is useful if\n // the provider does not return granted scopes on refresh or if they are normalized.\n this.cookieManager.setGrantedScopes(reqRes(req), scope, ctx.origin);\n\n return scope;\n }\n\n async clear(req: express.Request): Promise {\n if (this.cookieManager) {\n this.cookieManager.removeGrantedScopes(reqRes(req), req.get('origin'));\n }\n }\n\n async refresh(req: express.Request): Promise<{\n scope: string;\n commit(result: OAuthAuthenticatorResult): Promise;\n }> {\n const requestScope = splitScope(req.query.scope?.toString());\n const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));\n\n const scope = this.scopeTransform(requestScope, grantedScope);\n\n return {\n scope,\n commit: async result => {\n if (this.cookieManager) {\n this.cookieManager.setGrantedScopes(\n reqRes(req),\n scope,\n req.get('origin'),\n );\n return scope;\n }\n\n return Array.from(splitScope(result.session.scope)).join(' ');\n },\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport crypto from 'crypto';\nimport { URL } from 'url';\nimport {\n AuthenticationError,\n InputError,\n isError,\n NotAllowedError,\n} from '@backstage/errors';\nimport {\n encodeOAuthState,\n decodeOAuthState,\n OAuthStateTransform,\n} from './state';\nimport { sendWebMessageResponse } from '../flow';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n CookieConfigurer,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { Config } from '@backstage/config';\nimport { CookieScopeManager } from './CookieScopeManager';\n\n/** @public */\nexport interface OAuthRouteHandlersOptions {\n authenticator: OAuthAuthenticator;\n appUrl: string;\n baseUrl: string;\n isOriginAllowed: (origin: string) => boolean;\n providerId: string;\n config: Config;\n resolverContext: AuthResolverContext;\n additionalScopes?: string[];\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform>;\n cookieConfigurer?: CookieConfigurer;\n signInResolver?: SignInResolver>;\n}\n\n/** @internal */\ntype ClientOAuthResponse = ClientAuthResponse<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * (Optional) Id token issued for the signed in user.\n */\n idToken?: string;\n /**\n * Expiry of the access token in seconds.\n */\n expiresInSeconds?: number;\n /**\n * Scopes granted for the access token.\n */\n scope: string;\n}>;\n\n/** @public */\nexport function createOAuthRouteHandlers(\n options: OAuthRouteHandlersOptions,\n): AuthProviderRouteHandlers {\n const {\n authenticator,\n config,\n baseUrl,\n appUrl,\n providerId,\n isOriginAllowed,\n cookieConfigurer,\n resolverContext,\n signInResolver,\n } = options;\n\n const defaultAppOrigin = new URL(appUrl).origin;\n const callbackUrl =\n config.getOptionalString('callbackUrl') ??\n `${baseUrl}/${providerId}/handler/frame`;\n\n const stateTransform = options.stateTransform ?? (state => ({ state }));\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config, callbackUrl });\n const cookieManager = new OAuthCookieManager({\n baseUrl,\n callbackUrl,\n defaultAppOrigin,\n providerId,\n cookieConfigurer,\n });\n\n const scopeManager = CookieScopeManager.create({\n config,\n authenticator,\n cookieManager,\n additionalScopes: options.additionalScopes,\n });\n\n return {\n async start(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n const env = req.query.env?.toString();\n const origin = req.query.origin?.toString();\n const redirectUrl = req.query.redirectUrl?.toString();\n const flow = req.query.flow?.toString();\n\n if (!env) {\n throw new InputError('No env provided in request query parameters');\n }\n\n const nonce = crypto.randomBytes(16).toString('base64');\n // set a nonce cookie before redirecting to oauth provider\n cookieManager.setNonce(res, nonce, origin);\n\n const { scope, scopeState } = await scopeManager.start(req);\n\n const state = { nonce, env, origin, redirectUrl, flow, ...scopeState };\n const { state: transformedState } = await stateTransform(state, { req });\n\n const { url, status } = await options.authenticator.start(\n {\n req,\n scope,\n state: encodeOAuthState(transformedState),\n },\n authenticatorCtx,\n );\n\n res.statusCode = status || 302;\n res.setHeader('Location', url);\n res.setHeader('Content-Length', '0');\n res.end();\n },\n\n async frameHandler(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n let origin = defaultAppOrigin;\n\n try {\n const state = decodeOAuthState(req.query.state?.toString() ?? '');\n\n if (state.origin) {\n try {\n origin = new URL(state.origin).origin;\n } catch {\n throw new NotAllowedError('App origin is invalid, failed to parse');\n }\n if (!isOriginAllowed(origin)) {\n throw new NotAllowedError(`Origin '${origin}' is not allowed`);\n }\n }\n\n // The same nonce is passed through cookie and state, and they must match\n const cookieNonce = cookieManager.getNonce(req);\n const stateNonce = state.nonce;\n if (!cookieNonce) {\n throw new NotAllowedError('Auth response is missing cookie nonce');\n }\n if (cookieNonce !== stateNonce) {\n throw new NotAllowedError('Invalid nonce');\n }\n\n const result = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n const { profile } = await profileTransform(result, resolverContext);\n\n const signInResult =\n signInResolver &&\n (await signInResolver({ profile, result }, resolverContext));\n\n const grantedScopes = await scopeManager.handleCallback(req, {\n result,\n state,\n origin,\n });\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: grantedScopes,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n ...(signInResult && {\n backstageIdentity: prepareBackstageIdentityResponse(signInResult),\n }),\n };\n\n if (result.session.refreshToken) {\n // set new refresh token\n cookieManager.setRefreshToken(\n res,\n result.session.refreshToken,\n origin,\n );\n }\n\n // When using the redirect flow we rely on refresh token we just\n // acquired to get a new session once we're back in the app.\n if (state.flow === 'redirect') {\n if (!state.redirectUrl) {\n throw new InputError(\n 'No redirectUrl provided in request query parameters',\n );\n }\n res.redirect(state.redirectUrl);\n return;\n }\n\n // post message back to popup if successful\n sendWebMessageResponse(res, origin, {\n type: 'authorization_response',\n response,\n });\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n // post error message back to popup if failure\n sendWebMessageResponse(res, origin, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n },\n\n async logout(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (authenticator.logout) {\n const refreshToken = cookieManager.getRefreshToken(req);\n await authenticator.logout({ req, refreshToken }, authenticatorCtx);\n }\n\n // remove refresh token cookie if it is set\n cookieManager.removeRefreshToken(res, req.get('origin'));\n\n // remove persisted scopes\n await scopeManager.clear(req);\n\n res.status(200).end();\n },\n\n async refresh(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n try {\n const refreshToken = cookieManager.getRefreshToken(req);\n\n // throw error if refresh token is missing in the request\n if (!refreshToken) {\n throw new InputError('Missing session cookie');\n }\n\n const scopeRefresh = await scopeManager.refresh(req);\n\n const result = await authenticator.refresh(\n { req, scope: scopeRefresh.scope, refreshToken },\n authenticatorCtx,\n );\n\n const grantedScope = await scopeRefresh.commit(result);\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const newRefreshToken = result.session.refreshToken;\n if (newRefreshToken && newRefreshToken !== refreshToken) {\n cookieManager.setRefreshToken(\n res,\n newRefreshToken,\n req.get('origin'),\n );\n }\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: grantedScope,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n };\n\n if (signInResolver) {\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n response.backstageIdentity =\n prepareBackstageIdentityResponse(identity);\n }\n\n res.status(200).json(response);\n } catch (error) {\n throw new AuthenticationError('Refresh failed', error);\n }\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request } from 'express';\nimport { decodeJwt } from 'jose';\nimport { Strategy } from 'passport';\nimport { PassportProfile } from './types';\nimport { ProfileInfo } from '../types';\n\n// Re-declared here to avoid direct dependency on passport-oauth2\n/** @internal */\ninterface InternalOAuthError extends Error {\n oauthError?: {\n data?: string;\n };\n}\n\n/** @public */\nexport class PassportHelpers {\n private constructor() {}\n\n static transformProfile = (\n profile: PassportProfile,\n idToken?: string,\n ): ProfileInfo => {\n let email: string | undefined = undefined;\n if (profile.emails && profile.emails.length > 0) {\n const [firstEmail] = profile.emails;\n email = firstEmail.value;\n } else if (profile.email) {\n // This is the case for Atlassian\n email = profile.email;\n }\n\n let picture: string | undefined = undefined;\n if (profile.avatarUrl) {\n picture = profile.avatarUrl;\n } else if (profile.photos && profile.photos.length > 0) {\n const [firstPhoto] = profile.photos;\n picture = firstPhoto.value;\n } else if (profile.photo) {\n // This is the case for Atlassian\n picture = profile.photo;\n }\n\n let displayName: string | undefined =\n profile.displayName ?? profile.username ?? profile.id;\n\n if ((!email || !picture || !displayName) && idToken) {\n try {\n const decoded = decodeJwt(idToken) as {\n email?: string;\n name?: string;\n picture?: string;\n };\n if (!email && decoded.email) {\n email = decoded.email;\n }\n if (!picture && decoded.picture) {\n picture = decoded.picture;\n }\n if (!displayName && decoded.name) {\n displayName = decoded.name;\n }\n } catch (e) {\n throw new Error(`Failed to parse id token and get profile info, ${e}`);\n }\n }\n\n return {\n email,\n picture,\n displayName,\n };\n };\n\n static async executeRedirectStrategy(\n req: Request,\n providerStrategy: Strategy,\n options: Record,\n ): Promise<{\n /**\n * URL to redirect to\n */\n url: string;\n /**\n * Status code to use for the redirect\n */\n status?: number;\n }> {\n return new Promise(resolve => {\n const strategy = Object.create(providerStrategy);\n strategy.redirect = (url: string, status?: number) => {\n resolve({ url, status: status ?? undefined });\n };\n\n strategy.authenticate(req, { ...options });\n });\n }\n\n static async executeFrameHandlerStrategy(\n req: Request,\n providerStrategy: Strategy,\n options?: Record,\n ): Promise<{ result: TResult; privateInfo: TPrivateInfo }> {\n return new Promise((resolve, reject) => {\n const strategy = Object.create(providerStrategy);\n strategy.success = (result: any, privateInfo: any) => {\n resolve({ result, privateInfo });\n };\n strategy.fail = (\n info: { type: 'success' | 'error'; message?: string },\n // _status: number,\n ) => {\n reject(new Error(`Authentication rejected, ${info.message ?? ''}`));\n };\n strategy.error = (error: InternalOAuthError) => {\n let message = `Authentication failed, ${error.message}`;\n\n if (error.oauthError?.data) {\n try {\n const errorData = JSON.parse(error.oauthError.data);\n\n if (errorData.message) {\n message += ` - ${errorData.message}`;\n }\n } catch (parseError) {\n message += ` - ${error.oauthError}`;\n }\n }\n\n reject(new Error(message));\n };\n strategy.redirect = () => {\n reject(new Error('Unexpected redirect'));\n };\n strategy.authenticate(req, { ...(options ?? {}) });\n });\n }\n\n static async executeRefreshTokenStrategy(\n providerStrategy: Strategy,\n refreshToken: string,\n scope: string,\n ): Promise<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * Optionally, the server can issue a new Refresh Token for the user\n */\n refreshToken?: string;\n params: any;\n }> {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as any;\n const OAuth2 = anyStrategy._oauth2.constructor;\n const oauth2 = new OAuth2(\n anyStrategy._oauth2._clientId,\n anyStrategy._oauth2._clientSecret,\n anyStrategy._oauth2._baseSite,\n anyStrategy._oauth2._authorizeUrl,\n anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,\n anyStrategy._oauth2._customHeaders,\n );\n\n oauth2.getOAuthAccessToken(\n refreshToken,\n {\n scope,\n grant_type: 'refresh_token',\n },\n (\n err: Error | null,\n accessToken: string,\n newRefreshToken: string,\n params: any,\n ) => {\n if (err) {\n reject(\n new Error(`Failed to refresh access token ${err.toString()}`),\n );\n }\n if (!accessToken) {\n reject(\n new Error(\n `Failed to refresh access token, no access token received`,\n ),\n );\n }\n\n resolve({\n accessToken,\n refreshToken: newRefreshToken,\n params,\n });\n },\n );\n });\n }\n\n static async executeFetchUserProfileStrategy(\n providerStrategy: Strategy,\n accessToken: string,\n ): Promise {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as unknown as {\n userProfile(accessToken: string, callback: Function): void;\n };\n anyStrategy.userProfile(\n accessToken,\n (error: Error, rawProfile: PassportProfile) => {\n if (error) {\n reject(error);\n } else {\n resolve(rawProfile);\n }\n },\n );\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Strategy } from 'passport';\nimport {\n PassportDoneCallback,\n PassportHelpers,\n PassportProfile,\n} from '../passport';\nimport { ProfileTransform } from '../types';\nimport {\n OAuthAuthenticatorAuthenticateInput,\n OAuthAuthenticatorRefreshInput,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorStartInput,\n} from './types';\n\n/** @public */\nexport type PassportOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n id_token?: string;\n scope: string;\n token_type?: string;\n expires_in: number;\n };\n accessToken: string;\n};\n\n/** @public */\nexport type PassportOAuthPrivateInfo = {\n refreshToken?: string;\n};\n\n/** @public */\nexport type PassportOAuthDoneCallback = PassportDoneCallback<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n>;\n\n/** @public */\nexport class PassportOAuthAuthenticatorHelper {\n static defaultProfileTransform: ProfileTransform<\n OAuthAuthenticatorResult\n > = async input => ({\n profile: PassportHelpers.transformProfile(\n input.fullProfile ?? {},\n input.session.idToken,\n ),\n });\n\n static from(strategy: Strategy) {\n return new PassportOAuthAuthenticatorHelper(strategy);\n }\n\n readonly #strategy: Strategy;\n\n private constructor(strategy: Strategy) {\n this.#strategy = strategy;\n }\n\n async start(\n input: OAuthAuthenticatorStartInput,\n options: Record,\n ): Promise<{ url: string; status?: number }> {\n return PassportHelpers.executeRedirectStrategy(input.req, this.#strategy, {\n scope: input.scope,\n state: input.state,\n ...options,\n });\n }\n\n async authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ): Promise> {\n const { result, privateInfo } =\n await PassportHelpers.executeFrameHandlerStrategy<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n >(input.req, this.#strategy);\n\n return {\n fullProfile: result.fullProfile as PassportProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: privateInfo.refreshToken,\n },\n };\n }\n\n async refresh(\n input: OAuthAuthenticatorRefreshInput,\n ): Promise> {\n const result = await PassportHelpers.executeRefreshTokenStrategy(\n this.#strategy,\n input.refreshToken,\n input.scope,\n );\n const fullProfile = await this.fetchProfile(result.accessToken);\n return {\n fullProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: result.refreshToken,\n },\n };\n }\n\n async fetchProfile(accessToken: string): Promise {\n const profile = await PassportHelpers.executeFetchUserProfileStrategy(\n this.#strategy,\n accessToken,\n );\n return profile;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { AuthProviderRouteHandlers } from '../types';\nimport { decodeOAuthState } from './state';\n\n/** @public */\nexport class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {\n static mapConfig(\n config: Config,\n factoryFunc: (envConfig: Config) => AuthProviderRouteHandlers,\n ) {\n const envs = config.keys();\n const handlers = new Map();\n\n for (const env of envs) {\n const envConfig = config.getConfig(env);\n const handler = factoryFunc(envConfig);\n handlers.set(env, handler);\n }\n\n return new OAuthEnvironmentHandler(handlers);\n }\n\n constructor(\n private readonly handlers: Map,\n ) {}\n\n async start(req: express.Request, res: express.Response): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.start(req, res);\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.frameHandler(req, res);\n }\n\n async refresh(req: express.Request, res: express.Response): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.refresh?.(req, res);\n }\n\n async logout(req: express.Request, res: express.Response): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.logout?.(req, res);\n }\n\n private getEnvFromRequest(req: express.Request): string | undefined {\n const reqEnv = req.query.env?.toString();\n if (reqEnv) {\n return reqEnv;\n }\n const stateParams = req.query.state?.toString();\n if (!stateParams) {\n return undefined;\n }\n const { env } = decodeOAuthState(stateParams);\n return env;\n }\n\n private getProviderForEnv(req: express.Request): AuthProviderRouteHandlers {\n const env: string | undefined = this.getEnvFromRequest(req);\n\n if (!env) {\n throw new InputError(`Must specify 'env' query to select environment`);\n }\n\n const handler = this.handlers.get(env);\n if (!handler) {\n throw new NotFoundError(\n `No configuration available for the '${env}' environment of this provider.`,\n );\n }\n\n return handler;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ZodSchema, ZodTypeDef } from 'zod';\nimport { SignInResolver } from '../types';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { JsonObject } from '@backstage/types';\nimport { InputError } from '@backstage/errors';\n\n/** @public */\nexport interface SignInResolverFactory {\n (\n ...options: undefined extends TOptions\n ? [options?: TOptions]\n : [options: TOptions]\n ): SignInResolver;\n optionsJsonSchema?: JsonObject;\n}\n\n/** @public */\nexport interface SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n> {\n optionsSchema?: ZodSchema;\n create(options: TOptionsOutput): SignInResolver;\n}\n\n/** @public */\nexport function createSignInResolverFactory<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n>(\n options: SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput\n >,\n): SignInResolverFactory {\n const { optionsSchema } = options;\n if (!optionsSchema) {\n return (resolverOptions?: TOptionsInput) => {\n if (resolverOptions) {\n throw new InputError('sign-in resolver does not accept options');\n }\n return options.create(undefined as TOptionsOutput);\n };\n }\n const factory = (\n ...[resolverOptions]: undefined extends TOptionsInput\n ? [options?: TOptionsInput]\n : [options: TOptionsInput]\n ) => {\n const parsedOptions = optionsSchema.parse(resolverOptions);\n return options.create(parsedOptions);\n };\n\n factory.optionsJsonSchema = zodToJsonSchema(optionsSchema) as JsonObject;\n return factory;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { SignInResolver } from '../types';\nimport { SignInResolverFactory } from './createSignInResolverFactory';\n\n/** @public */\nexport interface ReadDeclarativeSignInResolverOptions {\n config: Config;\n signInResolverFactories: {\n [name in string]: SignInResolverFactory;\n };\n}\n\n/** @public */\nexport function readDeclarativeSignInResolver(\n options: ReadDeclarativeSignInResolverOptions,\n): SignInResolver | undefined {\n const resolvers =\n options.config\n .getOptionalConfigArray('signIn.resolvers')\n ?.map(resolverConfig => {\n const resolverName = resolverConfig.getString('resolver');\n if (!Object.hasOwn(options.signInResolverFactories, resolverName)) {\n throw new Error(\n `Sign-in resolver '${resolverName}' is not available`,\n );\n }\n const resolver = options.signInResolverFactories[resolverName];\n const { resolver: _ignored, ...resolverOptions } =\n resolverConfig.get();\n\n return resolver(\n Object.keys(resolverOptions).length > 0 ? resolverOptions : undefined,\n );\n }) ?? [];\n\n if (resolvers.length === 0) {\n return undefined;\n }\n\n return async (profile, context) => {\n for (const resolver of resolvers) {\n try {\n return await resolver(profile, context);\n } catch (error) {\n if (error?.name === 'NotFoundError') {\n continue;\n }\n throw error;\n }\n }\n\n throw new Error('Failed to sign-in, unable to resolve user identity');\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createSignInResolverFactory } from './createSignInResolverFactory';\n\n/**\n * A collection of common sign-in resolvers that work with any auth provider.\n *\n * @public\n */\nexport namespace commonSignInResolvers {\n /**\n * A common sign-in resolver that looks up the user using their email address\n * as email of the entity.\n */\n export const emailMatchingUserEntityProfileEmail =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n\n return ctx.signInWithCatalogUser({\n filter: {\n 'spec.profile.email': profile.email,\n },\n });\n };\n },\n });\n\n /**\n * A common sign-in resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\n export const emailLocalPartMatchingUserEntityName =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n const [localPart] = profile.email.split('@');\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: localPart },\n });\n };\n },\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readDeclarativeSignInResolver } from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthEnvironmentHandler } from './OAuthEnvironmentHandler';\nimport { createOAuthRouteHandlers } from './createOAuthRouteHandlers';\nimport { OAuthStateTransform } from './state';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { SignInResolverFactory } from '../sign-in/createSignInResolverFactory';\n\n/** @public */\nexport function createOAuthProviderFactory(options: {\n authenticator: OAuthAuthenticator;\n additionalScopes?: string[];\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform>;\n signInResolver?: SignInResolver>;\n signInResolverFactories?: {\n [name in string]: SignInResolverFactory<\n OAuthAuthenticatorResult,\n unknown\n >;\n };\n}): AuthProviderFactory {\n return ctx => {\n return OAuthEnvironmentHandler.mapConfig(ctx.config, envConfig => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: envConfig,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n return createOAuthRouteHandlers({\n authenticator: options.authenticator,\n appUrl: ctx.appUrl,\n baseUrl: ctx.baseUrl,\n config: envConfig,\n isOriginAllowed: ctx.isOriginAllowed,\n cookieConfigurer: ctx.cookieConfigurer,\n providerId: ctx.providerId,\n resolverContext: ctx.resolverContext,\n additionalScopes: options.additionalScopes,\n stateTransform: options.stateTransform,\n profileTransform: options.profileTransform,\n signInResolver,\n });\n });\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface OAuthSession {\n accessToken: string;\n tokenType: string;\n idToken?: string;\n scope: string;\n expiresInSeconds?: number;\n refreshToken?: string;\n refreshTokenExpiresInSeconds?: number;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorScopeOptions {\n persist?: boolean;\n required?: string[];\n transform?: (options: {\n /** Scopes requested by the client */\n requested: Iterable;\n /** Scopes which have already been granted */\n granted: Iterable;\n /** Scopes that are required for the authenticator to function */\n required: Iterable;\n /** Additional scopes added through configuration */\n additional: Iterable;\n }) => Iterable;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorStartInput {\n scope: string;\n state: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorAuthenticateInput {\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorRefreshInput {\n scope: string;\n refreshToken: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorLogoutInput {\n accessToken?: string;\n refreshToken?: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorResult {\n fullProfile: TProfile;\n session: OAuthSession;\n}\n\n/** @public */\nexport interface OAuthAuthenticator {\n defaultProfileTransform: ProfileTransform>;\n /** @deprecated use `scopes.persist` instead */\n shouldPersistScopes?: boolean;\n scopes?: OAuthAuthenticatorScopeOptions;\n initialize(ctx: { callbackUrl: string; config: Config }): TContext;\n start(\n input: OAuthAuthenticatorStartInput,\n ctx: TContext,\n ): Promise<{ url: string; status?: number }>;\n authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ctx: TContext,\n ): Promise>;\n refresh(\n input: OAuthAuthenticatorRefreshInput,\n ctx: TContext,\n ): Promise>;\n logout?(input: OAuthAuthenticatorLogoutInput, ctx: TContext): Promise;\n}\n\n/** @public */\nexport function createOAuthAuthenticator(\n authenticator: OAuthAuthenticator,\n): OAuthAuthenticator {\n return authenticator;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface ProxyAuthenticator<\n TContext,\n TResult,\n TProviderInfo = undefined,\n> {\n defaultProfileTransform: ProfileTransform;\n initialize(ctx: { config: Config }): TContext;\n authenticate(\n options: { req: Request },\n ctx: TContext,\n ): Promise<{ result: TResult; providerInfo?: TProviderInfo }>;\n}\n\n/** @public */\nexport function createProxyAuthenticator(\n authenticator: ProxyAuthenticator,\n): ProxyAuthenticator {\n return authenticator;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { Config } from '@backstage/config';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { ProxyAuthenticator } from './types';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { NotImplementedError } from '@backstage/errors';\n\n/** @public */\nexport interface ProxyAuthRouteHandlersOptions {\n authenticator: ProxyAuthenticator;\n config: Config;\n resolverContext: AuthResolverContext;\n signInResolver: SignInResolver;\n profileTransform?: ProfileTransform;\n}\n\n/** @public */\nexport function createProxyAuthRouteHandlers(\n options: ProxyAuthRouteHandlersOptions,\n): AuthProviderRouteHandlers {\n const { authenticator, config, resolverContext, signInResolver } = options;\n\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config });\n\n return {\n async start(): Promise {\n throw new NotImplementedError('Not implemented');\n },\n\n async frameHandler(): Promise {\n throw new NotImplementedError('Not implemented');\n },\n\n async refresh(this: never, req: Request, res: Response): Promise {\n const { result, providerInfo } = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n\n const response: ClientAuthResponse = {\n profile,\n providerInfo,\n backstageIdentity: prepareBackstageIdentityResponse(identity),\n };\n\n res.status(200).json(response);\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n readDeclarativeSignInResolver,\n SignInResolverFactory,\n} from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { createProxyAuthRouteHandlers } from './createProxyRouteHandlers';\nimport { ProxyAuthenticator } from './types';\n\n/** @public */\nexport function createProxyAuthProviderFactory(options: {\n authenticator: ProxyAuthenticator;\n profileTransform?: ProfileTransform;\n signInResolver?: SignInResolver;\n signInResolverFactories?: Record<\n string,\n SignInResolverFactory\n >;\n}): AuthProviderFactory {\n return ctx => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: ctx.config,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n if (!signInResolver) {\n throw new Error(\n `No sign-in resolver configured for proxy auth provider '${ctx.providerId}'`,\n );\n }\n\n return createProxyAuthRouteHandlers({\n signInResolver,\n config: ctx.config,\n authenticator: options.authenticator,\n resolverContext: ctx.resolverContext,\n profileTransform: options.profileTransform,\n });\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { Request, Response } from 'express';\n\n/**\n * A representation of a successful Backstage sign-in.\n *\n * Compared to the {@link BackstageIdentityResponse} this type omits\n * the decoded identity information embedded in the token.\n *\n * @public\n */\nexport interface BackstageSignInResult {\n /**\n * The token used to authenticate the user within Backstage.\n */\n token: string;\n}\n\n/**\n * Response object containing the {@link BackstageUserIdentity} and the token\n * from the authentication provider.\n *\n * @public\n */\nexport interface BackstageIdentityResponse extends BackstageSignInResult {\n /**\n * The number of seconds until the token expires. If not set, it can be assumed that the token does not expire.\n */\n expiresInSeconds?: number;\n\n /**\n * A plaintext description of the identity that is encapsulated within the token.\n */\n identity: BackstageUserIdentity;\n}\n\n/**\n * User identity information within Backstage.\n *\n * @public\n */\nexport type BackstageUserIdentity = {\n /**\n * The type of identity that this structure represents. In the frontend app\n * this will currently always be 'user'.\n */\n type: 'user';\n\n /**\n * The entityRef of the user in the catalog.\n * For example User:default/sandra\n */\n userEntityRef: string;\n\n /**\n * The user and group entities that the user claims ownership through\n */\n ownershipEntityRefs: string[];\n};\n\n/**\n * A query for a single user in the catalog.\n *\n * If `entityRef` is used, the default kind is `'User'`.\n *\n * If `annotations` are used, all annotations must be present and\n * match the provided value exactly. Only entities of kind `'User'` will be considered.\n *\n * If `filter` are used, only entities of kind `'User'` will be considered unless it is explicitly specified differently in the filter.\n *\n * Regardless of the query method, the query must match exactly one entity\n * in the catalog, or an error will be thrown.\n *\n * @public\n */\nexport type AuthResolverCatalogUserQuery =\n | {\n entityRef:\n | string\n | {\n kind?: string;\n namespace?: string;\n name: string;\n };\n }\n | {\n annotations: Record;\n }\n | {\n filter: EntityFilterQuery;\n };\n\n/**\n * Parameters used to issue new Backstage Tokens\n *\n * @public\n */\nexport type TokenParams = {\n /**\n * The claims that will be embedded within the token. At a minimum, this should include\n * the subject claim, `sub`. It is common to also list entity ownership relations in the\n * `ent` list. Additional claims may also be added at the developer's discretion except\n * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`,\n * `iat`, and `exp`. The Backstage team also maintains the right add new claims in the future\n * without listing the change as a \"breaking change\".\n */\n claims: {\n /** The token subject, i.e. User ID */\n sub: string;\n /** A list of entity references that the user claims ownership through */\n ent?: string[];\n } & Record;\n};\n\n/**\n * The context that is used for auth processing.\n *\n * @public\n */\nexport type AuthResolverContext = {\n /**\n * Issues a Backstage token using the provided parameters.\n */\n issueToken(params: TokenParams): Promise<{ token: string }>;\n\n /**\n * Finds a single user in the catalog using the provided query.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n findCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise<{ entity: Entity }>;\n\n /**\n * Finds a single user in the catalog using the provided query, and then\n * issues an identity for that user using default ownership resolution.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n signInWithCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise;\n};\n\n/**\n * Resolver interface for resolving the ownership entity references for entity\n *\n * @public\n */\nexport interface AuthOwnershipResolver {\n resolveOwnershipEntityRefs(\n entity: Entity,\n ): Promise<{ ownershipEntityRefs: string[] }>;\n}\n\n/**\n * Any Auth provider needs to implement this interface which handles the routes in the\n * auth backend. Any auth API requests from the frontend reaches these methods.\n *\n * The routes in the auth backend API are tied to these methods like below\n *\n * `/auth/[provider]/start -> start`\n * `/auth/[provider]/handler/frame -> frameHandler`\n * `/auth/[provider]/refresh -> refresh`\n * `/auth/[provider]/logout -> logout`\n *\n * @public\n */\nexport interface AuthProviderRouteHandlers {\n /**\n * Handles the start route of the API. This initiates a sign in request with an auth provider.\n *\n * Request\n * - scopes for the auth request (Optional)\n * Response\n * - redirect to the auth provider for the user to sign in or consent.\n * - sets a nonce cookie and also pass the nonce as 'state' query parameter in the redirect request\n */\n start(req: Request, res: Response): Promise;\n\n /**\n * Once the user signs in or consents in the OAuth screen, the auth provider redirects to the\n * callbackURL which is handled by this method.\n *\n * Request\n * - to contain a nonce cookie and a 'state' query parameter\n * Response\n * - postMessage to the window with a payload that contains accessToken, expiryInSeconds?, idToken? and scope.\n * - sets a refresh token cookie if the auth provider supports refresh tokens\n */\n frameHandler(req: Request, res: Response): Promise;\n\n /**\n * (Optional) If the auth provider supports refresh tokens then this method handles\n * requests to get a new access token.\n *\n * Other types of providers may also use this method to implement its own logic to create new sessions\n * upon request. For example, this can be used to create a new session for a provider that handles requests\n * from an authenticating proxy.\n *\n * Request\n * - to contain a refresh token cookie and scope (Optional) query parameter.\n * Response\n * - payload with accessToken, expiryInSeconds?, idToken?, scope and user profile information.\n */\n refresh?(req: Request, res: Response): Promise;\n\n /**\n * (Optional) Handles sign out requests\n *\n * Response\n * - removes the refresh token cookie\n */\n logout?(req: Request, res: Response): Promise;\n}\n\n/**\n * @public\n * @deprecated Use top-level properties passed to `AuthProviderFactory` instead\n */\nexport type AuthProviderConfig = {\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n};\n\n/** @public */\nexport type AuthProviderFactory = (options: {\n providerId: string;\n /** @deprecated Use top-level properties instead */\n globalConfig: AuthProviderConfig;\n config: Config;\n logger: LoggerService;\n resolverContext: AuthResolverContext;\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n}) => AuthProviderRouteHandlers;\n\n/** @public */\nexport type ClientAuthResponse = {\n providerInfo: TProviderInfo;\n profile: ProfileInfo;\n backstageIdentity?: BackstageIdentityResponse;\n};\n\n/**\n * Type of sign in information context. Includes the profile information and\n * authentication result which contains auth related information.\n *\n * @public\n */\nexport type SignInInfo = {\n /**\n * The simple profile passed down for use in the frontend.\n */\n profile: ProfileInfo;\n\n /**\n * The authentication result that was received from the authentication\n * provider.\n */\n result: TAuthResult;\n};\n\n/**\n * Describes the function which handles the result of a successful\n * authentication. Must return a valid {@link @backstage/plugin-auth-node#BackstageSignInResult}.\n *\n * @public\n */\nexport type SignInResolver = (\n info: SignInInfo,\n context: AuthResolverContext,\n) => Promise;\n\n/**\n * Describes the function that transforms the result of a successful\n * authentication into a {@link ProfileInfo} object.\n *\n * This function may optionally throw an error in order to reject authentication.\n *\n * @public\n */\nexport type ProfileTransform = (\n result: TResult,\n context: AuthResolverContext,\n) => Promise<{ profile: ProfileInfo }>;\n\n/**\n * Used to display login information to user, i.e. sidebar popup.\n *\n * It is also temporarily used as the profile of the signed-in user's Backstage\n * identity, but we want to replace that with data from identity and/org catalog\n * service\n *\n * @public\n */\nexport type ProfileInfo = {\n /**\n * Email ID of the signed in user.\n */\n email?: string;\n /**\n * Display name that can be presented to the signed in user.\n */\n displayName?: string;\n /**\n * URL to an image that can be used as the display image or avatar of the\n * signed in user.\n */\n picture?: string;\n};\n\n/**\n * The callback used to resolve the cookie configuration for auth providers that use cookies.\n * @public\n */\nexport type CookieConfigurer = (ctx: {\n /** ID of the auth provider that this configuration applies to */\n providerId: string;\n /** The externally reachable base URL of the auth-backend plugin */\n baseUrl: string;\n /** The configured callback URL of the auth provider */\n callbackUrl: string;\n /** The origin URL of the app */\n appOrigin: string;\n}) => {\n domain: string;\n path: string;\n secure: boolean;\n sameSite?: 'none' | 'lax' | 'strict';\n};\n\n/**\n * Core properties of various token types.\n *\n * @public\n */\nexport const tokenTypes = Object.freeze({\n user: Object.freeze({\n typParam: 'vnd.backstage.user',\n audClaim: 'backstage',\n }),\n limitedUser: Object.freeze({\n typParam: 'vnd.backstage.limited-user',\n }),\n plugin: Object.freeze({\n typParam: 'vnd.backstage.plugin',\n }),\n});\n"],"names":["createExtensionPoint","serializeError","crypto","InputError","AuthenticationError","jwtVerify","decodeJwt","decodeProtectedHeader","createRemoteJWKSet","pickBy","NotAllowedError","URL","isError","NotFoundError","zodToJsonSchema","commonSignInResolvers","NotImplementedError"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"index.cjs.js","sources":["../src/extensions/AuthProvidersExtensionPoint.ts","../src/extensions/AuthOwnershipResolutionExtensionPoint.ts","../src/flow/sendWebMessageResponse.ts","../src/identity/prepareBackstageIdentityResponse.ts","../src/identity/getBearerTokenFromAuthorizationHeader.ts","../src/identity/DefaultIdentityClient.ts","../src/identity/IdentityClient.ts","../src/oauth/state.ts","../src/oauth/OAuthCookieManager.ts","../src/oauth/CookieScopeManager.ts","../src/oauth/createOAuthRouteHandlers.ts","../src/passport/PassportHelpers.ts","../src/oauth/PassportOAuthAuthenticatorHelper.ts","../src/oauth/OAuthEnvironmentHandler.ts","../src/sign-in/createSignInResolverFactory.ts","../src/sign-in/readDeclarativeSignInResolver.ts","../src/sign-in/commonSignInResolvers.ts","../src/oauth/createOAuthProviderFactory.ts","../src/oauth/types.ts","../src/proxy/types.ts","../src/proxy/createProxyRouteHandlers.ts","../src/proxy/createProxyAuthProviderFactory.ts","../src/types.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { AuthProviderFactory } from '../types';\n\n/** @public */\nexport interface AuthProviderRegistrationOptions {\n providerId: string;\n factory: AuthProviderFactory;\n}\n\n/** @public */\nexport interface AuthProvidersExtensionPoint {\n registerProvider(options: AuthProviderRegistrationOptions): void;\n}\n\n/** @public */\nexport const authProvidersExtensionPoint =\n createExtensionPoint({\n id: 'auth.providers',\n });\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { AuthOwnershipResolver } from '../types';\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\n\n/** @public */\nexport interface AuthOwnershipResolutionExtensionPoint {\n setAuthOwnershipResolver(ownershipResolver: AuthOwnershipResolver): void;\n}\n\n/** @public */\nexport const authOwnershipResolutionExtensionPoint =\n createExtensionPoint({\n id: 'auth.ownershipResolution',\n });\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Response } from 'express';\nimport crypto from 'crypto';\nimport { ClientAuthResponse } from '../types';\nimport { serializeError } from '@backstage/errors';\n\n/**\n * Payload sent as a post message after the auth request is complete.\n * If successful then has a valid payload with Auth information else contains an error.\n *\n * @public\n */\nexport type WebMessageResponse =\n | {\n type: 'authorization_response';\n response: ClientAuthResponse;\n }\n | {\n type: 'authorization_response';\n error: Error;\n };\n\n/** @internal */\nexport function safelyEncodeURIComponent(value: string): string {\n // Note the g at the end of the regex; all occurrences of single quotes must\n // be replaced, which encodeURIComponent does not do itself by default\n return encodeURIComponent(value).replace(/'/g, '%27');\n}\n\n/** @public */\nexport function sendWebMessageResponse(\n res: Response,\n appOrigin: string,\n response: WebMessageResponse,\n): void {\n const jsonData = JSON.stringify(response, (_, value) => {\n if (value instanceof Error) {\n return serializeError(value);\n }\n return value;\n });\n const base64Data = safelyEncodeURIComponent(jsonData);\n const base64Origin = safelyEncodeURIComponent(appOrigin);\n\n // NOTE: It is absolutely imperative that we use the safe encoder above, to\n // be sure that the js code below does not allow the injection of malicious\n // data.\n\n // TODO: Make target app origin configurable globally\n\n //\n // postMessage fails silently if the targetOrigin is disallowed.\n // So 2 postMessages are sent from the popup to the parent window.\n // First, the origin being used to post the actual authorization response is\n // shared with the parent window with a postMessage with targetOrigin '*'.\n // Second, the actual authorization response is sent with the app origin\n // as the targetOrigin.\n // If the first message was received but the actual auth response was\n // never received, the event listener can conclude that targetOrigin\n // was disallowed, indicating potential misconfiguration.\n //\n const script = `\n var authResponse = decodeURIComponent('${base64Data}');\n var origin = decodeURIComponent('${base64Origin}');\n var originInfo = {'type': 'config_info', 'targetOrigin': origin};\n (window.opener || window.parent).postMessage(originInfo, '*');\n (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin);\n setTimeout(() => {\n window.close();\n }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)\n `;\n const hash = crypto.createHash('sha256').update(script).digest('base64');\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('X-Frame-Options', 'sameorigin');\n res.setHeader('Content-Security-Policy', `script-src 'sha256-${hash}'`);\n res.end(``);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport {\n BackstageIdentityResponse,\n BackstageSignInResult,\n} from '@backstage/plugin-auth-node';\n\nfunction parseJwtPayload(token: string) {\n const [_header, payload, _signature] = token.split('.');\n return JSON.parse(Buffer.from(payload, 'base64').toString());\n}\n\n/**\n * Parses a Backstage-issued token and decorates the\n * {@link @backstage/plugin-auth-node#BackstageIdentityResponse} with identity information sourced from the\n * token.\n *\n * @public\n */\nexport function prepareBackstageIdentityResponse(\n result: BackstageSignInResult,\n): BackstageIdentityResponse {\n if (!result.token) {\n throw new InputError(`Identity response must return a token`);\n }\n\n const { sub, ent = [], exp: expStr } = parseJwtPayload(result.token);\n if (!sub) {\n throw new InputError(\n `Identity response must return a token with subject claim`,\n );\n }\n\n const expAt = Number(expStr);\n\n // Default to 1 hour if no expiration is set, in particular to make testing simpler\n const exp = expAt ? Math.round(expAt - Date.now() / 1000) : undefined;\n if (exp && exp < 0) {\n throw new InputError(`Identity response must not return an expired token`);\n }\n\n return {\n ...result,\n expiresInSeconds: exp,\n identity: {\n type: 'user',\n userEntityRef: sub,\n ownershipEntityRefs: ent,\n },\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Parses the given authorization header and returns the bearer token, or\n * undefined if no bearer token is given.\n *\n * @remarks\n *\n * This function is explicitly built to tolerate bad inputs safely, so you may\n * call it directly with e.g. the output of `req.header('authorization')`\n * without first checking that it exists.\n *\n * @deprecated Use the `credentials` method of `HttpAuthService` from `@backstage/backend-plugin-api` instead\n * @public\n */\nexport function getBearerTokenFromAuthorizationHeader(\n authorizationHeader: unknown,\n): string | undefined {\n if (typeof authorizationHeader !== 'string') {\n return undefined;\n }\n const matches = authorizationHeader.match(/^Bearer[ ]+(\\S+)$/i);\n return matches?.[1];\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n jwtVerify,\n} from 'jose';\nimport { GetKeyFunction } from 'jose/dist/types/types';\nimport { getBearerTokenFromAuthorizationHeader } from './getBearerTokenFromAuthorizationHeader';\nimport { IdentityApi, IdentityApiGetIdentityRequest } from './IdentityApi';\nimport { BackstageIdentityResponse } from '../types';\n\nconst CLOCK_MARGIN_S = 10;\n\n/**\n * An identity client options object which allows extra configurations\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport type IdentityClientOptions = {\n discovery: PluginEndpointDiscovery;\n issuer?: string;\n\n /** JWS \"alg\" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.\n * More info on supported algorithms: https://github.com/panva/jose */\n algorithms?: string[];\n};\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport class DefaultIdentityClient implements IdentityApi {\n private readonly discovery: PluginEndpointDiscovery;\n private readonly issuer?: string;\n private readonly algorithms?: string[];\n private keyStore?: GetKeyFunction;\n private keyStoreUpdated: number = 0;\n\n /**\n * Create a new {@link DefaultIdentityClient} instance.\n */\n static create(options: IdentityClientOptions): DefaultIdentityClient {\n return new DefaultIdentityClient(options);\n }\n\n private constructor(options: IdentityClientOptions) {\n this.discovery = options.discovery;\n this.issuer = options.issuer;\n this.algorithms = options.hasOwnProperty('algorithms')\n ? options.algorithms\n : ['ES256'];\n }\n\n async getIdentity(options: IdentityApiGetIdentityRequest) {\n const {\n request: { headers },\n } = options;\n if (!headers.authorization) {\n return undefined;\n }\n try {\n return await this.authenticate(\n getBearerTokenFromAuthorizationHeader(headers.authorization),\n );\n } catch (e) {\n throw new AuthenticationError(e.message);\n }\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use getIdentity instead of authenticate to retrieve the user\n * identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise {\n // Extract token from header\n if (!token) {\n throw new AuthenticationError('No token specified');\n }\n\n // Verify token claims and signature\n // Note: Claims must match those set by TokenFactory when issuing tokens\n // Note: verify throws if verification fails\n // Check if the keystore needs to be updated\n await this.refreshKeyStore(token);\n if (!this.keyStore) {\n throw new AuthenticationError('No keystore exists');\n }\n const decoded = await jwtVerify(token, this.keyStore, {\n algorithms: this.algorithms,\n audience: 'backstage',\n issuer: this.issuer,\n });\n // Verified, return the matching user as BackstageIdentity\n // TODO: Settle internal user format/properties\n if (!decoded.payload.sub) {\n throw new AuthenticationError('No user sub found in token');\n }\n\n const user: BackstageIdentityResponse = {\n token,\n identity: {\n type: 'user',\n userEntityRef: decoded.payload.sub,\n ownershipEntityRefs: decoded.payload.ent\n ? (decoded.payload.ent as string[])\n : [],\n },\n };\n return user;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n private async refreshKeyStore(rawJwtToken: string): Promise {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const url = await this.discovery.getBaseUrl('auth');\n const endpoint = new URL(`${url}/.well-known/jwks.json`);\n this.keyStore = createRemoteJWKSet(endpoint);\n this.keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DefaultIdentityClient,\n IdentityClientOptions,\n} from './DefaultIdentityClient';\nimport { BackstageIdentityResponse } from '../types';\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @public\n * @experimental This is not a stable API yet\n * @deprecated Please migrate to the DefaultIdentityClient.\n */\nexport class IdentityClient {\n private readonly defaultIdentityClient: DefaultIdentityClient;\n static create(options: IdentityClientOptions): IdentityClient {\n return new IdentityClient(DefaultIdentityClient.create(options));\n }\n\n private constructor(defaultIdentityClient: DefaultIdentityClient) {\n this.defaultIdentityClient = defaultIdentityClient;\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use IdentityApi#getIdentity instead of authenticate\n * to retrieve the user identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise {\n return await this.defaultIdentityClient.authenticate(token);\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport pickBy from 'lodash/pickBy';\nimport { Request } from 'express';\nimport { NotAllowedError } from '@backstage/errors';\n\n/**\n * A type for the serialized value in the `state` parameter of the OAuth authorization flow\n * @public\n */\nexport type OAuthState = {\n nonce: string;\n env: string;\n origin?: string;\n scope?: string;\n redirectUrl?: string;\n flow?: string;\n audience?: string;\n};\n\n/** @public */\nexport type OAuthStateTransform = (\n state: OAuthState,\n context: { req: Request },\n) => Promise<{ state: OAuthState }>;\n\n/** @public */\nexport function encodeOAuthState(state: OAuthState): string {\n const stateString = new URLSearchParams(\n pickBy(state, value => value !== undefined),\n ).toString();\n\n return Buffer.from(stateString, 'utf-8').toString('hex');\n}\n\n/** @public */\nexport function decodeOAuthState(encodedState: string): OAuthState {\n const state = Object.fromEntries(\n new URLSearchParams(Buffer.from(encodedState, 'hex').toString('utf-8')),\n );\n if (!state.env || state.env?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing env');\n }\n if (!state.nonce || state.nonce?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing nonce');\n }\n\n return state as OAuthState;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { CookieConfigurer } from '../types';\n\nconst THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000;\nconst TEN_MINUTES_MS = 600 * 1000;\n\nconst defaultCookieConfigurer: CookieConfigurer = ({\n callbackUrl,\n providerId,\n appOrigin,\n}) => {\n const { hostname: domain, pathname, protocol } = new URL(callbackUrl);\n const secure = protocol === 'https:';\n\n // For situations where the auth-backend is running on a\n // different domain than the app, we set the SameSite attribute\n // to 'none' to allow third-party access to the cookie, but\n // only if it's in a secure context (https).\n let sameSite: ReturnType['sameSite'] = 'lax';\n if (new URL(appOrigin).hostname !== domain && secure) {\n sameSite = 'none';\n }\n\n // If the provider supports callbackUrls, the pathname will\n // contain the complete path to the frame handler so we need\n // to slice off the trailing part of the path.\n const path = pathname.endsWith(`${providerId}/handler/frame`)\n ? pathname.slice(0, -'/handler/frame'.length)\n : `${pathname}/${providerId}`;\n\n return { domain, path, secure, sameSite };\n};\n\n/** @internal */\nexport class OAuthCookieManager {\n private readonly cookieConfigurer: CookieConfigurer;\n private readonly nonceCookie: string;\n private readonly refreshTokenCookie: string;\n private readonly grantedScopeCookie: string;\n\n constructor(\n private readonly options: {\n providerId: string;\n defaultAppOrigin: string;\n baseUrl: string;\n callbackUrl: string;\n cookieConfigurer?: CookieConfigurer;\n },\n ) {\n this.cookieConfigurer = options.cookieConfigurer ?? defaultCookieConfigurer;\n\n this.nonceCookie = `${options.providerId}-nonce`;\n this.refreshTokenCookie = `${options.providerId}-refresh-token`;\n this.grantedScopeCookie = `${options.providerId}-granted-scope`;\n }\n\n private getConfig(origin?: string, pathSuffix: string = '') {\n const cookieConfig = this.cookieConfigurer({\n providerId: this.options.providerId,\n baseUrl: this.options.baseUrl,\n callbackUrl: this.options.callbackUrl,\n appOrigin: origin ?? this.options.defaultAppOrigin,\n });\n return {\n httpOnly: true,\n sameSite: 'lax' as const,\n ...cookieConfig,\n path: cookieConfig.path + pathSuffix,\n };\n }\n\n setNonce(res: Response, nonce: string, origin?: string) {\n res.cookie(this.nonceCookie, nonce, {\n maxAge: TEN_MINUTES_MS,\n ...this.getConfig(origin, '/handler'),\n });\n }\n\n setRefreshToken(res: Response, refreshToken: string, origin?: string) {\n res.cookie(this.refreshTokenCookie, refreshToken, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n removeRefreshToken(res: Response, origin?: string) {\n res.cookie(this.refreshTokenCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n removeGrantedScopes(res: Response, origin?: string) {\n res.cookie(this.grantedScopeCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n setGrantedScopes(res: Response, scope: string, origin?: string) {\n res.cookie(this.grantedScopeCookie, scope, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n getNonce(req: Request): string | undefined {\n return req.cookies[this.nonceCookie];\n }\n\n getRefreshToken(req: Request): string | undefined {\n return req.cookies[this.refreshTokenCookie];\n }\n\n getGrantedScopes(req: Request): string | undefined {\n return req.cookies[this.grantedScopeCookie];\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport {\n OAuthAuthenticator,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorScopeOptions,\n} from './types';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport { OAuthState } from './state';\nimport { AuthenticationError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\n\nfunction reqRes(req: express.Request): express.Response {\n const res = req.res;\n if (!res) {\n throw new Error('No response object found in request');\n }\n return res;\n}\n\nconst defaultTransform: Required['transform'] =\n ({ requested, granted, required, additional }) => {\n return [...requested, ...granted, ...required, ...additional];\n };\n\nfunction splitScope(scope?: string): Iterable {\n if (!scope) {\n return [];\n }\n\n return scope.split(/[\\s|,]/).filter(Boolean);\n}\n\nexport class CookieScopeManager {\n static create(options: {\n config?: Config;\n additionalScopes?: string[];\n authenticator: OAuthAuthenticator;\n cookieManager: OAuthCookieManager;\n }) {\n const { authenticator, config } = options;\n\n const shouldPersistScopes =\n authenticator.scopes?.persist ??\n authenticator.shouldPersistScopes ??\n false;\n\n const configScopes =\n typeof config?.getOptional('additionalScopes') === 'string'\n ? splitScope(config.getString('additionalScopes'))\n : config?.getOptionalStringArray('additionalScopes') ?? [];\n\n const transform = authenticator?.scopes?.transform ?? defaultTransform;\n const additional = [...configScopes, ...(options.additionalScopes ?? [])];\n const required = authenticator?.scopes?.required ?? [];\n\n return new CookieScopeManager(\n (requested, granted) =>\n Array.from(\n new Set(transform({ required, additional, requested, granted })),\n ).join(' '),\n shouldPersistScopes ? options.cookieManager : undefined,\n );\n }\n\n private constructor(\n private readonly scopeTransform: (\n requested: Iterable,\n granted: Iterable,\n ) => string,\n private readonly cookieManager?: OAuthCookieManager,\n ) {}\n\n async start(\n req: express.Request,\n ): Promise<{ scopeState?: Partial; scope: string }> {\n const requestScope = splitScope(req.query.scope?.toString());\n const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));\n\n const scope = this.scopeTransform(requestScope, grantedScope);\n\n if (this.cookieManager) {\n // If scopes are persisted then we pass them through the state so that we\n // can set the cookie on successful auth\n return {\n scope,\n scopeState: { scope },\n };\n }\n return { scope };\n }\n\n async handleCallback(\n req: express.Request,\n ctx: {\n result: OAuthAuthenticatorResult;\n state: OAuthState;\n origin?: string;\n },\n ): Promise {\n // If we are not persisting scopes we can forward the scope from the result\n if (!this.cookieManager) {\n return Array.from(splitScope(ctx.result.session.scope)).join(' ');\n }\n\n const scope = ctx.state.scope;\n if (scope === undefined) {\n throw new AuthenticationError('No scope found in OAuth state');\n }\n\n // Store the scope that we have been granted for this session. This is useful if\n // the provider does not return granted scopes on refresh or if they are normalized.\n this.cookieManager.setGrantedScopes(reqRes(req), scope, ctx.origin);\n\n return scope;\n }\n\n async clear(req: express.Request): Promise {\n if (this.cookieManager) {\n this.cookieManager.removeGrantedScopes(reqRes(req), req.get('origin'));\n }\n }\n\n async refresh(req: express.Request): Promise<{\n scope: string;\n commit(result: OAuthAuthenticatorResult): Promise;\n }> {\n const requestScope = splitScope(req.query.scope?.toString());\n const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));\n\n const scope = this.scopeTransform(requestScope, grantedScope);\n\n return {\n scope,\n commit: async result => {\n if (this.cookieManager) {\n this.cookieManager.setGrantedScopes(\n reqRes(req),\n scope,\n req.get('origin'),\n );\n return scope;\n }\n\n return Array.from(splitScope(result.session.scope)).join(' ');\n },\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport crypto from 'crypto';\nimport { URL } from 'url';\nimport {\n AuthenticationError,\n InputError,\n isError,\n NotAllowedError,\n} from '@backstage/errors';\nimport {\n encodeOAuthState,\n decodeOAuthState,\n OAuthStateTransform,\n} from './state';\nimport { sendWebMessageResponse } from '../flow';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n CookieConfigurer,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { Config } from '@backstage/config';\nimport { CookieScopeManager } from './CookieScopeManager';\n\n/** @public */\nexport interface OAuthRouteHandlersOptions {\n authenticator: OAuthAuthenticator;\n appUrl: string;\n baseUrl: string;\n isOriginAllowed: (origin: string) => boolean;\n providerId: string;\n config: Config;\n resolverContext: AuthResolverContext;\n additionalScopes?: string[];\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform>;\n cookieConfigurer?: CookieConfigurer;\n signInResolver?: SignInResolver>;\n}\n\n/** @internal */\ntype ClientOAuthResponse = ClientAuthResponse<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * (Optional) Id token issued for the signed in user.\n */\n idToken?: string;\n /**\n * Expiry of the access token in seconds.\n */\n expiresInSeconds?: number;\n /**\n * Scopes granted for the access token.\n */\n scope: string;\n}>;\n\n/** @public */\nexport function createOAuthRouteHandlers(\n options: OAuthRouteHandlersOptions,\n): AuthProviderRouteHandlers {\n const {\n authenticator,\n config,\n baseUrl,\n appUrl,\n providerId,\n isOriginAllowed,\n cookieConfigurer,\n resolverContext,\n signInResolver,\n } = options;\n\n const defaultAppOrigin = new URL(appUrl).origin;\n const callbackUrl =\n config.getOptionalString('callbackUrl') ??\n `${baseUrl}/${providerId}/handler/frame`;\n\n const stateTransform = options.stateTransform ?? (state => ({ state }));\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config, callbackUrl });\n const cookieManager = new OAuthCookieManager({\n baseUrl,\n callbackUrl,\n defaultAppOrigin,\n providerId,\n cookieConfigurer,\n });\n\n const scopeManager = CookieScopeManager.create({\n config,\n authenticator,\n cookieManager,\n additionalScopes: options.additionalScopes,\n });\n\n return {\n async start(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n const env = req.query.env?.toString();\n const origin = req.query.origin?.toString();\n const redirectUrl = req.query.redirectUrl?.toString();\n const flow = req.query.flow?.toString();\n\n if (!env) {\n throw new InputError('No env provided in request query parameters');\n }\n\n const nonce = crypto.randomBytes(16).toString('base64');\n // set a nonce cookie before redirecting to oauth provider\n cookieManager.setNonce(res, nonce, origin);\n\n const { scope, scopeState } = await scopeManager.start(req);\n\n const state = { nonce, env, origin, redirectUrl, flow, ...scopeState };\n const { state: transformedState } = await stateTransform(state, { req });\n\n const { url, status } = await options.authenticator.start(\n {\n req,\n scope,\n state: encodeOAuthState(transformedState),\n },\n authenticatorCtx,\n );\n\n res.statusCode = status || 302;\n res.setHeader('Location', url);\n res.setHeader('Content-Length', '0');\n res.end();\n },\n\n async frameHandler(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n let origin = defaultAppOrigin;\n\n try {\n const state = decodeOAuthState(req.query.state?.toString() ?? '');\n\n if (state.origin) {\n try {\n origin = new URL(state.origin).origin;\n } catch {\n throw new NotAllowedError('App origin is invalid, failed to parse');\n }\n if (!isOriginAllowed(origin)) {\n throw new NotAllowedError(`Origin '${origin}' is not allowed`);\n }\n }\n\n // The same nonce is passed through cookie and state, and they must match\n const cookieNonce = cookieManager.getNonce(req);\n const stateNonce = state.nonce;\n if (!cookieNonce) {\n throw new NotAllowedError('Auth response is missing cookie nonce');\n }\n if (cookieNonce !== stateNonce) {\n throw new NotAllowedError('Invalid nonce');\n }\n\n const result = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n const { profile } = await profileTransform(result, resolverContext);\n\n const signInResult =\n signInResolver &&\n (await signInResolver({ profile, result }, resolverContext));\n\n const grantedScopes = await scopeManager.handleCallback(req, {\n result,\n state,\n origin,\n });\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: grantedScopes,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n ...(signInResult && {\n backstageIdentity: prepareBackstageIdentityResponse(signInResult),\n }),\n };\n\n if (result.session.refreshToken) {\n // set new refresh token\n cookieManager.setRefreshToken(\n res,\n result.session.refreshToken,\n origin,\n );\n }\n\n // When using the redirect flow we rely on refresh token we just\n // acquired to get a new session once we're back in the app.\n if (state.flow === 'redirect') {\n if (!state.redirectUrl) {\n throw new InputError(\n 'No redirectUrl provided in request query parameters',\n );\n }\n res.redirect(state.redirectUrl);\n return;\n }\n\n // post message back to popup if successful\n sendWebMessageResponse(res, origin, {\n type: 'authorization_response',\n response,\n });\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n // post error message back to popup if failure\n sendWebMessageResponse(res, origin, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n },\n\n async logout(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (authenticator.logout) {\n const refreshToken = cookieManager.getRefreshToken(req);\n await authenticator.logout({ req, refreshToken }, authenticatorCtx);\n }\n\n // remove refresh token cookie if it is set\n cookieManager.removeRefreshToken(res, req.get('origin'));\n\n // remove persisted scopes\n await scopeManager.clear(req);\n\n res.status(200).end();\n },\n\n async refresh(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n try {\n const refreshToken = cookieManager.getRefreshToken(req);\n\n // throw error if refresh token is missing in the request\n if (!refreshToken) {\n throw new InputError('Missing session cookie');\n }\n\n const scopeRefresh = await scopeManager.refresh(req);\n\n const result = await authenticator.refresh(\n { req, scope: scopeRefresh.scope, refreshToken },\n authenticatorCtx,\n );\n\n const grantedScope = await scopeRefresh.commit(result);\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const newRefreshToken = result.session.refreshToken;\n if (newRefreshToken && newRefreshToken !== refreshToken) {\n cookieManager.setRefreshToken(\n res,\n newRefreshToken,\n req.get('origin'),\n );\n }\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: grantedScope,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n };\n\n if (signInResolver) {\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n response.backstageIdentity =\n prepareBackstageIdentityResponse(identity);\n }\n\n res.status(200).json(response);\n } catch (error) {\n throw new AuthenticationError('Refresh failed', error);\n }\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request } from 'express';\nimport { decodeJwt } from 'jose';\nimport { Strategy } from 'passport';\nimport { PassportProfile } from './types';\nimport { ProfileInfo } from '../types';\n\n// Re-declared here to avoid direct dependency on passport-oauth2\n/** @internal */\ninterface InternalOAuthError extends Error {\n oauthError?: {\n data?: string;\n };\n}\n\n/** @public */\nexport class PassportHelpers {\n private constructor() {}\n\n static transformProfile = (\n profile: PassportProfile,\n idToken?: string,\n ): ProfileInfo => {\n let email: string | undefined = undefined;\n if (profile.emails && profile.emails.length > 0) {\n const [firstEmail] = profile.emails;\n email = firstEmail.value;\n } else if (profile.email) {\n // This is the case for Atlassian\n email = profile.email;\n }\n\n let picture: string | undefined = undefined;\n if (profile.avatarUrl) {\n picture = profile.avatarUrl;\n } else if (profile.photos && profile.photos.length > 0) {\n const [firstPhoto] = profile.photos;\n picture = firstPhoto.value;\n } else if (profile.photo) {\n // This is the case for Atlassian\n picture = profile.photo;\n }\n\n let displayName: string | undefined =\n profile.displayName ?? profile.username ?? profile.id;\n\n if ((!email || !picture || !displayName) && idToken) {\n try {\n const decoded = decodeJwt(idToken) as {\n email?: string;\n name?: string;\n picture?: string;\n };\n if (!email && decoded.email) {\n email = decoded.email;\n }\n if (!picture && decoded.picture) {\n picture = decoded.picture;\n }\n if (!displayName && decoded.name) {\n displayName = decoded.name;\n }\n } catch (e) {\n throw new Error(`Failed to parse id token and get profile info, ${e}`);\n }\n }\n\n return {\n email,\n picture,\n displayName,\n };\n };\n\n static async executeRedirectStrategy(\n req: Request,\n providerStrategy: Strategy,\n options: Record,\n ): Promise<{\n /**\n * URL to redirect to\n */\n url: string;\n /**\n * Status code to use for the redirect\n */\n status?: number;\n }> {\n return new Promise(resolve => {\n const strategy = Object.create(providerStrategy);\n strategy.redirect = (url: string, status?: number) => {\n resolve({ url, status: status ?? undefined });\n };\n\n strategy.authenticate(req, { ...options });\n });\n }\n\n static async executeFrameHandlerStrategy(\n req: Request,\n providerStrategy: Strategy,\n options?: Record,\n ): Promise<{ result: TResult; privateInfo: TPrivateInfo }> {\n return new Promise((resolve, reject) => {\n const strategy = Object.create(providerStrategy);\n strategy.success = (result: any, privateInfo: any) => {\n resolve({ result, privateInfo });\n };\n strategy.fail = (\n info: { type: 'success' | 'error'; message?: string },\n // _status: number,\n ) => {\n reject(new Error(`Authentication rejected, ${info.message ?? ''}`));\n };\n strategy.error = (error: InternalOAuthError) => {\n let message = `Authentication failed, ${error.message}`;\n\n if (error.oauthError?.data) {\n try {\n const errorData = JSON.parse(error.oauthError.data);\n\n if (errorData.message) {\n message += ` - ${errorData.message}`;\n }\n } catch (parseError) {\n message += ` - ${error.oauthError}`;\n }\n }\n\n reject(new Error(message));\n };\n strategy.redirect = () => {\n reject(new Error('Unexpected redirect'));\n };\n strategy.authenticate(req, { ...(options ?? {}) });\n });\n }\n\n static async executeRefreshTokenStrategy(\n providerStrategy: Strategy,\n refreshToken: string,\n scope: string,\n ): Promise<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * Optionally, the server can issue a new Refresh Token for the user\n */\n refreshToken?: string;\n params: any;\n }> {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as any;\n const OAuth2 = anyStrategy._oauth2.constructor;\n const oauth2 = new OAuth2(\n anyStrategy._oauth2._clientId,\n anyStrategy._oauth2._clientSecret,\n anyStrategy._oauth2._baseSite,\n anyStrategy._oauth2._authorizeUrl,\n anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,\n anyStrategy._oauth2._customHeaders,\n );\n\n oauth2.getOAuthAccessToken(\n refreshToken,\n {\n scope,\n grant_type: 'refresh_token',\n },\n (\n err: Error | null,\n accessToken: string,\n newRefreshToken: string,\n params: any,\n ) => {\n if (err) {\n reject(\n new Error(`Failed to refresh access token ${err.toString()}`),\n );\n }\n if (!accessToken) {\n reject(\n new Error(\n `Failed to refresh access token, no access token received`,\n ),\n );\n }\n\n resolve({\n accessToken,\n refreshToken: newRefreshToken,\n params,\n });\n },\n );\n });\n }\n\n static async executeFetchUserProfileStrategy(\n providerStrategy: Strategy,\n accessToken: string,\n ): Promise {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as unknown as {\n userProfile(accessToken: string, callback: Function): void;\n };\n anyStrategy.userProfile(\n accessToken,\n (error: Error, rawProfile: PassportProfile) => {\n if (error) {\n reject(error);\n } else {\n resolve(rawProfile);\n }\n },\n );\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Strategy } from 'passport';\nimport {\n PassportDoneCallback,\n PassportHelpers,\n PassportProfile,\n} from '../passport';\nimport { ProfileTransform } from '../types';\nimport {\n OAuthAuthenticatorAuthenticateInput,\n OAuthAuthenticatorRefreshInput,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorStartInput,\n} from './types';\n\n/** @public */\nexport type PassportOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n id_token?: string;\n scope: string;\n token_type?: string;\n expires_in: number;\n };\n accessToken: string;\n};\n\n/** @public */\nexport type PassportOAuthPrivateInfo = {\n refreshToken?: string;\n};\n\n/** @public */\nexport type PassportOAuthDoneCallback = PassportDoneCallback<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n>;\n\n/** @public */\nexport class PassportOAuthAuthenticatorHelper {\n static defaultProfileTransform: ProfileTransform<\n OAuthAuthenticatorResult\n > = async input => ({\n profile: PassportHelpers.transformProfile(\n input.fullProfile ?? {},\n input.session.idToken,\n ),\n });\n\n static from(strategy: Strategy) {\n return new PassportOAuthAuthenticatorHelper(strategy);\n }\n\n readonly #strategy: Strategy;\n\n private constructor(strategy: Strategy) {\n this.#strategy = strategy;\n }\n\n async start(\n input: OAuthAuthenticatorStartInput,\n options: Record,\n ): Promise<{ url: string; status?: number }> {\n return PassportHelpers.executeRedirectStrategy(input.req, this.#strategy, {\n scope: input.scope,\n state: input.state,\n ...options,\n });\n }\n\n async authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ): Promise> {\n const { result, privateInfo } =\n await PassportHelpers.executeFrameHandlerStrategy<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n >(input.req, this.#strategy);\n\n return {\n fullProfile: result.fullProfile as PassportProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: privateInfo.refreshToken,\n },\n };\n }\n\n async refresh(\n input: OAuthAuthenticatorRefreshInput,\n ): Promise> {\n const result = await PassportHelpers.executeRefreshTokenStrategy(\n this.#strategy,\n input.refreshToken,\n input.scope,\n );\n const fullProfile = await this.fetchProfile(result.accessToken);\n return {\n fullProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: result.refreshToken,\n },\n };\n }\n\n async fetchProfile(accessToken: string): Promise {\n const profile = await PassportHelpers.executeFetchUserProfileStrategy(\n this.#strategy,\n accessToken,\n );\n return profile;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { AuthProviderRouteHandlers } from '../types';\nimport { decodeOAuthState } from './state';\n\n/** @public */\nexport class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {\n static mapConfig(\n config: Config,\n factoryFunc: (envConfig: Config) => AuthProviderRouteHandlers,\n ) {\n const envs = config.keys();\n const handlers = new Map();\n\n for (const env of envs) {\n const envConfig = config.getConfig(env);\n const handler = factoryFunc(envConfig);\n handlers.set(env, handler);\n }\n\n return new OAuthEnvironmentHandler(handlers);\n }\n\n constructor(\n private readonly handlers: Map,\n ) {}\n\n async start(req: express.Request, res: express.Response): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.start(req, res);\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.frameHandler(req, res);\n }\n\n async refresh(req: express.Request, res: express.Response): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.refresh?.(req, res);\n }\n\n async logout(req: express.Request, res: express.Response): Promise {\n const provider = this.getProviderForEnv(req);\n await provider.logout?.(req, res);\n }\n\n private getEnvFromRequest(req: express.Request): string | undefined {\n const reqEnv = req.query.env?.toString();\n if (reqEnv) {\n return reqEnv;\n }\n const stateParams = req.query.state?.toString();\n if (!stateParams) {\n return undefined;\n }\n const { env } = decodeOAuthState(stateParams);\n return env;\n }\n\n private getProviderForEnv(req: express.Request): AuthProviderRouteHandlers {\n const env: string | undefined = this.getEnvFromRequest(req);\n\n if (!env) {\n throw new InputError(`Must specify 'env' query to select environment`);\n }\n\n const handler = this.handlers.get(env);\n if (!handler) {\n throw new NotFoundError(\n `No configuration available for the '${env}' environment of this provider.`,\n );\n }\n\n return handler;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ZodSchema, ZodTypeDef } from 'zod';\nimport { SignInResolver } from '../types';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { JsonObject } from '@backstage/types';\nimport { InputError } from '@backstage/errors';\n\n/** @public */\nexport interface SignInResolverFactory {\n (\n ...options: undefined extends TOptions\n ? [options?: TOptions]\n : [options: TOptions]\n ): SignInResolver;\n optionsJsonSchema?: JsonObject;\n}\n\n/** @public */\nexport interface SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n> {\n optionsSchema?: ZodSchema;\n create(options: TOptionsOutput): SignInResolver;\n}\n\n/** @public */\nexport function createSignInResolverFactory<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n>(\n options: SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput\n >,\n): SignInResolverFactory {\n const { optionsSchema } = options;\n if (!optionsSchema) {\n return (resolverOptions?: TOptionsInput) => {\n if (resolverOptions) {\n throw new InputError('sign-in resolver does not accept options');\n }\n return options.create(undefined as TOptionsOutput);\n };\n }\n const factory = (\n ...[resolverOptions]: undefined extends TOptionsInput\n ? [options?: TOptionsInput]\n : [options: TOptionsInput]\n ) => {\n const parsedOptions = optionsSchema.parse(resolverOptions);\n return options.create(parsedOptions);\n };\n\n factory.optionsJsonSchema = zodToJsonSchema(optionsSchema) as JsonObject;\n return factory;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { SignInResolver } from '../types';\nimport { SignInResolverFactory } from './createSignInResolverFactory';\n\n/** @public */\nexport interface ReadDeclarativeSignInResolverOptions {\n config: Config;\n signInResolverFactories: {\n [name in string]: SignInResolverFactory;\n };\n}\n\n/** @public */\nexport function readDeclarativeSignInResolver(\n options: ReadDeclarativeSignInResolverOptions,\n): SignInResolver | undefined {\n const resolvers =\n options.config\n .getOptionalConfigArray('signIn.resolvers')\n ?.map(resolverConfig => {\n const resolverName = resolverConfig.getString('resolver');\n if (!Object.hasOwn(options.signInResolverFactories, resolverName)) {\n throw new Error(\n `Sign-in resolver '${resolverName}' is not available`,\n );\n }\n const resolver = options.signInResolverFactories[resolverName];\n const { resolver: _ignored, ...resolverOptions } =\n resolverConfig.get();\n\n return resolver(\n Object.keys(resolverOptions).length > 0 ? resolverOptions : undefined,\n );\n }) ?? [];\n\n if (resolvers.length === 0) {\n return undefined;\n }\n\n return async (profile, context) => {\n for (const resolver of resolvers) {\n try {\n return await resolver(profile, context);\n } catch (error) {\n if (error?.name === 'NotFoundError') {\n continue;\n }\n throw error;\n }\n }\n\n throw new Error('Failed to sign-in, unable to resolve user identity');\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createSignInResolverFactory } from './createSignInResolverFactory';\n\n/**\n * A collection of common sign-in resolvers that work with any auth provider.\n *\n * @public\n */\nexport namespace commonSignInResolvers {\n /**\n * A common sign-in resolver that looks up the user using their email address\n * as email of the entity.\n */\n export const emailMatchingUserEntityProfileEmail =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n\n return ctx.signInWithCatalogUser({\n filter: {\n 'spec.profile.email': profile.email,\n },\n });\n };\n },\n });\n\n /**\n * A common sign-in resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\n export const emailLocalPartMatchingUserEntityName =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n const [localPart] = profile.email.split('@');\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: localPart },\n });\n };\n },\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readDeclarativeSignInResolver } from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthEnvironmentHandler } from './OAuthEnvironmentHandler';\nimport { createOAuthRouteHandlers } from './createOAuthRouteHandlers';\nimport { OAuthStateTransform } from './state';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { SignInResolverFactory } from '../sign-in/createSignInResolverFactory';\n\n/** @public */\nexport function createOAuthProviderFactory(options: {\n authenticator: OAuthAuthenticator;\n additionalScopes?: string[];\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform>;\n signInResolver?: SignInResolver>;\n signInResolverFactories?: {\n [name in string]: SignInResolverFactory<\n OAuthAuthenticatorResult,\n unknown\n >;\n };\n}): AuthProviderFactory {\n return ctx => {\n return OAuthEnvironmentHandler.mapConfig(ctx.config, envConfig => {\n const signInResolver =\n readDeclarativeSignInResolver({\n config: envConfig,\n signInResolverFactories: options.signInResolverFactories ?? {},\n }) ?? options.signInResolver;\n\n return createOAuthRouteHandlers({\n authenticator: options.authenticator,\n appUrl: ctx.appUrl,\n baseUrl: ctx.baseUrl,\n config: envConfig,\n isOriginAllowed: ctx.isOriginAllowed,\n cookieConfigurer: ctx.cookieConfigurer,\n providerId: ctx.providerId,\n resolverContext: ctx.resolverContext,\n additionalScopes: options.additionalScopes,\n stateTransform: options.stateTransform,\n profileTransform: options.profileTransform,\n signInResolver,\n });\n });\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface OAuthSession {\n accessToken: string;\n tokenType: string;\n idToken?: string;\n scope: string;\n expiresInSeconds?: number;\n refreshToken?: string;\n refreshTokenExpiresInSeconds?: number;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorScopeOptions {\n persist?: boolean;\n required?: string[];\n transform?: (options: {\n /** Scopes requested by the client */\n requested: Iterable;\n /** Scopes which have already been granted */\n granted: Iterable;\n /** Scopes that are required for the authenticator to function */\n required: Iterable;\n /** Additional scopes added through configuration */\n additional: Iterable;\n }) => Iterable;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorStartInput {\n scope: string;\n state: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorAuthenticateInput {\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorRefreshInput {\n scope: string;\n refreshToken: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorLogoutInput {\n accessToken?: string;\n refreshToken?: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorResult {\n fullProfile: TProfile;\n session: OAuthSession;\n}\n\n/** @public */\nexport interface OAuthAuthenticator {\n defaultProfileTransform: ProfileTransform>;\n /** @deprecated use `scopes.persist` instead */\n shouldPersistScopes?: boolean;\n scopes?: OAuthAuthenticatorScopeOptions;\n initialize(ctx: { callbackUrl: string; config: Config }): TContext;\n start(\n input: OAuthAuthenticatorStartInput,\n ctx: TContext,\n ): Promise<{ url: string; status?: number }>;\n authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ctx: TContext,\n ): Promise>;\n refresh(\n input: OAuthAuthenticatorRefreshInput,\n ctx: TContext,\n ): Promise>;\n logout?(input: OAuthAuthenticatorLogoutInput, ctx: TContext): Promise;\n}\n\n/** @public */\nexport function createOAuthAuthenticator(\n authenticator: OAuthAuthenticator,\n): OAuthAuthenticator {\n return authenticator;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface ProxyAuthenticator<\n TContext,\n TResult,\n TProviderInfo = undefined,\n> {\n defaultProfileTransform: ProfileTransform;\n initialize(ctx: { config: Config }): TContext;\n authenticate(\n options: { req: Request },\n ctx: TContext,\n ): Promise<{ result: TResult; providerInfo?: TProviderInfo }>;\n}\n\n/** @public */\nexport function createProxyAuthenticator(\n authenticator: ProxyAuthenticator,\n): ProxyAuthenticator {\n return authenticator;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { Config } from '@backstage/config';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { ProxyAuthenticator } from './types';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { NotImplementedError } from '@backstage/errors';\n\n/** @public */\nexport interface ProxyAuthRouteHandlersOptions {\n authenticator: ProxyAuthenticator;\n config: Config;\n resolverContext: AuthResolverContext;\n signInResolver: SignInResolver;\n profileTransform?: ProfileTransform;\n}\n\n/** @public */\nexport function createProxyAuthRouteHandlers(\n options: ProxyAuthRouteHandlersOptions,\n): AuthProviderRouteHandlers {\n const { authenticator, config, resolverContext, signInResolver } = options;\n\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config });\n\n return {\n async start(): Promise {\n throw new NotImplementedError('Not implemented');\n },\n\n async frameHandler(): Promise {\n throw new NotImplementedError('Not implemented');\n },\n\n async refresh(this: never, req: Request, res: Response): Promise {\n const { result, providerInfo } = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n\n const response: ClientAuthResponse = {\n profile,\n providerInfo,\n backstageIdentity: prepareBackstageIdentityResponse(identity),\n };\n\n res.status(200).json(response);\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n readDeclarativeSignInResolver,\n SignInResolverFactory,\n} from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { createProxyAuthRouteHandlers } from './createProxyRouteHandlers';\nimport { ProxyAuthenticator } from './types';\n\n/** @public */\nexport function createProxyAuthProviderFactory(options: {\n authenticator: ProxyAuthenticator;\n profileTransform?: ProfileTransform;\n signInResolver?: SignInResolver;\n signInResolverFactories?: Record<\n string,\n SignInResolverFactory\n >;\n}): AuthProviderFactory {\n return ctx => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: ctx.config,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n if (!signInResolver) {\n throw new Error(\n `No sign-in resolver configured for proxy auth provider '${ctx.providerId}'`,\n );\n }\n\n return createProxyAuthRouteHandlers({\n signInResolver,\n config: ctx.config,\n authenticator: options.authenticator,\n resolverContext: ctx.resolverContext,\n profileTransform: options.profileTransform,\n });\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { Request, Response } from 'express';\n\n/**\n * A representation of a successful Backstage sign-in.\n *\n * Compared to the {@link BackstageIdentityResponse} this type omits\n * the decoded identity information embedded in the token.\n *\n * @public\n */\nexport interface BackstageSignInResult {\n /**\n * The token used to authenticate the user within Backstage.\n */\n token: string;\n}\n\n/**\n * Response object containing the {@link BackstageUserIdentity} and the token\n * from the authentication provider.\n *\n * @public\n */\nexport interface BackstageIdentityResponse extends BackstageSignInResult {\n /**\n * The number of seconds until the token expires. If not set, it can be assumed that the token does not expire.\n */\n expiresInSeconds?: number;\n\n /**\n * A plaintext description of the identity that is encapsulated within the token.\n */\n identity: BackstageUserIdentity;\n}\n\n/**\n * User identity information within Backstage.\n *\n * @public\n */\nexport type BackstageUserIdentity = {\n /**\n * The type of identity that this structure represents. In the frontend app\n * this will currently always be 'user'.\n */\n type: 'user';\n\n /**\n * The entityRef of the user in the catalog.\n * For example User:default/sandra\n */\n userEntityRef: string;\n\n /**\n * The user and group entities that the user claims ownership through\n */\n ownershipEntityRefs: string[];\n};\n\n/**\n * A query for a single user in the catalog.\n *\n * If `entityRef` is used, the default kind is `'User'`.\n *\n * If `annotations` are used, all annotations must be present and\n * match the provided value exactly. Only entities of kind `'User'` will be considered.\n *\n * If `filter` are used, only entities of kind `'User'` will be considered unless it is explicitly specified differently in the filter.\n *\n * Regardless of the query method, the query must match exactly one entity\n * in the catalog, or an error will be thrown.\n *\n * @public\n */\nexport type AuthResolverCatalogUserQuery =\n | {\n entityRef:\n | string\n | {\n kind?: string;\n namespace?: string;\n name: string;\n };\n }\n | {\n annotations: Record;\n }\n | {\n filter: EntityFilterQuery;\n };\n\n/**\n * Parameters used to issue new Backstage Tokens\n *\n * @public\n */\nexport type TokenParams = {\n /**\n * The claims that will be embedded within the token. At a minimum, this should include\n * the subject claim, `sub`. It is common to also list entity ownership relations in the\n * `ent` list. Additional claims may also be added at the developer's discretion except\n * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`,\n * `iat`, and `exp`. The Backstage team also maintains the right add new claims in the future\n * without listing the change as a \"breaking change\".\n */\n claims: {\n /** The token subject, i.e. User ID */\n sub: string;\n /** A list of entity references that the user claims ownership through */\n ent?: string[];\n } & Record;\n};\n\n/**\n * The context that is used for auth processing.\n *\n * @public\n */\nexport type AuthResolverContext = {\n /**\n * Issues a Backstage token using the provided parameters.\n */\n issueToken(params: TokenParams): Promise<{ token: string }>;\n\n /**\n * Finds a single user in the catalog using the provided query.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n findCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise<{ entity: Entity }>;\n\n /**\n * Finds a single user in the catalog using the provided query, and then\n * issues an identity for that user using default ownership resolution.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n signInWithCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise;\n};\n\n/**\n * Resolver interface for resolving the ownership entity references for entity\n *\n * @public\n */\nexport interface AuthOwnershipResolver {\n resolveOwnershipEntityRefs(\n entity: Entity,\n ): Promise<{ ownershipEntityRefs: string[] }>;\n}\n\n/**\n * Any Auth provider needs to implement this interface which handles the routes in the\n * auth backend. Any auth API requests from the frontend reaches these methods.\n *\n * The routes in the auth backend API are tied to these methods like below\n *\n * `/auth/[provider]/start -> start`\n * `/auth/[provider]/handler/frame -> frameHandler`\n * `/auth/[provider]/refresh -> refresh`\n * `/auth/[provider]/logout -> logout`\n *\n * @public\n */\nexport interface AuthProviderRouteHandlers {\n /**\n * Handles the start route of the API. This initiates a sign in request with an auth provider.\n *\n * Request\n * - scopes for the auth request (Optional)\n * Response\n * - redirect to the auth provider for the user to sign in or consent.\n * - sets a nonce cookie and also pass the nonce as 'state' query parameter in the redirect request\n */\n start(req: Request, res: Response): Promise;\n\n /**\n * Once the user signs in or consents in the OAuth screen, the auth provider redirects to the\n * callbackURL which is handled by this method.\n *\n * Request\n * - to contain a nonce cookie and a 'state' query parameter\n * Response\n * - postMessage to the window with a payload that contains accessToken, expiryInSeconds?, idToken? and scope.\n * - sets a refresh token cookie if the auth provider supports refresh tokens\n */\n frameHandler(req: Request, res: Response): Promise;\n\n /**\n * (Optional) If the auth provider supports refresh tokens then this method handles\n * requests to get a new access token.\n *\n * Other types of providers may also use this method to implement its own logic to create new sessions\n * upon request. For example, this can be used to create a new session for a provider that handles requests\n * from an authenticating proxy.\n *\n * Request\n * - to contain a refresh token cookie and scope (Optional) query parameter.\n * Response\n * - payload with accessToken, expiryInSeconds?, idToken?, scope and user profile information.\n */\n refresh?(req: Request, res: Response): Promise;\n\n /**\n * (Optional) Handles sign out requests\n *\n * Response\n * - removes the refresh token cookie\n */\n logout?(req: Request, res: Response): Promise;\n}\n\n/**\n * @public\n * @deprecated Use top-level properties passed to `AuthProviderFactory` instead\n */\nexport type AuthProviderConfig = {\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n};\n\n/** @public */\nexport type AuthProviderFactory = (options: {\n providerId: string;\n /** @deprecated Use top-level properties instead */\n globalConfig: AuthProviderConfig;\n config: Config;\n logger: LoggerService;\n resolverContext: AuthResolverContext;\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n}) => AuthProviderRouteHandlers;\n\n/** @public */\nexport type ClientAuthResponse = {\n providerInfo: TProviderInfo;\n profile: ProfileInfo;\n backstageIdentity?: BackstageIdentityResponse;\n};\n\n/**\n * Type of sign in information context. Includes the profile information and\n * authentication result which contains auth related information.\n *\n * @public\n */\nexport type SignInInfo = {\n /**\n * The simple profile passed down for use in the frontend.\n */\n profile: ProfileInfo;\n\n /**\n * The authentication result that was received from the authentication\n * provider.\n */\n result: TAuthResult;\n};\n\n/**\n * Describes the function which handles the result of a successful\n * authentication. Must return a valid {@link @backstage/plugin-auth-node#BackstageSignInResult}.\n *\n * @public\n */\nexport type SignInResolver = (\n info: SignInInfo,\n context: AuthResolverContext,\n) => Promise;\n\n/**\n * Describes the function that transforms the result of a successful\n * authentication into a {@link ProfileInfo} object.\n *\n * This function may optionally throw an error in order to reject authentication.\n *\n * @public\n */\nexport type ProfileTransform = (\n result: TResult,\n context: AuthResolverContext,\n) => Promise<{ profile: ProfileInfo }>;\n\n/**\n * Used to display login information to user, i.e. sidebar popup.\n *\n * It is also temporarily used as the profile of the signed-in user's Backstage\n * identity, but we want to replace that with data from identity and/org catalog\n * service\n *\n * @public\n */\nexport type ProfileInfo = {\n /**\n * Email ID of the signed in user.\n */\n email?: string;\n /**\n * Display name that can be presented to the signed in user.\n */\n displayName?: string;\n /**\n * URL to an image that can be used as the display image or avatar of the\n * signed in user.\n */\n picture?: string;\n};\n\n/**\n * The callback used to resolve the cookie configuration for auth providers that use cookies.\n * @public\n */\nexport type CookieConfigurer = (ctx: {\n /** ID of the auth provider that this configuration applies to */\n providerId: string;\n /** The externally reachable base URL of the auth-backend plugin */\n baseUrl: string;\n /** The configured callback URL of the auth provider */\n callbackUrl: string;\n /** The origin URL of the app */\n appOrigin: string;\n}) => {\n domain: string;\n path: string;\n secure: boolean;\n sameSite?: 'none' | 'lax' | 'strict';\n};\n\n/**\n * Core properties of various token types.\n *\n * @public\n */\nexport const tokenTypes = Object.freeze({\n user: Object.freeze({\n typParam: 'vnd.backstage.user',\n audClaim: 'backstage',\n }),\n limitedUser: Object.freeze({\n typParam: 'vnd.backstage.limited-user',\n }),\n plugin: Object.freeze({\n typParam: 'vnd.backstage.plugin',\n }),\n});\n"],"names":["createExtensionPoint","serializeError","crypto","InputError","AuthenticationError","jwtVerify","decodeJwt","decodeProtectedHeader","createRemoteJWKSet","pickBy","NotAllowedError","URL","isError","NotFoundError","zodToJsonSchema","commonSignInResolvers","NotImplementedError"],"mappings":"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"} -\ No newline at end of file diff --git a/patches/@backstage+plugin-catalog-backend+1.24.0.patch b/patches/@backstage+plugin-catalog-backend+1.24.0.patch deleted file mode 100644 index 0e621aff3e..0000000000 --- a/patches/@backstage+plugin-catalog-backend+1.24.0.patch +++ /dev/null @@ -1,1241 +0,0 @@ -diff --git a/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js b/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js -index f633a9b..c14a098 100644 ---- a/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js -+++ b/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js -@@ -36,6 +36,7 @@ require('@backstage/types'); - require('@backstage/catalog-client'); - require('yn'); - require('@backstage/backend-openapi-utils'); -+require('@janus-idp/backstage-plugin-audit-log-node'); - require('@backstage/plugin-permission-common'); - require('minimatch'); - require('@backstage/config'); -diff --git a/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js.map b/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js.map -index 5e24e7c..6de658e 100644 ---- a/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js.map -+++ b/node_modules/@backstage/plugin-catalog-backend/dist/alpha.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"alpha.cjs.js","sources":["../src/permissions/conditionExports.ts","../src/service/CatalogPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { createConditionExports } from '@backstage/plugin-permission-node';\nimport { permissionRules } from './rules';\n\nconst { conditions, createConditionalDecision } = createConditionExports({\n pluginId: 'catalog',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n rules: permissionRules,\n});\n\n/**\n * These conditions are used when creating conditional decisions for catalog\n * entities that are returned by authorization policies.\n *\n * @alpha\n */\nexport const catalogConditions = conditions;\n\n/**\n * `createCatalogConditionalDecision` can be used when authoring policies to\n * create conditional decisions. It requires a permission of type\n * `ResourcePermission<'catalog-entity'>` to be passed as the first parameter.\n * It's recommended that you use the provided `isResourcePermission` and\n * `isPermission` helper methods to narrow the type of the permission passed to\n * the handle method as shown below.\n *\n * ```\n * // MyAuthorizationPolicy.ts\n * ...\n * import { createCatalogPolicyDecision } from '@backstage/plugin-catalog-backend';\n * import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common';\n *\n * class MyAuthorizationPolicy implements PermissionPolicy {\n * async handle(request, user) {\n * ...\n *\n * if (isResourcePermission(request.permission, RESOURCE_TYPE_CATALOG_ENTITY)) {\n * return createCatalogConditionalDecision(\n * request.permission,\n * { anyOf: [...insert conditions here...] }\n * );\n * }\n *\n * ...\n * }\n * ```\n *\n * @alpha\n */\nexport const createCatalogConditionalDecision = createConditionalDecision;\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { Entity, Validators } from '@backstage/catalog-model';\nimport { CatalogBuilder, CatalogPermissionRuleInput } from './CatalogBuilder';\nimport {\n catalogAnalysisExtensionPoint,\n CatalogModelExtensionPoint,\n catalogModelExtensionPoint,\n CatalogPermissionExtensionPoint,\n catalogPermissionExtensionPoint,\n CatalogProcessingExtensionPoint,\n catalogProcessingExtensionPoint,\n} from '@backstage/plugin-catalog-node/alpha';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntityProvider,\n LocationAnalyzer,\n PlaceholderResolver,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { ForwardedError } from '@backstage/errors';\n\nclass CatalogProcessingExtensionPointImpl\n implements CatalogProcessingExtensionPoint\n{\n #processors = new Array();\n #entityProviders = new Array();\n #placeholderResolvers: Record = {};\n #onProcessingErrorHandler?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n\n addProcessor(\n ...processors: Array>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n addEntityProvider(\n ...providers: Array>\n ): void {\n this.#entityProviders.push(...providers.flat());\n }\n\n addPlaceholderResolver(key: string, resolver: PlaceholderResolver) {\n if (key in this.#placeholderResolvers)\n throw new Error(\n `A placeholder resolver for '${key}' has already been set up, please check your config.`,\n );\n this.#placeholderResolvers[key] = resolver;\n }\n\n setOnProcessingErrorHandler(\n handler: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void,\n ) {\n this.#onProcessingErrorHandler = handler;\n }\n\n get processors() {\n return this.#processors;\n }\n\n get entityProviders() {\n return this.#entityProviders;\n }\n\n get placeholderResolvers() {\n return this.#placeholderResolvers;\n }\n\n get onProcessingErrorHandler() {\n return this.#onProcessingErrorHandler;\n }\n}\n\nclass CatalogPermissionExtensionPointImpl\n implements CatalogPermissionExtensionPoint\n{\n #permissions = new Array();\n #permissionRules = new Array();\n\n addPermissions(...permission: Array>): void {\n this.#permissions.push(...permission.flat());\n }\n\n addPermissionRules(\n ...rules: Array<\n CatalogPermissionRuleInput | Array\n >\n ): void {\n this.#permissionRules.push(...rules.flat());\n }\n\n get permissions() {\n return this.#permissions;\n }\n\n get permissionRules() {\n return this.#permissionRules;\n }\n}\n\nclass CatalogModelExtensionPointImpl implements CatalogModelExtensionPoint {\n #fieldValidators: Partial = {};\n\n setFieldValidators(validators: Partial): void {\n merge(this.#fieldValidators, validators);\n }\n\n get fieldValidators() {\n return this.#fieldValidators;\n }\n\n #entityDataParser?: CatalogProcessorParser;\n\n setEntityDataParser(parser: CatalogProcessorParser): void {\n if (this.#entityDataParser) {\n throw new Error(\n 'Attempted to install second EntityDataParser. Only one can be set.',\n );\n }\n this.#entityDataParser = parser;\n }\n\n get entityDataParser() {\n return this.#entityDataParser;\n }\n}\n\n/**\n * Catalog plugin\n * @alpha\n */\nexport const catalogPlugin = createBackendPlugin({\n pluginId: 'catalog',\n register(env) {\n const processingExtensions = new CatalogProcessingExtensionPointImpl();\n // plugins depending on this API will be initialized before this plugins init method is executed.\n env.registerExtensionPoint(\n catalogProcessingExtensionPoint,\n processingExtensions,\n );\n\n let locationAnalyzerFactory:\n | ((options: {\n scmLocationAnalyzers: ScmLocationAnalyzer[];\n }) => Promise<{ locationAnalyzer: LocationAnalyzer }>)\n | undefined = undefined;\n const scmLocationAnalyzers = new Array();\n env.registerExtensionPoint(catalogAnalysisExtensionPoint, {\n setLocationAnalyzer(analyzerOrFactory) {\n if (locationAnalyzerFactory) {\n throw new Error('LocationAnalyzer has already been set');\n }\n if (typeof analyzerOrFactory === 'function') {\n locationAnalyzerFactory = analyzerOrFactory;\n } else {\n locationAnalyzerFactory = async () => ({\n locationAnalyzer: analyzerOrFactory,\n });\n }\n },\n addScmLocationAnalyzer(analyzer: ScmLocationAnalyzer) {\n scmLocationAnalyzers.push(analyzer);\n },\n });\n\n const permissionExtensions = new CatalogPermissionExtensionPointImpl();\n env.registerExtensionPoint(\n catalogPermissionExtensionPoint,\n permissionExtensions,\n );\n\n const modelExtensions = new CatalogModelExtensionPointImpl();\n env.registerExtensionPoint(catalogModelExtensionPoint, modelExtensions);\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n httpRouter: coreServices.httpRouter,\n lifecycle: coreServices.rootLifecycle,\n scheduler: coreServices.scheduler,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n events: eventsServiceRef,\n },\n async init({\n logger,\n config,\n reader,\n database,\n permissions,\n httpRouter,\n lifecycle,\n scheduler,\n discovery,\n auth,\n httpAuth,\n events,\n }) {\n const builder = await CatalogBuilder.create({\n config,\n reader,\n permissions,\n database,\n scheduler,\n logger,\n discovery,\n auth,\n httpAuth,\n });\n\n builder.setEventBroker(events);\n\n if (processingExtensions.onProcessingErrorHandler) {\n builder.subscribe({\n onProcessingError: processingExtensions.onProcessingErrorHandler,\n });\n }\n builder.addProcessor(...processingExtensions.processors);\n builder.addEntityProvider(...processingExtensions.entityProviders);\n\n if (modelExtensions.entityDataParser) {\n builder.setEntityDataParser(modelExtensions.entityDataParser);\n }\n\n Object.entries(processingExtensions.placeholderResolvers).forEach(\n ([key, resolver]) => builder.setPlaceholderResolver(key, resolver),\n );\n if (locationAnalyzerFactory) {\n const { locationAnalyzer } = await locationAnalyzerFactory({\n scmLocationAnalyzers,\n }).catch(e => {\n throw new ForwardedError('Failed to create LocationAnalyzer', e);\n });\n builder.setLocationAnalyzer(locationAnalyzer);\n } else {\n builder.addLocationAnalyzers(...scmLocationAnalyzers);\n }\n builder.addPermissions(...permissionExtensions.permissions);\n builder.addPermissionRules(...permissionExtensions.permissionRules);\n builder.setFieldFormatValidators(modelExtensions.fieldValidators);\n\n const { processingEngine, router } = await builder.build();\n\n lifecycle.addStartupHook(async () => {\n await processingEngine.start();\n });\n lifecycle.addShutdownHook(() => processingEngine.stop());\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createConditionExports","RESOURCE_TYPE_CATALOG_ENTITY","permissionRules","merge","createBackendPlugin","catalogProcessingExtensionPoint","catalogAnalysisExtensionPoint","catalogPermissionExtensionPoint","catalogModelExtensionPoint","coreServices","eventsServiceRef","CatalogBuilder","ForwardedError"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"alpha.cjs.js","sources":["../src/permissions/conditionExports.ts","../src/service/CatalogPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { createConditionExports } from '@backstage/plugin-permission-node';\nimport { permissionRules } from './rules';\n\nconst { conditions, createConditionalDecision } = createConditionExports({\n pluginId: 'catalog',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n rules: permissionRules,\n});\n\n/**\n * These conditions are used when creating conditional decisions for catalog\n * entities that are returned by authorization policies.\n *\n * @alpha\n */\nexport const catalogConditions = conditions;\n\n/**\n * `createCatalogConditionalDecision` can be used when authoring policies to\n * create conditional decisions. It requires a permission of type\n * `ResourcePermission<'catalog-entity'>` to be passed as the first parameter.\n * It's recommended that you use the provided `isResourcePermission` and\n * `isPermission` helper methods to narrow the type of the permission passed to\n * the handle method as shown below.\n *\n * ```\n * // MyAuthorizationPolicy.ts\n * ...\n * import { createCatalogPolicyDecision } from '@backstage/plugin-catalog-backend';\n * import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common';\n *\n * class MyAuthorizationPolicy implements PermissionPolicy {\n * async handle(request, user) {\n * ...\n *\n * if (isResourcePermission(request.permission, RESOURCE_TYPE_CATALOG_ENTITY)) {\n * return createCatalogConditionalDecision(\n * request.permission,\n * { anyOf: [...insert conditions here...] }\n * );\n * }\n *\n * ...\n * }\n * ```\n *\n * @alpha\n */\nexport const createCatalogConditionalDecision = createConditionalDecision;\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { Entity, Validators } from '@backstage/catalog-model';\nimport { CatalogBuilder, CatalogPermissionRuleInput } from './CatalogBuilder';\nimport {\n catalogAnalysisExtensionPoint,\n CatalogModelExtensionPoint,\n catalogModelExtensionPoint,\n CatalogPermissionExtensionPoint,\n catalogPermissionExtensionPoint,\n CatalogProcessingExtensionPoint,\n catalogProcessingExtensionPoint,\n} from '@backstage/plugin-catalog-node/alpha';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntityProvider,\n LocationAnalyzer,\n PlaceholderResolver,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { ForwardedError } from '@backstage/errors';\n\nclass CatalogProcessingExtensionPointImpl\n implements CatalogProcessingExtensionPoint\n{\n #processors = new Array();\n #entityProviders = new Array();\n #placeholderResolvers: Record = {};\n #onProcessingErrorHandler?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n\n addProcessor(\n ...processors: Array>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n addEntityProvider(\n ...providers: Array>\n ): void {\n this.#entityProviders.push(...providers.flat());\n }\n\n addPlaceholderResolver(key: string, resolver: PlaceholderResolver) {\n if (key in this.#placeholderResolvers)\n throw new Error(\n `A placeholder resolver for '${key}' has already been set up, please check your config.`,\n );\n this.#placeholderResolvers[key] = resolver;\n }\n\n setOnProcessingErrorHandler(\n handler: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void,\n ) {\n this.#onProcessingErrorHandler = handler;\n }\n\n get processors() {\n return this.#processors;\n }\n\n get entityProviders() {\n return this.#entityProviders;\n }\n\n get placeholderResolvers() {\n return this.#placeholderResolvers;\n }\n\n get onProcessingErrorHandler() {\n return this.#onProcessingErrorHandler;\n }\n}\n\nclass CatalogPermissionExtensionPointImpl\n implements CatalogPermissionExtensionPoint\n{\n #permissions = new Array();\n #permissionRules = new Array();\n\n addPermissions(...permission: Array>): void {\n this.#permissions.push(...permission.flat());\n }\n\n addPermissionRules(\n ...rules: Array<\n CatalogPermissionRuleInput | Array\n >\n ): void {\n this.#permissionRules.push(...rules.flat());\n }\n\n get permissions() {\n return this.#permissions;\n }\n\n get permissionRules() {\n return this.#permissionRules;\n }\n}\n\nclass CatalogModelExtensionPointImpl implements CatalogModelExtensionPoint {\n #fieldValidators: Partial = {};\n\n setFieldValidators(validators: Partial): void {\n merge(this.#fieldValidators, validators);\n }\n\n get fieldValidators() {\n return this.#fieldValidators;\n }\n\n #entityDataParser?: CatalogProcessorParser;\n\n setEntityDataParser(parser: CatalogProcessorParser): void {\n if (this.#entityDataParser) {\n throw new Error(\n 'Attempted to install second EntityDataParser. Only one can be set.',\n );\n }\n this.#entityDataParser = parser;\n }\n\n get entityDataParser() {\n return this.#entityDataParser;\n }\n}\n\n/**\n * Catalog plugin\n * @alpha\n */\nexport const catalogPlugin = createBackendPlugin({\n pluginId: 'catalog',\n register(env) {\n const processingExtensions = new CatalogProcessingExtensionPointImpl();\n // plugins depending on this API will be initialized before this plugins init method is executed.\n env.registerExtensionPoint(\n catalogProcessingExtensionPoint,\n processingExtensions,\n );\n\n let locationAnalyzerFactory:\n | ((options: {\n scmLocationAnalyzers: ScmLocationAnalyzer[];\n }) => Promise<{ locationAnalyzer: LocationAnalyzer }>)\n | undefined = undefined;\n const scmLocationAnalyzers = new Array();\n env.registerExtensionPoint(catalogAnalysisExtensionPoint, {\n setLocationAnalyzer(analyzerOrFactory) {\n if (locationAnalyzerFactory) {\n throw new Error('LocationAnalyzer has already been set');\n }\n if (typeof analyzerOrFactory === 'function') {\n locationAnalyzerFactory = analyzerOrFactory;\n } else {\n locationAnalyzerFactory = async () => ({\n locationAnalyzer: analyzerOrFactory,\n });\n }\n },\n addScmLocationAnalyzer(analyzer: ScmLocationAnalyzer) {\n scmLocationAnalyzers.push(analyzer);\n },\n });\n\n const permissionExtensions = new CatalogPermissionExtensionPointImpl();\n env.registerExtensionPoint(\n catalogPermissionExtensionPoint,\n permissionExtensions,\n );\n\n const modelExtensions = new CatalogModelExtensionPointImpl();\n env.registerExtensionPoint(catalogModelExtensionPoint, modelExtensions);\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n httpRouter: coreServices.httpRouter,\n lifecycle: coreServices.rootLifecycle,\n scheduler: coreServices.scheduler,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n events: eventsServiceRef,\n },\n async init({\n logger,\n config,\n reader,\n database,\n permissions,\n httpRouter,\n lifecycle,\n scheduler,\n discovery,\n auth,\n httpAuth,\n events,\n }) {\n const builder = await CatalogBuilder.create({\n config,\n reader,\n permissions,\n database,\n scheduler,\n logger,\n discovery,\n auth,\n httpAuth,\n });\n\n builder.setEventBroker(events);\n\n if (processingExtensions.onProcessingErrorHandler) {\n builder.subscribe({\n onProcessingError: processingExtensions.onProcessingErrorHandler,\n });\n }\n builder.addProcessor(...processingExtensions.processors);\n builder.addEntityProvider(...processingExtensions.entityProviders);\n\n if (modelExtensions.entityDataParser) {\n builder.setEntityDataParser(modelExtensions.entityDataParser);\n }\n\n Object.entries(processingExtensions.placeholderResolvers).forEach(\n ([key, resolver]) => builder.setPlaceholderResolver(key, resolver),\n );\n if (locationAnalyzerFactory) {\n const { locationAnalyzer } = await locationAnalyzerFactory({\n scmLocationAnalyzers,\n }).catch(e => {\n throw new ForwardedError('Failed to create LocationAnalyzer', e);\n });\n builder.setLocationAnalyzer(locationAnalyzer);\n } else {\n builder.addLocationAnalyzers(...scmLocationAnalyzers);\n }\n builder.addPermissions(...permissionExtensions.permissions);\n builder.addPermissionRules(...permissionExtensions.permissionRules);\n builder.setFieldFormatValidators(modelExtensions.fieldValidators);\n\n const { processingEngine, router } = await builder.build();\n\n lifecycle.addStartupHook(async () => {\n await processingEngine.start();\n });\n lifecycle.addShutdownHook(() => processingEngine.stop());\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createConditionExports","RESOURCE_TYPE_CATALOG_ENTITY","permissionRules","merge","createBackendPlugin","catalogProcessingExtensionPoint","catalogAnalysisExtensionPoint","catalogPermissionExtensionPoint","catalogModelExtensionPoint","coreServices","eventsServiceRef","CatalogBuilder","ForwardedError"],"mappings":"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"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js b/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js -index f74e6f9..13f053b 100644 ---- a/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js -+++ b/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js -@@ -29,6 +29,7 @@ var types = require('@backstage/types'); - var catalogClient = require('@backstage/catalog-client'); - var yn = require('yn'); - var backendOpenapiUtils = require('@backstage/backend-openapi-utils'); -+var backstagePluginAuditLogNode = require('@janus-idp/backstage-plugin-audit-log-node'); - var alpha = require('@backstage/plugin-catalog-common/alpha'); - var pluginPermissionCommon = require('@backstage/plugin-permission-common'); - var minimatch = require('minimatch'); -@@ -5438,6 +5439,11 @@ async function createRouter(options) { - auth, - httpAuth - } = options; -+ const auditLogger = new backstagePluginAuditLogNode.DefaultAuditLogger({ -+ logger, -+ authService: auth, -+ httpAuthService: httpAuth -+ }); - const readonlyEnabled = config.getOptionalBoolean("catalog.readonly") || false; - if (readonlyEnabled) { - logger.info("Catalog is running in readonly mode"); -@@ -5445,12 +5451,61 @@ async function createRouter(options) { - if (refreshService) { - router.post("/refresh", async (req, res) => { - const { authorizationToken, ...restBody } = req.body; -- const credentials = authorizationToken ? await auth.authenticate(authorizationToken) : await httpAuth.credentials(req); -- await refreshService.refresh({ -- ...restBody, -- credentials -- }); -- res.status(200).end(); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityRefresh", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ metadata: { -+ entityRef: restBody.entityRef -+ }, -+ request: req, -+ message: `Refresh attempt for ${restBody.entityRef} initiated by ${actorId}` -+ }); -+ const credentials = authorizationToken ? await auth.authenticate(authorizationToken) : await httpAuth.credentials(req); -+ await refreshService.refresh({ -+ ...restBody, -+ credentials -+ }); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityRefresh", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ metadata: { -+ entityRef: restBody.entityRef -+ }, -+ response: { -+ status: 200 -+ }, -+ request: req, -+ message: `Refresh attempt for ${restBody.entityRef} triggered by ${actorId}` -+ }); -+ res.status(200).end(); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityRefresh", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ metadata: { -+ entityRef: restBody.entityRef -+ }, -+ request: req, -+ message: `Refresh attempt for ${restBody.entityRef} by ${actorId} failed` -+ }); -+ throw err; -+ } - }); - } - if (permissionIntegrationRouter) { -@@ -5458,204 +5513,953 @@ async function createRouter(options) { - } - if (entitiesCatalog) { - router.get("/entities", async (req, res) => { -- const { entities, pageInfo } = await entitiesCatalog.entities({ -- filter: parseEntityFilterParams(req.query), -- fields: parseEntityTransformParams(req.query), -- order: parseEntityOrderParams(req.query), -- pagination: parseEntityPaginationParams(req.query), -- credentials: await httpAuth.credentials(req) -- }); -- if (pageInfo.hasNextPage) { -- const url = new URL(`http://ignored${req.url}`); -- url.searchParams.delete("offset"); -- url.searchParams.set("after", pageInfo.endCursor); -- res.setHeader("link", `<${url.pathname}${url.search}>; rel="next"`); -+ const actorId = await auditLogger.getActorId( -+ req -+ ); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetch", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ message: `Entity fetch attempt initiated by ${actorId}` -+ }); -+ const { entities, pageInfo } = await entitiesCatalog.entities({ -+ filter: parseEntityFilterParams(req.query), -+ fields: parseEntityTransformParams(req.query), -+ order: parseEntityOrderParams(req.query), -+ pagination: parseEntityPaginationParams(req.query), -+ credentials: await httpAuth.credentials(req) -+ }); -+ if (pageInfo.hasNextPage) { -+ const url = new URL(`http://ignored${req.url}`); -+ url.searchParams.delete("offset"); -+ url.searchParams.set("after", pageInfo.endCursor); -+ res.setHeader("link", `<${url.pathname}${url.search}>; rel="next"`); -+ } -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetch", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ // Let's not log out the entities since this can make the log very big due to it not being paged? -+ response: { -+ status: 200 -+ }, -+ message: `Entity fetch attempt by ${actorId} succeeded` -+ }); -+ res.json(entities); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetch", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Entity fetch attempt by ${actorId} failed` -+ }); -+ throw err; - } -- res.json(entities); - }).get("/entities/by-query", async (req, res) => { -- const { items, pageInfo, totalItems } = await entitiesCatalog.queryEntities({ -- limit: req.query.limit, -- ...parseQueryEntitiesParams(req.query), -- credentials: await httpAuth.credentials(req) -- }); -- res.json({ -- items, -- totalItems, -- pageInfo: { -- ...pageInfo.nextCursor && { -- nextCursor: encodeCursor(pageInfo.nextCursor) -- }, -- ...pageInfo.prevCursor && { -- prevCursor: encodeCursor(pageInfo.prevCursor) -+ const actorId = await auditLogger.getActorId( -+ req -+ ); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "QueriedCatalogEntityFetch", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ message: `Queried entity fetch attempt initiated by ${actorId}` -+ }); -+ const { items, pageInfo, totalItems } = await entitiesCatalog.queryEntities({ -+ limit: req.query.limit, -+ ...parseQueryEntitiesParams(req.query), -+ credentials: await httpAuth.credentials(req) -+ }); -+ res.json({ -+ items, -+ totalItems, -+ pageInfo: { -+ ...pageInfo.nextCursor && { -+ nextCursor: encodeCursor(pageInfo.nextCursor) -+ }, -+ ...pageInfo.prevCursor && { -+ prevCursor: encodeCursor(pageInfo.prevCursor) -+ } - } -- } -- }); -+ }); -+ await auditLogger.auditLog({ -+ eventName: "QueriedCatalogEntityFetch", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ metadata: { -+ totalEntities: totalItems, -+ pageInfo: { -+ ...pageInfo.nextCursor && { -+ nextCursor: encodeCursor(pageInfo.nextCursor) -+ }, -+ ...pageInfo.prevCursor && { -+ prevCursor: encodeCursor(pageInfo.prevCursor) -+ } -+ } -+ }, -+ // Let's not log out the entities since this can make the log very big -+ response: { -+ status: 200 -+ }, -+ message: `Queried entity fetch attempt by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "QueriedCatalogEntityFetch", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Queried entity fetch attempt by ${actorId} failed` -+ }); -+ throw err; -+ } - }).get("/entities/by-uid/:uid", async (req, res) => { - const { uid } = req.params; -- const { entities } = await entitiesCatalog.entities({ -- filter: basicEntityFilter({ "metadata.uid": uid }), -- credentials: await httpAuth.credentials(req) -- }); -- if (!entities.length) { -- throw new errors.NotFoundError(`No entity with uid ${uid}`); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetchByUid", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ metadata: { -+ uid -+ }, -+ message: `Fetch attempt for entity with uid ${uid} initiated by ${actorId}` -+ }); -+ const { entities } = await entitiesCatalog.entities({ -+ filter: basicEntityFilter({ "metadata.uid": uid }), -+ credentials: await httpAuth.credentials(req) -+ }); -+ if (!entities.length) { -+ throw new errors.NotFoundError(`No entity with uid ${uid}`); -+ } -+ res.status(200).json(entities[0]); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetchByUid", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ metadata: { -+ uid, -+ entityRef: catalogModel.stringifyEntityRef(entities[0]) -+ }, -+ response: { -+ status: 200 -+ }, -+ message: `Fetch attempt for entity with uid ${uid} by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetchByUid", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ metadata: { -+ uid -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Fetch attempt for entity with uid ${uid} by ${actorId} failed` -+ }); -+ throw err; - } -- res.status(200).json(entities[0]); - }).delete("/entities/by-uid/:uid", async (req, res) => { - const { uid } = req.params; -- await entitiesCatalog.removeEntityByUid(uid, { -- credentials: await httpAuth.credentials(req) -- }); -- res.status(204).end(); -+ const actorId = await auditLogger.getActorId(req); -+ let entityRef; -+ try { -+ const { entities } = await entitiesCatalog.entities({ -+ filter: basicEntityFilter({ "metadata.uid": uid }), -+ credentials: await httpAuth.credentials(req) -+ }); -+ if (entities.length) { -+ entityRef = catalogModel.stringifyEntityRef(entities[0]); -+ } -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityDeletion", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ metadata: { -+ uid, -+ entityRef -+ }, -+ message: `Deletion attempt for entity with uid ${uid} initiated by ${actorId}` -+ }); -+ await entitiesCatalog.removeEntityByUid(uid, { -+ credentials: await httpAuth.credentials(req) -+ }); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityDeletion", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ metadata: { -+ uid, -+ entityRef -+ }, -+ response: { -+ status: 204 -+ }, -+ message: `Deletion attempt for entity with uid ${uid} by ${actorId} succeeded` -+ }); -+ res.status(204).end(); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityDeletion", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Deletion attempt for entity with uid ${uid} by ${actorId} failed` -+ }); -+ throw err; -+ } - }).get("/entities/by-name/:kind/:namespace/:name", async (req, res) => { - const { kind, namespace, name } = req.params; -- const { entities } = await entitiesCatalog.entities({ -- filter: basicEntityFilter({ -- kind, -- "metadata.namespace": namespace, -- "metadata.name": name -- }), -- credentials: await httpAuth.credentials(req) -- }); -- if (!entities.length) { -- throw new errors.NotFoundError( -- `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'` -- ); -+ const entityRef = catalogModel.stringifyEntityRef({ kind, namespace, name }); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetchByName", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ metadata: { -+ entityRef -+ }, -+ message: `Fetch attempt for entity with entityRef ${entityRef} initiated by ${actorId}` -+ }); -+ const { entities } = await entitiesCatalog.entities({ -+ filter: basicEntityFilter({ -+ kind, -+ "metadata.namespace": namespace, -+ "metadata.name": name -+ }), -+ credentials: await httpAuth.credentials(req) -+ }); -+ if (!entities.length) { -+ throw new errors.NotFoundError( -+ `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'` -+ ); -+ } -+ res.status(200).json(entities[0]); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetchByName", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ metadata: { -+ entityRef -+ }, -+ response: { -+ status: 200 -+ }, -+ message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFetchByName", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ metadata: { -+ entityRef -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} failed` -+ }); -+ throw err; - } -- res.status(200).json(entities[0]); - }).get( - "/entities/by-name/:kind/:namespace/:name/ancestry", - async (req, res) => { - const { kind, namespace, name } = req.params; - const entityRef = catalogModel.stringifyEntityRef({ kind, namespace, name }); -- const response = await entitiesCatalog.entityAncestry(entityRef, { -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityAncestryFetch", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ metadata: { -+ entityRef -+ }, -+ message: `Fetch attempt for entity ancestor of entity ${entityRef} initiated by ${actorId}` -+ }); -+ const response = await entitiesCatalog.entityAncestry(entityRef, { -+ credentials: await httpAuth.credentials(req) -+ }); -+ res.status(200).json(response); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityAncestryFetch", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ metadata: { -+ rootEntityRef: response.rootEntityRef, -+ ancestry: response.items.map((ancestryLink) => { -+ return { -+ entityRef: catalogModel.stringifyEntityRef(ancestryLink.entity), -+ parentEntityRefs: ancestryLink.parentEntityRefs -+ }; -+ }) -+ }, -+ response: { -+ status: 200 -+ }, -+ message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityAncestryFetch", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ metadata: { -+ entityRef -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} failed` -+ }); -+ throw err; -+ } -+ } -+ ).post("/entities/by-refs", async (req, res) => { -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityBatchFetch", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ message: `Batch entity fetch attempt initiated by ${actorId}` -+ }); -+ const request = entitiesBatchRequest(req); -+ const response = await entitiesCatalog.entitiesBatch({ -+ entityRefs: request.entityRefs, -+ filter: parseEntityFilterParams(req.query), -+ fields: parseEntityTransformParams(req.query, request.fields), - credentials: await httpAuth.credentials(req) - }); - res.status(200).json(response); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityBatchFetch", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ metadata: { -+ ...request -+ }, -+ response: { -+ status: 200 -+ }, -+ message: `Batch entity fetch attempt by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityBatchFetch", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Batch entity fetch attempt by ${actorId} failed` -+ }); -+ throw err; - } -- ).post("/entities/by-refs", async (req, res) => { -- const request = entitiesBatchRequest(req); -- const response = await entitiesCatalog.entitiesBatch({ -- entityRefs: request.entityRefs, -- filter: parseEntityFilterParams(req.query), -- fields: parseEntityTransformParams(req.query, request.fields), -- credentials: await httpAuth.credentials(req) -- }); -- res.status(200).json(response); - }).get("/entity-facets", async (req, res) => { -- const response = await entitiesCatalog.facets({ -- filter: parseEntityFilterParams(req.query), -- facets: parseEntityFacetParams(req.query), -- credentials: await httpAuth.credentials(req) -- }); -- res.status(200).json(response); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFacetFetch", -+ actorId, -+ status: "succeeded", -+ stage: "initiation", -+ request: req, -+ message: `Entity facet fetch attempt initiated by ${actorId}` -+ }); -+ const response = await entitiesCatalog.facets({ -+ filter: parseEntityFilterParams(req.query), -+ facets: parseEntityFacetParams(req.query), -+ credentials: await httpAuth.credentials(req) -+ }); -+ res.status(200).json(response); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFacetFetch", -+ actorId, -+ status: "succeeded", -+ stage: "completion", -+ request: req, -+ response: { status: 200 }, -+ message: `Entity facet fetch attempt by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityFacetFetch", -+ actorId, -+ status: "failed", -+ stage: "completion", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Entity facet fetch attempt by ${actorId} failed` -+ }); -+ throw err; -+ } - }); - } - if (locationService) { - router.post("/locations", async (req, res) => { -+ const credentials = await httpAuth.credentials(req); -+ const actorId = await auditLogger.getActorId(req); - const location = await validateRequestBody(req, locationInput); - const dryRun = yn__default.default(req.query.dryRun, { default: false }); -- if (!dryRun) { -- disallowReadonlyMode(readonlyEnabled); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationCreation", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ metadata: { -+ location, -+ isDryRun: dryRun -+ }, -+ request: req, -+ message: `Creation attempt of location entity for ${location.target} initiated by ${actorId}` -+ }); -+ if (!dryRun) { -+ disallowReadonlyMode(readonlyEnabled); -+ } -+ const output = await locationService.createLocation( -+ location, -+ dryRun, -+ { -+ credentials -+ } -+ ); -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationCreation", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ metadata: { -+ location: output.location, -+ isDryRun: dryRun -+ }, -+ request: req, -+ response: { -+ status: 201 -+ }, -+ message: `Creation of location entity for ${location.target} initiated by ${actorId} succeeded` -+ }); -+ res.status(201).json(output); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationCreation", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ actorId, -+ metadata: { -+ location, -+ isDryRun: dryRun -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ request: req, -+ message: `Creation of location entity for ${location.target} initiated by ${actorId} failed` -+ }); -+ throw err; - } -- const output = await locationService.createLocation(location, dryRun, { -- credentials: await httpAuth.credentials(req) -- }); -- res.status(201).json(output); - }).get("/locations", async (req, res) => { -- const locations = await locationService.listLocations({ -- credentials: await httpAuth.credentials(req) -- }); -- res.status(200).json(locations.map((l) => ({ data: l }))); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetch", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ request: req, -+ message: `Fetch attempt of locations initiated by ${actorId}` -+ }); -+ const locations = await locationService.listLocations({ -+ credentials: await httpAuth.credentials(req) -+ }); -+ res.status(200).json(locations.map((l) => ({ data: l }))); -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetch", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ request: req, -+ response: { -+ status: 200 -+ }, -+ message: `Fetch attempt of locations by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetch", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ actorId, -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Fetch attempt of locations by ${actorId} failed` -+ }); -+ throw err; -+ } - }).get("/locations/:id", async (req, res) => { - const { id } = req.params; -- const output = await locationService.getLocation(id, { -- credentials: await httpAuth.credentials(req) -- }); -- res.status(200).json(output); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetchById", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ metadata: { -+ id -+ }, -+ request: req, -+ message: `Fetch attempt of location with id: ${id} initiated by ${actorId}` -+ }); -+ const output = await locationService.getLocation(id, { -+ credentials: await httpAuth.credentials(req) -+ }); -+ res.status(200).json(output); -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetchById", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ metadata: { -+ id -+ }, -+ response: { -+ status: 200, -+ body: output -+ }, -+ request: req, -+ message: `Fetch attempt of location with id: ${id} by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetchById", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ actorId, -+ metadata: { -+ id -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ request: req, -+ message: `Fetch attempt of location with id: ${id} by ${actorId} failed` -+ }); -+ throw err; -+ } - }).delete("/locations/:id", async (req, res) => { -- disallowReadonlyMode(readonlyEnabled); -+ const actorId = await auditLogger.getActorId(req); - const { id } = req.params; -- await locationService.deleteLocation(id, { -- credentials: await httpAuth.credentials(req) -- }); -- res.status(204).end(); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationDeletion", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ metadata: { -+ id -+ }, -+ request: req, -+ message: `Deletion attempt of location with id: ${id} initiated by ${actorId}` -+ }); -+ disallowReadonlyMode(readonlyEnabled); -+ const location = await locationService.getLocation(id, { -+ credentials: await httpAuth.credentials(req) -+ }); -+ await locationService.deleteLocation(id, { -+ credentials: await httpAuth.credentials(req) -+ }); -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationDeletion", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ metadata: { -+ location -+ }, -+ response: { -+ status: 204 -+ }, -+ request: req, -+ message: `Deletion attempt of location with id: ${id} by ${actorId} succeeded` -+ }); -+ res.status(204).end(); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationDeletion", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ actorId, -+ metadata: { -+ id -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ request: req, -+ message: `Deletion attempt of location with id: ${id} by ${actorId} failed` -+ }); -+ throw err; -+ } - }).get("/locations/by-entity/:kind/:namespace/:name", async (req, res) => { - const { kind, namespace, name } = req.params; -- const output = await locationService.getLocationByEntity( -- { kind, namespace, name }, -- { credentials: await httpAuth.credentials(req) } -- ); -- res.status(200).json(output); -+ const actorId = await auditLogger.getActorId(req); -+ const locationRef = `${kind}:${namespace}/${name}`; -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetchByEntityRef", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ metadata: { -+ locationRef -+ }, -+ request: req, -+ message: `Fetch attempt for location ${locationRef} initiated by ${actorId}` -+ }); -+ const output = await locationService.getLocationByEntity( -+ { kind, namespace, name }, -+ { credentials: await httpAuth.credentials(req) } -+ ); -+ res.status(200).json(output); -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetchByEntityRef", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ metadata: { -+ locationRef -+ }, -+ response: { -+ status: 200, -+ body: output -+ }, -+ request: req, -+ message: `Fetch attempt for location ${locationRef} by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationFetchByEntityRef", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ actorId, -+ metadata: { -+ locationRef -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ request: req, -+ message: `Fetch attempt for location ${locationRef} by ${actorId} failed` -+ }); -+ throw err; -+ } - }); - } - if (locationAnalyzer) { - router.post("/analyze-location", async (req, res) => { -- const body = await validateRequestBody( -- req, -- zod.z.object({ -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationAnalyze", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ request: req, -+ message: `Analyze location for location initiated by ${actorId}` -+ }); -+ const body = await validateRequestBody( -+ req, -+ zod.z.object({ -+ location: locationInput, -+ catalogFilename: zod.z.string().optional() -+ }) -+ ); -+ const schema = zod.z.object({ - location: locationInput, - catalogFilename: zod.z.string().optional() -- }) -- ); -- const schema = zod.z.object({ -- location: locationInput, -- catalogFilename: zod.z.string().optional() -- }); -- const parsedBody = schema.parse(body); -- try { -- const output = await locationAnalyzer.analyzeLocation(parsedBody); -- res.status(200).json(output); -- } catch (err) { -- if ( -- // Catch errors from parse-url library. -- err.name === "Error" && "subject_url" in err -- ) { -- throw new errors.InputError("The given location.target is not a URL"); -+ }); -+ const parsedBody = schema.parse(body); -+ try { -+ const output = await locationAnalyzer.analyzeLocation(parsedBody); -+ res.status(200).json(output); -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationAnalyze", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ request: req, -+ response: { -+ status: 200, -+ body: output -+ }, -+ message: `Analyze location for location by ${actorId} succeeded` -+ }); -+ } catch (err) { -+ if ( -+ // Catch errors from parse-url library. -+ err.name === "Error" && "subject_url" in err -+ ) { -+ throw new errors.InputError("The given location.target is not a URL"); -+ } -+ throw err; - } -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogLocationAnalyze", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ actorId, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ request: req, -+ message: `Analyze location for location by ${actorId} failed` -+ }); - throw err; - } - }); - } - if (orchestrator) { - router.post("/validate-entity", async (req, res) => { -- const bodySchema = zod.z.object({ -- entity: zod.z.unknown(), -- location: zod.z.string() -- }); -- let body; -- let entity; -- let location; -+ const actorId = await auditLogger.getActorId(req); - try { -- body = await validateRequestBody(req, bodySchema); -- entity = validateEntityEnvelope(body.entity); -- location = catalogModel.parseLocationRef(body.location); -- if (location.type !== "url") -- throw new TypeError( -- `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path` -- ); -- } catch (err) { -- return res.status(400).json({ -- errors: [errors.serializeError(err)] -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityValidate", -+ status: "succeeded", -+ stage: "initiation", -+ actorId, -+ request: req, -+ message: `Entity validation for entity initiated by ${actorId}` - }); -- } -- const processingResult = await orchestrator.process({ -- entity: { -- ...entity, -- metadata: { -- ...entity.metadata, -- annotations: { -- [catalogModel.ANNOTATION_LOCATION]: body.location, -- [catalogModel.ANNOTATION_ORIGIN_LOCATION]: body.location, -- ...entity.metadata.annotations -+ const bodySchema = zod.z.object({ -+ entity: zod.z.unknown(), -+ location: zod.z.string() -+ }); -+ let body; -+ let entity; -+ let location; -+ try { -+ body = await validateRequestBody(req, bodySchema); -+ entity = validateEntityEnvelope(body.entity); -+ location = catalogModel.parseLocationRef(body.location); -+ if (location.type !== "url") -+ throw new TypeError( -+ `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path` -+ ); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityValidate", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ actorId, -+ request: req, -+ message: `Entity validation for entity initiated by ${actorId} failed` -+ }); -+ return res.status(400).json({ -+ errors: [errors.serializeError(err)] -+ }); -+ } -+ const processingResult = await orchestrator.process({ -+ entity: { -+ ...entity, -+ metadata: { -+ ...entity.metadata, -+ annotations: { -+ [catalogModel.ANNOTATION_LOCATION]: body.location, -+ [catalogModel.ANNOTATION_ORIGIN_LOCATION]: body.location, -+ ...entity.metadata.annotations -+ } - } - } -+ }); -+ if (!processingResult.ok) { -+ const errors$1 = processingResult.errors.map((e) => errors.serializeError(e)); -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityValidate", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ errors: errors$1, -+ response: { -+ status: 400 -+ }, -+ actorId, -+ request: req, -+ message: `Entity validation for entity initiated by ${actorId} failed` -+ }); -+ return res.status(400).json({ -+ errors: errors$1 -+ }); - } -- }); -- if (!processingResult.ok) -- res.status(400).json({ -- errors: processingResult.errors.map((e) => errors.serializeError(e)) -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityValidate", -+ status: "succeeded", -+ stage: "completion", -+ actorId, -+ response: { -+ status: 200 -+ }, -+ request: req, -+ message: `Entity validation for entity by ${actorId} succeeded` -+ }); -+ return res.status(200).end(); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "CatalogEntityValidate", -+ status: "failed", -+ stage: "completion", -+ level: "error", -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ actorId, -+ request: req, -+ message: `Entity validation for entity initiated by ${actorId} failed` - }); -- return res.status(200).end(); -+ throw err; -+ } - }); - } - router.use(backendCommon.errorHandler()); -diff --git a/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js.map b/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js.map -index 57954cf..b99b5b2 100644 ---- a/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js.map -+++ b/node_modules/@backstage/plugin-catalog-backend/dist/cjs/CatalogBuilder-D0vAEZa8.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"CatalogBuilder-D0vAEZa8.cjs.js","sources":["../../src/modules/codeowners/lib/resolve.ts","../../src/modules/codeowners/lib/scm.ts","../../src/modules/codeowners/lib/read.ts","../../src/modules/codeowners/CodeOwnersProcessor.ts","../../src/modules/core/AnnotateLocationEntityProcessor.ts","../../src/modules/core/BuiltinKindsEntityProcessor.ts","../../src/modules/core/FileReaderProcessor.ts","../../src/modules/core/PlaceholderProcessor.ts","../../src/modules/core/UrlReaderProcessor.ts","../../src/modules/util/parse.ts","../../src/processing/refresh.ts","../../src/processing/util.ts","../../src/util/conversion.ts","../../src/modules/core/ConfigLocationEntityProvider.ts","../../src/modules/core/DefaultLocationStore.ts","../../src/ingestion/LocationAnalyzer.ts","../../src/database/conversion.ts","../../src/util/metrics.ts","../../src/database/metrics.ts","../../src/database/operations/refreshState/checkLocationKeyConflict.ts","../../src/database/operations/refreshState/insertUnprocessedEntity.ts","../../src/database/operations/refreshState/updateUnprocessedEntity.ts","../../src/database/util.ts","../../src/constants.ts","../../src/database/DefaultProcessingDatabase.ts","../../src/database/migrations.ts","../../src/stitching/types.ts","../../src/util/opentelemetry.ts","../../src/processing/TaskPipeline.ts","../../src/database/operations/stitcher/markForStitching.ts","../../src/database/operations/util/deleteOrphanedEntities.ts","../../src/processing/DefaultCatalogProcessingEngine.ts","../../src/service/DefaultLocationService.ts","../../src/service/util.ts","../../src/service/DefaultEntitiesCatalog.ts","../../src/processing/ProcessorOutputCollector.ts","../../src/processing/ProcessorCacheManager.ts","../../src/processing/DefaultCatalogProcessingOrchestrator.ts","../../src/database/operations/stitcher/getDeferredStitchableEntities.ts","../../src/database/operations/stitcher/buildEntitySearch.ts","../../src/database/operations/stitcher/markDeferredStitchCompleted.ts","../../src/database/operations/stitcher/util.ts","../../src/database/operations/stitcher/performStitching.ts","../../src/stitching/progressTracker.ts","../../src/stitching/DefaultStitcher.ts","../../src/service/request/entitiesBatchRequest.ts","../../src/service/request/basicEntityFilter.ts","../../src/service/request/common.ts","../../src/service/request/parseEntityFilterParams.ts","../../src/service/request/parseEntityTransformParams.ts","../../src/service/request/parseEntityOrderFieldParams.ts","../../src/service/request/parseQueryEntitiesParams.ts","../../src/service/request/parseEntityFacetParams.ts","../../src/service/request/parseEntityOrderParams.ts","../../src/schema/openapi.generated.ts","../../src/service/request/parseEntityPaginationParams.ts","../../src/service/createRouter.ts","../../src/service/DefaultRefreshService.ts","../../src/service/AuthorizedRefreshService.ts","../../src/ingestion/CatalogRules.ts","../../src/processing/connectEntityProviders.ts","../../src/permissions/rules/util.ts","../../src/permissions/rules/hasAnnotation.ts","../../src/permissions/rules/isEntityKind.ts","../../src/permissions/rules/isEntityOwner.ts","../../src/permissions/rules/hasLabel.ts","../../src/permissions/rules/createPropertyRule.ts","../../src/permissions/rules/hasMetadata.ts","../../src/permissions/rules/hasSpec.ts","../../src/permissions/rules/index.ts","../../src/service/AuthorizedEntitiesCatalog.ts","../../src/service/AuthorizedLocationService.ts","../../src/database/operations/provider/deleteWithEagerPruningOfChildren.ts","../../src/database/operations/provider/refreshByRefreshKeys.ts","../../src/database/DefaultProviderDatabase.ts","../../src/database/DefaultCatalogDatabase.ts","../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as codeowners from 'codeowners-utils';\nimport parseGitUrl from 'git-url-parse';\n\nconst USER_PATTERN = /^@.*/;\nconst GROUP_PATTERN = /^@.*\\/.*/;\nconst EMAIL_PATTERN = /^.*@.*\\..*$/;\n\nexport function resolveCodeOwner(\n contents: string,\n catalogInfoFileUrl: string,\n): string | undefined {\n const codeOwnerEntries = codeowners.parse(contents);\n\n const { filepath } = parseGitUrl(catalogInfoFileUrl);\n const match = codeowners.matchFile(filepath, codeOwnerEntries);\n\n return match ? normalizeCodeOwner(match.owners[0]) : undefined;\n}\n\nexport function normalizeCodeOwner(owner: string) {\n if (owner.match(GROUP_PATTERN)) {\n return owner.split('/')[1];\n } else if (owner.match(USER_PATTERN)) {\n return `User:${owner.substring(1)}`;\n } else if (owner.match(EMAIL_PATTERN)) {\n return owner.split('@')[0];\n }\n\n return owner;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst CODEOWNERS = 'CODEOWNERS';\n\nexport const scmCodeOwnersPaths: Record = {\n // https://mibexsoftware.atlassian.net/wiki/spaces/CODEOWNERS/pages/222822413/Usage\n bitbucket: [CODEOWNERS, `.bitbucket/${CODEOWNERS}`],\n\n // https://docs.gitlab.com/ee/user/project/code_owners.html#how-to-set-up-code-owners\n gitlab: [CODEOWNERS, `.gitlab/${CODEOWNERS}`, `docs/${CODEOWNERS}`],\n\n // https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-file-location\n github: [CODEOWNERS, `.github/${CODEOWNERS}`, `docs/${CODEOWNERS}`],\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { NotFoundError } from '@backstage/errors';\nimport { ScmIntegration } from '@backstage/integration';\nimport 'core-js/features/promise'; // NOTE: This can be removed when ES2021 is implemented\nimport { resolveCodeOwner } from './resolve';\nimport { scmCodeOwnersPaths } from './scm';\n\nexport async function readCodeOwners(\n reader: UrlReader,\n sourceUrl: string,\n codeownersPaths: string[],\n): Promise {\n const readOwnerLocation = async (path: string): Promise => {\n const url = `${sourceUrl}${path}`;\n const data = await reader.readUrl(url);\n const buffer = await data.buffer();\n return buffer.toString();\n };\n\n const candidates = codeownersPaths.map(readOwnerLocation);\n\n return Promise.any(candidates).catch((aggregateError: AggregateError) => {\n const hardError = aggregateError.errors.find(\n error => !(error instanceof NotFoundError),\n );\n\n if (hardError) {\n throw hardError;\n }\n\n return undefined;\n });\n}\n\nexport async function findCodeOwnerByTarget(\n reader: UrlReader,\n targetUrl: string,\n scmIntegration: ScmIntegration,\n): Promise {\n const codeownersPaths = scmCodeOwnersPaths[scmIntegration?.type ?? ''];\n\n const sourceUrl = scmIntegration?.resolveUrl({\n url: '/',\n base: targetUrl,\n });\n\n if (!sourceUrl || !codeownersPaths) {\n return undefined;\n }\n\n const contents = await readCodeOwners(reader, sourceUrl, codeownersPaths);\n\n if (!contents) {\n return undefined;\n }\n\n const owner = resolveCodeOwner(contents, targetUrl);\n\n return owner;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\nimport { findCodeOwnerByTarget } from './lib';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst ALLOWED_KINDS = ['API', 'Component', 'Domain', 'Resource', 'System'];\nconst ALLOWED_LOCATION_TYPES = ['url'];\n\n/** @public */\nexport class CodeOwnersProcessor implements CatalogProcessor {\n private readonly integrations: ScmIntegrationRegistry;\n private readonly logger: LoggerService;\n private readonly reader: UrlReader;\n\n static fromConfig(\n config: Config,\n options: { logger: LoggerService; reader: UrlReader },\n ) {\n const integrations = ScmIntegrations.fromConfig(config);\n\n return new CodeOwnersProcessor({\n ...options,\n integrations,\n });\n }\n\n constructor(options: {\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n reader: UrlReader;\n }) {\n this.integrations = options.integrations;\n this.logger = options.logger;\n this.reader = options.reader;\n }\n\n getProcessorName(): string {\n return 'CodeOwnersProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise {\n // Only continue if the owner is not set\n if (\n !entity ||\n !ALLOWED_KINDS.includes(entity.kind) ||\n !ALLOWED_LOCATION_TYPES.includes(location.type) ||\n (entity.spec && entity.spec.owner)\n ) {\n return entity;\n }\n\n const scmIntegration = this.integrations.byUrl(location.target);\n if (!scmIntegration) {\n return entity;\n }\n\n const owner = await findCodeOwnerByTarget(\n this.reader,\n location.target,\n scmIntegration,\n );\n\n if (!owner) {\n this.logger.debug(\n `CodeOwnerProcessor could not resolve owner for ${location.target}`,\n );\n return entity;\n }\n\n return {\n ...entity,\n spec: { ...entity.spec, owner },\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_EDIT_URL,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n ANNOTATION_SOURCE_LOCATION,\n ANNOTATION_VIEW_URL,\n Entity,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { identity, merge, pickBy } from 'lodash';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n} from '@backstage/plugin-catalog-node';\n\nconst commitHashRegExp = /\\b[0-9a-f]{40,}\\b/;\n/** @public */\nexport class AnnotateLocationEntityProcessor implements CatalogProcessor {\n constructor(\n private readonly options: {\n integrations: ScmIntegrationRegistry;\n },\n ) {}\n\n getProcessorName(): string {\n return 'AnnotateLocationEntityProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n _: CatalogProcessorEmit,\n originLocation: LocationSpec,\n ): Promise {\n const { integrations } = this.options;\n let viewUrl;\n let editUrl;\n let sourceLocation;\n\n if (location.type === 'url') {\n const scmIntegration = integrations.byUrl(location.target);\n\n viewUrl = location.target;\n\n if (!commitHashRegExp.test(location.target)) {\n editUrl = scmIntegration?.resolveEditUrl(location.target);\n }\n\n const sourceUrl = scmIntegration?.resolveUrl({\n url: './',\n base: location.target,\n });\n\n if (sourceUrl) {\n sourceLocation = stringifyLocationRef({\n type: 'url',\n target: sourceUrl,\n });\n }\n }\n\n return merge(\n {\n metadata: {\n annotations: pickBy(\n {\n [ANNOTATION_LOCATION]: stringifyLocationRef(location),\n [ANNOTATION_ORIGIN_LOCATION]:\n stringifyLocationRef(originLocation),\n [ANNOTATION_VIEW_URL]: viewUrl,\n [ANNOTATION_EDIT_URL]: editUrl,\n [ANNOTATION_SOURCE_LOCATION]: sourceLocation,\n },\n identity,\n ),\n },\n },\n entity,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiEntity,\n apiEntityV1alpha1Validator,\n ComponentEntity,\n componentEntityV1alpha1Validator,\n DomainEntity,\n domainEntityV1alpha1Validator,\n Entity,\n getCompoundEntityRef,\n GroupEntity,\n groupEntityV1alpha1Validator,\n locationEntityV1alpha1Validator,\n parseEntityRef,\n RELATION_API_CONSUMED_BY,\n RELATION_API_PROVIDED_BY,\n RELATION_CHILD_OF,\n RELATION_CONSUMES_API,\n RELATION_DEPENDENCY_OF,\n RELATION_DEPENDS_ON,\n RELATION_HAS_MEMBER,\n RELATION_HAS_PART,\n RELATION_MEMBER_OF,\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n RELATION_PARENT_OF,\n RELATION_PART_OF,\n RELATION_PROVIDES_API,\n ResourceEntity,\n resourceEntityV1alpha1Validator,\n SystemEntity,\n systemEntityV1alpha1Validator,\n UserEntity,\n userEntityV1alpha1Validator,\n} from '@backstage/catalog-model';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\n/** @public */\nexport class BuiltinKindsEntityProcessor implements CatalogProcessor {\n private readonly validators = [\n apiEntityV1alpha1Validator,\n componentEntityV1alpha1Validator,\n resourceEntityV1alpha1Validator,\n groupEntityV1alpha1Validator,\n locationEntityV1alpha1Validator,\n userEntityV1alpha1Validator,\n systemEntityV1alpha1Validator,\n domainEntityV1alpha1Validator,\n ];\n\n getProcessorName(): string {\n return 'BuiltinKindsEntityProcessor';\n }\n\n async validateEntityKind(entity: Entity): Promise {\n for (const validator of this.validators) {\n const results = await validator.check(entity);\n if (results) {\n return true;\n }\n }\n\n return false;\n }\n\n async postProcessEntity(\n entity: Entity,\n _location: LocationSpec,\n emit: CatalogProcessorEmit,\n ): Promise {\n const selfRef = getCompoundEntityRef(entity);\n\n /*\n * Utilities\n */\n\n function doEmit(\n targets: string | string[] | undefined,\n context: { defaultKind?: string; defaultNamespace: string },\n outgoingRelation: string,\n incomingRelation: string,\n ): void {\n if (!targets) {\n return;\n }\n for (const target of [targets].flat()) {\n const targetRef = parseEntityRef(target, context);\n emit(\n processingResult.relation({\n source: selfRef,\n type: outgoingRelation,\n target: {\n kind: targetRef.kind,\n namespace: targetRef.namespace,\n name: targetRef.name,\n },\n }),\n );\n emit(\n processingResult.relation({\n source: {\n kind: targetRef.kind,\n namespace: targetRef.namespace,\n name: targetRef.name,\n },\n type: incomingRelation,\n target: selfRef,\n }),\n );\n }\n }\n\n /*\n * Emit relations for the Component kind\n */\n\n if (entity.kind === 'Component') {\n const component = entity as ComponentEntity;\n doEmit(\n component.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n component.spec.subcomponentOf,\n { defaultKind: 'Component', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n doEmit(\n component.spec.providesApis,\n { defaultKind: 'API', defaultNamespace: selfRef.namespace },\n RELATION_PROVIDES_API,\n RELATION_API_PROVIDED_BY,\n );\n doEmit(\n component.spec.consumesApis,\n { defaultKind: 'API', defaultNamespace: selfRef.namespace },\n RELATION_CONSUMES_API,\n RELATION_API_CONSUMED_BY,\n );\n doEmit(\n component.spec.dependsOn,\n { defaultNamespace: selfRef.namespace },\n RELATION_DEPENDS_ON,\n RELATION_DEPENDENCY_OF,\n );\n doEmit(\n component.spec.system,\n { defaultKind: 'System', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the API kind\n */\n\n if (entity.kind === 'API') {\n const api = entity as ApiEntity;\n doEmit(\n api.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n api.spec.system,\n { defaultKind: 'System', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the Resource kind\n */\n\n if (entity.kind === 'Resource') {\n const resource = entity as ResourceEntity;\n doEmit(\n resource.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n resource.spec.dependsOn,\n { defaultNamespace: selfRef.namespace },\n RELATION_DEPENDS_ON,\n RELATION_DEPENDENCY_OF,\n );\n doEmit(\n resource.spec.dependencyOf,\n { defaultNamespace: selfRef.namespace },\n RELATION_DEPENDENCY_OF,\n RELATION_DEPENDS_ON,\n );\n doEmit(\n resource.spec.system,\n { defaultKind: 'System', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the User kind\n */\n\n if (entity.kind === 'User') {\n const user = entity as UserEntity;\n doEmit(\n user.spec.memberOf,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_MEMBER_OF,\n RELATION_HAS_MEMBER,\n );\n }\n\n /*\n * Emit relations for the Group kind\n */\n\n if (entity.kind === 'Group') {\n const group = entity as GroupEntity;\n doEmit(\n group.spec.parent,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_CHILD_OF,\n RELATION_PARENT_OF,\n );\n doEmit(\n group.spec.children,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_PARENT_OF,\n RELATION_CHILD_OF,\n );\n doEmit(\n group.spec.members,\n { defaultKind: 'User', defaultNamespace: selfRef.namespace },\n RELATION_HAS_MEMBER,\n RELATION_MEMBER_OF,\n );\n }\n\n /*\n * Emit relations for the System kind\n */\n\n if (entity.kind === 'System') {\n const system = entity as SystemEntity;\n doEmit(\n system.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n system.spec.domain,\n { defaultKind: 'Domain', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the Domain kind\n */\n\n if (entity.kind === 'Domain') {\n const domain = entity as DomainEntity;\n doEmit(\n domain.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n domain.spec.subdomainOf,\n { defaultKind: 'Domain', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n return entity;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport g from 'glob';\nimport path from 'path';\nimport { promisify } from 'util';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n CatalogProcessorParser,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\nconst glob = promisify(g);\n\nconst LOCATION_TYPE = 'file';\n\n/** @public */\nexport class FileReaderProcessor implements CatalogProcessor {\n getProcessorName(): string {\n return 'FileReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n optional: boolean,\n emit: CatalogProcessorEmit,\n parser: CatalogProcessorParser,\n ): Promise {\n if (location.type !== LOCATION_TYPE) {\n return false;\n }\n\n try {\n const fileMatches = await glob(location.target);\n\n if (fileMatches.length > 0) {\n for (const fileMatch of fileMatches) {\n const data = await fs.readFile(fileMatch);\n const normalizedFilePath = path.normalize(fileMatch);\n\n // The normalize converts to native slashes; the glob library returns\n // forward slashes even on windows\n for await (const parseResult of parser({\n data: data,\n location: {\n type: LOCATION_TYPE,\n target: normalizedFilePath,\n },\n })) {\n emit(parseResult);\n emit(\n processingResult.refresh(\n `${LOCATION_TYPE}:${normalizedFilePath}`,\n ),\n );\n }\n }\n } else if (!optional) {\n const message = `${location.type} ${location.target} does not exist`;\n emit(processingResult.notFoundError(location, message));\n }\n } catch (e) {\n const message = `${location.type} ${location.target} could not be read, ${e}`;\n emit(processingResult.generalError(location, message));\n }\n\n return true;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { JsonValue } from '@backstage/types';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport yaml from 'yaml';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n PlaceholderResolver,\n PlaceholderResolverParams,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\n/** @public */\nexport type PlaceholderProcessorOptions = {\n resolvers: Record;\n reader: UrlReader;\n integrations: ScmIntegrationRegistry;\n};\n\n/**\n * Traverses raw entity JSON looking for occurrences of $-prefixed placeholders\n * that it then fills in with actual data.\n * @public\n */\nexport class PlaceholderProcessor implements CatalogProcessor {\n constructor(private readonly options: PlaceholderProcessorOptions) {}\n\n getProcessorName(): string {\n return 'PlaceholderProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n emit: CatalogProcessorEmit,\n ): Promise {\n const process = async (data: any): Promise<[any, boolean]> => {\n if (!data || !(data instanceof Object)) {\n // Scalars can't have placeholders\n return [data, false];\n }\n\n if (Array.isArray(data)) {\n // We're an array - process all entries recursively\n const items = await Promise.all(data.map(item => process(item)));\n return items.every(([, changed]) => !changed)\n ? [data, false]\n : [items.map(([item]) => item), true];\n }\n\n const keys = Object.keys(data);\n if (!keys.some(k => k.startsWith('$'))) {\n // We're an object but no placeholders at this level - process all\n // entries recursively\n const entries = await Promise.all(\n Object.entries(data).map(([k, v]) =>\n process(v).then(vp => [k, vp] as const),\n ),\n );\n return entries.every(([, [, changed]]) => !changed)\n ? [data, false]\n : [Object.fromEntries(entries.map(([k, [v]]) => [k, v])), true];\n } else if (keys.length !== 1) {\n // This was an object that had more than one key, some of which were\n // dollar prefixed. We only handle the case where there is exactly one\n // such key; anything else is left alone.\n return [data, false];\n }\n\n const resolverKey = keys[0].substring(1);\n const resolverValue = data[keys[0]];\n\n const resolver = this.options.resolvers[resolverKey];\n if (!resolver) {\n // If there was no such placeholder resolver, we err on the side of safety\n // and assume that this is something that's best left alone. For example, if\n // the input contains JSONSchema, there may be \"$ref\": \"#/definitions/node\"\n // nodes in the document.\n return [data, false];\n }\n\n const read = async (url: string): Promise => {\n const response = await this.options.reader.readUrl(url);\n const buffer = await response.buffer();\n return buffer;\n };\n\n const resolveUrl = (url: string, base: string): string =>\n this.options.integrations.resolveUrl({\n url,\n base,\n });\n\n return [\n await resolver({\n key: resolverKey,\n value: resolverValue,\n baseUrl: location.target,\n read,\n resolveUrl,\n emit,\n }),\n true,\n ];\n };\n\n const [result] = await process(entity);\n return result;\n }\n}\n\n/*\n * Resolvers\n */\n\nexport async function yamlPlaceholderResolver(\n params: PlaceholderResolverParams,\n): Promise {\n const { content, url } = await readTextLocation(params);\n\n params.emit(processingResult.refresh(`url:${url}`));\n\n let documents: yaml.Document.Parsed[];\n try {\n documents = yaml.parseAllDocuments(content).filter(d => d);\n } catch (e) {\n throw new Error(\n `Placeholder \\$${params.key} failed to parse YAML data at ${params.value}, ${e}`,\n );\n }\n\n if (documents.length !== 1) {\n throw new Error(\n `Placeholder \\$${params.key} expected to find exactly one document of data at ${params.value}, found ${documents.length}`,\n );\n }\n\n const document = documents[0];\n\n if (document.errors?.length) {\n throw new Error(\n `Placeholder \\$${params.key} found an error in the data at ${params.value}, ${document.errors[0]}`,\n );\n }\n\n return document.toJSON();\n}\n\nexport async function jsonPlaceholderResolver(\n params: PlaceholderResolverParams,\n): Promise {\n const { content, url } = await readTextLocation(params);\n\n params.emit(processingResult.refresh(`url:${url}`));\n\n try {\n return JSON.parse(content);\n } catch (e) {\n throw new Error(\n `Placeholder \\$${params.key} failed to parse JSON data at ${params.value}, ${e}`,\n );\n }\n}\n\nexport async function textPlaceholderResolver(\n params: PlaceholderResolverParams,\n): Promise {\n const { content, url } = await readTextLocation(params);\n\n params.emit(processingResult.refresh(`url:${url}`));\n\n return content;\n}\n\n/*\n * Helpers\n */\n\nasync function readTextLocation(\n params: PlaceholderResolverParams,\n): Promise<{ content: string; url: string }> {\n const newUrl = relativeUrl(params);\n\n try {\n const data = await params.read(newUrl);\n return { content: data.toString('utf-8'), url: newUrl };\n } catch (e) {\n throw new Error(\n `Placeholder \\$${params.key} could not read location ${params.value}, ${e}`,\n );\n }\n}\n\nfunction relativeUrl({\n key,\n value,\n baseUrl,\n resolveUrl,\n}: PlaceholderResolverParams): string {\n if (typeof value !== 'string') {\n throw new Error(\n `Placeholder \\$${key} expected a string value parameter, in the form of an absolute URL or a relative path`,\n );\n }\n\n try {\n return resolveUrl(value, baseUrl);\n } catch (e) {\n // The only remaining case that isn't support is a relative file path that should be\n // resolved using a relative file location. Accessing local file paths can lead to\n // path traversal attacks and access to any file on the host system. Implementing this\n // would require additional security measures.\n throw new Error(\n `Placeholder \\$${key} could not form a URL out of ${baseUrl} and ${value}, ${e}`,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { assertError } from '@backstage/errors';\nimport limiterFactory from 'p-limit';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport parseGitUrl from 'git-url-parse';\nimport {\n CatalogProcessor,\n CatalogProcessorCache,\n CatalogProcessorEmit,\n CatalogProcessorEntityResult,\n CatalogProcessorParser,\n CatalogProcessorResult,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst CACHE_KEY = 'v1';\n\n// WARNING: If you change this type, you likely need to bump the CACHE_KEY as well\ntype CacheItem = {\n etag: string;\n value: {\n type: 'entity';\n entity: Entity;\n location: LocationSpec;\n }[];\n};\n\n/** @public */\nexport class UrlReaderProcessor implements CatalogProcessor {\n constructor(\n private readonly options: {\n reader: UrlReader;\n logger: LoggerService;\n },\n ) {}\n\n getProcessorName() {\n return 'url-reader';\n }\n\n async readLocation(\n location: LocationSpec,\n optional: boolean,\n emit: CatalogProcessorEmit,\n parser: CatalogProcessorParser,\n cache: CatalogProcessorCache,\n ): Promise {\n if (location.type !== 'url') {\n return false;\n }\n\n const cacheItem = await cache.get(CACHE_KEY);\n\n try {\n const { response, etag: newEtag } = await this.doRead(\n location.target,\n cacheItem?.etag,\n );\n\n const parseResults: CatalogProcessorResult[] = [];\n for (const item of response) {\n for await (const parseResult of parser({\n data: item.data,\n location: { type: location.type, target: item.url },\n })) {\n parseResults.push(parseResult);\n emit(parseResult);\n }\n }\n\n const isOnlyEntities = parseResults.every(r => r.type === 'entity');\n if (newEtag && isOnlyEntities) {\n await cache.set(CACHE_KEY, {\n etag: newEtag,\n value: parseResults as CatalogProcessorEntityResult[],\n });\n }\n\n emit(processingResult.refresh(`${location.type}:${location.target}`));\n } catch (error) {\n assertError(error);\n const message = `Unable to read ${location.type}, ${error}`.substring(\n 0,\n 5000,\n );\n if (error.name === 'NotModifiedError' && cacheItem) {\n for (const parseResult of cacheItem.value) {\n emit(parseResult);\n }\n emit(processingResult.refresh(`${location.type}:${location.target}`));\n } else if (error.name === 'NotFoundError') {\n if (!optional) {\n emit(processingResult.notFoundError(location, message));\n }\n } else {\n emit(processingResult.generalError(location, message));\n }\n }\n\n return true;\n }\n\n private async doRead(\n location: string,\n etag?: string,\n ): Promise<{ response: { data: Buffer; url: string }[]; etag?: string }> {\n // Does it contain globs? I.e. does it contain asterisks or question marks\n // (no curly braces for now)\n\n const { filepath } = parseGitUrl(location);\n if (filepath?.match(/[*?]/)) {\n const limiter = limiterFactory(5);\n const response = await this.options.reader.search(location, { etag });\n const output = response.files.map(async file => ({\n url: file.url,\n data: await limiter(file.content),\n }));\n return { response: await Promise.all(output), etag: response.etag };\n }\n\n const data = await this.options.reader.readUrl(location, { etag });\n return {\n response: [{ url: location, data: await data.buffer() }],\n etag: data.etag,\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyLocationRef } from '@backstage/catalog-model';\nimport lodash from 'lodash';\nimport yaml from 'yaml';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessorParser,\n CatalogProcessorResult,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\n/** @public */\nexport function* parseEntityYaml(\n data: Buffer,\n location: LocationSpec,\n): Iterable {\n let documents: yaml.Document.Parsed[];\n try {\n documents = yaml.parseAllDocuments(data.toString('utf8')).filter(d => d);\n } catch (e) {\n const loc = stringifyLocationRef(location);\n const message = `Failed to parse YAML at ${loc}, ${e}`;\n yield processingResult.generalError(location, message);\n return;\n }\n\n for (const document of documents) {\n if (document.errors?.length) {\n const loc = stringifyLocationRef(location);\n const message = `YAML error at ${loc}, ${document.errors[0]}`;\n yield processingResult.generalError(location, message);\n } else {\n const json = document.toJSON();\n if (lodash.isPlainObject(json)) {\n yield processingResult.entity(location, json as Entity);\n } else if (json === null) {\n // Ignore null values, these happen if there is an empty document in the\n // YAML file, for example if --- is added to the end of the file.\n } else {\n const message = `Expected object at root, got ${typeof json}`;\n yield processingResult.generalError(location, message);\n }\n }\n }\n}\n\nexport const defaultEntityDataParser: CatalogProcessorParser =\n async function* defaultEntityDataParser({ data, location }) {\n for (const e of parseEntityYaml(data, location)) {\n yield e;\n }\n };\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Function that returns the catalog processing interval in seconds.\n * @public\n */\nexport type ProcessingIntervalFunction = () => number;\n\n/**\n * Creates a function that returns a random processing interval between minSeconds and maxSeconds.\n * @returns A {@link ProcessingIntervalFunction} that provides the next processing interval\n * @public\n */\nexport function createRandomProcessingInterval(options: {\n minSeconds: number;\n maxSeconds: number;\n}): ProcessingIntervalFunction {\n const { minSeconds, maxSeconds } = options;\n return () => {\n return Math.random() * (maxSeconds - minSeconds) + minSeconds;\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n entityEnvelopeSchemaValidator,\n entitySchemaValidator,\n LocationEntity,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\n\nexport function isLocationEntity(entity: Entity): entity is LocationEntity {\n return entity.kind === 'Location';\n}\n\nexport function getEntityLocationRef(entity: Entity): string {\n const ref = entity.metadata.annotations?.[ANNOTATION_LOCATION];\n if (!ref) {\n const entityRef = stringifyEntityRef(entity);\n throw new InputError(\n `Entity '${entityRef}' does not have the annotation ${ANNOTATION_LOCATION}`,\n );\n }\n return ref;\n}\n\nexport function getEntityOriginLocationRef(entity: Entity): string {\n const ref = entity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION];\n if (!ref) {\n const entityRef = stringifyEntityRef(entity);\n throw new InputError(\n `Entity '${entityRef}' does not have the annotation ${ANNOTATION_ORIGIN_LOCATION}`,\n );\n }\n return ref;\n}\n\nexport function toAbsoluteUrl(\n integrations: ScmIntegrationRegistry,\n base: LocationSpec,\n type: string,\n target: string,\n): string {\n if (base.type !== type) {\n return target;\n }\n try {\n if (type === 'file') {\n if (target.startsWith('.')) {\n return path.join(path.dirname(base.target), target);\n }\n return target;\n } else if (type === 'url') {\n return integrations.resolveUrl({ url: target, base: base.target });\n }\n return target;\n } catch (e) {\n return target;\n }\n}\n\nexport function isObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport const validateEntity = entitySchemaValidator();\n\nexport const validateEntityEnvelope = entityEnvelopeSchemaValidator();\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n LocationEntityV1alpha1,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n stringifyEntityRef,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\n\nexport function locationSpecToMetadataName(location: LocationSpec) {\n const hash = createHash('sha1')\n .update(`${location.type}:${location.target}`)\n .digest('hex');\n return `generated-${hash}`;\n}\n\n/** @public */\nexport function locationSpecToLocationEntity(opts: {\n location: LocationSpec;\n parentEntity?: Entity;\n}): LocationEntityV1alpha1 {\n const location = opts.location;\n const parentEntity = opts.parentEntity;\n\n let ownLocation: string;\n let originLocation: string;\n if (parentEntity) {\n const maybeOwnLocation =\n parentEntity.metadata.annotations?.[ANNOTATION_LOCATION];\n if (!maybeOwnLocation) {\n throw new Error(\n `Parent entity '${stringifyEntityRef(\n parentEntity,\n )}' of location '${stringifyLocationRef(\n location,\n )}' does not have a location annotation`,\n );\n }\n ownLocation = maybeOwnLocation;\n const maybeOriginLocation =\n parentEntity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION];\n if (!maybeOriginLocation) {\n throw new Error(\n `Parent entity '${stringifyEntityRef(\n parentEntity,\n )}' of location '${stringifyLocationRef(\n location,\n )}' does not have an origin location annotation`,\n );\n }\n originLocation = maybeOriginLocation;\n } else {\n ownLocation = stringifyLocationRef(location);\n originLocation = ownLocation;\n }\n\n const result: LocationEntityV1alpha1 = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Location',\n metadata: {\n name: locationSpecToMetadataName(location),\n annotations: {\n [ANNOTATION_LOCATION]: ownLocation,\n [ANNOTATION_ORIGIN_LOCATION]: originLocation,\n },\n },\n spec: {\n type: location.type,\n target: location.target,\n presence: location.presence,\n },\n };\n\n return result;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport path from 'path';\nimport { getEntityLocationRef } from '../../processing/util';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { locationSpecToLocationEntity } from '../../util/conversion';\n\nexport class ConfigLocationEntityProvider implements EntityProvider {\n constructor(private readonly config: Config) {}\n\n getProviderName(): string {\n return 'ConfigLocationProvider';\n }\n\n async connect(connection: EntityProviderConnection): Promise {\n const entities = this.getEntitiesFromConfig();\n await connection.applyMutation({\n type: 'full',\n entities,\n });\n\n if (this.config.subscribe) {\n let currentKey = JSON.stringify(entities);\n\n this.config.subscribe(() => {\n const newEntities = this.getEntitiesFromConfig();\n const newKey = JSON.stringify(newEntities);\n\n if (currentKey !== newKey) {\n currentKey = newKey;\n connection.applyMutation({\n type: 'full',\n entities: newEntities,\n });\n }\n });\n }\n }\n\n private getEntitiesFromConfig() {\n const locationConfigs =\n this.config.getOptionalConfigArray('catalog.locations') ?? [];\n\n return locationConfigs.map(location => {\n const type = location.getString('type');\n const target = location.getString('target');\n const entity = locationSpecToLocationEntity({\n location: {\n type,\n target: type === 'file' ? path.resolve(target) : target,\n },\n });\n const locationKey = getEntityLocationRef(entity);\n return { entity, locationKey };\n });\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Location } from '@backstage/catalog-client';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport {\n DbLocationsRow,\n DbRefreshStateRow,\n DbSearchRow,\n} from '../../database/tables';\nimport { getEntityLocationRef } from '../../processing/util';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { locationSpecToLocationEntity } from '../../util/conversion';\nimport { LocationInput, LocationStore } from '../../service/types';\nimport {\n ANNOTATION_ORIGIN_LOCATION,\n CompoundEntityRef,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\n\nexport class DefaultLocationStore implements LocationStore, EntityProvider {\n private _connection: EntityProviderConnection | undefined;\n\n constructor(private readonly db: Knex) {}\n\n getProviderName(): string {\n return 'DefaultLocationStore';\n }\n\n async createLocation(input: LocationInput): Promise {\n const location = await this.db.transaction(async tx => {\n // Attempt to find a previous location matching the input\n const previousLocations = await this.locations(tx);\n // TODO: when location id's are a compilation of input target we can remove this full\n // lookup of locations first and just grab the by that instead.\n const previousLocation = previousLocations.some(\n l => input.type === l.type && input.target === l.target,\n );\n if (previousLocation) {\n throw new ConflictError(\n `Location ${input.type}:${input.target} already exists`,\n );\n }\n\n const inner: DbLocationsRow = {\n id: uuid(),\n type: input.type,\n target: input.target,\n };\n\n await tx('locations').insert(inner);\n\n return inner;\n });\n const entity = locationSpecToLocationEntity({ location });\n await this.connection.applyMutation({\n type: 'delta',\n added: [{ entity, locationKey: getEntityLocationRef(entity) }],\n removed: [],\n });\n\n return location;\n }\n\n async listLocations(): Promise {\n return await this.locations();\n }\n\n async getLocation(id: string): Promise {\n const items = await this.db('locations')\n .where({ id })\n .select();\n\n if (!items.length) {\n throw new NotFoundError(`Found no location with ID ${id}`);\n }\n return items[0];\n }\n\n async deleteLocation(id: string): Promise {\n if (!this.connection) {\n throw new Error('location store is not initialized');\n }\n\n const deleted = await this.db.transaction(async tx => {\n const [location] = await tx('locations')\n .where({ id })\n .select();\n\n if (!location) {\n throw new NotFoundError(`Found no location with ID ${id}`);\n }\n\n await tx('locations').where({ id }).del();\n return location;\n });\n const entity = locationSpecToLocationEntity({ location: deleted });\n await this.connection.applyMutation({\n type: 'delta',\n added: [],\n removed: [{ entity, locationKey: getEntityLocationRef(entity) }],\n });\n }\n\n async getLocationByEntity(entityRef: CompoundEntityRef): Promise {\n const entityRefString = stringifyEntityRef(entityRef);\n\n const [entityRow] = await this.db('refresh_state')\n .where({ entity_ref: entityRefString })\n .select('entity_id')\n .limit(1);\n if (!entityRow) {\n throw new NotFoundError(`found no entity for ref ${entityRefString}`);\n }\n\n const [searchRow] = await this.db('search')\n .where({\n entity_id: entityRow.entity_id,\n key: `metadata.annotations.${ANNOTATION_ORIGIN_LOCATION}`,\n })\n .select('value')\n .limit(1);\n if (!searchRow?.value) {\n throw new NotFoundError(\n `found no origin annotation for ref ${entityRefString}`,\n );\n }\n\n const { type, target } = parseLocationRef(searchRow.value);\n const [locationRow] = await this.db('locations')\n .where({ type, target })\n .select()\n .limit(1);\n\n if (!locationRow) {\n throw new NotFoundError(\n `Found no location with type ${type} and target ${target}`,\n );\n }\n\n return locationRow;\n }\n\n private get connection(): EntityProviderConnection {\n if (!this._connection) {\n throw new Error('location store is not initialized');\n }\n\n return this._connection;\n }\n\n async connect(connection: EntityProviderConnection): Promise {\n this._connection = connection;\n\n const locations = await this.locations();\n\n const entities = locations.map(location => {\n const entity = locationSpecToLocationEntity({ location });\n return { entity, locationKey: getEntityLocationRef(entity) };\n });\n\n await this.connection.applyMutation({\n type: 'full',\n entities,\n });\n }\n\n private async locations(dbOrTx: Knex.Transaction | Knex = this.db) {\n const locations = await dbOrTx('locations').select();\n return (\n locations\n // TODO(blam): We should create a mutation to remove this location for everyone\n // eventually when it's all done and dusted\n .filter(({ type }) => type !== 'bootstrap')\n .map(item => ({\n id: item.id,\n target: item.target,\n type: item.type,\n }))\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport parseGitUrl from 'git-url-parse';\nimport { Entity } from '@backstage/catalog-model';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport {\n AnalyzeLocationRequest,\n AnalyzeLocationResponse,\n} from '@backstage/plugin-catalog-common';\nimport {\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class RepoLocationAnalyzer implements LocationAnalyzer {\n private readonly logger: LoggerService;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n private readonly analyzers: ScmLocationAnalyzer[];\n\n constructor(\n logger: LoggerService,\n scmIntegrations: ScmIntegrationRegistry,\n analyzers: ScmLocationAnalyzer[],\n ) {\n this.logger = logger;\n this.scmIntegrations = scmIntegrations;\n this.analyzers = analyzers;\n }\n async analyzeLocation(\n request: AnalyzeLocationRequest,\n ): Promise {\n const integration = this.scmIntegrations.byUrl(request.location.target);\n const { owner, name } = parseGitUrl(request.location.target);\n\n let annotationPrefix;\n switch (integration?.type) {\n case 'azure':\n annotationPrefix = 'dev.azure.com';\n break;\n case 'bitbucket':\n annotationPrefix = 'bitbucket.org';\n break;\n case 'github':\n annotationPrefix = 'github.com';\n break;\n case 'gitlab':\n annotationPrefix = 'gitlab.com';\n break;\n default:\n break;\n }\n\n const analyzer = this.analyzers.find(a =>\n a.supports(request.location.target),\n );\n if (analyzer) {\n const analyzerResult = await analyzer.analyze({\n url: request.location.target,\n });\n if (analyzerResult.existing.length > 0) {\n this.logger.debug(\n `entity for ${request.location.target} already exists.`,\n );\n return {\n existingEntityFiles: analyzerResult.existing,\n generateEntities: [],\n };\n }\n }\n\n const entity: Entity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Component',\n metadata: {\n name: name,\n },\n spec: { type: 'other', lifecycle: 'unknown' },\n };\n\n if (annotationPrefix) {\n entity.metadata.annotations = {\n [`${annotationPrefix}/project-slug`]: `${owner}/${name}`,\n };\n }\n\n this.logger.debug(`entity created for ${request.location.target}`);\n return {\n existingEntityFiles: [],\n generateEntities: [{ entity, fields: [] }],\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isDatabaseConflictError } from '@backstage/backend-plugin-api';\nimport { ConflictError, InputError } from '@backstage/errors';\nimport { DateTime } from 'luxon';\n\n/**\n * Takes a TIMESTAMP type column and converts it to a DateTime.\n *\n * Some engines return the SQL string form (e.g. 'YYYY-MM-DD hh:mm:ss'), some\n * return ISO string form (e.g. 'YYYY-MM-DDThh:mm:ss.SSSZ'), some return a js\n * Date object.\n */\nexport function timestampToDateTime(input: Date | string): DateTime {\n try {\n if (typeof input === 'object') {\n return DateTime.fromJSDate(input).toUTC();\n }\n\n const result = input.includes(' ')\n ? DateTime.fromSQL(input, { zone: 'utc' })\n : DateTime.fromISO(input, { zone: 'utc' });\n if (!result.isValid) {\n throw new TypeError('Not valid');\n }\n\n return result;\n } catch (e) {\n throw new InputError(`Failed to parse database timestamp ${input}`, e);\n }\n}\n\n/**\n * Rethrows an error, possibly translating it to a more precise error type.\n */\nexport function rethrowError(e: any): never {\n if (isDatabaseConflictError(e)) {\n throw new ConflictError(`Rejected due to a conflicting entity`, e);\n }\n\n throw e;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Counter,\n CounterConfiguration,\n Gauge,\n GaugeConfiguration,\n Histogram,\n HistogramConfiguration,\n register,\n Summary,\n SummaryConfiguration,\n} from 'prom-client';\n\nexport function createCounterMetric(\n config: CounterConfiguration,\n): Counter {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Counter(config);\n register.registerMetric(metric);\n }\n return metric as Counter;\n}\n\nexport function createGaugeMetric(\n config: GaugeConfiguration,\n): Gauge {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Gauge(config);\n register.registerMetric(metric);\n }\n return metric as Gauge;\n}\n\nexport function createSummaryMetric(\n config: SummaryConfiguration,\n): Summary {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Summary(config);\n register.registerMetric(metric);\n }\n\n return metric as Summary;\n}\n\nexport function createHistogramMetric(\n config: HistogramConfiguration,\n): Histogram {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Histogram(config);\n register.registerMetric(metric);\n }\n\n return metric as Histogram;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { createGaugeMetric } from '../util/metrics';\nimport { DbRefreshStateRow, DbRelationsRow, DbLocationsRow } from './tables';\nimport { metrics } from '@opentelemetry/api';\nimport { parseEntityRef } from '@backstage/catalog-model';\n\nexport function initDatabaseMetrics(knex: Knex) {\n const seenProm = new Set();\n const seen = new Set();\n const meter = metrics.getMeter('default');\n return {\n entities_count_prom: createGaugeMetric({\n name: 'catalog_entities_count',\n help: 'Total amount of entities in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n labelNames: ['kind'],\n async collect() {\n const result = await knex('refresh_state').select(\n 'entity_ref',\n );\n const results = result\n .map(row => row.entity_ref.split(':')[0])\n .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());\n\n results.forEach((value, key) => {\n seenProm.add(key);\n this.set({ kind: key }, value);\n });\n\n // Set all the entities that were not seenProm to 0 and delete them from the seenProm set.\n seenProm.forEach(key => {\n if (!results.has(key)) {\n this.set({ kind: key }, 0);\n seenProm.delete(key);\n }\n });\n },\n }),\n registered_locations_prom: createGaugeMetric({\n name: 'catalog_registered_locations_count',\n help: 'Total amount of registered locations in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex('locations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n relations_prom: createGaugeMetric({\n name: 'catalog_relations_count',\n help: 'Total amount of relations between entities. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex('relations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n entities_count: meter\n .createObservableGauge('catalog_entities_count', {\n description: 'Total amount of entities in the catalog',\n })\n .addCallback(async gauge => {\n const result = await knex('refresh_state').select(\n 'entity_ref',\n );\n const results = result\n .map(row => parseEntityRef(row.entity_ref).kind)\n .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());\n\n results.forEach((value, key) => {\n seen.add(key);\n gauge.observe(value, { kind: key });\n });\n\n // Set all the entities that were not seen to 0 and delete them from the seen set.\n seen.forEach(key => {\n if (!results.has(key)) {\n gauge.observe(0, { kind: key });\n seen.delete(key);\n }\n });\n }),\n registered_locations: meter\n .createObservableGauge('catalog_registered_locations_count', {\n description: 'Total amount of registered locations in the catalog',\n })\n .addCallback(async gauge => {\n const total = await knex('locations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }),\n relations: meter\n .createObservableGauge('catalog_relations_count', {\n description: 'Total amount of relations between entities',\n })\n .addCallback(async gauge => {\n const total = await knex('relations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }),\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Checks whether a refresh state exists for the given entity that has a\n * location key that does not match the provided location key.\n *\n * @returns The conflicting key if there is one.\n */\nexport async function checkLocationKeyConflict(options: {\n tx: Knex.Transaction;\n entityRef: string;\n locationKey?: string;\n}): Promise {\n const { tx, entityRef, locationKey } = options;\n\n const row = await tx('refresh_state')\n .select('location_key')\n .where('entity_ref', entityRef)\n .first();\n\n const conflictingKey = row?.location_key;\n\n // If there's no existing key we can't have a conflict\n if (!conflictingKey) {\n return undefined;\n }\n\n if (conflictingKey !== locationKey) {\n return conflictingKey;\n }\n return undefined;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\nimport { v4 as uuid } from 'uuid';\nimport {\n LoggerService,\n isDatabaseConflictError,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Attempts to insert a new refresh state row for the given entity, returning\n * true if successful and false if there was a conflict.\n */\nexport async function insertUnprocessedEntity(options: {\n tx: Knex.Transaction;\n entity: Entity;\n hash: string;\n locationKey?: string;\n logger: LoggerService;\n}): Promise {\n const { tx, entity, hash, logger, locationKey } = options;\n\n const entityRef = stringifyEntityRef(entity);\n const serializedEntity = JSON.stringify(entity);\n\n try {\n let query = tx('refresh_state').insert({\n entity_id: uuid(),\n entity_ref: entityRef,\n unprocessed_entity: serializedEntity,\n unprocessed_hash: hash,\n errors: '',\n location_key: locationKey,\n next_update_at: tx.fn.now(),\n last_discovery_at: tx.fn.now(),\n });\n\n // TODO(Rugvip): only tested towards MySQL, Postgres and SQLite.\n // We have to do this because the only way to detect if there was a conflict with\n // SQLite is to catch the error, while Postgres needs to ignore the conflict to not\n // break the ongoing transaction.\n if (tx.client.config.client.includes('pg')) {\n query = query.onConflict('entity_ref').ignore() as any; // type here does not match runtime\n }\n\n // Postgres gives as an object with rowCount, SQLite gives us an array\n const result: { rowCount?: number; length?: number } = await query;\n return result.rowCount === 1 || result.length === 1;\n } catch (error) {\n // SQLite, or MySQL reached this rather than the rowCount check above\n if (!isDatabaseConflictError(error)) {\n throw error;\n } else {\n logger.debug(`Unable to insert a new refresh state row, ${error}`);\n return false;\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Attempts to update an existing refresh state row, returning true if it was\n * updated and false if there was no entity with a matching ref and location key.\n *\n * Updating the entity will also cause it to be scheduled for immediate processing.\n */\nexport async function updateUnprocessedEntity(options: {\n tx: Knex.Transaction;\n entity: Entity;\n hash: string;\n locationKey?: string;\n}): Promise {\n const { tx, entity, hash, locationKey } = options;\n\n const entityRef = stringifyEntityRef(entity);\n const serializedEntity = JSON.stringify(entity);\n\n const refreshResult = await tx('refresh_state')\n .update({\n unprocessed_entity: serializedEntity,\n unprocessed_hash: hash,\n location_key: locationKey,\n last_discovery_at: tx.fn.now(),\n // We only get to this point if a processed entity actually had any changes, or\n // if an entity provider requested this mutation, meaning that we can safely\n // bump the deferred entities to the front of the queue for immediate processing.\n next_update_at: tx.fn.now(),\n })\n .where('entity_ref', entityRef)\n .andWhere(inner => {\n if (!locationKey) {\n return inner.whereNull('location_key');\n }\n return inner\n .where('location_key', locationKey)\n .orWhereNull('location_key');\n });\n\n return refreshResult === 1;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\n\nexport function generateStableHash(entity: Entity) {\n return createHash('sha1')\n .update(stableStringify({ ...entity }))\n .digest('hex');\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport const CATALOG_CONFLICTS_TOPIC = 'experimental.catalog.conflict';\n/** @public */\nexport const CATALOG_ERRORS_TOPIC = 'experimental.catalog.errors';\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { ConflictError } from '@backstage/errors';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport { ProcessingIntervalFunction } from '../processing';\nimport { rethrowError, timestampToDateTime } from './conversion';\nimport { initDatabaseMetrics } from './metrics';\nimport {\n DbRefreshKeysRow,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n} from './tables';\nimport {\n GetProcessableEntitiesResult,\n ListParentsOptions,\n ListParentsResult,\n ProcessingDatabase,\n RefreshStateItem,\n Transaction,\n UpdateEntityCacheOptions,\n UpdateProcessedEntityOptions,\n} from './types';\nimport { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict';\nimport { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity';\nimport { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity';\nimport { generateStableHash } from './util';\nimport {\n EventBroker,\n EventParams,\n EventsService,\n} from '@backstage/plugin-events-node';\nimport { DateTime } from 'luxon';\nimport { CATALOG_CONFLICTS_TOPIC } from '../constants';\nimport { CatalogConflictEventPayload } from '../catalog/types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nconst BATCH_SIZE = 50;\n\nexport class DefaultProcessingDatabase implements ProcessingDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n refreshInterval: ProcessingIntervalFunction;\n eventBroker?: EventBroker | EventsService;\n },\n ) {\n initDatabaseMetrics(options.database);\n }\n\n async updateProcessedEntity(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise<{ previous: { relations: DbRelationsRow[] } }> {\n const tx = txOpaque as Knex.Transaction;\n const {\n id,\n processedEntity,\n resultHash,\n errors,\n relations,\n deferredEntities,\n refreshKeys,\n locationKey,\n } = options;\n const configClient = tx.client.config.client;\n const refreshResult = await tx('refresh_state')\n .update({\n processed_entity: JSON.stringify(processedEntity),\n result_hash: resultHash,\n errors,\n location_key: locationKey,\n })\n .where('entity_id', id)\n .andWhere(inner => {\n if (!locationKey) {\n return inner.whereNull('location_key');\n }\n return inner\n .where('location_key', locationKey)\n .orWhereNull('location_key');\n });\n if (refreshResult === 0) {\n throw new ConflictError(\n `Conflicting write of processing result for ${id} with location key '${locationKey}'`,\n );\n }\n const sourceEntityRef = stringifyEntityRef(processedEntity);\n\n // Schedule all deferred entities for future processing.\n await this.addUnprocessedEntities(tx, {\n entities: deferredEntities,\n sourceEntityRef,\n });\n\n // Delete old relations\n // NOTE(freben): knex implemented support for returning() on update queries for sqlite, but at the current time of writing (Sep 2022) not for delete() queries.\n let previousRelationRows: DbRelationsRow[];\n if (configClient.includes('sqlite3') || configClient.includes('mysql')) {\n previousRelationRows = await tx('relations')\n .select('*')\n .where({ originating_entity_id: id });\n await tx('relations')\n .where({ originating_entity_id: id })\n .delete();\n } else {\n previousRelationRows = await tx('relations')\n .where({ originating_entity_id: id })\n .delete()\n .returning('*');\n }\n\n // Batch insert new relations\n const relationRows: DbRelationsRow[] = relations.map(\n ({ source, target, type }) => ({\n originating_entity_id: id,\n source_entity_ref: stringifyEntityRef(source),\n target_entity_ref: stringifyEntityRef(target),\n type,\n }),\n );\n\n await tx.batchInsert(\n 'relations',\n this.deduplicateRelations(relationRows),\n BATCH_SIZE,\n );\n\n // Delete old refresh keys\n await tx('refresh_keys')\n .where({ entity_id: id })\n .delete();\n\n // Insert the refresh keys for the processed entity\n await tx.batchInsert(\n 'refresh_keys',\n refreshKeys.map(k => ({\n entity_id: id,\n key: k.key,\n })),\n BATCH_SIZE,\n );\n\n return {\n previous: {\n relations: previousRelationRows,\n },\n };\n }\n\n async updateProcessedEntityErrors(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { id, errors, resultHash } = options;\n\n await tx('refresh_state')\n .update({\n errors,\n result_hash: resultHash,\n })\n .where('entity_id', id);\n }\n\n async updateEntityCache(\n txOpaque: Transaction,\n options: UpdateEntityCacheOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { id, state } = options;\n\n await tx('refresh_state')\n .update({ cache: JSON.stringify(state ?? {}) })\n .where('entity_id', id);\n }\n\n async getProcessableEntities(\n txOpaque: Transaction,\n request: { processBatchSize: number },\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n\n let itemsQuery = tx('refresh_state').select();\n\n // This avoids duplication of work because of race conditions and is\n // also fast because locked rows are ignored rather than blocking.\n // It's only available in MySQL and PostgreSQL\n if (['mysql', 'mysql2', 'pg'].includes(tx.client.config.client)) {\n itemsQuery = itemsQuery.forUpdate().skipLocked();\n }\n\n const items = await itemsQuery\n .where('next_update_at', '<=', tx.fn.now())\n .limit(request.processBatchSize)\n .orderBy('next_update_at', 'asc');\n\n const interval = this.options.refreshInterval();\n\n const nextUpdateAt = (refreshInterval: number) => {\n if (tx.client.config.client.includes('sqlite3')) {\n return tx.raw(`datetime('now', ?)`, [`${refreshInterval} seconds`]);\n }\n\n if (tx.client.config.client.includes('mysql')) {\n return tx.raw(`now() + interval ${refreshInterval} second`);\n }\n\n return tx.raw(`now() + interval '${refreshInterval} seconds'`);\n };\n\n await tx('refresh_state')\n .whereIn(\n 'entity_ref',\n items.map(i => i.entity_ref),\n )\n .update({\n next_update_at: nextUpdateAt(interval),\n });\n\n return {\n items: items.map(\n i =>\n ({\n id: i.entity_id,\n entityRef: i.entity_ref,\n unprocessedEntity: JSON.parse(i.unprocessed_entity) as Entity,\n processedEntity: i.processed_entity\n ? (JSON.parse(i.processed_entity) as Entity)\n : undefined,\n resultHash: i.result_hash || '',\n nextUpdateAt: timestampToDateTime(i.next_update_at),\n lastDiscoveryAt: timestampToDateTime(i.last_discovery_at),\n state: i.cache ? JSON.parse(i.cache) : undefined,\n errors: i.errors,\n locationKey: i.location_key,\n } as RefreshStateItem),\n ),\n };\n }\n\n async listParents(\n txOpaque: Transaction,\n options: ListParentsOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n\n const rows = await tx(\n 'refresh_state_references',\n )\n .where({ target_entity_ref: options.entityRef })\n .select();\n\n const entityRefs = rows.map(r => r.source_entity_ref!).filter(Boolean);\n\n return { entityRefs };\n }\n\n async transaction(fn: (tx: Transaction) => Promise): Promise {\n try {\n let result: T | undefined = undefined;\n\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n private deduplicateRelations(rows: DbRelationsRow[]): DbRelationsRow[] {\n return lodash.uniqBy(\n rows,\n r => `${r.source_entity_ref}:${r.target_entity_ref}:${r.type}`,\n );\n }\n\n /**\n * Add a set of deferred entities for processing.\n * The entities will be added at the front of the processing queue.\n */\n private async addUnprocessedEntities(\n txOpaque: Transaction,\n options: {\n sourceEntityRef: string;\n entities: DeferredEntity[];\n },\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n\n // Keeps track of the entities that we end up inserting to update refresh_state_references afterwards\n const stateReferences = new Array();\n\n // Upsert all of the unprocessed entities into the refresh_state table, by\n // their entity ref.\n for (const { entity, locationKey } of options.entities) {\n const entityRef = stringifyEntityRef(entity);\n const hash = generateStableHash(entity);\n\n const updated = await updateUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n });\n if (updated) {\n stateReferences.push(entityRef);\n continue;\n }\n\n const inserted = await insertUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n logger: this.options.logger,\n });\n if (inserted) {\n stateReferences.push(entityRef);\n continue;\n }\n\n // If the row can't be inserted, we have a conflict, but it could be either\n // because of a conflicting locationKey or a race with another instance, so check\n // whether the conflicting entity has the same entityRef but a different locationKey\n const conflictingKey = await checkLocationKeyConflict({\n tx,\n entityRef,\n locationKey,\n });\n if (conflictingKey) {\n this.options.logger.warn(\n `Detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`,\n );\n if (this.options.eventBroker && locationKey) {\n const eventParams: EventParams = {\n topic: CATALOG_CONFLICTS_TOPIC,\n eventPayload: {\n unprocessedEntity: entity,\n entityRef,\n newLocationKey: locationKey,\n existingLocationKey: conflictingKey,\n lastConflictAt: DateTime.now().toISO()!,\n },\n };\n await this.options.eventBroker?.publish(eventParams);\n }\n }\n }\n\n // Replace all references for the originating entity or source and then create new ones\n await tx('refresh_state_references')\n .andWhere({ source_entity_ref: options.sourceEntityRef })\n .delete();\n await tx.batchInsert(\n 'refresh_state_references',\n stateReferences.map(entityRef => ({\n source_entity_ref: options.sourceEntityRef,\n target_entity_ref: entityRef,\n })),\n BATCH_SIZE,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { Knex } from 'knex';\n\nexport async function applyDatabaseMigrations(knex: Knex): Promise {\n const migrationsDir = resolvePackagePath(\n '@backstage/plugin-catalog-backend',\n 'migrations',\n );\n\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport interface Stitcher {\n stitch(options: {\n entityRefs?: Iterable;\n entityIds?: Iterable;\n }): Promise;\n}\n\n/**\n * The strategies supported by the stitching process, in terms of when to\n * perform stitching.\n *\n * @remarks\n *\n * In immediate mode, stitching happens \"in-band\" (blocking) immediately when\n * each processing task finishes. When set to `'deferred'`, stitching is instead\n * deferred to happen on a separate asynchronous worker queue just like\n * processing.\n *\n * Deferred stitching should make performance smoother when ingesting large\n * amounts of entities, and reduce p99 processing times and repeated\n * over-stitching of hot spot entities when fan-out/fan-in in terms of relations\n * is very large. It does however also come with some performance cost due to\n * the queuing with how much wall-clock time some types of task take.\n */\nexport type StitchingStrategy =\n | {\n mode: 'immediate';\n }\n | {\n mode: 'deferred';\n pollingInterval: HumanDuration;\n stitchTimeout: HumanDuration;\n };\n\nexport function stitchingStrategyFromConfig(config: Config): StitchingStrategy {\n const strategyMode = config.getOptionalString(\n 'catalog.stitchingStrategy.mode',\n );\n\n if (strategyMode === undefined || strategyMode === 'immediate') {\n return {\n mode: 'immediate',\n };\n } else if (strategyMode === 'deferred') {\n // TODO(freben): Make parameters configurable\n return {\n mode: 'deferred',\n pollingInterval: { seconds: 1 },\n stitchTimeout: { seconds: 60 },\n };\n }\n\n throw new Error(\n `Invalid stitching strategy mode '${strategyMode}', expected one of 'immediate' or 'deferred'`,\n );\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Span, SpanOptions, SpanStatusCode, Tracer } from '@opentelemetry/api';\nimport { Entity } from '@backstage/catalog-model';\n\nexport const TRACER_ID = 'backstage-plugin-catalog-backend';\n\nfunction setAttributeIfDefined(span: Span, attribute: string, value?: string) {\n if (value !== null && value !== undefined) {\n span.setAttribute(attribute, value);\n }\n}\n\nexport function addEntityAttributes(span: Span, entity: Entity) {\n setAttributeIfDefined(span, 'backstage.entity.apiVersion', entity.apiVersion);\n setAttributeIfDefined(span, 'backstage.entity.kind', entity.kind);\n setAttributeIfDefined(\n span,\n 'backstage.entity.metadata.namespace',\n entity.metadata?.namespace,\n );\n setAttributeIfDefined(\n span,\n 'backstage.entity.metadata.name',\n entity.metadata?.name,\n );\n}\n\n// Adapted from https://github.com/open-telemetry/opentelemetry-js/blob/359fbcc40a859057a02b14e84599eac399b8dba7/api/src/trace/SugaredTracer.ts\n// While waiting for something like https://github.com/open-telemetry/opentelemetry-js/pull/3317 to land upstream\n\nconst onException = (e: Error, span: Span) => {\n span.recordException(e);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n });\n};\n\nfunction isPromiseLike(obj: PromiseLike | S): obj is PromiseLike {\n return (\n !!obj &&\n (typeof obj === 'object' || typeof obj === 'function') &&\n 'then' in obj &&\n typeof obj.then === 'function'\n );\n}\n\nfunction handleFn ReturnType>(\n span: Span,\n fn: F,\n): ReturnType {\n try {\n const ret = fn(span);\n\n // if fn is an async function attach a recordException and spanEnd callback to the promise\n if (isPromiseLike(ret)) {\n ret.then(\n () => {\n span.end();\n },\n e => {\n onException(e, span);\n span.end();\n },\n );\n } else {\n span.end();\n }\n\n return ret;\n } catch (e) {\n onException(e, span);\n span.end();\n throw e;\n }\n}\n\nexport function withActiveSpan ReturnType>(\n tracer: Tracer,\n name: string,\n fn: F,\n spanOptions: SpanOptions = {},\n): ReturnType {\n return tracer.startActiveSpan(name, spanOptions, (span: Span) => {\n return handleFn(span, fn);\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TRACER_ID, withActiveSpan } from '../util/opentelemetry';\nimport { trace } from '@opentelemetry/api';\n\nconst DEFAULT_POLLING_INTERVAL_MS = 1000;\nconst tracer = trace.getTracer(TRACER_ID);\n\ntype Options = {\n /**\n * The callback used to load in new tasks. The number of items returned\n * in the array must be at most `count` number of items, but may be lower.\n *\n * Any error thrown from this method fill be treated as an unhandled rejection.\n */\n loadTasks: (count: number) => Promise>;\n\n /**\n * The callback used to process a single item.\n *\n * Any error thrown from this method fill be treated as an unhandled rejection.\n */\n processTask: (item: T) => Promise;\n\n /**\n * The target minimum number of items to process in parallel. Once the number\n * of in-flight tasks reaches this count, more tasks will be loaded in.\n */\n lowWatermark: number;\n\n /**\n * The maximum number of items to process in parallel.\n */\n highWatermark: number;\n\n /**\n * The interval at which tasks are polled for in the background when\n * there aren't enough tasks to load to satisfy the low watermark.\n *\n * @default 1000\n */\n pollingIntervalMs?: number;\n};\n\n/**\n * Creates a task processing pipeline which continuously loads in tasks to\n * keep the number of parallel in-flight tasks between a low and high watermark.\n *\n * @param options - The options for the pipeline.\n * @returns A stop function which when called halts all processing.\n */\nexport function startTaskPipeline(options: Options) {\n const {\n loadTasks,\n processTask,\n lowWatermark,\n highWatermark,\n pollingIntervalMs = DEFAULT_POLLING_INTERVAL_MS,\n } = options;\n\n if (lowWatermark >= highWatermark) {\n throw new Error('lowWatermark must be lower than highWatermark');\n }\n\n // State is in an object so that it can be stably referenced from within\n // callbacks below\n const state = { inFlightCount: 0 };\n const abortController = new AbortController();\n const abortSignal = abortController.signal;\n\n const barrier = createBarrier({\n waitTimeoutMillis: pollingIntervalMs,\n signal: abortSignal,\n });\n\n async function pipelineLoop() {\n while (!abortSignal.aborted) {\n if (state.inFlightCount <= lowWatermark) {\n await withActiveSpan(tracer, 'TaskPipelineLoop', async span => {\n const loadCount = highWatermark - state.inFlightCount;\n const loadedItems = await Promise.resolve()\n .then(() => loadTasks(loadCount))\n .catch(() => {\n // Silently swallow errors and go back to sleep to try again; we\n // delegate to the loadTasks function itself to catch errors and log\n // if it so desires\n return [];\n });\n span.setAttribute('itemCount', loadedItems.length);\n if (loadedItems.length && !abortSignal.aborted) {\n state.inFlightCount += loadedItems.length;\n for (const item of loadedItems) {\n Promise.resolve()\n .then(() => processTask(item))\n .catch(() => {\n // Silently swallow errors and go back to sleep to try again; we\n // delegate to the processTask function itself to catch errors\n // and log if it so desires\n })\n .finally(() => {\n state.inFlightCount -= 1;\n barrier.release();\n });\n }\n }\n });\n }\n await barrier.wait();\n }\n }\n\n pipelineLoop().catch(error => {\n // This should be impossible, but if it did happen, it would signal a\n // programming error inside the loop (errors should definitely be caught\n // inside of it). Let's rethrow with more information, and let it be caught\n // by the process' uncaught exception handler, which will log the occurrence\n // at a high level.\n throw new Error(`Unexpected error in processing pipeline loop`, error);\n });\n\n return () => {\n abortController.abort();\n barrier.destroy();\n };\n}\n\n/**\n * Creates a barrier with a timeout, that can be awaited or prematurely\n * released either manually or by an abort signal.\n */\nexport function createBarrier(options: {\n waitTimeoutMillis: number;\n signal: AbortSignal;\n}): {\n wait: () => Promise;\n release: () => void;\n destroy: () => void;\n} {\n const { waitTimeoutMillis, signal } = options;\n const resolvers = new Set<() => void>();\n\n function wait() {\n if (signal.aborted || !(waitTimeoutMillis > 0)) {\n return Promise.resolve();\n }\n\n return new Promise(resolve => {\n const timeoutHandle = setTimeout(done, waitTimeoutMillis);\n\n function done() {\n resolvers.delete(done);\n clearTimeout(timeoutHandle);\n resolve();\n }\n\n resolvers.add(done);\n });\n }\n\n function release() {\n const resolversToCall = new Set(resolvers);\n resolvers.clear();\n for (const resolver of resolversToCall) {\n resolver();\n }\n }\n\n signal.addEventListener('abort', release);\n\n return {\n wait,\n release,\n destroy: () => signal.removeEventListener('abort', release),\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport splitToChunks from 'lodash/chunk';\nimport { v4 as uuid } from 'uuid';\nimport { StitchingStrategy } from '../../../stitching/types';\nimport { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables';\n\n/**\n * Marks a number of entities for stitching some time in the near\n * future.\n *\n * @remarks\n */\nexport async function markForStitching(options: {\n knex: Knex | Knex.Transaction;\n strategy: StitchingStrategy;\n entityRefs?: Iterable;\n entityIds?: Iterable;\n}): Promise {\n // Splitting to chunks just to cover pathological cases that upset the db\n const entityRefs = split(options.entityRefs);\n const entityIds = split(options.entityIds);\n const knex = options.knex;\n const mode = options.strategy.mode;\n\n if (mode === 'immediate') {\n for (const chunk of entityRefs) {\n await knex\n .table('final_entities')\n .update({\n hash: 'force-stitching',\n })\n .whereIn(\n 'entity_id',\n knex('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', chunk),\n );\n await knex\n .table('refresh_state')\n .update({\n result_hash: 'force-stitching',\n next_update_at: knex.fn.now(),\n })\n .whereIn('entity_ref', chunk);\n }\n\n for (const chunk of entityIds) {\n await knex\n .table('final_entities')\n .update({\n hash: 'force-stitching',\n })\n .whereIn('entity_id', chunk);\n await knex\n .table('refresh_state')\n .update({\n result_hash: 'force-stitching',\n next_update_at: knex.fn.now(),\n })\n .whereIn('entity_id', chunk);\n }\n } else if (mode === 'deferred') {\n // It's OK that this is shared across refresh state rows; it just needs to\n // be uniquely generated for every new stitch request.\n const ticket = uuid();\n\n for (const chunk of entityRefs) {\n await knex('refresh_state')\n .update({\n next_stitch_at: knex.fn.now(),\n next_stitch_ticket: ticket,\n })\n .whereIn('entity_ref', chunk);\n }\n\n for (const chunk of entityIds) {\n await knex('refresh_state')\n .update({\n next_stitch_at: knex.fn.now(),\n next_stitch_ticket: ticket,\n })\n .whereIn('entity_id', chunk);\n }\n } else {\n throw new Error(`Unknown stitching strategy mode ${mode}`);\n }\n}\n\nfunction split(input: Iterable | undefined): string[][] {\n if (!input) {\n return [];\n }\n return splitToChunks(Array.isArray(input) ? input : [...input], 200);\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport uniq from 'lodash/uniq';\nimport { StitchingStrategy } from '../../../stitching/types';\nimport { DbRefreshStateRow } from '../../tables';\nimport { markForStitching } from '../stitcher/markForStitching';\n\n/**\n * Finds and deletes all orphaned entities, i.e. entities that do not have any\n * incoming references to them, and also eagerly deletes all of their children\n * that would otherwise become orphaned.\n */\nexport async function deleteOrphanedEntities(options: {\n knex: Knex.Transaction | Knex;\n strategy: StitchingStrategy;\n}): Promise {\n const { knex, strategy } = options;\n\n let total = 0;\n\n // Limit iterations for sanity\n for (let i = 0; i < 100; ++i) {\n const candidates = await knex\n .with('orphans', ['entity_id', 'entity_ref'], orphans =>\n orphans\n .from('refresh_state')\n .select('refresh_state.entity_id', 'refresh_state.entity_ref')\n .leftOuterJoin(\n 'refresh_state_references',\n 'refresh_state_references.target_entity_ref',\n 'refresh_state.entity_ref',\n )\n .whereNull('refresh_state_references.target_entity_ref'),\n )\n .select({\n entityId: 'orphans.entity_id',\n relationSourceId: 'refresh_state.entity_id',\n })\n .from('orphans')\n .leftOuterJoin(\n 'relations',\n 'relations.target_entity_ref',\n 'orphans.entity_ref',\n )\n .leftOuterJoin(\n 'refresh_state',\n 'refresh_state.entity_ref',\n 'relations.source_entity_ref',\n );\n\n if (!candidates.length) {\n break;\n }\n\n const orphanIds: string[] = uniq(candidates.map(r => r.entityId));\n const orphanRelationIds: string[] = uniq(\n candidates.map(r => r.relationSourceId).filter(Boolean),\n );\n\n total += orphanIds.length;\n\n // Delete the orphans themselves\n await knex\n .table('refresh_state')\n .delete()\n .whereIn('entity_id', orphanIds);\n\n // Mark all of the things that the orphans had relations to for stitching\n await markForStitching({\n knex,\n strategy,\n entityIds: orphanRelationIds,\n });\n }\n\n return total;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_LOCATION,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { assertError, serializeError, stringifyError } from '@backstage/errors';\nimport { Hash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\nimport { Knex } from 'knex';\nimport { metrics, trace } from '@opentelemetry/api';\nimport { ProcessingDatabase, RefreshStateItem } from '../database/types';\nimport { createCounterMetric, createSummaryMetric } from '../util/metrics';\nimport { CatalogProcessingOrchestrator, EntityProcessingResult } from './types';\nimport { Stitcher, stitchingStrategyFromConfig } from '../stitching/types';\nimport { startTaskPipeline } from './TaskPipeline';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\nimport {\n addEntityAttributes,\n TRACER_ID,\n withActiveSpan,\n} from '../util/opentelemetry';\nimport { deleteOrphanedEntities } from '../database/operations/util/deleteOrphanedEntities';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { CATALOG_ERRORS_TOPIC } from '../constants';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst CACHE_TTL = 5;\n\nconst tracer = trace.getTracer(TRACER_ID);\n\nexport type ProgressTracker = ReturnType;\n\n// NOTE(freben): Perhaps surprisingly, this class does not implement the\n// CatalogProcessingEngine type. That type is externally visible and its name is\n// the way it is for historic reasons. This class has no particular reason to\n// implement that precise interface; nowadays there are several different\n// engines \"hiding\" behind the CatalogProcessingEngine interface, of which this\n// is just one.\nexport class DefaultCatalogProcessingEngine {\n private readonly config: Config;\n private readonly scheduler?: PluginTaskScheduler;\n private readonly logger: LoggerService;\n private readonly knex: Knex;\n private readonly processingDatabase: ProcessingDatabase;\n private readonly orchestrator: CatalogProcessingOrchestrator;\n private readonly stitcher: Stitcher;\n private readonly createHash: () => Hash;\n private readonly pollingIntervalMs: number;\n private readonly orphanCleanupIntervalMs: number;\n private readonly onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n private readonly tracker: ProgressTracker;\n private readonly eventBroker?: EventBroker | EventsService;\n\n private stopFunc?: () => void;\n\n constructor(options: {\n config: Config;\n scheduler?: PluginTaskScheduler;\n logger: LoggerService;\n knex: Knex;\n processingDatabase: ProcessingDatabase;\n orchestrator: CatalogProcessingOrchestrator;\n stitcher: Stitcher;\n createHash: () => Hash;\n pollingIntervalMs?: number;\n orphanCleanupIntervalMs?: number;\n onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n tracker?: ProgressTracker;\n eventBroker?: EventBroker | EventsService;\n }) {\n this.config = options.config;\n this.scheduler = options.scheduler;\n this.logger = options.logger;\n this.knex = options.knex;\n this.processingDatabase = options.processingDatabase;\n this.orchestrator = options.orchestrator;\n this.stitcher = options.stitcher;\n this.createHash = options.createHash;\n this.pollingIntervalMs = options.pollingIntervalMs ?? 1_000;\n this.orphanCleanupIntervalMs = options.orphanCleanupIntervalMs ?? 30_000;\n this.onProcessingError = options.onProcessingError;\n this.tracker = options.tracker ?? progressTracker();\n this.eventBroker = options.eventBroker;\n\n this.stopFunc = undefined;\n }\n\n async start() {\n if (this.stopFunc) {\n throw new Error('Processing engine is already started');\n }\n\n const stopPipeline = this.startPipeline();\n const stopCleanup = this.startOrphanCleanup();\n\n this.stopFunc = () => {\n stopPipeline();\n stopCleanup();\n };\n }\n\n async stop() {\n if (this.stopFunc) {\n this.stopFunc();\n this.stopFunc = undefined;\n }\n }\n\n private startPipeline(): () => void {\n return startTaskPipeline({\n lowWatermark: 5,\n highWatermark: 10,\n pollingIntervalMs: this.pollingIntervalMs,\n loadTasks: async count => {\n try {\n const { items } = await this.processingDatabase.transaction(\n async tx => {\n return this.processingDatabase.getProcessableEntities(tx, {\n processBatchSize: count,\n });\n },\n );\n return items;\n } catch (error) {\n this.logger.warn('Failed to load processing items', error);\n return [];\n }\n },\n processTask: async item => {\n await withActiveSpan(tracer, 'ProcessingRun', async span => {\n const track = this.tracker.processStart(item, this.logger);\n addEntityAttributes(span, item.unprocessedEntity);\n\n try {\n const {\n id,\n state,\n unprocessedEntity,\n entityRef,\n locationKey,\n resultHash: previousResultHash,\n } = item;\n const result = await this.orchestrator.process({\n entity: unprocessedEntity,\n state,\n });\n\n track.markProcessorsCompleted(result);\n\n if (result.ok) {\n const { ttl: _, ...stateWithoutTtl } = state ?? {};\n if (\n stableStringify(stateWithoutTtl) !==\n stableStringify(result.state)\n ) {\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: {\n ttl: CACHE_TTL,\n ...result.state,\n },\n });\n });\n }\n } else {\n const maybeTtl = state?.ttl;\n const ttl = Number.isInteger(maybeTtl) ? (maybeTtl as number) : 0;\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: ttl > 0 ? { ...state, ttl: ttl - 1 } : {},\n });\n });\n }\n\n const location =\n unprocessedEntity?.metadata?.annotations?.[ANNOTATION_LOCATION];\n if (result.errors.length) {\n this.eventBroker?.publish({\n topic: CATALOG_ERRORS_TOPIC,\n eventPayload: {\n entity: entityRef,\n location,\n errors: result.errors,\n },\n });\n }\n const errorsString = JSON.stringify(\n result.errors.map(e => serializeError(e)),\n );\n\n let hashBuilder = this.createHash().update(errorsString);\n\n if (result.ok) {\n const { entityRefs: parents } =\n await this.processingDatabase.transaction(tx =>\n this.processingDatabase.listParents(tx, {\n entityRef,\n }),\n );\n\n hashBuilder = hashBuilder\n .update(stableStringify({ ...result.completedEntity }))\n .update(stableStringify([...result.deferredEntities]))\n .update(stableStringify([...result.relations]))\n .update(stableStringify([...result.refreshKeys]))\n .update(stableStringify([...parents]));\n }\n\n const resultHash = hashBuilder.digest('hex');\n if (resultHash === previousResultHash) {\n // If nothing changed in our produced outputs, we cannot have any\n // significant effect on our surroundings; therefore, we just abort\n // without any updates / stitching.\n track.markSuccessfulWithNoChanges();\n return;\n }\n\n // If the result was marked as not OK, it signals that some part of the\n // processing pipeline threw an exception. This can happen both as part of\n // non-catastrophic things such as due to validation errors, as well as if\n // something fatal happens inside the processing for other reasons. In any\n // case, this means we can't trust that anything in the output is okay. So\n // just store the errors and trigger a stich so that they become visible to\n // the outside.\n if (!result.ok) {\n // notify the error listener if the entity can not be processed.\n Promise.resolve(undefined)\n .then(() =>\n this.onProcessingError?.({\n unprocessedEntity,\n errors: result.errors,\n }),\n )\n .catch(error => {\n this.logger.debug(\n `Processing error listener threw an exception, ${stringifyError(\n error,\n )}`,\n );\n });\n\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateProcessedEntityErrors(tx, {\n id,\n errors: errorsString,\n resultHash,\n });\n });\n\n await this.stitcher.stitch({\n entityRefs: [stringifyEntityRef(unprocessedEntity)],\n });\n\n track.markSuccessfulWithErrors();\n return;\n }\n\n result.completedEntity.metadata.uid = id;\n let oldRelationSources: Map;\n await this.processingDatabase.transaction(async tx => {\n const { previous } =\n await this.processingDatabase.updateProcessedEntity(tx, {\n id,\n processedEntity: result.completedEntity,\n resultHash,\n errors: errorsString,\n relations: result.relations,\n deferredEntities: result.deferredEntities,\n locationKey,\n refreshKeys: result.refreshKeys,\n });\n oldRelationSources = new Map(\n previous.relations.map(r => [\n `${r.source_entity_ref}:${r.type}`,\n r.source_entity_ref,\n ]),\n );\n });\n\n const newRelationSources = new Map(\n result.relations.map(relation => {\n const sourceEntityRef = stringifyEntityRef(relation.source);\n return [`${sourceEntityRef}:${relation.type}`, sourceEntityRef];\n }),\n );\n\n const setOfThingsToStitch = new Set([\n stringifyEntityRef(result.completedEntity),\n ]);\n newRelationSources.forEach((sourceEntityRef, uniqueKey) => {\n if (!oldRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n oldRelationSources!.forEach((sourceEntityRef, uniqueKey) => {\n if (!newRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n\n await this.stitcher.stitch({\n entityRefs: setOfThingsToStitch,\n });\n\n track.markSuccessfulWithChanges();\n } catch (error) {\n assertError(error);\n track.markFailed(error);\n }\n });\n },\n });\n }\n\n private startOrphanCleanup(): () => void {\n const orphanStrategy =\n this.config.getOptionalString('catalog.orphanStrategy') ?? 'keep';\n if (orphanStrategy !== 'delete') {\n return () => {};\n }\n\n const stitchingStrategy = stitchingStrategyFromConfig(this.config);\n\n const runOnce = async () => {\n try {\n const n = await deleteOrphanedEntities({\n knex: this.knex,\n strategy: stitchingStrategy,\n });\n if (n > 0) {\n this.logger.info(`Deleted ${n} orphaned entities`);\n }\n } catch (error) {\n this.logger.warn(`Failed to delete orphaned entities`, error);\n }\n };\n\n if (this.scheduler) {\n const abortController = new AbortController();\n\n this.scheduler.scheduleTask({\n id: 'catalog_orphan_cleanup',\n frequency: { milliseconds: this.orphanCleanupIntervalMs },\n timeout: { milliseconds: this.orphanCleanupIntervalMs * 0.8 },\n fn: runOnce,\n signal: abortController.signal,\n });\n\n return () => {\n abortController.abort();\n };\n }\n\n const intervalKey = setInterval(runOnce, this.orphanCleanupIntervalMs);\n return () => {\n clearInterval(intervalKey);\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction progressTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promProcessedEntities = createCounterMetric({\n name: 'catalog_processed_entities_count',\n help: 'Amount of entities processed, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingDuration = createSummaryMetric({\n name: 'catalog_processing_duration_seconds',\n help: 'Time spent executing the full processing flow, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessorsDuration = createSummaryMetric({\n name: 'catalog_processors_duration_seconds',\n help: 'Time spent executing catalog processors, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingQueueDelay = createSummaryMetric({\n name: 'catalog_processing_queue_delay_seconds',\n help: 'The amount of delay between being scheduled for processing, and the start of actually being processed, DEPRECATED, use OpenTelemetry metrics instead',\n });\n\n const meter = metrics.getMeter('default');\n const processedEntities = meter.createCounter(\n 'catalog.processed.entities.count',\n { description: 'Amount of entities processed' },\n );\n\n const processingDuration = meter.createHistogram(\n 'catalog.processing.duration',\n {\n description: 'Time spent executing the full processing flow',\n unit: 'seconds',\n },\n );\n\n const processorsDuration = meter.createHistogram(\n 'catalog.processors.duration',\n {\n description: 'Time spent executing catalog processors',\n unit: 'seconds',\n },\n );\n\n const processingQueueDelay = meter.createHistogram(\n 'catalog.processing.queue.delay',\n {\n description:\n 'The amount of delay between being scheduled for processing, and the start of actually being processed',\n unit: 'seconds',\n },\n );\n\n function processStart(item: RefreshStateItem, logger: LoggerService) {\n const startTime = process.hrtime();\n const endOverallTimer = promProcessingDuration.startTimer();\n const endProcessorsTimer = promProcessorsDuration.startTimer();\n\n logger.debug(`Processing ${item.entityRef}`);\n\n if (item.nextUpdateAt) {\n const seconds = -item.nextUpdateAt.diffNow().as('seconds');\n promProcessingQueueDelay.observe(seconds);\n processingQueueDelay.record(seconds);\n }\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n function markProcessorsCompleted(result: EntityProcessingResult) {\n endProcessorsTimer({ result: result.ok ? 'ok' : 'failed' });\n processorsDuration.record(endTime(), {\n result: result.ok ? 'ok' : 'failed',\n });\n }\n\n function markSuccessfulWithNoChanges() {\n endOverallTimer({ result: 'unchanged' });\n promProcessedEntities.inc({ result: 'unchanged' }, 1);\n\n processingDuration.record(endTime(), { result: 'unchanged' });\n processedEntities.add(1, { result: 'unchanged' });\n }\n\n function markSuccessfulWithErrors() {\n endOverallTimer({ result: 'errors' });\n promProcessedEntities.inc({ result: 'errors' }, 1);\n\n processingDuration.record(endTime(), { result: 'errors' });\n processedEntities.add(1, { result: 'errors' });\n }\n\n function markSuccessfulWithChanges() {\n endOverallTimer({ result: 'changed' });\n promProcessedEntities.inc({ result: 'changed' }, 1);\n\n processingDuration.record(endTime(), { result: 'changed' });\n processedEntities.add(1, { result: 'changed' });\n }\n\n function markFailed(error: Error) {\n promProcessedEntities.inc({ result: 'failed' }, 1);\n processedEntities.add(1, { result: 'failed' });\n logger.warn(`Processing of ${item.entityRef} failed`, error);\n }\n\n return {\n markProcessorsCompleted,\n markSuccessfulWithNoChanges,\n markSuccessfulWithErrors,\n markSuccessfulWithChanges,\n markFailed,\n };\n }\n\n return { processStart };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n stringifyEntityRef,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\nimport { Location } from '@backstage/catalog-client';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { LocationInput, LocationService, LocationStore } from './types';\nimport { locationSpecToMetadataName } from '../util/conversion';\nimport { InputError } from '@backstage/errors';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\n\nexport type DefaultLocationServiceOptions = {\n allowedLocationTypes: string[];\n};\n\nexport class DefaultLocationService implements LocationService {\n constructor(\n private readonly store: LocationStore,\n private readonly orchestrator: CatalogProcessingOrchestrator,\n private readonly options: DefaultLocationServiceOptions = {\n allowedLocationTypes: ['url'],\n },\n ) {}\n\n async createLocation(\n input: LocationInput,\n dryRun: boolean,\n ): Promise<{ location: Location; entities: Entity[]; exists?: boolean }> {\n if (!this.options.allowedLocationTypes.includes(input.type)) {\n throw new InputError(\n `Registered locations must be of an allowed type ${JSON.stringify(\n this.options.allowedLocationTypes,\n )}`,\n );\n }\n if (dryRun) {\n return this.dryRunCreateLocation(input);\n }\n const location = await this.store.createLocation(input);\n return { location, entities: [] };\n }\n\n listLocations(): Promise {\n return this.store.listLocations();\n }\n getLocation(id: string): Promise {\n return this.store.getLocation(id);\n }\n deleteLocation(id: string): Promise {\n return this.store.deleteLocation(id);\n }\n\n getLocationByEntity(\n entityRef: CompoundEntityRef | string,\n ): Promise {\n return this.store.getLocationByEntity(parseEntityRef(entityRef));\n }\n\n private async processEntities(\n unprocessedEntities: DeferredEntity[],\n ): Promise {\n const entities: Entity[] = [];\n while (unprocessedEntities.length) {\n const currentEntity = unprocessedEntities.pop();\n if (!currentEntity) {\n continue;\n }\n const processed = await this.orchestrator.process({\n entity: currentEntity.entity,\n state: {}, // we process without the existing cache\n });\n\n if (processed.ok) {\n if (\n entities.some(\n e =>\n stringifyEntityRef(e) ===\n stringifyEntityRef(processed.completedEntity),\n )\n ) {\n throw new InputError(\n `Duplicate nested entity: ${stringifyEntityRef(\n processed.completedEntity,\n )}`,\n );\n }\n unprocessedEntities.push(...processed.deferredEntities);\n entities.push(processed.completedEntity);\n } else {\n throw new InputError(processed.errors.map(String).join(', '));\n }\n }\n return entities;\n }\n\n private async dryRunCreateLocation(\n spec: LocationInput,\n ): Promise<{ location: Location; entities: Entity[]; exists?: boolean }> {\n // Run the existence check in parallel with the processing\n const existsPromise = this.store\n .listLocations()\n .then(locations =>\n locations.some(l => l.type === spec.type && l.target === spec.target),\n );\n\n const entity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Location',\n metadata: {\n name: locationSpecToMetadataName({\n type: spec.type,\n target: spec.target,\n }),\n namespace: 'default',\n annotations: {\n [ANNOTATION_LOCATION]: `${spec.type}:${spec.target}`,\n [ANNOTATION_ORIGIN_LOCATION]: `${spec.type}:${spec.target}`,\n },\n },\n spec: {\n type: spec.type,\n target: spec.target,\n },\n };\n const unprocessedEntities: DeferredEntity[] = [\n { entity, locationKey: `${spec.type}:${spec.target}` },\n ];\n const entities: Entity[] = await this.processEntities(unprocessedEntities);\n\n return {\n exists: await existsPromise,\n location: { ...spec, id: `${spec.type}:${spec.target}` },\n entities,\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError, NotAllowedError } from '@backstage/errors';\nimport { Request } from 'express';\nimport lodash from 'lodash';\nimport { z } from 'zod';\nimport {\n Cursor,\n QueryEntitiesCursorRequest,\n QueryEntitiesInitialRequest,\n QueryEntitiesRequest,\n} from '../catalog/types';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\n\nexport async function requireRequestBody(req: Request): Promise {\n const contentType = req.header('content-type');\n if (!contentType) {\n throw new InputError('Content-Type missing');\n } else if (!contentType.match(/^application\\/json($|;)/)) {\n throw new InputError('Illegal Content-Type');\n }\n\n const body = req.body;\n if (!body) {\n throw new InputError('Missing request body');\n } else if (!lodash.isPlainObject(body)) {\n throw new InputError('Expected body to be a JSON object');\n } else if (Object.keys(body).length === 0) {\n // Because of how express.json() translates the empty body to {}\n throw new InputError('Empty request body');\n }\n\n return body;\n}\n\nexport const locationInput = z\n .object({\n type: z.string(),\n target: z.string(),\n presence: z.literal('required').or(z.literal('optional')).optional(),\n })\n .strict(); // no unknown keys;\n\nexport async function validateRequestBody(\n req: Request,\n schema: z.Schema,\n): Promise {\n const body = await requireRequestBody(req);\n try {\n return await schema.parse(body);\n } catch (e) {\n throw new InputError(`Malformed request: ${e}`);\n }\n}\n\nexport function disallowReadonlyMode(readonly: boolean) {\n if (readonly) {\n throw new NotAllowedError('This operation not allowed in readonly mode');\n }\n}\n\nexport function isQueryEntitiesInitialRequest(\n input: QueryEntitiesRequest | undefined,\n): input is QueryEntitiesInitialRequest {\n if (!input) {\n return false;\n }\n return !isQueryEntitiesCursorRequest(input);\n}\n\nexport function isQueryEntitiesCursorRequest(\n input: QueryEntitiesRequest | undefined,\n): input is QueryEntitiesCursorRequest {\n if (!input) {\n return false;\n }\n return !!(input as QueryEntitiesCursorRequest).cursor;\n}\n\nconst entityFilterParser: z.ZodSchema = z.lazy(() =>\n z\n .object({\n key: z.string(),\n values: z.array(z.string()).optional(),\n })\n .or(z.object({ not: entityFilterParser }))\n .or(z.object({ anyOf: z.array(entityFilterParser) }))\n .or(z.object({ allOf: z.array(entityFilterParser) })),\n);\n\nexport const cursorParser: z.ZodSchema = z.object({\n orderFields: z.array(\n z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),\n ),\n fullTextFilter: z\n .object({\n term: z.string(),\n fields: z.array(z.string()).optional(),\n })\n .optional(),\n orderFieldValues: z.array(z.string().or(z.null())),\n filter: entityFilterParser.optional(),\n isPrevious: z.boolean(),\n query: z.string().optional(),\n firstSortFieldValues: z.array(z.string().or(z.null())).optional(),\n totalItems: z.number().optional(),\n});\n\nexport function encodeCursor(cursor: Cursor) {\n const json = JSON.stringify(cursor);\n return Buffer.from(json, 'utf8').toString('base64');\n}\n\nexport function decodeCursor(encodedCursor: string) {\n try {\n const data = Buffer.from(encodedCursor, 'base64').toString('utf8');\n const result = cursorParser.safeParse(JSON.parse(data));\n\n if (!result.success) {\n throw new InputError(`Malformed cursor: ${result.error}`);\n }\n return result.data;\n } catch (e) {\n throw new InputError(`Malformed cursor: ${e}`);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { chunk as lodashChunk, isEqual } from 'lodash';\nimport { z } from 'zod';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n EntityOrder,\n EntityPagination,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport {\n DbFinalEntitiesRow,\n DbPageInfo,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n DbSearchRow,\n} from '../database/tables';\nimport { Stitcher } from '../stitching/types';\n\nimport {\n isQueryEntitiesCursorRequest,\n isQueryEntitiesInitialRequest,\n} from './util';\nimport {\n EntitiesSearchFilter,\n EntityFilter,\n} from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst defaultSortField: EntityOrder = {\n field: 'metadata.uid',\n order: 'asc',\n};\n\nconst DEFAULT_LIMIT = 20;\n\nfunction parsePagination(input?: EntityPagination): EntityPagination {\n if (!input) {\n return {};\n }\n\n let { limit, offset } = input;\n\n if (input.after === undefined) {\n return { limit, offset };\n }\n\n let cursor;\n try {\n const json = Buffer.from(input.after, 'base64').toString('utf8');\n cursor = JSON.parse(json);\n } catch {\n throw new InputError('Malformed after cursor, could not be parsed');\n }\n\n if (cursor.limit !== undefined) {\n if (!Number.isInteger(cursor.limit)) {\n throw new InputError('Malformed after cursor, limit was not an number');\n }\n limit = cursor.limit;\n }\n\n if (cursor.offset !== undefined) {\n if (!Number.isInteger(cursor.offset)) {\n throw new InputError('Malformed after cursor, offset was not a number');\n }\n offset = cursor.offset;\n }\n\n return { limit, offset };\n}\n\nfunction stringifyPagination(\n input: Required>,\n): string {\n const { limit, offset } = input;\n const json = JSON.stringify({ limit, offset });\n const base64 = Buffer.from(json, 'utf8').toString('base64');\n return base64;\n}\n\nfunction addCondition(\n queryBuilder: Knex.QueryBuilder,\n db: Knex,\n filter: EntitiesSearchFilter,\n negate: boolean = false,\n entityIdField = 'entity_id',\n): void {\n const key = filter.key.toLowerCase();\n const values = filter.values?.map(v => v.toLowerCase());\n\n // NOTE(freben): This used to be a set of OUTER JOIN, which may seem to\n // make a lot of sense. However, it had abysmal performance on sqlite\n // when datasets grew large, so we're using IN instead.\n const matchQuery = db('search')\n .select('search.entity_id')\n .where({ key })\n .andWhere(function keyFilter() {\n if (values?.length === 1) {\n this.where({ value: values.at(0) });\n } else if (values) {\n this.andWhere('value', 'in', values);\n }\n });\n queryBuilder.andWhere(entityIdField, negate ? 'not in' : 'in', matchQuery);\n}\n\nfunction isEntitiesSearchFilter(\n filter: EntitiesSearchFilter | EntityFilter,\n): filter is EntitiesSearchFilter {\n return filter.hasOwnProperty('key');\n}\n\nfunction isOrEntityFilter(\n filter: { anyOf: EntityFilter[] } | EntityFilter,\n): filter is { anyOf: EntityFilter[] } {\n return filter.hasOwnProperty('anyOf');\n}\n\nfunction isNegationEntityFilter(\n filter: { not: EntityFilter } | EntityFilter,\n): filter is { not: EntityFilter } {\n return filter.hasOwnProperty('not');\n}\n\nfunction parseFilter(\n filter: EntityFilter,\n query: Knex.QueryBuilder,\n db: Knex,\n negate: boolean = false,\n entityIdField = 'entity_id',\n): Knex.QueryBuilder {\n if (isNegationEntityFilter(filter)) {\n return parseFilter(filter.not, query, db, !negate, entityIdField);\n }\n\n if (isEntitiesSearchFilter(filter)) {\n return query.andWhere(function filterFunction() {\n addCondition(this, db, filter, negate, entityIdField);\n });\n }\n\n return query[negate ? 'andWhereNot' : 'andWhere'](function filterFunction() {\n if (isOrEntityFilter(filter)) {\n for (const subFilter of filter.anyOf ?? []) {\n this.orWhere(subQuery =>\n parseFilter(subFilter, subQuery, db, false, entityIdField),\n );\n }\n } else {\n for (const subFilter of filter.allOf ?? []) {\n this.andWhere(subQuery =>\n parseFilter(subFilter, subQuery, db, false, entityIdField),\n );\n }\n }\n });\n}\n\nexport class DefaultEntitiesCatalog implements EntitiesCatalog {\n private readonly database: Knex;\n private readonly logger: LoggerService;\n private readonly stitcher: Stitcher;\n\n constructor(options: {\n database: Knex;\n logger: LoggerService;\n stitcher: Stitcher;\n }) {\n this.database = options.database;\n this.logger = options.logger;\n this.stitcher = options.stitcher;\n }\n\n async entities(request?: EntitiesRequest): Promise {\n const db = this.database;\n\n let entitiesQuery =\n db('final_entities').select('final_entities.*');\n\n request?.order?.forEach(({ field }, index) => {\n const alias = `order_${index}`;\n entitiesQuery = entitiesQuery.leftOuterJoin(\n { [alias]: 'search' },\n function search(inner) {\n inner\n .on(`${alias}.entity_id`, 'final_entities.entity_id')\n .andOn(`${alias}.key`, db.raw('?', [field]));\n },\n );\n });\n\n entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity');\n\n if (request?.filter) {\n entitiesQuery = parseFilter(\n request.filter,\n entitiesQuery,\n db,\n false,\n 'final_entities.entity_id',\n );\n }\n\n request?.order?.forEach(({ order }, index) => {\n if (db.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order, nulls: 'last' },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value \" while avoiding to give an order\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order: undefined, nulls: 'last' },\n { column: `order_${index}.value`, order },\n ]);\n }\n });\n entitiesQuery = entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort\n\n const { limit, offset } = parsePagination(request?.pagination);\n if (limit !== undefined) {\n entitiesQuery = entitiesQuery.limit(limit + 1);\n }\n if (offset !== undefined) {\n entitiesQuery = entitiesQuery.offset(offset);\n }\n\n let rows = await entitiesQuery;\n let pageInfo: DbPageInfo;\n if (limit === undefined || rows.length <= limit) {\n pageInfo = { hasNextPage: false };\n } else {\n rows = rows.slice(0, -1);\n pageInfo = {\n hasNextPage: true,\n endCursor: stringifyPagination({\n limit,\n offset: (offset ?? 0) + limit,\n }),\n };\n }\n\n let entities: Entity[] = rows.map(e => JSON.parse(e.final_entity!));\n\n if (request?.fields) {\n entities = entities.map(e => request.fields!(e));\n }\n\n // TODO(freben): This is added as a compatibility guarantee, until we can be\n // sure that all adopters have re-stitched their entities so that the new\n // targetRef field is present on them, and that they have stopped consuming\n // the now-removed old field\n // TODO(jhaals): Remove this in April 2022\n for (const entity of entities) {\n if (entity.relations) {\n for (const relation of entity.relations as any) {\n if (!relation.targetRef && relation.target) {\n // This is the case where an old-form entity, not yet stitched with\n // the updated code, was in the database\n relation.targetRef = stringifyEntityRef(relation.target);\n } else if (!relation.target && relation.targetRef) {\n // This is the case where a new-form entity, stitched with the\n // updated code, was in the database but we still want to produce\n // the old data shape as well for compatibility reasons\n relation.target = parseEntityRef(relation.targetRef);\n }\n }\n }\n }\n\n return {\n entities,\n pageInfo,\n };\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise {\n const lookup = new Map();\n\n for (const chunk of lodashChunk(request.entityRefs, 200)) {\n let query = this.database('final_entities')\n .innerJoin(\n 'refresh_state',\n 'refresh_state.entity_id',\n 'final_entities.entity_id',\n )\n .select({\n entityRef: 'refresh_state.entity_ref',\n entity: 'final_entities.final_entity',\n })\n .whereIn('refresh_state.entity_ref', chunk);\n\n if (request?.filter) {\n query = parseFilter(\n request.filter,\n query,\n this.database,\n false,\n 'refresh_state.entity_id',\n );\n }\n\n for (const row of await query) {\n lookup.set(row.entityRef, row.entity ? JSON.parse(row.entity) : null);\n }\n }\n\n let items = request.entityRefs.map(ref => lookup.get(ref) ?? null);\n\n if (request.fields) {\n items = items.map(e => e && request.fields!(e));\n }\n\n return { items };\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise {\n const db = this.database;\n\n const limit = request.limit ?? DEFAULT_LIMIT;\n\n const cursor: Omit & {\n orderFieldValues?: (string | null)[];\n } = {\n orderFields: [defaultSortField],\n isPrevious: false,\n ...parseCursorFromRequest(request),\n };\n\n const isFetchingBackwards = cursor.isPrevious;\n\n if (cursor.orderFields.length > 1) {\n this.logger.warn(`Only one sort field is supported, ignoring the rest`);\n }\n\n const sortField: EntityOrder = {\n ...defaultSortField,\n ...cursor.orderFields[0],\n };\n\n const [prevItemOrderFieldValue, prevItemUid] =\n cursor.orderFieldValues || [];\n\n const dbQuery = db('search')\n .join('final_entities', 'search.entity_id', 'final_entities.entity_id')\n .where('search.key', sortField.field);\n\n if (cursor.filter) {\n parseFilter(cursor.filter, dbQuery, db, false, 'search.entity_id');\n }\n\n const normalizedFullTextFilterTerm = cursor.fullTextFilter?.term?.trim();\n const textFilterFields = cursor.fullTextFilter?.fields ?? [sortField.field];\n if (normalizedFullTextFilterTerm) {\n if (\n textFilterFields.length === 1 &&\n textFilterFields[0] === sortField.field\n ) {\n // If there is one item, apply the like query to the top level query which is already\n // filtered based on the singular sortField.\n dbQuery.andWhereRaw(\n 'value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n } else {\n const matchQuery = db('search')\n .select('search.entity_id')\n .whereIn('key', textFilterFields)\n .andWhere(function keyFilter() {\n this.andWhereRaw(\n 'value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n });\n dbQuery.andWhere('search.entity_id', 'in', matchQuery);\n }\n }\n\n const countQuery = dbQuery.clone();\n\n const isOrderingDescending = sortField.order === 'desc';\n\n if (prevItemOrderFieldValue) {\n dbQuery.andWhere(function nested() {\n this.where(\n 'value',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n prevItemOrderFieldValue,\n )\n .orWhere('value', '=', prevItemOrderFieldValue)\n .andWhere(\n 'search.entity_id',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n prevItemUid,\n );\n });\n }\n\n dbQuery\n .orderBy([\n {\n column: 'value',\n order: isFetchingBackwards\n ? invertOrder(sortField.order)\n : sortField.order,\n },\n {\n column: 'search.entity_id',\n order: isFetchingBackwards\n ? invertOrder(sortField.order)\n : sortField.order,\n },\n ])\n // fetch an extra item to check if there are more items.\n .limit(isFetchingBackwards ? limit : limit + 1);\n\n countQuery.count('search.entity_id', { as: 'count' });\n\n const [rows, [{ count }]] = await Promise.all([\n limit > 0 ? dbQuery : [],\n // for performance reasons we invoke the countQuery\n // only on the first request.\n // The result is then embedded into the cursor\n // for subsequent requests.\n typeof cursor.totalItems === 'undefined'\n ? countQuery\n : [{ count: cursor.totalItems }],\n ]);\n\n const totalItems = Number(count);\n\n if (isFetchingBackwards) {\n rows.reverse();\n }\n const hasMoreResults =\n limit > 0 && (isFetchingBackwards || rows.length > limit);\n\n // discard the extra item only when fetching forward.\n if (rows.length > limit) {\n rows.length -= 1;\n }\n\n const isInitialRequest = cursor.firstSortFieldValues === undefined;\n\n const firstRow = rows[0];\n const lastRow = rows[rows.length - 1];\n\n const firstSortFieldValues = cursor.firstSortFieldValues || [\n firstRow?.value,\n firstRow?.entity_id,\n ];\n\n const nextCursor: Cursor | undefined = hasMoreResults\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(lastRow),\n firstSortFieldValues,\n isPrevious: false,\n totalItems,\n }\n : undefined;\n\n const prevCursor: Cursor | undefined =\n !isInitialRequest &&\n rows.length > 0 &&\n !isEqual(sortFieldsFromRow(firstRow), cursor.firstSortFieldValues)\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(firstRow),\n firstSortFieldValues: cursor.firstSortFieldValues,\n isPrevious: true,\n totalItems,\n }\n : undefined;\n\n const items = rows\n .map(e => JSON.parse(e.final_entity!))\n .map(e => (request.fields ? request.fields(e) : e));\n\n return {\n items,\n pageInfo: {\n ...(!!prevCursor && { prevCursor }),\n ...(!!nextCursor && { nextCursor }),\n },\n totalItems,\n };\n }\n\n async removeEntityByUid(uid: string): Promise {\n const dbConfig = this.database.client.config;\n\n // Clear the hashed state of the immediate parents of the deleted entity.\n // This makes sure that when they get reprocessed, their output is written\n // down again. The reason for wanting to do this, is that if the user\n // deletes entities that ARE still emitted by the parent, the parent\n // processing will still generate the same output hash as always, which\n // means it'll never try to write down the children again (it assumes that\n // they already exist). This means that without the code below, the database\n // never \"heals\" from accidental deletes.\n if (dbConfig.client.includes('mysql')) {\n // MySQL doesn't support the syntax we need to do this in a single query,\n // http://dev.mysql.com/doc/refman/5.6/en/update.html\n const results = await this.database('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from('refresh_state')\n .innerJoin(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n await this.database('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn(\n 'entity_id',\n results.map(key => key.entity_id),\n );\n } else {\n await this.database('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from('refresh_state')\n .innerJoin(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n }\n\n // Stitch the entities that the deleted one had relations to. If we do not\n // do this, the entities in the other end of the relations will still look\n // like they have a relation to the entity that was deleted, despite not\n // having any corresponding rows in the relations table.\n const relationPeers = await this.database\n .from('relations')\n .innerJoin('refresh_state', {\n 'refresh_state.entity_ref': 'relations.target_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.target_entity_ref' })\n .union(other =>\n other\n .from('relations')\n .innerJoin('refresh_state', {\n 'refresh_state.entity_ref': 'relations.source_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.source_entity_ref' }),\n );\n\n await this.database('refresh_state')\n .where('entity_id', uid)\n .delete();\n\n await this.stitcher.stitch({\n entityRefs: new Set(relationPeers.map(p => p.ref)),\n });\n }\n\n async entityAncestry(rootRef: string): Promise {\n const [rootRow] = await this.database('refresh_state')\n .leftJoin('final_entities', {\n 'refresh_state.entity_id': 'final_entities.entity_id',\n })\n .where('refresh_state.entity_ref', '=', rootRef)\n .select({\n entityJson: 'final_entities.final_entity',\n });\n\n if (!rootRow) {\n throw new NotFoundError(`No such entity ${rootRef}`);\n }\n\n const rootEntity = JSON.parse(rootRow.entityJson) as Entity;\n const seenEntityRefs = new Set();\n const todo = new Array();\n const items = new Array<{ entity: Entity; parentEntityRefs: string[] }>();\n\n for (\n let current: Entity | undefined = rootEntity;\n current;\n current = todo.pop()\n ) {\n const currentRef = stringifyEntityRef(current);\n seenEntityRefs.add(currentRef);\n\n const parentRows = await this.database(\n 'refresh_state_references',\n )\n .innerJoin('refresh_state', {\n 'refresh_state_references.source_entity_ref':\n 'refresh_state.entity_ref',\n })\n .innerJoin('final_entities', {\n 'refresh_state.entity_id': 'final_entities.entity_id',\n })\n .where('refresh_state_references.target_entity_ref', '=', currentRef)\n .select({\n parentEntityRef: 'refresh_state.entity_ref',\n parentEntityJson: 'final_entities.final_entity',\n });\n\n const parentRefs: string[] = [];\n for (const { parentEntityRef, parentEntityJson } of parentRows) {\n parentRefs.push(parentEntityRef);\n if (!seenEntityRefs.has(parentEntityRef)) {\n seenEntityRefs.add(parentEntityRef);\n todo.push(JSON.parse(parentEntityJson));\n }\n }\n\n items.push({\n entity: current,\n parentEntityRefs: parentRefs,\n });\n }\n\n return {\n rootEntityRef: stringifyEntityRef(rootEntity),\n items,\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise {\n const facets: EntityFacetsResponse['facets'] = {};\n const db = this.database;\n\n for (const facet of request.facets) {\n const dbQuery = db('search')\n .where('search.key', facet.toLocaleLowerCase('en-US'))\n .whereNotNull('search.original_value')\n .select({ value: 'search.original_value', count: db.raw('count(*)') })\n .groupBy('search.original_value');\n\n if (request?.filter) {\n parseFilter(request.filter, dbQuery, db, false, 'search.entity_id');\n }\n\n const result = await dbQuery;\n\n facets[facet] = result.map(data => ({\n value: String(data.value),\n count: Number(data.count),\n }));\n }\n\n return { facets };\n }\n}\n\nconst entityFilterParser: z.ZodSchema = z.lazy(() =>\n z\n .object({\n key: z.string(),\n values: z.array(z.string()).optional(),\n })\n .or(z.object({ not: entityFilterParser }))\n .or(z.object({ anyOf: z.array(entityFilterParser) }))\n .or(z.object({ allOf: z.array(entityFilterParser) })),\n);\n\nexport const cursorParser: z.ZodSchema = z.object({\n orderFields: z.array(\n z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),\n ),\n orderFieldValues: z.array(z.string().or(z.null())),\n filter: entityFilterParser.optional(),\n isPrevious: z.boolean(),\n query: z.string().optional(),\n firstSortFieldValues: z.array(z.string().or(z.null())).optional(),\n totalItems: z.number().optional(),\n});\n\nfunction parseCursorFromRequest(\n request?: QueryEntitiesRequest,\n): Partial {\n if (isQueryEntitiesInitialRequest(request)) {\n const {\n filter,\n orderFields: sortFields = [defaultSortField],\n fullTextFilter,\n } = request;\n return { filter, orderFields: sortFields, fullTextFilter };\n }\n if (isQueryEntitiesCursorRequest(request)) {\n return request.cursor;\n }\n return {};\n}\n\nfunction invertOrder(order: EntityOrder['order']) {\n return order === 'asc' ? 'desc' : 'asc';\n}\n\nfunction sortFieldsFromRow(row: DbSearchRow) {\n return [row.value, row.entity_id];\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n stringifyEntityRef,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport { assertError } from '@backstage/errors';\nimport {\n CatalogProcessor,\n CatalogProcessorResult,\n DeferredEntity,\n EntityRelationSpec,\n} from '@backstage/plugin-catalog-node';\nimport { locationSpecToLocationEntity } from '../util/conversion';\nimport {\n getEntityLocationRef,\n getEntityOriginLocationRef,\n validateEntityEnvelope,\n} from './util';\nimport { RefreshKeyData } from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Helper class for aggregating all of the emitted data from processors.\n */\nexport class ProcessorOutputCollector {\n private readonly errors = new Array();\n private readonly relations = new Array();\n private readonly deferredEntities = new Array();\n private readonly refreshKeys = new Array();\n private done = false;\n\n constructor(\n private readonly logger: LoggerService,\n private readonly parentEntity: Entity,\n ) {}\n\n generic(): (i: CatalogProcessorResult) => void {\n return i => this.receive(this.logger, i);\n }\n\n forProcessor(\n processor: CatalogProcessor,\n ): (i: CatalogProcessorResult) => void {\n const logger = this.logger.child({\n processor: processor.getProcessorName(),\n });\n return i => this.receive(logger, i);\n }\n\n results() {\n this.done = true;\n return {\n errors: this.errors,\n relations: this.relations,\n refreshKeys: this.refreshKeys,\n deferredEntities: this.deferredEntities,\n };\n }\n\n private receive(logger: LoggerService, i: CatalogProcessorResult) {\n if (this.done) {\n logger.warn(\n `Item of type \"${\n i.type\n }\" was emitted after processing had completed. Stack trace: ${\n new Error().stack\n }`,\n );\n return;\n }\n\n if (i.type === 'entity') {\n let entity: Entity;\n const location = stringifyLocationRef(i.location);\n\n try {\n entity = validateEntityEnvelope(i.entity);\n } catch (e) {\n assertError(e);\n logger.debug(`Envelope validation failed at ${location}, ${e}`);\n this.errors.push(e);\n return;\n }\n\n // The processor contract says you should return the \"trunk\" (current)\n // entity, not emit it. But it happens that this is misunderstood or\n // accidentally forgotten. This can lead to circular references which at\n // best is wasteful, so we try to be helpful by ignoring such emitted\n // entities.\n const entityRef = stringifyEntityRef(entity);\n if (entityRef === stringifyEntityRef(this.parentEntity)) {\n logger.warn(\n `Ignored emitted entity ${entityRef} whose ref was identical to the one being processed. This commonly indicates mistakenly emitting the input entity instead of returning it.`,\n );\n return;\n }\n\n // Note that at this point, we have only validated the envelope part of\n // the entity data. Annotations are not part of that, so we have to be\n // defensive. If the annotations were malformed (e.g. were not a valid\n // object), we just skip over this step and let the full entity\n // validation at the next step of processing catch that.\n const annotations = entity.metadata.annotations || {};\n if (typeof annotations === 'object' && !Array.isArray(annotations)) {\n const originLocation = getEntityOriginLocationRef(this.parentEntity);\n entity = {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n ...annotations,\n [ANNOTATION_ORIGIN_LOCATION]: originLocation,\n [ANNOTATION_LOCATION]: location,\n },\n },\n };\n }\n\n this.deferredEntities.push({ entity, locationKey: location });\n } else if (i.type === 'location') {\n const entity = locationSpecToLocationEntity({\n location: i.location,\n parentEntity: this.parentEntity,\n });\n const locationKey = getEntityLocationRef(entity);\n this.deferredEntities.push({ entity, locationKey });\n } else if (i.type === 'relation') {\n this.relations.push(i.relation);\n } else if (i.type === 'error') {\n this.errors.push(i.error);\n } else if (i.type === 'refresh') {\n this.refreshKeys.push({ key: i.key });\n }\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport {\n CatalogProcessor,\n CatalogProcessorCache,\n} from '@backstage/plugin-catalog-node';\nimport { isObject } from './util';\n\nclass SingleProcessorSubCache implements CatalogProcessorCache {\n private newState?: JsonObject;\n\n constructor(private readonly existingState?: JsonObject) {}\n\n async get(\n key: string,\n ): Promise {\n return this.existingState?.[key] as ItemType | undefined;\n }\n\n async set(\n key: string,\n value: ItemType,\n ): Promise {\n if (!this.newState) {\n this.newState = {};\n }\n\n this.newState[key] = value;\n }\n\n collect(): JsonObject | undefined {\n return this.newState ?? this.existingState;\n }\n}\n\nclass SingleProcessorCache implements CatalogProcessorCache {\n private newState?: JsonObject;\n private subCaches: Map = new Map();\n\n constructor(private readonly existingState?: JsonObject) {}\n\n async get(\n key: string,\n ): Promise {\n return this.existingState?.[key] as ItemType | undefined;\n }\n\n async set(\n key: string,\n value: ItemType,\n ): Promise {\n if (!this.newState) {\n this.newState = {};\n }\n\n this.newState[key] = value;\n }\n\n withKey(key: string) {\n const existingSubCache = this.subCaches.get(key);\n if (existingSubCache) {\n return existingSubCache;\n }\n const existing = this.existingState?.[key];\n const subCache = new SingleProcessorSubCache(\n isObject(existing) ? existing : undefined,\n );\n this.subCaches.set(key, subCache);\n return subCache;\n }\n\n collect(): JsonObject | undefined {\n let obj = this.newState ?? this.existingState;\n for (const [key, subCache] of this.subCaches) {\n const subCacheValue = subCache.collect();\n if (subCacheValue) {\n obj = { ...obj, [key]: subCacheValue };\n }\n }\n return obj;\n }\n}\n\nexport class ProcessorCacheManager {\n private caches = new Map();\n\n constructor(private readonly existingState: JsonObject) {}\n\n forProcessor(\n processor: CatalogProcessor,\n key?: string,\n ): CatalogProcessorCache {\n // constructor name will be deprecated in the future when we make `getProcessorName` required in the implementation\n const name = processor.getProcessorName();\n const cache = this.caches.get(name);\n if (cache) {\n return key ? cache.withKey(key) : cache;\n }\n\n const existing = this.existingState[name];\n\n const newCache = new SingleProcessorCache(\n isObject(existing) ? existing : undefined,\n );\n this.caches.set(name, newCache);\n return key ? newCache.withKey(key) : newCache;\n }\n\n collect(): JsonObject {\n const result: JsonObject = {};\n for (const [key, value] of this.caches.entries()) {\n result[key] = value.collect();\n }\n\n return result;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Span, trace } from '@opentelemetry/api';\nimport {\n Entity,\n EntityPolicy,\n LocationEntity,\n parseLocationRef,\n stringifyEntityRef,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport {\n assertError,\n ConflictError,\n InputError,\n NotAllowedError,\n} from '@backstage/errors';\nimport { JsonValue } from '@backstage/types';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport {\n CatalogProcessingOrchestrator,\n EntityProcessingRequest,\n EntityProcessingResult,\n} from './types';\nimport { ProcessorOutputCollector } from './ProcessorOutputCollector';\nimport {\n getEntityLocationRef,\n getEntityOriginLocationRef,\n isLocationEntity,\n isObject,\n toAbsoluteUrl,\n validateEntity,\n validateEntityEnvelope,\n} from './util';\nimport { CatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { ProcessorCacheManager } from './ProcessorCacheManager';\nimport {\n addEntityAttributes,\n TRACER_ID,\n withActiveSpan,\n} from '../util/opentelemetry';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst tracer = trace.getTracer(TRACER_ID);\n\ntype Context = {\n entityRef: string;\n location: LocationSpec;\n originLocation: LocationSpec;\n collector: ProcessorOutputCollector;\n cache: ProcessorCacheManager;\n};\n\nfunction addProcessorAttributes(\n span: Span,\n stage: string,\n processor: CatalogProcessor,\n) {\n span.setAttribute('backstage.catalog.processor.stage', stage);\n span.setAttribute(\n 'backstage.catalog.processor.name',\n processor.getProcessorName(),\n );\n}\n\n/** @public */\nexport class DefaultCatalogProcessingOrchestrator\n implements CatalogProcessingOrchestrator\n{\n constructor(\n private readonly options: {\n processors: CatalogProcessor[];\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n parser: CatalogProcessorParser;\n policy: EntityPolicy;\n rulesEnforcer: CatalogRulesEnforcer;\n legacySingleProcessorValidation: boolean;\n },\n ) {}\n\n async process(\n request: EntityProcessingRequest,\n ): Promise {\n return this.processSingleEntity(request.entity, request.state);\n }\n\n private async processSingleEntity(\n unprocessedEntity: Entity,\n state: JsonValue | undefined,\n ): Promise {\n const collector = new ProcessorOutputCollector(\n this.options.logger,\n unprocessedEntity,\n );\n\n // Cache that is scoped to the entity and processor\n const cache = new ProcessorCacheManager(\n isObject(state) && isObject(state.cache) ? state.cache : {},\n );\n\n try {\n // This will be checked and mutated step by step below\n let entity: Entity = unprocessedEntity;\n\n // NOTE: At this early point, we can only rely on the envelope having to\n // be valid; full entity + kind validation happens after the (potentially\n // mutative) pre-steps. This means that the code below can't make a lot\n // of assumptions about the data despite it using the Entity type.\n try {\n validateEntityEnvelope(entity);\n } catch (e) {\n throw new InputError(\n `Entity envelope failed validation before processing`,\n e,\n );\n }\n\n // TODO: which one do we actually use for the location?\n // source-location? - maybe probably doesn't exist yet?\n const context: Context = {\n entityRef: stringifyEntityRef(entity),\n location: parseLocationRef(getEntityLocationRef(entity)),\n originLocation: parseLocationRef(getEntityOriginLocationRef(entity)),\n cache,\n collector,\n };\n\n // Run the steps\n entity = await this.runPreProcessStep(entity, context);\n entity = await this.runPolicyStep(entity);\n await this.runValidateStep(entity, context);\n if (isLocationEntity(entity)) {\n await this.runSpecialLocationStep(entity, context);\n }\n entity = await this.runPostProcessStep(entity, context);\n\n // Check that any emitted entities are permitted to originate from that\n // particular location according to the catalog rules\n const collectorResults = context.collector.results();\n for (const deferredEntity of collectorResults.deferredEntities) {\n if (\n !this.options.rulesEnforcer.isAllowed(\n deferredEntity.entity,\n context.originLocation,\n )\n ) {\n throw new NotAllowedError(\n `Entity ${stringifyEntityRef(\n deferredEntity.entity,\n )} at ${stringifyLocationRef(\n context.location,\n )}, originated at ${stringifyLocationRef(\n context.originLocation,\n )}, is not of an allowed kind for that location`,\n );\n }\n }\n\n return {\n ...collectorResults,\n completedEntity: entity,\n state: { cache: cache.collect() },\n ok: collectorResults.errors.length === 0,\n };\n } catch (error) {\n assertError(error);\n return {\n ok: false,\n errors: collector.results().errors.concat(error),\n };\n }\n }\n\n // Pre-process phase, used to populate entities with data that is required\n // during the main processing step\n private async runPreProcessStep(\n entity: Entity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute('backstage.catalog.processor.stage', 'preProcess');\n let res = entity;\n\n for (const processor of this.options.processors) {\n if (processor.preProcessEntity) {\n let innerRes = res;\n res = await withActiveSpan(tracer, 'ProcessingStep', async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'preProcessEntity', processor);\n try {\n innerRes = await processor.preProcessEntity!(\n innerRes,\n context.location,\n context.collector.forProcessor(processor),\n context.originLocation,\n context.cache.forProcessor(processor),\n );\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while preprocessing`,\n e,\n );\n }\n return innerRes;\n });\n }\n }\n\n return res;\n });\n }\n\n /**\n * Enforce entity policies making sure that entities conform to a general schema\n */\n private async runPolicyStep(entity: Entity): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute(\n 'backstage.catalog.processor.stage',\n 'enforcePolicy',\n );\n let policyEnforcedEntity: Entity | undefined;\n\n try {\n policyEnforcedEntity = await this.options.policy.enforce(entity);\n } catch (e) {\n throw new InputError(\n `Policy check failed for ${stringifyEntityRef(entity)}`,\n e,\n );\n }\n\n if (!policyEnforcedEntity) {\n throw new Error(\n `Policy unexpectedly returned no data for ${stringifyEntityRef(\n entity,\n )}`,\n );\n }\n\n return policyEnforcedEntity;\n });\n }\n\n /**\n * Validate the given entity\n */\n private async runValidateStep(\n entity: Entity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute('backstage.catalog.processor.stage', 'validate');\n // Double check that none of the previous steps tried to change something\n // related to the entity ref, which would break downstream\n if (stringifyEntityRef(entity) !== context.entityRef) {\n throw new ConflictError(\n 'Fatal: The entity kind, namespace, or name changed during processing',\n );\n }\n\n // Validate that the end result is a valid Entity at all\n try {\n validateEntity(entity);\n } catch (e) {\n throw new ConflictError(\n `Entity envelope for ${context.entityRef} failed validation after preprocessing`,\n e,\n );\n }\n\n let valid = false;\n\n for (const processor of this.options.processors) {\n if (processor.validateEntityKind) {\n try {\n const thisValid = await withActiveSpan(\n tracer,\n 'ProcessingStep',\n async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'validateEntityKind', processor);\n return await processor.validateEntityKind!(entity);\n },\n );\n if (thisValid) {\n valid = true;\n if (this.options.legacySingleProcessorValidation) {\n break;\n }\n }\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while validating the entity ${context.entityRef}`,\n e,\n );\n }\n }\n }\n\n if (!valid) {\n throw new InputError(\n `No processor recognized the entity ${context.entityRef} as valid, possibly caused by a foreign kind or apiVersion`,\n );\n }\n });\n }\n\n /**\n * Backwards compatible processing of location entities\n */\n private async runSpecialLocationStep(\n entity: LocationEntity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute(\n 'backstage.catalog.processor.stage',\n 'readLocation',\n );\n const { type = context.location.type, presence = 'required' } =\n entity.spec;\n const targets = new Array();\n if (entity.spec.target) {\n targets.push(entity.spec.target);\n }\n if (entity.spec.targets) {\n targets.push(...entity.spec.targets);\n }\n\n for (const maybeRelativeTarget of targets) {\n if (type === 'file' && maybeRelativeTarget.endsWith(path.sep)) {\n context.collector.generic()(\n processingResult.inputError(\n context.location,\n `LocationEntityProcessor cannot handle ${type} type location with target ${context.location.target} that ends with a path separator`,\n ),\n );\n continue;\n }\n const target = toAbsoluteUrl(\n this.options.integrations,\n context.location,\n type,\n maybeRelativeTarget,\n );\n\n let didRead = false;\n for (const processor of this.options.processors) {\n if (processor.readLocation) {\n try {\n const read = await withActiveSpan(\n tracer,\n 'ProcessingStep',\n async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'readLocation', processor);\n return await processor.readLocation!(\n {\n type,\n target,\n presence,\n },\n presence === 'optional',\n context.collector.forProcessor(processor),\n this.options.parser,\n context.cache.forProcessor(processor, target),\n );\n },\n );\n if (read) {\n didRead = true;\n break;\n }\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while reading ${type}:${target}`,\n e,\n );\n }\n }\n }\n if (!didRead) {\n throw new InputError(\n `No processor was able to handle reading of ${type}:${target}`,\n );\n }\n }\n });\n }\n\n /**\n * Main processing step of the entity\n */\n private async runPostProcessStep(\n entity: Entity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute(\n 'backstage.catalog.processor.stage',\n 'postProcessEntity',\n );\n let res = entity;\n\n for (const processor of this.options.processors) {\n if (processor.postProcessEntity) {\n let innerRes = res;\n res = await withActiveSpan(tracer, 'ProcessingStep', async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'postProcessEntity', processor);\n try {\n innerRes = await processor.postProcessEntity!(\n innerRes,\n context.location,\n context.collector.forProcessor(processor),\n context.cache.forProcessor(processor),\n );\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while postprocessing`,\n e,\n );\n }\n return innerRes;\n });\n }\n }\n\n return res;\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { timestampToDateTime } from '../../conversion';\nimport { DbRefreshStateRow } from '../../tables';\n\n// TODO(freben): There is no retry counter or similar. If items start\n// perpetually crashing during stitching, they'll just get silently retried over\n// and over again, for better or worse. This will be visible in metrics though.\n\n/**\n * Finds entities that are marked for deferred stitching.\n *\n * @remarks\n *\n * This assumes that the stitching strategy is set to deferred.\n *\n * They are expected to already have the next_stitch_ticket set (by\n * markForStitching) so that their tickets can be returned with each item.\n *\n * All returned items have their next_stitch_at updated to be moved forward by\n * the given timeout duration. This has the effect that they will be picked up\n * for stitching again in the future, if it hasn't completed by that point for\n * some reason (restarts, crashes, etc).\n */\nexport async function getDeferredStitchableEntities(options: {\n knex: Knex | Knex.Transaction;\n batchSize: number;\n stitchTimeout: HumanDuration;\n}): Promise<\n Array<{\n entityRef: string;\n stitchTicket: string;\n stitchRequestedAt: DateTime; // the time BEFORE moving it forward by the timeout\n }>\n> {\n const { knex, batchSize, stitchTimeout } = options;\n\n let itemsQuery = knex('refresh_state').select(\n 'entity_ref',\n 'next_stitch_at',\n 'next_stitch_ticket',\n );\n\n // This avoids duplication of work because of race conditions and is\n // also fast because locked rows are ignored rather than blocking.\n // It's only available in MySQL and PostgreSQL\n if (['mysql', 'mysql2', 'pg'].includes(knex.client.config.client)) {\n itemsQuery = itemsQuery.forUpdate().skipLocked();\n }\n\n const items = await itemsQuery\n .whereNotNull('next_stitch_at')\n .whereNotNull('next_stitch_ticket')\n .where('next_stitch_at', '<=', knex.fn.now())\n .orderBy('next_stitch_at', 'asc')\n .limit(batchSize);\n\n if (!items.length) {\n return [];\n }\n\n await knex('refresh_state')\n .whereIn(\n 'entity_ref',\n items.map(i => i.entity_ref),\n )\n // avoid race condition where someone completes a stitch right between these statements\n .whereNotNull('next_stitch_ticket')\n .update({\n next_stitch_at: nowPlus(knex, stitchTimeout),\n });\n\n return items.map(i => ({\n entityRef: i.entity_ref,\n stitchTicket: i.next_stitch_ticket!,\n stitchRequestedAt: timestampToDateTime(i.next_stitch_at!),\n }));\n}\n\nfunction nowPlus(knex: Knex, duration: HumanDuration): Knex.Raw {\n const seconds = durationToMilliseconds(duration) / 1000;\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);\n } else if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`now() + interval ${seconds} second`);\n }\n return knex.raw(`now() + interval '${seconds} seconds'`);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DEFAULT_NAMESPACE, Entity } from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport { DbSearchRow } from '../../tables';\n\n// These are excluded in the generic loop, either because they do not make sense\n// to index, or because they are special-case always inserted whether they are\n// null or not\nconst SPECIAL_KEYS = [\n 'attachments',\n 'relations',\n 'status',\n 'metadata.name',\n 'metadata.namespace',\n 'metadata.uid',\n 'metadata.etag',\n];\n\n// The maximum length allowed for search values. These columns are indexed, and\n// database engines do not like to index on massive values. For example,\n// postgres will balk after 8191 byte line sizes.\nconst MAX_KEY_LENGTH = 200;\nconst MAX_VALUE_LENGTH = 200;\n\ntype Kv = {\n key: string;\n value: unknown;\n};\n\n// Helper for traversing through a nested structure and outputting a list of\n// path->value entries of the leaves.\n//\n// For example, this yaml structure\n//\n// a: 1\n// b:\n// c: null\n// e: [f, g]\n// h:\n// - i: 1\n// j: k\n// - i: 2\n// j: l\n//\n// will result in\n//\n// \"a\", 1\n// \"b.c\", null\n// \"b.e\": \"f\"\n// \"b.e.f\": true\n// \"b.e\": \"g\"\n// \"b.e.g\": true\n// \"h.i\": 1\n// \"h.j\": \"k\"\n// \"h.i\": 2\n// \"h.j\": \"l\"\nexport function traverse(root: unknown): Kv[] {\n const output: Kv[] = [];\n\n function visit(path: string, current: unknown) {\n if (SPECIAL_KEYS.includes(path)) {\n return;\n }\n\n // empty or scalar\n if (\n current === undefined ||\n current === null ||\n ['string', 'number', 'boolean'].includes(typeof current)\n ) {\n output.push({ key: path, value: current });\n return;\n }\n\n // unknown\n if (typeof current !== 'object') {\n return;\n }\n\n // array\n if (Array.isArray(current)) {\n for (const item of current) {\n // NOTE(freben): The reason that these are output in two different ways,\n // is to support use cases where you want to express that MORE than one\n // tag is present in a list. Since the EntityFilters structure is a\n // record, you can't have several entries of the same key. Therefore\n // you will have to match on\n //\n // { \"a.b\": [\"true\"], \"a.c\": [\"true\"] }\n //\n // rather than\n //\n // { \"a\": [\"b\", \"c\"] }\n //\n // because the latter means EITHER b or c has to be present.\n visit(path, item);\n if (typeof item === 'string') {\n output.push({ key: `${path}.${item}`, value: true });\n }\n }\n return;\n }\n\n // object\n for (const [key, value] of Object.entries(current!)) {\n visit(path ? `${path}.${key}` : key, value);\n }\n }\n\n visit('', root);\n\n return output;\n}\n\n// Translates a number of raw data rows to search table rows\nexport function mapToRows(input: Kv[], entityId: string): DbSearchRow[] {\n const result: DbSearchRow[] = [];\n\n for (const { key: rawKey, value: rawValue } of input) {\n const key = rawKey.toLocaleLowerCase('en-US');\n if (key.length > MAX_KEY_LENGTH) {\n continue;\n }\n if (rawValue === undefined || rawValue === null) {\n result.push({\n entity_id: entityId,\n key,\n original_value: null,\n value: null,\n });\n } else {\n const value = String(rawValue).toLocaleLowerCase('en-US');\n if (value.length <= MAX_VALUE_LENGTH) {\n result.push({\n entity_id: entityId,\n key,\n original_value: String(rawValue),\n value: value,\n });\n } else {\n result.push({\n entity_id: entityId,\n key,\n original_value: null,\n value: null,\n });\n }\n }\n }\n\n return result;\n}\n\n/**\n * Generates all of the search rows that are relevant for this entity.\n *\n * @param entityId - The uid of the entity\n * @param entity - The entity\n * @returns A list of entity search rows\n */\nexport function buildEntitySearch(\n entityId: string,\n entity: Entity,\n): DbSearchRow[] {\n // Visit the base structure recursively\n const raw = traverse(entity);\n\n // Start with some special keys that are always present because you want to\n // be able to easily search for null specifically\n raw.push({ key: 'metadata.name', value: entity.metadata.name });\n raw.push({ key: 'metadata.namespace', value: entity.metadata.namespace });\n raw.push({ key: 'metadata.uid', value: entity.metadata.uid });\n\n // Namespace not specified has the default value \"default\", so we want to\n // match on that as well\n if (!entity.metadata.namespace) {\n raw.push({ key: 'metadata.namespace', value: DEFAULT_NAMESPACE });\n }\n\n // Visit relations\n for (const relation of entity.relations ?? []) {\n raw.push({\n key: `relations.${relation.type}`,\n value: relation.targetRef,\n });\n }\n\n // This validates that there are no keys that vary only in casing, such\n // as `spec.foo` and `spec.Foo`.\n const keys = new Set(raw.map(r => r.key));\n const lowerKeys = new Set(raw.map(r => r.key.toLocaleLowerCase('en-US')));\n if (keys.size !== lowerKeys.size) {\n const difference = [];\n for (const key of keys) {\n const lower = key.toLocaleLowerCase('en-US');\n if (!lowerKeys.delete(lower)) {\n difference.push(lower);\n }\n }\n const badKeys = `'${difference.join(\"', '\")}'`;\n throw new InputError(\n `Entity has duplicate keys that vary only in casing, ${badKeys}`,\n );\n }\n\n return mapToRows(raw, entityId);\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Marks a single entity as having been stitched.\n *\n * @remarks\n *\n * This assumes that the stitching strategy is set to deferred.\n *\n * The timestamp and ticket are only reset if the ticket hasn't changed. If it\n * has, it means that a new stitch request has been made, and the entity should\n * be stitched once more some time in the future - or is indeed already being\n * stitched concurrently with ourselves.\n */\nexport async function markDeferredStitchCompleted(option: {\n knex: Knex | Knex.Transaction;\n entityRef: string;\n stitchTicket: string;\n}): Promise {\n const { knex, entityRef, stitchTicket } = option;\n\n await knex('refresh_state')\n .update({\n next_stitch_at: null,\n next_stitch_ticket: null,\n })\n .where('entity_ref', '=', entityRef)\n .andWhere('next_stitch_ticket', '=', stitchTicket);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nexport const BATCH_SIZE = 50;\n\nexport function generateStableHash(entity: Entity) {\n return createHash('sha1')\n .update(stableStringify({ ...entity }))\n .digest('hex');\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from '@backstage/catalog-client';\nimport {\n ANNOTATION_EDIT_URL,\n ANNOTATION_VIEW_URL,\n EntityRelation,\n} from '@backstage/catalog-model';\nimport { AlphaEntity, EntityStatusItem } from '@backstage/catalog-model/alpha';\nimport { SerializedError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport { StitchingStrategy } from '../../../stitching/types';\nimport {\n DbFinalEntitiesRow,\n DbRefreshStateRow,\n DbSearchRow,\n} from '../../tables';\nimport { buildEntitySearch } from './buildEntitySearch';\nimport { markDeferredStitchCompleted } from './markDeferredStitchCompleted';\nimport { BATCH_SIZE, generateStableHash } from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// See https://github.com/facebook/react/blob/f0cf832e1d0c8544c36aa8b310960885a11a847c/packages/react-dom-bindings/src/shared/sanitizeURL.js\nconst scriptProtocolPattern =\n // eslint-disable-next-line no-control-regex\n /^[\\u0000-\\u001F ]*j[\\r\\n\\t]*a[\\r\\n\\t]*v[\\r\\n\\t]*a[\\r\\n\\t]*s[\\r\\n\\t]*c[\\r\\n\\t]*r[\\r\\n\\t]*i[\\r\\n\\t]*p[\\r\\n\\t]*t[\\r\\n\\t]*\\:/i;\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport async function performStitching(options: {\n knex: Knex | Knex.Transaction;\n logger: LoggerService;\n strategy: StitchingStrategy;\n entityRef: string;\n stitchTicket?: string;\n}): Promise<'changed' | 'unchanged' | 'abandoned'> {\n const { knex, logger, entityRef } = options;\n const stitchTicket = options.stitchTicket ?? uuid();\n\n const entityResult = await knex('refresh_state')\n .where({ entity_ref: entityRef })\n .limit(1)\n .select('entity_id');\n if (!entityResult.length) {\n // Entity does no exist in refresh state table, no stitching required.\n return 'abandoned';\n }\n\n // Insert stitching ticket that will be compared before inserting the final entity.\n await knex('final_entities')\n .insert({\n entity_id: entityResult[0].entity_id,\n hash: '',\n stitch_ticket: stitchTicket,\n })\n .onConflict('entity_id')\n .merge(['stitch_ticket']);\n\n // Selecting from refresh_state and final_entities should yield exactly\n // one row (except in abnormal cases where the stitch was invoked for\n // something that didn't exist at all, in which case it's zero rows).\n // The join with the temporary incoming_references still gives one row.\n const [processedResult, relationsResult] = await Promise.all([\n knex\n .with('incoming_references', function incomingReferences(builder) {\n return builder\n .from('refresh_state_references')\n .where({ target_entity_ref: entityRef })\n .count({ count: '*' });\n })\n .select({\n entityId: 'refresh_state.entity_id',\n processedEntity: 'refresh_state.processed_entity',\n errors: 'refresh_state.errors',\n incomingReferenceCount: 'incoming_references.count',\n previousHash: 'final_entities.hash',\n })\n .from('refresh_state')\n .where({ 'refresh_state.entity_ref': entityRef })\n .crossJoin(knex.raw('incoming_references'))\n .leftOuterJoin('final_entities', {\n 'final_entities.entity_id': 'refresh_state.entity_id',\n }),\n knex\n .distinct({\n relationType: 'type',\n relationTarget: 'target_entity_ref',\n })\n .from('relations')\n .where({ source_entity_ref: entityRef })\n .orderBy('relationType', 'asc')\n .orderBy('relationTarget', 'asc'),\n ]);\n\n // If there were no rows returned, it would mean that there was no\n // matching row even in the refresh_state. This can happen for example\n // if we emit a relation to something that hasn't been ingested yet.\n // It's safe to ignore this stitch attempt in that case.\n if (!processedResult.length) {\n logger.debug(\n `Unable to stitch ${entityRef}, item does not exist in refresh state table`,\n );\n return 'abandoned';\n }\n\n const {\n entityId,\n processedEntity,\n errors,\n incomingReferenceCount,\n previousHash,\n } = processedResult[0];\n\n // If there was no processed entity in place, the target hasn't been\n // through the processing steps yet. It's safe to ignore this stitch\n // attempt in that case, since another stitch will be triggered when\n // that processing has finished.\n if (!processedEntity) {\n logger.debug(\n `Unable to stitch ${entityRef}, the entity has not yet been processed`,\n );\n return 'abandoned';\n }\n\n // Grab the processed entity and stitch all of the relevant data into\n // it\n const entity = JSON.parse(processedEntity) as AlphaEntity;\n const isOrphan = Number(incomingReferenceCount) === 0;\n let statusItems: EntityStatusItem[] = [];\n\n if (isOrphan) {\n logger.debug(`${entityRef} is an orphan`);\n entity.metadata.annotations = {\n ...entity.metadata.annotations,\n ['backstage.io/orphan']: 'true',\n };\n }\n if (errors) {\n const parsedErrors = JSON.parse(errors) as SerializedError[];\n if (Array.isArray(parsedErrors) && parsedErrors.length) {\n statusItems = parsedErrors.map(e => ({\n type: ENTITY_STATUS_CATALOG_PROCESSING_TYPE,\n level: 'error',\n message: `${e.name}: ${e.message}`,\n error: e,\n }));\n }\n }\n // We opt to do this check here as we otherwise can't guarantee that it will be run after all processors\n for (const annotation of [ANNOTATION_VIEW_URL, ANNOTATION_EDIT_URL]) {\n const value = entity.metadata.annotations?.[annotation];\n if (typeof value === 'string' && scriptProtocolPattern.test(value)) {\n entity.metadata.annotations![annotation] =\n 'https://backstage.io/annotation-rejected-for-security-reasons';\n }\n }\n\n // TODO: entityRef is lower case and should be uppercase in the final\n // result\n entity.relations = relationsResult\n .filter(row => row.relationType /* exclude null row, if relevant */)\n .map(row => ({\n type: row.relationType!,\n targetRef: row.relationTarget!,\n }));\n if (statusItems.length) {\n entity.status = {\n ...entity.status,\n items: [...(entity.status?.items ?? []), ...statusItems],\n };\n }\n\n // If the output entity was actually not changed, just abort\n const hash = generateStableHash(entity);\n if (hash === previousHash) {\n logger.debug(`Skipped stitching of ${entityRef}, no changes`);\n return 'unchanged';\n }\n\n entity.metadata.uid = entityId;\n if (!entity.metadata.etag) {\n // If the original data source did not have its own etag handling,\n // use the hash as a good-quality etag\n entity.metadata.etag = hash;\n }\n\n // This may throw if the entity is invalid, so we call it before\n // the final_entities write, even though we may end up not needing\n // to write the search index.\n const searchEntries = buildEntitySearch(entityId, entity);\n\n const amountOfRowsChanged = await knex('final_entities')\n .update({\n final_entity: JSON.stringify(entity),\n hash,\n last_updated_at: knex.fn.now(),\n })\n .where('entity_id', entityId)\n .where('stitch_ticket', stitchTicket)\n .onConflict('entity_id')\n .merge(['final_entity', 'hash', 'last_updated_at']);\n\n if (options.strategy.mode === 'deferred') {\n await markDeferredStitchCompleted({\n knex: knex,\n entityRef,\n stitchTicket,\n });\n }\n\n if (amountOfRowsChanged === 0) {\n logger.debug(`Entity ${entityRef} is already stitched, skipping write.`);\n return 'abandoned';\n }\n\n // TODO(freben): Search will probably need a similar safeguard against\n // race conditions like the final_entities ticket handling above.\n // Otherwise, it can be the case that:\n // A writes the entity ->\n // B writes the entity ->\n // B writes search ->\n // A writes search\n await knex('search').where({ entity_id: entityId }).delete();\n await knex.batchInsert('search', searchEntries, BATCH_SIZE);\n\n return 'changed';\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyError } from '@backstage/errors';\nimport { metrics } from '@opentelemetry/api';\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { DbRefreshStateRow } from '../database/tables';\nimport { createCounterMetric } from '../util/metrics';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// Helps wrap the timing and logging behaviors\nexport function progressTracker(knex: Knex, logger: LoggerService) {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promStitchedEntities = createCounterMetric({\n name: 'catalog_stitched_entities_count',\n help: 'Amount of entities stitched. DEPRECATED, use OpenTelemetry metrics instead',\n });\n\n const meter = metrics.getMeter('default');\n\n const stitchedEntities = meter.createCounter(\n 'catalog.stitched.entities.count',\n {\n description: 'Amount of entities stitched',\n },\n );\n\n const stitchingDuration = meter.createHistogram(\n 'catalog.stitching.duration',\n {\n description: 'Time spent executing the full stitching flow',\n unit: 'seconds',\n },\n );\n\n const stitchingQueueCount = meter.createObservableGauge(\n 'catalog.stitching.queue.length',\n { description: 'Number of entities currently in the stitching queue' },\n );\n stitchingQueueCount.addCallback(async result => {\n const total = await knex('refresh_state')\n .count({ count: '*' })\n .whereNotNull('next_stitch_at')\n .where('next_stitch_at', '<=', knex.fn.now());\n result.observe(Number(total[0].count));\n });\n\n const stitchingQueueDelay = meter.createHistogram(\n 'catalog.stitching.queue.delay',\n {\n description:\n 'The amount of delay between being scheduled for stitching, and the start of actually being stitched',\n unit: 'seconds',\n },\n );\n\n function stitchStart(item: {\n entityRef: string;\n stitchRequestedAt?: DateTime;\n }) {\n logger.debug(`Stitching ${item.entityRef}`);\n\n const startTime = process.hrtime();\n if (item.stitchRequestedAt) {\n stitchingQueueDelay.record(\n -item.stitchRequestedAt.diffNow().as('seconds'),\n );\n }\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n function markComplete(result: string) {\n promStitchedEntities.inc(1);\n stitchedEntities.add(1, { result });\n stitchingDuration.record(endTime(), { result });\n }\n\n function markFailed(error: Error) {\n promStitchedEntities.inc(1);\n stitchedEntities.add(1, { result: 'error' });\n stitchingDuration.record(endTime(), { result: 'error' });\n logger.error(\n `Failed to stitch ${item.entityRef}, ${stringifyError(error)}`,\n );\n }\n\n return {\n markComplete,\n markFailed,\n };\n }\n\n return { stitchStart };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\nimport { Knex } from 'knex';\nimport splitToChunks from 'lodash/chunk';\nimport { DateTime } from 'luxon';\nimport { getDeferredStitchableEntities } from '../database/operations/stitcher/getDeferredStitchableEntities';\nimport { markForStitching } from '../database/operations/stitcher/markForStitching';\nimport { performStitching } from '../database/operations/stitcher/performStitching';\nimport { DbRefreshStateRow } from '../database/tables';\nimport { startTaskPipeline } from '../processing/TaskPipeline';\nimport { progressTracker } from './progressTracker';\nimport {\n Stitcher,\n StitchingStrategy,\n stitchingStrategyFromConfig,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype DeferredStitchItem = Awaited<\n ReturnType\n>[0];\n\ntype StitchProgressTracker = ReturnType;\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport class DefaultStitcher implements Stitcher {\n private readonly knex: Knex;\n private readonly logger: LoggerService;\n private readonly strategy: StitchingStrategy;\n private readonly tracker: StitchProgressTracker;\n private stopFunc?: () => void;\n\n static fromConfig(\n config: Config,\n options: {\n knex: Knex;\n logger: LoggerService;\n },\n ): DefaultStitcher {\n return new DefaultStitcher({\n knex: options.knex,\n logger: options.logger,\n strategy: stitchingStrategyFromConfig(config),\n });\n }\n\n constructor(options: {\n knex: Knex;\n logger: LoggerService;\n strategy: StitchingStrategy;\n }) {\n this.knex = options.knex;\n this.logger = options.logger;\n this.strategy = options.strategy;\n this.tracker = progressTracker(options.knex, options.logger);\n }\n\n async stitch(options: {\n entityRefs?: Iterable;\n entityIds?: Iterable;\n }) {\n const { entityRefs, entityIds } = options;\n\n if (this.strategy.mode === 'deferred') {\n await markForStitching({\n knex: this.knex,\n strategy: this.strategy,\n entityRefs,\n entityIds,\n });\n return;\n }\n\n if (entityRefs) {\n for (const entityRef of entityRefs) {\n await this.#stitchOne({ entityRef });\n }\n }\n\n if (entityIds) {\n const chunks = splitToChunks(\n Array.isArray(entityIds) ? entityIds : [...entityIds],\n 100,\n );\n for (const chunk of chunks) {\n const rows = await this.knex('refresh_state')\n .select('entity_ref')\n .whereIn('entity_id', chunk);\n for (const row of rows) {\n await this.#stitchOne({ entityRef: row.entity_ref });\n }\n }\n }\n }\n\n async start() {\n if (this.strategy.mode === 'deferred') {\n if (this.stopFunc) {\n throw new Error('Processing engine is already started');\n }\n\n const { pollingInterval, stitchTimeout } = this.strategy;\n\n const stopPipeline = startTaskPipeline({\n lowWatermark: 2,\n highWatermark: 5,\n pollingIntervalMs: durationToMilliseconds(pollingInterval),\n loadTasks: async count => {\n return await this.#getStitchableEntities(count, stitchTimeout);\n },\n processTask: async item => {\n return await this.#stitchOne({\n entityRef: item.entityRef,\n stitchTicket: item.stitchTicket,\n stitchRequestedAt: item.stitchRequestedAt,\n });\n },\n });\n\n this.stopFunc = () => {\n stopPipeline();\n };\n }\n }\n\n async stop() {\n if (this.strategy.mode === 'deferred') {\n if (this.stopFunc) {\n this.stopFunc();\n this.stopFunc = undefined;\n }\n }\n }\n\n async #getStitchableEntities(count: number, stitchTimeout: HumanDuration) {\n try {\n return await getDeferredStitchableEntities({\n knex: this.knex,\n batchSize: count,\n stitchTimeout: stitchTimeout,\n });\n } catch (error) {\n this.logger.warn('Failed to load stitchable entities', error);\n return [];\n }\n }\n\n async #stitchOne(options: {\n entityRef: string;\n stitchTicket?: string;\n stitchRequestedAt?: DateTime;\n }) {\n const track = this.tracker.stitchStart({\n entityRef: options.entityRef,\n stitchRequestedAt: options.stitchRequestedAt,\n });\n\n try {\n const result = await performStitching({\n knex: this.knex,\n logger: this.logger,\n strategy: this.strategy,\n entityRef: options.entityRef,\n stitchTicket: options.stitchTicket,\n });\n track.markComplete(result);\n } catch (error) {\n track.markFailed(error);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { Request } from 'express';\nimport { z } from 'zod';\n\nconst schema = z.object({\n entityRefs: z.array(z.string()),\n fields: z.array(z.string()).optional(),\n});\n\nexport function entitiesBatchRequest(req: Request): z.infer {\n try {\n return schema.parse(req.body);\n } catch (error) {\n throw new InputError(\n `Malformed request body (did you remember to specify an application/json content type?), ${error.message}`,\n );\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EntitiesSearchFilter,\n EntityFilter,\n} from '@backstage/plugin-catalog-node';\n\n/**\n * Forms a full EntityFilter based on a single key-value(s) object.\n */\nexport function basicEntityFilter(\n items: Record,\n): EntityFilter {\n const filtersByKey: Record = {};\n\n for (const [key, value] of Object.entries(items)) {\n const values = [value].flat();\n\n const f =\n key in filtersByKey\n ? filtersByKey[key]\n : (filtersByKey[key] = { key, values: [] });\n\n f.values!.push(...values);\n }\n\n return { anyOf: [{ allOf: Object.values(filtersByKey) }] };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\n\n/**\n * Takes a single unknown parameter and makes sure that it's a string that can\n * be parsed as an integer.\n */\nexport function parseIntegerParam(\n param: unknown,\n ctx: string,\n): number | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n if (typeof param !== 'string') {\n throw new InputError(`Invalid ${ctx}, not an integer on string form`);\n }\n\n const parsed = parseInt(param, 10);\n if (!Number.isInteger(parsed) || String(parsed) !== param) {\n throw new InputError(`Invalid ${ctx}, not an integer`);\n }\n\n return parsed;\n}\n\n/**\n * Takes a single unknown parameter and makes sure that it's a string.\n */\nexport function parseStringParam(\n param: unknown,\n ctx: string,\n): string | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n if (typeof param !== 'string') {\n throw new InputError(`Invalid ${ctx}, not a string`);\n }\n\n return param;\n}\n\n/**\n * Takes a single unknown parameter and makes sure that it's a single string or\n * an array of strings, and returns as an array.\n */\nexport function parseStringsParam(\n param: unknown,\n ctx: string,\n): string[] | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n const array = [param].flat();\n if (array.some(p => typeof p !== 'string')) {\n throw new InputError(`Invalid ${ctx}, not a string`);\n }\n\n return array as string[];\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { parseStringsParam } from './common';\nimport {\n EntitiesSearchFilter,\n EntityFilter,\n} from '@backstage/plugin-catalog-node';\n\n/**\n * Parses the filtering part of a query, like\n * /entities?filter=metadata.namespace=default,kind=Component\n */\nexport function parseEntityFilterParams(\n params: Record,\n): EntityFilter | undefined {\n // Each filter string is on the form a=b,c=d\n const filterStrings = parseStringsParam(params.filter, 'filter');\n if (!filterStrings) {\n return undefined;\n }\n\n // Outer array: \"any of the inner ones\"\n // Inner arrays: \"all of these must match\"\n const filters = filterStrings.map(parseEntityFilterString).filter(Boolean);\n if (!filters.length) {\n return undefined;\n }\n\n return { anyOf: filters.map(f => ({ allOf: f! })) };\n}\n\n/**\n * Parses a single filter string as seen in a filter query, for example\n * metadata.namespace=default,kind=Component\n */\nexport function parseEntityFilterString(\n filterString: string,\n): EntitiesSearchFilter[] | undefined {\n const statements = filterString\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n if (!statements.length) {\n return undefined;\n }\n\n const filtersByKey: Record = {};\n\n for (const statement of statements) {\n const equalsIndex = statement.indexOf('=');\n\n const key =\n equalsIndex === -1\n ? statement\n : statement.substring(0, equalsIndex).trim();\n const value =\n equalsIndex === -1\n ? undefined\n : statement.substring(equalsIndex + 1).trim();\n if (!key) {\n throw new InputError(\n `Invalid filter, '${statement}' is not a valid statement (expected a string on the form a=b or a= or a)`,\n );\n }\n\n const f =\n key in filtersByKey ? filtersByKey[key] : (filtersByKey[key] = { key });\n\n if (value !== undefined) {\n f.values = f.values || [];\n f.values.push(value);\n }\n }\n\n return Object.values(filtersByKey);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport lodash from 'lodash';\nimport { RecursivePartial } from '../../util/RecursivePartial';\nimport { parseStringsParam } from './common';\n\nfunction getPathArrayAndValue(input: Entity, field: string) {\n return field.split('.').reduce(\n ([pathArray, inputSubset], pathPart, index, fieldParts) => {\n if (lodash.hasIn(inputSubset, pathPart)) {\n return [pathArray.concat(pathPart), inputSubset[pathPart]];\n } else if (fieldParts[index + 1] !== undefined) {\n fieldParts[index + 1] = `${pathPart}.${fieldParts[index + 1]}`;\n return [pathArray, inputSubset];\n }\n\n return [pathArray, undefined];\n },\n [[] as string[], input as any],\n );\n}\n\nexport function parseEntityTransformParams(\n params: Record,\n extra?: string[],\n): ((entity: Entity) => Entity) | undefined {\n const queryFields = parseStringsParam(params.fields, 'fields');\n\n const fields = Array.from(\n new Set(\n [...(extra ?? []), ...(queryFields?.map(s => s.split(',')) ?? [])]\n .flat()\n .map(s => s.trim())\n .filter(Boolean),\n ),\n );\n\n if (!fields.length) {\n return undefined;\n }\n\n const arrayTypeField = fields.find(f => f.includes('['));\n if (arrayTypeField) {\n throw new InputError(\n `Invalid field \"${arrayTypeField}\", array type fields are not supported`,\n );\n }\n\n return input => {\n const output: RecursivePartial = {};\n\n for (const field of fields) {\n const [pathArray, value] = getPathArrayAndValue(input, field);\n\n if (value !== undefined) {\n lodash.set(output, pathArray, value);\n }\n }\n\n return output as Entity;\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { EntityOrder } from '../../catalog/types';\nimport { parseStringsParam } from './common';\n\nexport function parseEntityOrderFieldParams(\n params: Record,\n): EntityOrder[] | undefined {\n const orderFieldStrings = parseStringsParam(params.orderField, 'orderField');\n if (!orderFieldStrings) {\n return undefined;\n }\n\n return orderFieldStrings.map(orderFieldString => {\n const [field, order] = orderFieldString.split(',');\n\n if (order !== undefined && !isOrder(order)) {\n throw new InputError('Invalid order field order, must be asc or desc');\n }\n return { field, order };\n });\n}\n\nexport function isOrder(order: string): order is 'asc' | 'desc' {\n return ['asc', 'desc'].includes(order);\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n QueryEntitiesCursorRequest,\n QueryEntitiesInitialRequest,\n QueryEntitiesRequest,\n} from '../../catalog/types';\nimport { decodeCursor } from '../util';\nimport { parseEntityFilterParams } from './parseEntityFilterParams';\nimport { parseEntityOrderFieldParams } from './parseEntityOrderFieldParams';\nimport { parseEntityTransformParams } from './parseEntityTransformParams';\nimport { spec } from '../../schema/openapi.generated';\nimport { internal } from '@backstage/backend-openapi-utils';\n\nexport function parseQueryEntitiesParams(\n params: internal.QuerySchema,\n): Omit {\n const fields = parseEntityTransformParams(params);\n\n if (params.cursor) {\n const decodedCursor = decodeCursor(params.cursor);\n const response: Omit = {\n cursor: decodedCursor,\n fields,\n };\n return response;\n }\n\n const filter = parseEntityFilterParams(params);\n const orderFields = parseEntityOrderFieldParams(params);\n\n const response: Omit = {\n fields,\n filter,\n orderFields,\n fullTextFilter: {\n term: params.fullTextFilterTerm || '',\n fields: params.fullTextFilterFields,\n },\n };\n\n return response;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { parseStringsParam } from './common';\n\n/**\n * Parses the facets part of a facet query, like\n * /entity-facets?filter=metadata.namespace=default,kind=Component&facet=metadata.namespace\n */\nexport function parseEntityFacetParams(\n params: Record,\n): string[] {\n // Each facet string is on the form a.b.c\n const facetStrings = parseStringsParam(params.facet, 'facet');\n if (facetStrings) {\n const filtered = facetStrings.filter(Boolean);\n if (filtered.length) {\n return filtered;\n }\n }\n\n throw new InputError('Missing facet parameter');\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { EntityOrder } from '../../catalog/types';\nimport { parseStringsParam } from './common';\n\nexport function parseEntityOrderParams(\n params: Record,\n): EntityOrder[] | undefined {\n return parseStringsParam(params.order, 'order')?.map(item => {\n const match = item.match(/^(asc|desc):(.+)$/);\n if (!match) {\n throw new InputError(\n `Invalid order parameter \"${item}\", expected \":\"`,\n );\n }\n\n return {\n order: match[1] as 'asc' | 'desc',\n field: match[2],\n };\n });\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ******************************************************************\n// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *\n// ******************************************************************\nimport { createValidatedOpenApiRouter } from '@backstage/backend-openapi-utils';\n\nexport const spec = {\n openapi: '3.0.3',\n info: {\n title: 'catalog',\n version: '1',\n description:\n 'The Backstage backend plugin that provides the Backstage catalog',\n license: {\n name: 'Apache-2.0',\n url: 'http://www.apache.org/licenses/LICENSE-2.0.html',\n },\n contact: {},\n },\n servers: [\n {\n url: '/',\n },\n ],\n components: {\n examples: {},\n headers: {},\n parameters: {\n kind: {\n name: 'kind',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n namespace: {\n name: 'namespace',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n name: {\n name: 'name',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n uid: {\n name: 'uid',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n cursor: {\n name: 'cursor',\n in: 'query',\n description: 'Cursor to a set page of results.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n minLength: 1,\n },\n },\n after: {\n name: 'after',\n in: 'query',\n description: 'Pointer to the previous page of results.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n minLength: 1,\n },\n },\n fields: {\n name: 'fields',\n in: 'query',\n description: 'Restrict to just these fields in the response.',\n required: false,\n allowReserved: true,\n explode: false,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n examples: {\n 'Get name and the entire relations collection': {\n value: ['metadata.name', 'relations'],\n },\n 'Get kind, name and namespace': {\n value: ['kind', 'metadata.name', 'metadata.namespace'],\n },\n },\n },\n filter: {\n name: 'filter',\n in: 'query',\n description: 'Filter for just the entities defined by this filter.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n examples: {\n 'Get groups': {\n value: ['kind=group'],\n },\n 'Get orphaned components': {\n value: [\n 'kind=component,metadata.annotations.backstage.io/orphan=true',\n ],\n },\n },\n },\n offset: {\n name: 'offset',\n in: 'query',\n description: 'Number of records to skip in the query page.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'integer',\n minimum: 0,\n },\n },\n limit: {\n name: 'limit',\n in: 'query',\n description: 'Number of records to return in the response.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'integer',\n minimum: 0,\n },\n },\n orderField: {\n name: 'orderField',\n in: 'query',\n description: 'The fields to sort returned results by.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n description: 'A two-item tuple of [field, order].',\n },\n },\n explode: true,\n style: 'form',\n examples: {\n 'Order ascending by name': {\n value: ['metadata.name,asc'],\n },\n 'Order descending by owner': {\n value: ['spec.owner,desc'],\n },\n },\n },\n },\n requestBodies: {},\n responses: {\n ErrorResponse: {\n description: 'An error response from the backend.',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Error',\n },\n },\n },\n },\n },\n schemas: {\n Error: {\n type: 'object',\n properties: {\n error: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n },\n message: {\n type: 'string',\n },\n stack: {\n type: 'string',\n },\n code: {\n type: 'string',\n },\n },\n required: ['name', 'message'],\n },\n request: {\n type: 'object',\n properties: {\n method: {\n type: 'string',\n },\n url: {\n type: 'string',\n },\n },\n required: ['method', 'url'],\n },\n response: {\n type: 'object',\n properties: {\n statusCode: {\n type: 'number',\n },\n },\n required: ['statusCode'],\n },\n },\n required: ['error', 'response'],\n additionalProperties: {},\n },\n JsonObject: {\n type: 'object',\n properties: {},\n description: 'A type representing all allowed JSON object values.',\n additionalProperties: {},\n },\n MapStringString: {\n type: 'object',\n properties: {},\n additionalProperties: {\n type: 'string',\n },\n description: 'Construct a type with a set of properties K of type T',\n },\n EntityLink: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n description:\n 'An optional value to categorize links into specific groups',\n },\n icon: {\n type: 'string',\n description:\n 'An optional semantic key that represents a visual icon.',\n },\n title: {\n type: 'string',\n description: 'An optional descriptive title for the link.',\n },\n url: {\n type: 'string',\n description: 'The url to the external site, document, etc.',\n },\n },\n required: ['url'],\n description:\n 'A link to external information that is related to the entity.',\n additionalProperties: false,\n },\n EntityMeta: {\n type: 'object',\n properties: {\n links: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityLink',\n },\n description: 'A list of external hyperlinks related to the entity.',\n },\n tags: {\n type: 'array',\n items: {\n type: 'string',\n },\n description:\n 'A list of single-valued strings, to for example classify catalog entities in\\nvarious ways.',\n },\n annotations: {\n $ref: '#/components/schemas/MapStringString',\n },\n labels: {\n $ref: '#/components/schemas/MapStringString',\n },\n description: {\n type: 'string',\n description:\n 'A short (typically relatively few words, on one line) description of the\\nentity.',\n },\n title: {\n type: 'string',\n description:\n 'A display name of the entity, to be presented in user interfaces instead\\nof the `name` property above, when available.\\nThis field is sometimes useful when the `name` is cumbersome or ends up\\nbeing perceived as overly technical. The title generally does not have\\nas stringent format requirements on it, so it may contain special\\ncharacters and be more explanatory. Do keep it very short though, and\\navoid situations where a title can be confused with the name of another\\nentity, or where two entities share a title.\\nNote that this is only for display purposes, and may be ignored by some\\nparts of the code. Entity references still always make use of the `name`\\nproperty, not the title.',\n },\n namespace: {\n type: 'string',\n description: 'The namespace that the entity belongs to.',\n },\n name: {\n type: 'string',\n description:\n 'The name of the entity.\\nMust be unique within the catalog at any given point in time, for any\\ngiven namespace + kind pair. This value is part of the technical\\nidentifier of the entity, and as such it will appear in URLs, database\\ntables, entity references, and similar. It is subject to restrictions\\nregarding what characters are allowed.\\nIf you want to use a different, more human readable string with fewer\\nrestrictions on it in user interfaces, see the `title` field below.',\n },\n etag: {\n type: 'string',\n description:\n 'An opaque string that changes for each update operation to any part of\\nthe entity, including metadata.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, and the server will then reject the\\noperation if it does not match the current stored value.',\n },\n uid: {\n type: 'string',\n description:\n 'A globally unique ID for the entity.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, but the server is free to reject requests\\nthat do so in such a way that it breaks semantics.',\n },\n },\n required: ['name'],\n description: 'Metadata fields common to all versions/kinds of entity.',\n additionalProperties: {},\n },\n EntityRelation: {\n type: 'object',\n properties: {\n targetRef: {\n type: 'string',\n description: 'The entity ref of the target of this relation.',\n },\n type: {\n type: 'string',\n description: 'The type of the relation.',\n },\n },\n required: ['targetRef', 'type'],\n description:\n 'A relation of a specific type to another entity in the catalog.',\n additionalProperties: false,\n },\n Entity: {\n type: 'object',\n properties: {\n relations: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityRelation',\n },\n description:\n 'The relations that this entity has with other entities.',\n },\n spec: {\n $ref: '#/components/schemas/JsonObject',\n },\n metadata: {\n $ref: '#/components/schemas/EntityMeta',\n },\n kind: {\n type: 'string',\n description: 'The high level entity type being described.',\n },\n apiVersion: {\n type: 'string',\n description:\n 'The version of specification format for this particular entity that\\nthis is written against.',\n },\n },\n required: ['metadata', 'kind', 'apiVersion'],\n description:\n \"The parts of the format that's common to all versions/kinds of entity.\",\n },\n NullableEntity: {\n type: 'object',\n properties: {\n relations: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityRelation',\n },\n description:\n 'The relations that this entity has with other entities.',\n },\n spec: {\n $ref: '#/components/schemas/JsonObject',\n },\n metadata: {\n $ref: '#/components/schemas/EntityMeta',\n },\n kind: {\n type: 'string',\n description: 'The high level entity type being described.',\n },\n apiVersion: {\n type: 'string',\n description:\n 'The version of specification format for this particular entity that\\nthis is written against.',\n },\n },\n required: ['metadata', 'kind', 'apiVersion'],\n description:\n \"The parts of the format that's common to all versions/kinds of entity.\",\n nullable: true,\n },\n EntityAncestryResponse: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n parentEntityRefs: {\n items: {\n type: 'string',\n },\n type: 'array',\n },\n entity: {\n $ref: '#/components/schemas/Entity',\n },\n },\n required: ['parentEntityRefs', 'entity'],\n },\n },\n rootEntityRef: {\n type: 'string',\n },\n },\n required: ['items', 'rootEntityRef'],\n additionalProperties: false,\n },\n EntitiesBatchResponse: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/NullableEntity',\n },\n description:\n 'The list of entities, in the same order as the refs in the request. Entries\\nthat are null signify that no entity existed with that ref.',\n },\n },\n required: ['items'],\n additionalProperties: false,\n },\n EntityFacet: {\n type: 'object',\n properties: {\n value: {\n type: 'string',\n },\n count: {\n type: 'number',\n },\n },\n required: ['value', 'count'],\n additionalProperties: false,\n },\n EntityFacetsResponse: {\n type: 'object',\n properties: {\n facets: {\n type: 'object',\n additionalProperties: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityFacet',\n },\n },\n },\n },\n required: ['facets'],\n additionalProperties: false,\n },\n Location: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n },\n type: {\n type: 'string',\n },\n id: {\n type: 'string',\n },\n },\n required: ['target', 'type', 'id'],\n description: 'Entity location for a specific entity.',\n additionalProperties: false,\n },\n LocationSpec: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n },\n type: {\n type: 'string',\n },\n },\n required: ['target', 'type'],\n description: 'Holds the entity location information.',\n additionalProperties: false,\n },\n AnalyzeLocationExistingEntity: {\n type: 'object',\n properties: {\n entity: {\n $ref: '#/components/schemas/Entity',\n },\n isRegistered: {\n type: 'boolean',\n },\n location: {\n $ref: '#/components/schemas/LocationSpec',\n },\n },\n required: ['entity', 'isRegistered', 'location'],\n description:\n \"If the folder pointed to already contained catalog info yaml files, they are\\nread and emitted like this so that the frontend can inform the user that it\\nlocated them and can make sure to register them as well if they weren't\\nalready\",\n additionalProperties: false,\n },\n RecursivePartialEntityRelation: {\n type: 'object',\n properties: {\n targetRef: {\n type: 'string',\n description: 'The entity ref of the target of this relation.',\n },\n type: {\n type: 'string',\n description: 'The type of the relation.',\n },\n },\n description:\n 'A relation of a specific type to another entity in the catalog.',\n additionalProperties: false,\n },\n RecursivePartialEntityMeta: {\n allOf: [\n {\n $ref: '#/components/schemas/JsonObject',\n },\n {\n type: 'object',\n properties: {\n links: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityLink',\n },\n description:\n 'A list of external hyperlinks related to the entity.',\n },\n tags: {\n type: 'array',\n items: {\n type: 'string',\n },\n description:\n 'A list of single-valued strings, to for example classify catalog entities in\\nvarious ways.',\n },\n annotations: {\n $ref: '#/components/schemas/MapStringString',\n },\n labels: {\n $ref: '#/components/schemas/MapStringString',\n },\n description: {\n type: 'string',\n description:\n 'A short (typically relatively few words, on one line) description of the\\nentity.',\n },\n title: {\n type: 'string',\n description:\n 'A display name of the entity, to be presented in user interfaces instead\\nof the `name` property above, when available.\\nThis field is sometimes useful when the `name` is cumbersome or ends up\\nbeing perceived as overly technical. The title generally does not have\\nas stringent format requirements on it, so it may contain special\\ncharacters and be more explanatory. Do keep it very short though, and\\navoid situations where a title can be confused with the name of another\\nentity, or where two entities share a title.\\nNote that this is only for display purposes, and may be ignored by some\\nparts of the code. Entity references still always make use of the `name`\\nproperty, not the title.',\n },\n namespace: {\n type: 'string',\n description: 'The namespace that the entity belongs to.',\n },\n name: {\n type: 'string',\n description:\n 'The name of the entity.\\nMust be unique within the catalog at any given point in time, for any\\ngiven namespace + kind pair. This value is part of the technical\\nidentifier of the entity, and as such it will appear in URLs, database\\ntables, entity references, and similar. It is subject to restrictions\\nregarding what characters are allowed.\\nIf you want to use a different, more human readable string with fewer\\nrestrictions on it in user interfaces, see the `title` field below.',\n },\n etag: {\n type: 'string',\n description:\n 'An opaque string that changes for each update operation to any part of\\nthe entity, including metadata.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, and the server will then reject the\\noperation if it does not match the current stored value.',\n },\n uid: {\n type: 'string',\n description:\n 'A globally unique ID for the entity.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, but the server is free to reject requests\\nthat do so in such a way that it breaks semantics.',\n },\n },\n description:\n 'Metadata fields common to all versions/kinds of entity.',\n },\n ],\n additionalProperties: false,\n },\n RecursivePartialEntity: {\n type: 'object',\n properties: {\n apiVersion: {\n type: 'string',\n description:\n 'The version of specification format for this particular entity that\\nthis is written against.',\n },\n kind: {\n type: 'string',\n description: 'The high level entity type being described.',\n },\n metadata: {\n $ref: '#/components/schemas/RecursivePartialEntityMeta',\n },\n spec: {\n $ref: '#/components/schemas/JsonObject',\n },\n relations: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/RecursivePartialEntityRelation',\n },\n description:\n 'The relations that this entity has with other entities.',\n },\n },\n description: 'Makes all keys of an entire hierarchy optional.',\n additionalProperties: false,\n },\n AnalyzeLocationEntityField: {\n type: 'object',\n properties: {\n description: {\n type: 'string',\n description:\n 'A text to show to the user to inform about the choices made. Like, it could say\\n\"Found a CODEOWNERS file that covers this target, so we suggest leaving this\\nfield empty; which would currently make it owned by X\" where X is taken from the\\ncodeowners file.',\n },\n value: {\n type: 'string',\n nullable: true,\n },\n state: {\n type: 'string',\n enum: [\n 'analysisSuggestedValue',\n 'analysisSuggestedNoValue',\n 'needsUserInput',\n ],\n description:\n 'The outcome of the analysis for this particular field',\n },\n field: {\n type: 'string',\n description:\n 'e.g. \"spec.owner\"? The frontend needs to know how to \"inject\" the field into the\\nentity again if the user wants to change it',\n },\n },\n required: ['description', 'value', 'state', 'field'],\n additionalProperties: false,\n },\n AnalyzeLocationGenerateEntity: {\n type: 'object',\n properties: {\n fields: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/AnalyzeLocationEntityField',\n },\n },\n entity: {\n $ref: '#/components/schemas/RecursivePartialEntity',\n },\n },\n required: ['fields', 'entity'],\n description:\n \"This is some form of representation of what the analyzer could deduce.\\nWe should probably have a chat about how this can best be conveyed to\\nthe frontend. It'll probably contain a (possibly incomplete) entity, plus\\nenough info for the frontend to know what form data to show to the user\\nfor overriding/completing the info.\",\n additionalProperties: false,\n },\n AnalyzeLocationResponse: {\n type: 'object',\n properties: {\n generateEntities: {\n items: {\n $ref: '#/components/schemas/AnalyzeLocationGenerateEntity',\n },\n type: 'array',\n },\n existingEntityFiles: {\n items: {\n $ref: '#/components/schemas/AnalyzeLocationExistingEntity',\n },\n type: 'array',\n },\n },\n required: ['generateEntities', 'existingEntityFiles'],\n additionalProperties: false,\n },\n LocationInput: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n },\n target: {\n type: 'string',\n },\n },\n required: ['type', 'target'],\n additionalProperties: false,\n },\n EntitiesQueryResponse: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/Entity',\n },\n description: 'The list of entities paginated by a specific filter.',\n },\n totalItems: {\n type: 'number',\n },\n pageInfo: {\n type: 'object',\n properties: {\n nextCursor: {\n type: 'string',\n description: 'The cursor for the next batch of entities.',\n },\n prevCursor: {\n type: 'string',\n description: 'The cursor for the previous batch of entities.',\n },\n },\n },\n },\n required: ['items', 'totalItems', 'pageInfo'],\n additionalProperties: false,\n },\n },\n securitySchemes: {\n JWT: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n },\n },\n },\n paths: {\n '/refresh': {\n post: {\n operationId: 'RefreshEntity',\n description: 'Refresh the entity related to entityRef.',\n responses: {\n '200': {\n description: 'Refreshed',\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n authorizationToken: {\n type: 'string',\n },\n entityRef: {\n type: 'string',\n description:\n 'The reference to a single entity that should be refreshed',\n },\n },\n required: ['entityRef'],\n description:\n 'Options for requesting a refresh of entities in the catalog.',\n additionalProperties: false,\n },\n },\n },\n },\n },\n },\n '/entities': {\n get: {\n operationId: 'GetEntities',\n description: 'Get all entities matching a given filter.',\n responses: {\n '200': {\n description: '',\n content: {\n 'application/json': {\n schema: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/Entity',\n },\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/fields',\n },\n {\n $ref: '#/components/parameters/limit',\n },\n {\n $ref: '#/components/parameters/filter',\n },\n {\n $ref: '#/components/parameters/offset',\n },\n {\n $ref: '#/components/parameters/after',\n },\n {\n name: 'order',\n in: 'query',\n allowReserved: true,\n required: false,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n },\n ],\n },\n },\n '/entities/by-uid/{uid}': {\n get: {\n operationId: 'GetEntityByUid',\n description: 'Get a single entity by the UID.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Entity',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/uid',\n },\n ],\n },\n delete: {\n operationId: 'DeleteEntityByUid',\n description: 'Delete a single entity by UID.',\n responses: {\n '204': {\n description: 'Deleted successfully.',\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/uid',\n },\n ],\n },\n },\n '/entities/by-name/{kind}/{namespace}/{name}': {\n get: {\n operationId: 'GetEntityByName',\n description: 'Get an entity by an entity ref.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Entity',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/kind',\n },\n {\n $ref: '#/components/parameters/namespace',\n },\n {\n $ref: '#/components/parameters/name',\n },\n ],\n },\n },\n '/entities/by-name/{kind}/{namespace}/{name}/ancestry': {\n get: {\n operationId: 'GetEntityAncestryByName',\n description: \"Get an entity's ancestry by entity ref.\",\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntityAncestryResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/kind',\n },\n {\n $ref: '#/components/parameters/namespace',\n },\n {\n $ref: '#/components/parameters/name',\n },\n ],\n },\n },\n '/entities/by-refs': {\n post: {\n operationId: 'GetEntitiesByRefs',\n description:\n 'Get a batch set of entities given an array of entityRefs.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntitiesBatchResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n requestBody: {\n required: false,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n required: ['entityRefs'],\n properties: {\n entityRefs: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n fields: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n },\n },\n examples: {\n 'Fetch Backstage entities': {\n value: {\n entityRefs: [\n 'component:default/backstage',\n 'api:default/backstage',\n ],\n },\n },\n 'Fetch annotations for backstage entity': {\n value: {\n entityRefs: ['component:default/backstage'],\n fields: ['metadata.annotations'],\n },\n },\n },\n },\n },\n },\n parameters: [\n {\n $ref: '#/components/parameters/filter',\n },\n ],\n },\n },\n '/entities/by-query': {\n get: {\n operationId: 'GetEntitiesByQuery',\n description: 'Search for entities by a given query.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntitiesQueryResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/fields',\n },\n {\n $ref: '#/components/parameters/limit',\n },\n {\n $ref: '#/components/parameters/orderField',\n },\n {\n $ref: '#/components/parameters/cursor',\n },\n {\n $ref: '#/components/parameters/filter',\n },\n {\n name: 'fullTextFilterTerm',\n in: 'query',\n description: 'Text search term.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n {\n name: 'fullTextFilterFields',\n in: 'query',\n description:\n 'A comma separated list of fields to sort returned results by.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n explode: false,\n style: 'form',\n },\n ],\n },\n },\n '/entity-facets': {\n get: {\n operationId: 'GetEntityFacets',\n description: 'Get all entity facets that match the given filters.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntityFacetsResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'query',\n name: 'facet',\n required: true,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n examples: {\n 'Entities by kind': {\n value: ['kind'],\n },\n 'Entities by spec type': {\n value: ['spec.type'],\n },\n },\n },\n {\n $ref: '#/components/parameters/filter',\n },\n ],\n },\n },\n '/locations': {\n post: {\n operationId: 'CreateLocation',\n description: 'Create a location for a given target.',\n responses: {\n '201': {\n description: 'Created',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n exists: {\n type: 'boolean',\n },\n entities: {\n items: {\n $ref: '#/components/schemas/Entity',\n },\n type: 'array',\n },\n location: {\n $ref: '#/components/schemas/Location',\n },\n },\n required: ['entities', 'location'],\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'query',\n name: 'dryRun',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n },\n type: {\n type: 'string',\n },\n },\n required: ['target', 'type'],\n },\n },\n },\n },\n },\n get: {\n operationId: 'GetLocations',\n description: 'Get all locations',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n data: {\n $ref: '#/components/schemas/Location',\n },\n },\n required: ['data'],\n },\n },\n },\n },\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n },\n },\n '/locations/{id}': {\n get: {\n operationId: 'GetLocation',\n description: 'Get a location by id.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Location',\n },\n },\n },\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'path',\n name: 'id',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n },\n delete: {\n operationId: 'DeleteLocation',\n description: 'Delete a location by id.',\n responses: {\n '204': {\n description: 'No content',\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'path',\n name: 'id',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n },\n },\n '/locations/by-entity/{kind}/{namespace}/{name}': {\n get: {\n operationId: 'getLocationByEntity',\n description: 'Get a location for entity.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Location',\n },\n },\n },\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'path',\n name: 'kind',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n {\n in: 'path',\n name: 'namespace',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n {\n in: 'path',\n name: 'name',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n },\n },\n '/analyze-location': {\n post: {\n operationId: 'AnalyzeLocation',\n description: 'Validate a given location.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/AnalyzeLocationResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n catalogFileName: {\n type: 'string',\n },\n location: {\n $ref: '#/components/schemas/LocationInput',\n },\n },\n required: ['location'],\n },\n },\n },\n },\n },\n },\n '/validate-entity': {\n post: {\n operationId: 'ValidateEntity',\n description:\n 'Validate that a passed in entity has no errors in schema.',\n responses: {\n '200': {\n description: 'Ok',\n },\n '400': {\n description: 'Validation errors.',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n errors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n },\n message: {\n type: 'string',\n },\n },\n required: ['name', 'message'],\n additionalProperties: {},\n },\n },\n },\n required: ['errors'],\n },\n },\n },\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n location: {\n type: 'string',\n },\n entity: {\n type: 'object',\n additionalProperties: {},\n },\n },\n required: ['location', 'entity'],\n },\n },\n },\n },\n },\n },\n },\n} as const;\nexport const createOpenApiRouter = async (\n options?: Parameters['1'],\n) => createValidatedOpenApiRouter(spec, options);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { EntityPagination } from '../../catalog/types';\n\n/**\n * Parses the pagination related parameters out of a query, e.g.\n * /entities?offset=100&limit=10\n */\nexport function parseEntityPaginationParams({\n limit,\n offset,\n after,\n}: {\n offset?: number;\n limit?: number;\n after?: string;\n}): EntityPagination | undefined {\n if (offset === undefined && limit === undefined && after === undefined) {\n return undefined;\n }\n\n if (offset !== undefined && offset < 0) {\n throw new InputError(`Invalid offset, must be zero or greater`);\n }\n if (limit !== undefined && limit <= 0) {\n throw new InputError(`Invalid limit, must be greater than zero`);\n }\n if (after !== undefined && !after) {\n throw new InputError(`Invalid after, must not be empty`);\n }\n\n return {\n ...(offset !== undefined ? { offset } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(after !== undefined ? { after } : {}),\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError, serializeError } from '@backstage/errors';\nimport express from 'express';\nimport yn from 'yn';\nimport { z } from 'zod';\nimport { EntitiesCatalog } from '../catalog/types';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { validateEntityEnvelope } from '../processing/util';\nimport {\n basicEntityFilter,\n entitiesBatchRequest,\n parseEntityFilterParams,\n parseEntityTransformParams,\n parseQueryEntitiesParams,\n} from './request';\nimport { parseEntityFacetParams } from './request/parseEntityFacetParams';\nimport { parseEntityOrderParams } from './request/parseEntityOrderParams';\nimport { LocationService, RefreshService } from './types';\nimport {\n disallowReadonlyMode,\n encodeCursor,\n locationInput,\n validateRequestBody,\n} from './util';\nimport { createOpenApiRouter } from '../schema/openapi.generated';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { parseEntityPaginationParams } from './request/parseEntityPaginationParams';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { LocationAnalyzer } from '@backstage/plugin-catalog-node';\n\n/**\n * Options used by {@link createRouter}.\n *\n * @public\n */\nexport interface RouterOptions {\n entitiesCatalog?: EntitiesCatalog;\n locationAnalyzer?: LocationAnalyzer;\n locationService: LocationService;\n orchestrator?: CatalogProcessingOrchestrator;\n refreshService?: RefreshService;\n scheduler?: PluginTaskScheduler;\n logger: LoggerService;\n config: Config;\n permissionIntegrationRouter?: express.Router;\n auth: AuthService;\n httpAuth: HttpAuthService;\n}\n\n/**\n * Creates a catalog router.\n *\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = await createOpenApiRouter({\n validatorOptions: {\n // We want the spec to be up to date with the expected value, but the return type needs\n // to be controlled by the router implementation not the request validator.\n ignorePaths: /^\\/validate-entity\\/?$/,\n },\n });\n const {\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n config,\n logger,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n } = options;\n\n const readonlyEnabled =\n config.getOptionalBoolean('catalog.readonly') || false;\n if (readonlyEnabled) {\n logger.info('Catalog is running in readonly mode');\n }\n\n if (refreshService) {\n router.post('/refresh', async (req, res) => {\n const { authorizationToken, ...restBody } = req.body;\n\n const credentials = authorizationToken\n ? await auth.authenticate(authorizationToken)\n : await httpAuth.credentials(req);\n\n await refreshService.refresh({\n ...restBody,\n credentials,\n });\n res.status(200).end();\n });\n }\n\n if (permissionIntegrationRouter) {\n router.use(permissionIntegrationRouter);\n }\n\n if (entitiesCatalog) {\n router\n .get('/entities', async (req, res) => {\n const { entities, pageInfo } = await entitiesCatalog.entities({\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query),\n order: parseEntityOrderParams(req.query),\n pagination: parseEntityPaginationParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n // Add a Link header to the next page\n if (pageInfo.hasNextPage) {\n const url = new URL(`http://ignored${req.url}`);\n url.searchParams.delete('offset');\n url.searchParams.set('after', pageInfo.endCursor);\n res.setHeader('link', `<${url.pathname}${url.search}>; rel=\"next\"`);\n }\n\n // TODO(freben): encode the pageInfo in the response\n res.json(entities);\n })\n .get('/entities/by-query', async (req, res) => {\n const { items, pageInfo, totalItems } =\n await entitiesCatalog.queryEntities({\n limit: req.query.limit,\n ...parseQueryEntitiesParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n res.json({\n items,\n totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n });\n })\n .get('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(`No entity with uid ${uid}`);\n }\n res.status(200).json(entities[0]);\n })\n .delete('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n await entitiesCatalog.removeEntityByUid(uid, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(204).end();\n })\n .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({\n kind: kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(\n `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`,\n );\n }\n res.status(200).json(entities[0]);\n })\n .get(\n '/entities/by-name/:kind/:namespace/:name/ancestry',\n async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const response = await entitiesCatalog.entityAncestry(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n },\n )\n .post('/entities/by-refs', async (req, res) => {\n const request = entitiesBatchRequest(req);\n const response = await entitiesCatalog.entitiesBatch({\n entityRefs: request.entityRefs,\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query, request.fields),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n })\n .get('/entity-facets', async (req, res) => {\n const response = await entitiesCatalog.facets({\n filter: parseEntityFilterParams(req.query),\n facets: parseEntityFacetParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n });\n }\n\n if (locationService) {\n router\n .post('/locations', async (req, res) => {\n const location = await validateRequestBody(req, locationInput);\n const dryRun = yn(req.query.dryRun, { default: false });\n\n // when in dryRun addLocation is effectively a read operation so we don't\n // need to disallow readonly\n if (!dryRun) {\n disallowReadonlyMode(readonlyEnabled);\n }\n\n const output = await locationService.createLocation(location, dryRun, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(201).json(output);\n })\n .get('/locations', async (req, res) => {\n const locations = await locationService.listLocations({\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(locations.map(l => ({ data: l })));\n })\n\n .get('/locations/:id', async (req, res) => {\n const { id } = req.params;\n const output = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(output);\n })\n .delete('/locations/:id', async (req, res) => {\n disallowReadonlyMode(readonlyEnabled);\n\n const { id } = req.params;\n await locationService.deleteLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(204).end();\n })\n .get('/locations/by-entity/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const output = await locationService.getLocationByEntity(\n { kind, namespace, name },\n { credentials: await httpAuth.credentials(req) },\n );\n res.status(200).json(output);\n });\n }\n\n if (locationAnalyzer) {\n router.post('/analyze-location', async (req, res) => {\n const body = await validateRequestBody(\n req,\n z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n }),\n );\n const schema = z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n });\n const parsedBody = schema.parse(body);\n try {\n const output = await locationAnalyzer.analyzeLocation(parsedBody);\n res.status(200).json(output);\n } catch (err) {\n if (\n // Catch errors from parse-url library.\n err.name === 'Error' &&\n 'subject_url' in err\n ) {\n throw new InputError('The given location.target is not a URL');\n }\n throw err;\n }\n });\n }\n\n if (orchestrator) {\n router.post('/validate-entity', async (req, res) => {\n const bodySchema = z.object({\n entity: z.unknown(),\n location: z.string(),\n });\n\n let body: z.infer;\n let entity: Entity;\n let location: { type: string; target: string };\n try {\n body = await validateRequestBody(req, bodySchema);\n entity = validateEntityEnvelope(body.entity);\n location = parseLocationRef(body.location);\n if (location.type !== 'url')\n throw new TypeError(\n `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path`,\n );\n } catch (err) {\n return res.status(400).json({\n errors: [serializeError(err)],\n });\n }\n\n const processingResult = await orchestrator.process({\n entity: {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n [ANNOTATION_LOCATION]: body.location,\n [ANNOTATION_ORIGIN_LOCATION]: body.location,\n ...entity.metadata.annotations,\n },\n },\n },\n });\n\n if (!processingResult.ok)\n res.status(400).json({\n errors: processingResult.errors.map(e => serializeError(e)),\n });\n return res.status(200).end();\n });\n }\n\n router.use(errorHandler());\n return router;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { RefreshOptions, RefreshService } from './types';\n\nexport class DefaultRefreshService implements RefreshService {\n private database: DefaultCatalogDatabase;\n\n constructor(options: { database: DefaultCatalogDatabase }) {\n this.database = options.database;\n }\n\n async refresh(options: RefreshOptions) {\n await this.database.transaction(async tx => {\n const { entityRefs } = await this.database.listAncestors(tx, {\n entityRef: options.entityRef,\n });\n const locationAncestor = entityRefs.find(ref =>\n ref.startsWith('location:'),\n );\n\n // TODO: Refreshes are currently scheduled(as soon as possible) for execution and will therefore happen in the future.\n // There's room for improvements here where the refresh could potentially hang or return an ID so that the user can check progress.\n if (locationAncestor) {\n await this.database.refresh(tx, {\n entityRef: locationAncestor,\n });\n }\n await this.database.refresh(tx, {\n entityRef: options.entityRef,\n });\n });\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotAllowedError } from '@backstage/errors';\nimport { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { RefreshOptions, RefreshService } from './types';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\n\nexport class AuthorizedRefreshService implements RefreshService {\n constructor(\n private readonly service: RefreshService,\n private readonly permissionApi: PermissionsService,\n ) {}\n\n async refresh(options: RefreshOptions) {\n const authorizeDecision = (\n await this.permissionApi.authorize(\n [\n {\n permission: catalogEntityRefreshPermission,\n resourceRef: options.entityRef,\n },\n ],\n { credentials: options.credentials },\n )\n )[0];\n if (authorizeDecision.result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError();\n }\n await this.service.refresh(options);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Entity } from '@backstage/catalog-model';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { minimatch } from 'minimatch';\n\n/**\n * Rules to apply to catalog entities.\n *\n * An undefined list of matchers means match all, an empty list of matchers means match none.\n */\nexport type CatalogRule = {\n allow: Array<{\n kind: string;\n }>;\n locations?: Array<{\n exact?: string;\n type: string;\n pattern?: string;\n }>;\n};\n\n/**\n * Decides whether an entity from a given location is allowed to enter the\n * catalog, according to some rule set.\n */\nexport type CatalogRulesEnforcer = {\n isAllowed(entity: Entity, location: LocationSpec): boolean;\n};\n\n/**\n * Implements the default catalog rule set, consuming the config keys\n * `catalog.rules` and `catalog.locations.[].rules`.\n */\nexport class DefaultCatalogRulesEnforcer implements CatalogRulesEnforcer {\n /**\n * Default rules used by the catalog.\n *\n * Denies any location from specifying user or group entities.\n */\n static readonly defaultRules: CatalogRule[] = [\n {\n allow: ['Component', 'API', 'Location'].map(kind => ({ kind })),\n },\n ];\n\n /**\n * Loads catalog rules from config.\n *\n * This reads `catalog.rules` and defaults to the default rules if no value is present.\n * The value of the config should be a list of config objects, each with a single `allow`\n * field which in turn is a list of entity kinds to allow.\n *\n * If there is no matching rule to allow an ingested entity, it will be rejected by the catalog.\n *\n * It also reads in rules from `catalog.locations`, where each location can have a list\n * of rules for that specific location, specified in a `rules` field.\n *\n * For example:\n *\n * ```yaml\n * catalog:\n * rules:\n * - allow: [Component, API]\n * - allow: [Template]\n * locations:\n * - type: url\n * pattern: https://github.com/org/*\\/blob/master/template.yaml\n * - allow: [Location]\n * locations:\n * - type: url\n * pattern: https://github.com/org/repo/blob/master/location.yaml\n *\n * locations:\n * - type: url\n * target: https://github.com/org/repo/blob/master/users.yaml\n * rules:\n * - allow: [User, Group]\n * - type: url\n * target: https://github.com/org/repo/blob/master/systems.yaml\n * rules:\n * - allow: [System]\n * ```\n */\n static fromConfig(config: Config) {\n const rules = new Array();\n\n if (config.has('catalog.rules')) {\n const globalRules = config\n .getConfigArray('catalog.rules')\n .map(ruleConf => ({\n allow: ruleConf.getStringArray('allow').map(kind => ({ kind })),\n locations: ruleConf\n .getOptionalConfigArray('locations')\n ?.map(locationConfig => {\n const location = {\n pattern: locationConfig.getOptionalString('pattern'),\n type: locationConfig.getString('type'),\n exact: locationConfig.getOptionalString('exact'),\n };\n if (location.pattern && location.exact) {\n throw new Error(\n 'A catalog rule location cannot have both exact and pattern values',\n );\n }\n return location;\n }),\n }));\n rules.push(...globalRules);\n } else {\n rules.push(...DefaultCatalogRulesEnforcer.defaultRules);\n }\n\n if (config.has('catalog.locations')) {\n const locationRules = config\n .getConfigArray('catalog.locations')\n .flatMap(locConf => {\n if (!locConf.has('rules')) {\n return [];\n }\n const type = locConf.getString('type');\n const exact = resolveTarget(type, locConf.getString('target'));\n\n return locConf.getConfigArray('rules').map(ruleConf => ({\n allow: ruleConf.getStringArray('allow').map(kind => ({ kind })),\n locations: [{ type, exact }],\n }));\n });\n\n rules.push(...locationRules);\n }\n\n return new DefaultCatalogRulesEnforcer(rules);\n }\n\n constructor(private readonly rules: CatalogRule[]) {}\n\n /**\n * Checks whether a specific entity/location combination is allowed\n * according to the configured rules.\n */\n isAllowed(entity: Entity, location: LocationSpec) {\n for (const rule of this.rules) {\n if (!this.matchLocation(location, rule.locations)) {\n continue;\n }\n\n if (this.matchEntity(entity, rule.allow)) {\n return true;\n }\n }\n\n return false;\n }\n\n private matchLocation(\n location: LocationSpec,\n matchers?: { exact?: string; type: string; pattern?: string }[],\n ): boolean {\n if (!matchers) {\n return true;\n }\n\n for (const matcher of matchers) {\n if (matcher.type !== location?.type) {\n continue;\n }\n if (matcher.exact && matcher.exact !== location?.target) {\n continue;\n }\n if (\n matcher.pattern &&\n !minimatch(location?.target, matcher.pattern, {\n nocase: true,\n dot: true,\n })\n ) {\n continue;\n }\n return true;\n }\n\n return false;\n }\n\n private matchEntity(entity: Entity, matchers?: { kind: string }[]): boolean {\n if (!matchers) {\n return true;\n }\n\n for (const matcher of matchers) {\n if (entity?.kind?.toLowerCase() !== matcher.kind.toLowerCase()) {\n continue;\n }\n\n return true;\n }\n\n return false;\n }\n}\n\nfunction resolveTarget(type: string, target: string): string {\n if (type !== 'file') {\n return target;\n }\n\n return path.resolve(target);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n entityEnvelopeSchemaValidator,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { ProviderDatabase } from '../database/types';\nimport {\n EntityProvider,\n EntityProviderConnection,\n EntityProviderRefreshOptions,\n EntityProviderMutation,\n} from '@backstage/plugin-catalog-node';\n\nclass Connection implements EntityProviderConnection {\n readonly validateEntityEnvelope = entityEnvelopeSchemaValidator();\n\n constructor(\n private readonly config: {\n id: string;\n providerDatabase: ProviderDatabase;\n },\n ) {}\n\n async applyMutation(mutation: EntityProviderMutation): Promise {\n const db = this.config.providerDatabase;\n\n if (mutation.type === 'full') {\n this.check(mutation.entities.map(e => e.entity));\n await db.transaction(async tx => {\n await db.replaceUnprocessedEntities(tx, {\n sourceKey: this.config.id,\n type: 'full',\n items: mutation.entities,\n });\n });\n } else if (mutation.type === 'delta') {\n this.check(mutation.added.map(e => e.entity));\n this.check(\n mutation.removed\n .map(e => ('entity' in e ? e.entity : undefined))\n .filter((e): e is Entity => Boolean(e)),\n );\n await db.transaction(async tx => {\n await db.replaceUnprocessedEntities(tx, {\n sourceKey: this.config.id,\n type: 'delta',\n added: mutation.added,\n removed: mutation.removed.map(r =>\n 'entityRef' in r\n ? r\n : {\n entityRef: stringifyEntityRef(r.entity),\n locationKey: r.locationKey,\n },\n ),\n });\n });\n }\n }\n\n async refresh(options: EntityProviderRefreshOptions): Promise {\n const db = this.config.providerDatabase;\n\n await db.transaction(async (tx: any) => {\n return db.refreshByRefreshKeys(tx, {\n keys: options.keys,\n });\n });\n }\n\n private check(entities: Entity[]) {\n for (const entity of entities) {\n try {\n this.validateEntityEnvelope(entity);\n } catch (e) {\n throw new TypeError(`Malformed entity envelope, ${e}`);\n }\n }\n }\n}\n\nexport async function connectEntityProviders(\n db: ProviderDatabase,\n providers: EntityProvider[],\n) {\n await Promise.all(\n providers.map(async provider => {\n const connection = new Connection({\n id: provider.getProviderName(),\n providerDatabase: db,\n });\n return provider.connect(connection);\n }),\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { EntitiesSearchFilter } from '@backstage/plugin-catalog-node';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport {\n makeCreatePermissionRule,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\n\n/**\n * Convenience type for {@link @backstage/plugin-permission-node#PermissionRule}\n * instances with the correct resource type, resource, and filter to work with\n * the catalog.\n *\n * @alpha\n */\nexport type CatalogPermissionRule<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule;\n\n/**\n * Helper function for creating correctly-typed\n * {@link @backstage/plugin-permission-node#PermissionRule}s for the\n * catalog-backend.\n *\n * @alpha\n */\nexport const createCatalogPermissionRule = makeCreatePermissionRule<\n Entity,\n EntitiesSearchFilter,\n typeof RESOURCE_TYPE_CATALOG_ENTITY\n>();\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for the presence of an annotation on a given entity.\n *\n * If a value is given, it filters for the annotation value, too.\n *\n * @alpha\n */\nexport const hasAnnotation = createCatalogPermissionRule({\n name: 'HAS_ANNOTATION',\n description: 'Allow entities with the specified annotation',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n annotation: z.string().describe('Name of the annotation to match on'),\n value: z\n .string()\n .optional()\n .describe('Value of the annotation to match on'),\n }),\n apply: (resource, { annotation, value }) =>\n !!resource.metadata.annotations?.hasOwnProperty(annotation) &&\n (value === undefined\n ? true\n : resource.metadata.annotations?.[annotation] === value),\n toQuery: ({ annotation, value }) =>\n value === undefined\n ? {\n key: `metadata.annotations.${annotation}`,\n }\n : {\n key: `metadata.annotations.${annotation}`,\n values: [value],\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified kind.\n * @alpha\n */\nexport const isEntityKind = createCatalogPermissionRule({\n name: 'IS_ENTITY_KIND',\n description: 'Allow entities matching a specified kind',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n kinds: z\n .array(z.string())\n .describe('List of kinds to match at least one of'),\n }),\n apply(resource, { kinds }) {\n const resourceKind = resource.kind.toLocaleLowerCase('en-US');\n return kinds.some(kind => kind.toLocaleLowerCase('en-US') === resourceKind);\n },\n toQuery({ kinds }) {\n return {\n key: 'kind',\n values: kinds.map(kind => kind.toLocaleLowerCase('en-US')),\n };\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified owner.\n *\n * @alpha\n */\nexport const isEntityOwner = createCatalogPermissionRule({\n name: 'IS_ENTITY_OWNER',\n description: 'Allow entities owned by a specified claim',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n claims: z\n .array(z.string())\n .describe(\n `List of claims to match at least one on within ${RELATION_OWNED_BY}`,\n ),\n }),\n apply: (resource, { claims }) => {\n if (!resource.relations) {\n return false;\n }\n\n return resource.relations\n .filter(relation => relation.type === RELATION_OWNED_BY)\n .some(relation => claims.includes(relation.targetRef));\n },\n toQuery: ({ claims }) => ({\n key: 'relations.ownedBy',\n values: claims,\n }),\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified label in its metadata.\n * @alpha\n */\nexport const hasLabel = createCatalogPermissionRule({\n name: 'HAS_LABEL',\n description: 'Allow entities with the specified label',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n label: z.string().describe('Name of the label to match on'),\n }),\n apply: (resource, { label }) =>\n !!resource.metadata.labels?.hasOwnProperty(label),\n toQuery: ({ label }) => ({\n key: `metadata.labels.${label}`,\n }),\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { get } from 'lodash';\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { createCatalogPermissionRule } from './util';\nimport { z } from 'zod';\n\nexport const createPropertyRule = (propertyType: 'metadata' | 'spec') =>\n createCatalogPermissionRule({\n name: `HAS_${propertyType.toUpperCase()}`,\n description: `Allow entities with the specified ${propertyType} subfield`,\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n key: z\n .string()\n .describe(`Property within the entities ${propertyType} to match on`),\n value: z\n .string()\n .optional()\n .describe(`Value of the given property to match on`),\n }),\n apply: (resource, { key, value }) => {\n const foundValue = get(resource[propertyType], key);\n\n if (Array.isArray(foundValue)) {\n if (value !== undefined) {\n return foundValue.includes(value);\n }\n return foundValue.length > 0;\n }\n if (value !== undefined) {\n return value === foundValue;\n }\n return !!foundValue;\n },\n toQuery: ({ key, value }) => ({\n key: `${propertyType}.${key}`,\n ...(value !== undefined && { values: [value] }),\n }),\n });\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPropertyRule } from './createPropertyRule';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with the specified metadata subfield. Also matches on\n * values if value is provided.\n *\n * The key argument to the `apply` and `toQuery` methods can be nested, such as\n * 'field.nestedfield'.\n * @alpha\n */\nexport const hasMetadata = createPropertyRule('metadata');\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPropertyRule } from './createPropertyRule';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with the specified spec subfield. Also matches on values\n * if value is provided.\n *\n * The key argument to the `apply` and `toQuery` methods can be nested, such as\n * 'field.nestedfield'.\n * @alpha\n */\nexport const hasSpec = createPropertyRule('spec');\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { hasAnnotation } from './hasAnnotation';\nimport { isEntityKind } from './isEntityKind';\nimport { isEntityOwner } from './isEntityOwner';\nimport { hasLabel } from './hasLabel';\nimport { hasMetadata } from './hasMetadata';\nimport { hasSpec } from './hasSpec';\n\n/**\n * These permission rules can be used to conditionally filter catalog entities\n * or describe a user's access to the entities.\n *\n * @alpha\n */\nexport const permissionRules = {\n hasAnnotation,\n hasLabel,\n hasMetadata,\n hasSpec,\n isEntityKind,\n isEntityOwner,\n};\n\nexport type { CatalogPermissionRule } from './util';\nexport { createCatalogPermissionRule } from './util';\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n catalogEntityDeletePermission,\n catalogEntityReadPermission,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { ConditionTransformer } from '@backstage/plugin-permission-node';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport { basicEntityFilter } from './request';\nimport { isQueryEntitiesCursorRequest } from './util';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\nexport class AuthorizedEntitiesCatalog implements EntitiesCatalog {\n constructor(\n private readonly entitiesCatalog: EntitiesCatalog,\n private readonly permissionApi: PermissionsService,\n private readonly transformConditions: ConditionTransformer,\n ) {}\n\n async entities(request: EntitiesRequest): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n entities: [],\n pageInfo: { hasNextPage: false },\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entities({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entities(request);\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: new Array(request.entityRefs.length).fill(null),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entitiesBatch({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entitiesBatch(request);\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: [],\n pageInfo: {},\n totalItems: 0,\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n\n let permissionedRequest: QueryEntitiesRequest;\n let requestFilter: EntityFilter | undefined;\n\n if (isQueryEntitiesCursorRequest(request)) {\n requestFilter = request.cursor.filter;\n\n permissionedRequest = {\n ...request,\n cursor: {\n ...request.cursor,\n filter: request.cursor.filter\n ? { allOf: [permissionFilter, request.cursor.filter] }\n : permissionFilter,\n },\n };\n } else {\n permissionedRequest = {\n ...request,\n filter: request.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n };\n requestFilter = request.filter;\n }\n\n const response = await this.entitiesCatalog.queryEntities(\n permissionedRequest,\n );\n\n const prevCursor: Cursor | undefined = response.pageInfo.prevCursor && {\n ...response.pageInfo.prevCursor,\n filter: requestFilter,\n };\n\n const nextCursor: Cursor | undefined = response.pageInfo.nextCursor && {\n ...response.pageInfo.nextCursor,\n filter: requestFilter,\n };\n\n return {\n ...response,\n pageInfo: {\n prevCursor,\n nextCursor,\n },\n };\n }\n\n return this.entitiesCatalog.queryEntities(request);\n }\n\n async removeEntityByUid(\n uid: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizeResponse = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityDeletePermission }],\n { credentials: options.credentials },\n )\n )[0];\n if (authorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n if (authorizeResponse.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeResponse.conditions,\n );\n const { entities } = await this.entitiesCatalog.entities({\n credentials: options.credentials,\n filter: {\n allOf: [permissionFilter, basicEntityFilter({ 'metadata.uid': uid })],\n },\n });\n if (entities.length === 0) {\n throw new NotAllowedError();\n }\n }\n return this.entitiesCatalog.removeEntityByUid(uid, {\n credentials: options.credentials,\n });\n }\n\n async entityAncestry(\n entityRef: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const rootEntityAuthorizeResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogEntityReadPermission, resourceRef: entityRef }],\n { credentials: options.credentials },\n )\n )[0];\n if (rootEntityAuthorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n const ancestryResult = await this.entitiesCatalog.entityAncestry(\n entityRef,\n { credentials: options.credentials },\n );\n const authorizeResponse = await this.permissionApi.authorize(\n ancestryResult.items.map(item => ({\n permission: catalogEntityReadPermission,\n resourceRef: stringifyEntityRef(item.entity),\n })),\n { credentials: options.credentials },\n );\n const unauthorizedAncestryItems = ancestryResult.items.filter(\n (_, index) => authorizeResponse[index].result === AuthorizeResult.DENY,\n );\n if (unauthorizedAncestryItems.length === 0) {\n return ancestryResult;\n }\n const rootUnauthorizedEntityRefs = unauthorizedAncestryItems.map(\n ancestryItem => stringifyEntityRef(ancestryItem.entity),\n );\n const allUnauthorizedEntityRefs = new Set(\n rootUnauthorizedEntityRefs.flatMap(rootEntityRef =>\n this.findParents(\n rootEntityRef,\n ancestryResult.items,\n new Set(rootUnauthorizedEntityRefs),\n ),\n ),\n );\n return {\n rootEntityRef: ancestryResult.rootEntityRef,\n items: ancestryResult.items.filter(\n ancestryItem =>\n !allUnauthorizedEntityRefs.has(\n stringifyEntityRef(ancestryItem.entity),\n ),\n ),\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n facets: Object.fromEntries(request.facets.map(f => [f, []])),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.facets({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.facets(request);\n }\n\n private findParents(\n entityRef: string,\n allAncestryItems: { entity: Entity; parentEntityRefs: string[] }[],\n seenEntityRefs: Set,\n ): string[] {\n const entity = allAncestryItems.find(\n ancestryItem => stringifyEntityRef(ancestryItem.entity) === entityRef,\n );\n if (!entity) return [];\n\n const newSeenEntityRefs = new Set(seenEntityRefs);\n entity.parentEntityRefs.forEach(parentRef =>\n newSeenEntityRefs.add(parentRef),\n );\n\n return [\n entityRef,\n ...entity.parentEntityRefs.flatMap(parentRef =>\n seenEntityRefs.has(parentRef)\n ? []\n : this.findParents(parentRef, allAncestryItems, newSeenEntityRefs),\n ),\n ];\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Location } from '@backstage/catalog-client';\nimport { CompoundEntityRef, Entity } from '@backstage/catalog-model';\nimport { NotAllowedError, NotFoundError } from '@backstage/errors';\nimport {\n catalogLocationCreatePermission,\n catalogLocationDeletePermission,\n catalogLocationReadPermission,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { LocationInput, LocationService } from './types';\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\nexport class AuthorizedLocationService implements LocationService {\n constructor(\n private readonly locationService: LocationService,\n private readonly permissionApi: PermissionsService,\n ) {}\n\n async createLocation(\n spec: LocationInput,\n dryRun: boolean,\n options: {\n credentials: BackstageCredentials;\n },\n ): Promise<{\n location: Location;\n entities: Entity[];\n exists?: boolean | undefined;\n }> {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationCreatePermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n return this.locationService.createLocation(spec, dryRun, options);\n }\n\n async listLocations(options: {\n credentials: BackstageCredentials;\n }): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationReadPermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n return [];\n }\n\n return this.locationService.listLocations(options);\n }\n\n async getLocation(\n id: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationReadPermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotFoundError(`Found no location with ID ${id}`);\n }\n\n return this.locationService.getLocation(id, options);\n }\n\n async deleteLocation(\n id: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationDeletePermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n return this.locationService.deleteLocation(id, options);\n }\n\n async getLocationByEntity(\n entityRef: CompoundEntityRef | string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationReadPermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotFoundError();\n }\n return this.locationService.getLocationByEntity(entityRef, options);\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport {\n DbFinalEntitiesRow,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n} from '../../tables';\n\n/**\n * Given a number of entity refs originally created by a given entity provider\n * (source key), remove those entities from the refresh state, and at the same\n * time recursively remove every child that is a direct or indirect result of\n * processing those entities, if they would have otherwise become orphaned by\n * the removal of their parents.\n */\nexport async function deleteWithEagerPruningOfChildren(options: {\n knex: Knex | Knex.Transaction;\n entityRefs: string[];\n sourceKey: string;\n}): Promise {\n const { knex, entityRefs, sourceKey } = options;\n\n // Split up the operation by (large) chunks, so that we do not hit database\n // limits for the number of permitted bindings on a precompiled statement\n let removedCount = 0;\n for (const refs of lodash.chunk(entityRefs, 1000)) {\n const { orphanEntityRefs } =\n await findDescendantsThatWouldHaveBeenOrphanedByDeletion({\n knex: options.knex,\n refs,\n sourceKey,\n });\n\n // Chunk again - these can be many more than the outer chunk size\n for (const refsToDelete of lodash.chunk(orphanEntityRefs, 1000)) {\n await markEntitiesAffectedByDeletionForStitching({\n knex: options.knex,\n entityRefs: refsToDelete,\n });\n await knex\n .delete()\n .from('refresh_state')\n .whereIn('entity_ref', refsToDelete);\n }\n\n // Delete the references that originate only from this entity provider. Note\n // that there may be more than one entity provider making a \"claim\" for a\n // given root entity, if they emit with the same location key.\n await knex('refresh_state_references')\n .where('source_key', '=', sourceKey)\n .whereIn('target_entity_ref', refs)\n .delete();\n\n removedCount += orphanEntityRefs.length;\n }\n\n return removedCount;\n}\n\nasync function findDescendantsThatWouldHaveBeenOrphanedByDeletion(options: {\n knex: Knex | Knex.Transaction;\n refs: string[];\n sourceKey: string;\n}): Promise<{ orphanEntityRefs: string[] }> {\n const { knex, refs, sourceKey } = options;\n\n const orphans: string[] =\n // First find all nodes that can be reached downwards from the roots\n // (deletion targets), including the roots themselves, by traversing\n // down the refresh_state_references table. Note that this query\n // starts with a condition that source_key = our source key, and\n // target_entity_ref is one of the deletion targets. This has two\n // effects: it won't match attempts at deleting something that didn't\n // originate from us in the first place, and also won't match non-root\n // entities (source_key would be null for those).\n //\n // KeyA - R1 - R2 Legend:\n // \\ -----------------------------------------\n // R3 Key* Source key\n // / R* Entity ref\n // KeyA - R4 - R5 lines Individual references; sources to\n // / the left and targets to the right\n // KeyB --- R6\n //\n // The scenario is that KeyA wants to delete R1.\n //\n // The query starts with the KeyA-R1 reference, and then traverses\n // down to also find R2 and R3. It uses union instead of union all,\n // because it wants to find the set of unique descendants even if\n // the tree has unexpected loops etc.\n await knex\n .withRecursive('descendants', ['entity_ref'], initial =>\n initial\n .select('target_entity_ref')\n .from('refresh_state_references')\n .where('source_key', '=', sourceKey)\n .whereIn('target_entity_ref', refs)\n .union(recursive =>\n recursive\n .select('refresh_state_references.target_entity_ref')\n .from('descendants')\n .join(\n 'refresh_state_references',\n 'descendants.entity_ref',\n 'refresh_state_references.source_entity_ref',\n ),\n ),\n )\n // Then for each descendant, traverse all the way back upwards through\n // the refresh_state_references table to get an exhaustive list of all\n // references that are part of keeping that particular descendant\n // alive.\n //\n // Continuing the scenario from above, starting from R3, it goes\n // upwards to find every pair along every relation line.\n //\n // Top branch: R2-R3, R1-R2, KeyA-R1\n // Middle branch: R5-R3, R4-R5, KeyA-R4\n // Bottom branch: R6-R5, KeyB-R6\n //\n // Note that this all applied to the subject R3. The exact same thing\n // will be done starting from each other descendant (R2 and R1). They\n // only have one and two references to find, respectively.\n //\n // This query also uses union instead of union all, to get the set of\n // distinct relations even if the tree has unexpected loops etc.\n .withRecursive(\n 'ancestors',\n ['source_key', 'source_entity_ref', 'target_entity_ref', 'subject'],\n initial =>\n initial\n .select(\n 'refresh_state_references.source_key',\n 'refresh_state_references.source_entity_ref',\n 'refresh_state_references.target_entity_ref',\n 'descendants.entity_ref',\n )\n .from('descendants')\n .join(\n 'refresh_state_references',\n 'refresh_state_references.target_entity_ref',\n 'descendants.entity_ref',\n )\n .union(recursive =>\n recursive\n .select(\n 'refresh_state_references.source_key',\n 'refresh_state_references.source_entity_ref',\n 'refresh_state_references.target_entity_ref',\n 'ancestors.subject',\n )\n .from('ancestors')\n .join(\n 'refresh_state_references',\n 'refresh_state_references.target_entity_ref',\n 'ancestors.source_entity_ref',\n ),\n ),\n )\n // Finally, from that list of ancestor relations per descendant, pick\n // out the ones that are roots (have a source_key). Specifically, find\n // ones that seem to be be either (1) from another source, or (2)\n // aren't part of the deletion targets. Those are markers that tell us\n // that the corresponding descendant should be kept alive and NOT\n // subject to eager deletion, because there's \"something else\" (not\n // targeted for deletion) that has references down through the tree to\n // it.\n //\n // Continuing the scenario from above, for R3 we have\n //\n // KeyA-R1, KeyA-R4, KeyB-R6\n //\n // This tells us that R3 should be kept alive for two reasons: it's\n // referenced by a node that isn't being deleted (R4), and also by\n // another source (KeyB). What about R1 and R2? They both have\n //\n // KeyA-R1\n //\n // So those should be deleted, since they are definitely only being\n // kept alive by something that's about to be deleted.\n //\n // Final shape of the tree:\n //\n // R3\n // /\n // KeyA - R4 - R5\n // /\n // KeyB --- R6\n .with('retained', ['entity_ref'], notPartOfDeletion =>\n notPartOfDeletion\n .select('subject')\n .from('ancestors')\n .whereNotNull('ancestors.source_key')\n .where(foreignKeyOrRef =>\n foreignKeyOrRef\n .where('ancestors.source_key', '!=', sourceKey)\n .orWhereNotIn('ancestors.target_entity_ref', refs),\n ),\n )\n // Return all descendants minus the retained ones\n .select('descendants.entity_ref AS entity_ref')\n .from('descendants')\n .leftOuterJoin(\n 'retained',\n 'retained.entity_ref',\n 'descendants.entity_ref',\n )\n .whereNull('retained.entity_ref')\n .then(rows => rows.map(row => row.entity_ref));\n\n return { orphanEntityRefs: orphans };\n}\n\nasync function markEntitiesAffectedByDeletionForStitching(options: {\n knex: Knex | Knex.Transaction;\n entityRefs: string[];\n}) {\n const { knex, entityRefs } = options;\n\n // We want to re-stitch anything that has a relation pointing to the\n // soon-to-be-deleted entity. In many circumstances we also re-stitch children\n // in the refresh_state_references graph because their orphan state might\n // change, but not here - this code by its very definition is meant to not\n // leave any orphans behind, so we can simplify away that.\n const affectedIds = await knex\n .select('refresh_state.entity_id AS entity_id')\n .from('relations')\n .join(\n 'refresh_state',\n 'relations.source_entity_ref',\n 'refresh_state.entity_ref',\n )\n .whereIn('relations.target_entity_ref', entityRefs)\n .then(rows => rows.map(row => row.entity_id));\n\n for (const ids of lodash.chunk(affectedIds, 1000)) {\n await knex\n .table('final_entities')\n .update({\n hash: 'force-stitching',\n })\n .whereIn('entity_id', ids);\n await knex\n .table('refresh_state')\n .update({\n result_hash: 'force-stitching',\n next_update_at: knex.fn.now(),\n })\n .whereIn('entity_id', ids);\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Schedules a future refresh of entities, by so called \"refresh keys\" that may\n * be associated with one or more entities. Note that this does not mean that\n * the refresh happens immediately, but rather that their scheduling time gets\n * moved up the queue and will get picked up eventually by the regular\n * processing loop.\n */\nexport async function refreshByRefreshKeys(options: {\n tx: Knex.Transaction;\n keys: string[];\n}): Promise {\n const { tx, keys } = options;\n\n await tx('refresh_state')\n .whereIn('entity_id', function selectEntityRefs(inner) {\n inner\n .whereIn('key', keys)\n .select({\n entity_id: 'refresh_keys.entity_id',\n })\n .from('refresh_keys');\n })\n .update({ next_update_at: tx.fn.now() });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport { v4 as uuid } from 'uuid';\nimport { rethrowError } from './conversion';\nimport { deleteWithEagerPruningOfChildren } from './operations/provider/deleteWithEagerPruningOfChildren';\nimport { refreshByRefreshKeys } from './operations/provider/refreshByRefreshKeys';\nimport { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict';\nimport { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity';\nimport { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity';\nimport { DbRefreshStateReferencesRow, DbRefreshStateRow } from './tables';\nimport {\n ProviderDatabase,\n RefreshByKeyOptions,\n ReplaceUnprocessedEntitiesOptions,\n Transaction,\n} from './types';\nimport { generateStableHash } from './util';\nimport {\n LoggerService,\n isDatabaseConflictError,\n} from '@backstage/backend-plugin-api';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nconst BATCH_SIZE = 50;\n\nexport class DefaultProviderDatabase implements ProviderDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n },\n ) {}\n\n async transaction(fn: (tx: Transaction) => Promise): Promise {\n try {\n let result: T | undefined = undefined;\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the\n // transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n async replaceUnprocessedEntities(\n txOpaque: Transaction,\n options: ReplaceUnprocessedEntitiesOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { toAdd, toUpsert, toRemove } = await this.createDelta(tx, options);\n\n if (toRemove.length) {\n const removedCount = await deleteWithEagerPruningOfChildren({\n knex: tx,\n entityRefs: toRemove,\n sourceKey: options.sourceKey,\n });\n this.options.logger.debug(\n `removed, ${removedCount} entities: ${JSON.stringify(toRemove)}`,\n );\n }\n\n if (toAdd.length) {\n // The reason for this chunking, rather than just massively batch\n // inserting the entire payload, is that we fall back to the individual\n // upsert mechanism below on conflicts. That path is massively slower than\n // the fast batch path, so we don't want to end up accidentally having to\n // for example item-by-item upsert tens of thousands of entities in a\n // large initial delivery dump. The implication is that the size of these\n // chunks needs to weigh the benefit of fast successful inserts, against\n // the drawback of super slow but more rare fallbacks. There's quickly\n // diminishing returns though with turning up this value way high.\n for (const chunk of lodash.chunk(toAdd, 50)) {\n try {\n await tx.batchInsert(\n 'refresh_state',\n chunk.map(item => ({\n entity_id: uuid(),\n entity_ref: stringifyEntityRef(item.deferred.entity),\n unprocessed_entity: JSON.stringify(item.deferred.entity),\n unprocessed_hash: item.hash,\n errors: '',\n location_key: item.deferred.locationKey,\n next_update_at: tx.fn.now(),\n last_discovery_at: tx.fn.now(),\n })),\n BATCH_SIZE,\n );\n await tx.batchInsert(\n 'refresh_state_references',\n chunk.map(item => ({\n source_key: options.sourceKey,\n target_entity_ref: stringifyEntityRef(item.deferred.entity),\n })),\n BATCH_SIZE,\n );\n } catch (error) {\n if (!isDatabaseConflictError(error)) {\n throw error;\n } else {\n this.options.logger.debug(\n `Fast insert path failed, falling back to slow path, ${error}`,\n );\n toUpsert.push(...chunk);\n }\n }\n }\n }\n\n if (toUpsert.length) {\n for (const {\n deferred: { entity, locationKey },\n hash,\n } of toUpsert) {\n const entityRef = stringifyEntityRef(entity);\n\n try {\n let ok = await updateUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n });\n if (!ok) {\n ok = await insertUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n logger: this.options.logger,\n });\n }\n\n await tx('refresh_state_references')\n .where('target_entity_ref', entityRef)\n .andWhere({ source_key: options.sourceKey })\n .delete();\n\n if (ok) {\n await tx(\n 'refresh_state_references',\n ).insert({\n source_key: options.sourceKey,\n target_entity_ref: entityRef,\n });\n } else {\n const conflictingKey = await checkLocationKeyConflict({\n tx,\n entityRef,\n locationKey,\n });\n if (conflictingKey) {\n this.options.logger.warn(\n `Source ${options.sourceKey} detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`,\n );\n }\n }\n } catch (error) {\n this.options.logger.error(\n `Failed to add '${entityRef}' from source '${options.sourceKey}', ${error}`,\n );\n }\n }\n }\n }\n\n async refreshByRefreshKeys(\n txOpaque: Transaction,\n options: RefreshByKeyOptions,\n ) {\n const tx = txOpaque as Knex.Transaction;\n await refreshByRefreshKeys({ tx, keys: options.keys });\n }\n\n private async createDelta(\n tx: Knex.Transaction,\n options: ReplaceUnprocessedEntitiesOptions,\n ): Promise<{\n toAdd: { deferred: DeferredEntity; hash: string }[];\n toUpsert: { deferred: DeferredEntity; hash: string }[];\n toRemove: string[];\n }> {\n if (options.type === 'delta') {\n return {\n toAdd: [],\n toUpsert: options.added.map(e => ({\n deferred: e,\n hash: generateStableHash(e.entity),\n })),\n toRemove: options.removed.map(e => e.entityRef),\n };\n }\n\n // Grab all of the existing references from the same source, and their locationKeys as well\n const oldRefs = await tx(\n 'refresh_state_references',\n )\n .leftJoin('refresh_state', {\n target_entity_ref: 'entity_ref',\n })\n .where({ source_key: options.sourceKey })\n .select({\n target_entity_ref: 'refresh_state_references.target_entity_ref',\n location_key: 'refresh_state.location_key',\n unprocessed_hash: 'refresh_state.unprocessed_hash',\n });\n\n const items = options.items.map(deferred => ({\n deferred,\n ref: stringifyEntityRef(deferred.entity),\n hash: generateStableHash(deferred.entity),\n }));\n\n const oldRefsSet = new Map(\n oldRefs.map(r => [\n r.target_entity_ref,\n {\n locationKey: r.location_key,\n oldEntityHash: r.unprocessed_hash,\n },\n ]),\n );\n const newRefsSet = new Set(items.map(item => item.ref));\n\n const toAdd = new Array<{ deferred: DeferredEntity; hash: string }>();\n const toUpsert = new Array<{ deferred: DeferredEntity; hash: string }>();\n const toRemove = oldRefs\n .map(row => row.target_entity_ref)\n .filter(ref => !newRefsSet.has(ref));\n\n for (const item of items) {\n const oldRef = oldRefsSet.get(item.ref);\n const upsertItem = { deferred: item.deferred, hash: item.hash };\n if (!oldRef) {\n // Add any entity that does not exist in the database\n toAdd.push(upsertItem);\n } else if (\n (oldRef?.locationKey ?? undefined) !==\n (item.deferred.locationKey ?? undefined)\n ) {\n // Remove and then re-add any entity that exists, but with a different location key\n toRemove.push(item.ref);\n toAdd.push(upsertItem);\n } else if (oldRef.oldEntityHash !== item.hash) {\n // Entities with modifications should be pushed through too\n toUpsert.push(upsertItem);\n }\n }\n\n return { toAdd, toUpsert, toRemove };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport {\n CatalogDatabase,\n ListAncestorsOptions,\n ListAncestorsResult,\n RefreshOptions,\n Transaction,\n} from './types';\nimport { DbRefreshStateReferencesRow, DbRefreshStateRow } from './tables';\nimport { rethrowError } from './conversion';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst MAX_ANCESTOR_DEPTH = 32;\n\nexport class DefaultCatalogDatabase implements CatalogDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n },\n ) {}\n\n async transaction(fn: (tx: Transaction) => Promise): Promise {\n try {\n let result: T | undefined = undefined;\n\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n async listAncestors(\n txOpaque: Transaction,\n options: ListAncestorsOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { entityRef } = options;\n const entityRefs = new Array();\n\n let currentRef = entityRef.toLocaleLowerCase('en-US');\n for (let depth = 1; depth <= MAX_ANCESTOR_DEPTH; depth += 1) {\n const rows = await tx(\n 'refresh_state_references',\n )\n .where({ target_entity_ref: currentRef })\n .select();\n\n if (rows.length === 0) {\n if (depth === 1) {\n throw new NotFoundError(`Entity ${currentRef} not found`);\n }\n throw new NotFoundError(\n `Entity ${entityRef} has a broken parent reference chain at ${currentRef}`,\n );\n }\n\n const parentRef = rows.find(r => r.source_entity_ref)?.source_entity_ref;\n if (!parentRef) {\n // We've reached the top of the tree which is the entityProvider.\n // In this case we refresh the entity itself.\n return { entityRefs };\n }\n entityRefs.push(parentRef);\n currentRef = parentRef;\n }\n throw new Error(\n `Unable receive ancestors for ${entityRef}, reached maximum depth of ${MAX_ANCESTOR_DEPTH}`,\n );\n }\n\n async refresh(txOpaque: Transaction, options: RefreshOptions): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { entityRef } = options;\n\n const updateResult = await tx('refresh_state')\n .where({ entity_ref: entityRef.toLocaleLowerCase('en-US') })\n .update({ next_update_at: tx.fn.now() });\n if (updateResult === 0) {\n throw new NotFoundError(`Failed to schedule ${entityRef} for refresh`);\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n PluginDatabaseManager,\n UrlReader,\n} from '@backstage/backend-common';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport {\n DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n parseEntityRef,\n SchemaValidEntityPolicy,\n stringifyEntityRef,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash, { keyBy } from 'lodash';\n\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntitiesSearchFilter,\n EntityProvider,\n PlaceholderResolver,\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n CodeOwnersProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../modules';\nimport { ConfigLocationEntityProvider } from '../modules/core/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../modules/core/DefaultLocationStore';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../modules/core/PlaceholderProcessor';\nimport { defaultEntityDataParser } from '../modules/util/parse';\nimport {\n CatalogProcessingEngine,\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { createRouter } from './createRouter';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport {\n Permission,\n PermissionAuthorizer,\n PermissionRuleParams,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { basicEntityFilter } from './request';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API.\n *\n * @public\n */\nexport type CatalogPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule;\n\n/** @public */\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: PluginDatabaseManager;\n config: Config;\n reader: UrlReader;\n permissions: PermissionsService | PermissionAuthorizer;\n scheduler?: PluginTaskScheduler;\n discovery?: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n *\n * @public\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record;\n private fieldFormatValidators: Partial;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n CodeOwnersProcessor.fromConfig(config, { logger, reader }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n discovery = HostDiscovery.fromConfig(config),\n } = this.env;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...this.env,\n discovery,\n });\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n createConditionTransformer(this.permissionRules),\n );\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources: async (resourceRefs: string[]) => {\n const { entities } = await unauthorizedEntitiesCatalog.entities({\n credentials: await auth.getOwnServiceCredentials(),\n filter: {\n anyOf: resourceRefs.map(resourceRef => {\n const { kind, namespace, name } = parseEntityRef(resourceRef);\n\n return basicEntityFilter({\n kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n });\n }),\n },\n });\n\n const entitiesByRef = keyBy(entities, stringifyEntityRef);\n\n return resourceRefs.map(\n resourceRef =>\n entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],\n );\n },\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers);\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n });\n\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n // These are only added unless the user replaced them all\n if (!this.processorsReplace) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["codeowners","parseGitUrl","NotFoundError","ScmIntegrations","stringifyLocationRef","merge","pickBy","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","ANNOTATION_VIEW_URL","ANNOTATION_EDIT_URL","ANNOTATION_SOURCE_LOCATION","identity","apiEntityV1alpha1Validator","componentEntityV1alpha1Validator","resourceEntityV1alpha1Validator","groupEntityV1alpha1Validator","locationEntityV1alpha1Validator","userEntityV1alpha1Validator","systemEntityV1alpha1Validator","domainEntityV1alpha1Validator","getCompoundEntityRef","parseEntityRef","processingResult","RELATION_OWNED_BY","RELATION_OWNER_OF","RELATION_PART_OF","RELATION_HAS_PART","RELATION_PROVIDES_API","RELATION_API_PROVIDED_BY","RELATION_CONSUMES_API","RELATION_API_CONSUMED_BY","RELATION_DEPENDS_ON","RELATION_DEPENDENCY_OF","RELATION_MEMBER_OF","RELATION_HAS_MEMBER","RELATION_CHILD_OF","RELATION_PARENT_OF","promisify","g","fs","path","yaml","assertError","limiterFactory","lodash","defaultEntityDataParser","stringifyEntityRef","InputError","entitySchemaValidator","entityEnvelopeSchemaValidator","createHash","ConflictError","uuid","parseLocationRef","DateTime","isDatabaseConflictError","register","Counter","Gauge","Summary","metrics","generateStableHash","stableStringify","BATCH_SIZE","errors","resolvePackagePath","SpanStatusCode","tracer","trace","splitToChunks","uniq","progressTracker","serializeError","stringifyError","z","NotAllowedError","entityFilterParser","lodashChunk","isEqual","durationToMilliseconds","DEFAULT_NAMESPACE","ENTITY_STATUS_CATALOG_PROCESSING_TYPE","response","createValidatedOpenApiRouter","yn","errorHandler","catalogEntityRefreshPermission","AuthorizeResult","minimatch","makeCreatePermissionRule","RESOURCE_TYPE_CATALOG_ENTITY","get","catalogEntityReadPermission","catalogEntityDeletePermission","catalogLocationCreatePermission","catalogLocationReadPermission","catalogLocationDeletePermission","catalogPermissions","catalogPermissionRules","HostDiscovery","createLegacyAuthAdapters","toPermissionEvaluator","createConditionTransformer","createPermissionIntegrationRouter","keyBy","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","config","readDurationFromConfig"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"CatalogBuilder-D0vAEZa8.cjs.js","sources":["../../src/modules/codeowners/lib/resolve.ts","../../src/modules/codeowners/lib/scm.ts","../../src/modules/codeowners/lib/read.ts","../../src/modules/codeowners/CodeOwnersProcessor.ts","../../src/modules/core/AnnotateLocationEntityProcessor.ts","../../src/modules/core/BuiltinKindsEntityProcessor.ts","../../src/modules/core/FileReaderProcessor.ts","../../src/modules/core/PlaceholderProcessor.ts","../../src/modules/core/UrlReaderProcessor.ts","../../src/modules/util/parse.ts","../../src/processing/refresh.ts","../../src/processing/util.ts","../../src/util/conversion.ts","../../src/modules/core/ConfigLocationEntityProvider.ts","../../src/modules/core/DefaultLocationStore.ts","../../src/ingestion/LocationAnalyzer.ts","../../src/database/conversion.ts","../../src/util/metrics.ts","../../src/database/metrics.ts","../../src/database/operations/refreshState/checkLocationKeyConflict.ts","../../src/database/operations/refreshState/insertUnprocessedEntity.ts","../../src/database/operations/refreshState/updateUnprocessedEntity.ts","../../src/database/util.ts","../../src/constants.ts","../../src/database/DefaultProcessingDatabase.ts","../../src/database/migrations.ts","../../src/stitching/types.ts","../../src/util/opentelemetry.ts","../../src/processing/TaskPipeline.ts","../../src/database/operations/stitcher/markForStitching.ts","../../src/database/operations/util/deleteOrphanedEntities.ts","../../src/processing/DefaultCatalogProcessingEngine.ts","../../src/service/DefaultLocationService.ts","../../src/service/util.ts","../../src/service/DefaultEntitiesCatalog.ts","../../src/processing/ProcessorOutputCollector.ts","../../src/processing/ProcessorCacheManager.ts","../../src/processing/DefaultCatalogProcessingOrchestrator.ts","../../src/database/operations/stitcher/getDeferredStitchableEntities.ts","../../src/database/operations/stitcher/buildEntitySearch.ts","../../src/database/operations/stitcher/markDeferredStitchCompleted.ts","../../src/database/operations/stitcher/util.ts","../../src/database/operations/stitcher/performStitching.ts","../../src/stitching/progressTracker.ts","../../src/stitching/DefaultStitcher.ts","../../src/service/request/entitiesBatchRequest.ts","../../src/service/request/basicEntityFilter.ts","../../src/service/request/common.ts","../../src/service/request/parseEntityFilterParams.ts","../../src/service/request/parseEntityTransformParams.ts","../../src/service/request/parseEntityOrderFieldParams.ts","../../src/service/request/parseQueryEntitiesParams.ts","../../src/service/request/parseEntityFacetParams.ts","../../src/service/request/parseEntityOrderParams.ts","../../src/schema/openapi.generated.ts","../../src/service/request/parseEntityPaginationParams.ts","../../src/service/createRouter.ts","../../src/service/DefaultRefreshService.ts","../../src/service/AuthorizedRefreshService.ts","../../src/ingestion/CatalogRules.ts","../../src/processing/connectEntityProviders.ts","../../src/permissions/rules/util.ts","../../src/permissions/rules/hasAnnotation.ts","../../src/permissions/rules/isEntityKind.ts","../../src/permissions/rules/isEntityOwner.ts","../../src/permissions/rules/hasLabel.ts","../../src/permissions/rules/createPropertyRule.ts","../../src/permissions/rules/hasMetadata.ts","../../src/permissions/rules/hasSpec.ts","../../src/permissions/rules/index.ts","../../src/service/AuthorizedEntitiesCatalog.ts","../../src/service/AuthorizedLocationService.ts","../../src/database/operations/provider/deleteWithEagerPruningOfChildren.ts","../../src/database/operations/provider/refreshByRefreshKeys.ts","../../src/database/DefaultProviderDatabase.ts","../../src/database/DefaultCatalogDatabase.ts","../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as codeowners from 'codeowners-utils';\nimport parseGitUrl from 'git-url-parse';\n\nconst USER_PATTERN = /^@.*/;\nconst GROUP_PATTERN = /^@.*\\/.*/;\nconst EMAIL_PATTERN = /^.*@.*\\..*$/;\n\nexport function resolveCodeOwner(\n contents: string,\n catalogInfoFileUrl: string,\n): string | undefined {\n const codeOwnerEntries = codeowners.parse(contents);\n\n const { filepath } = parseGitUrl(catalogInfoFileUrl);\n const match = codeowners.matchFile(filepath, codeOwnerEntries);\n\n return match ? normalizeCodeOwner(match.owners[0]) : undefined;\n}\n\nexport function normalizeCodeOwner(owner: string) {\n if (owner.match(GROUP_PATTERN)) {\n return owner.split('/')[1];\n } else if (owner.match(USER_PATTERN)) {\n return `User:${owner.substring(1)}`;\n } else if (owner.match(EMAIL_PATTERN)) {\n return owner.split('@')[0];\n }\n\n return owner;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst CODEOWNERS = 'CODEOWNERS';\n\nexport const scmCodeOwnersPaths: Record = {\n // https://mibexsoftware.atlassian.net/wiki/spaces/CODEOWNERS/pages/222822413/Usage\n bitbucket: [CODEOWNERS, `.bitbucket/${CODEOWNERS}`],\n\n // https://docs.gitlab.com/ee/user/project/code_owners.html#how-to-set-up-code-owners\n gitlab: [CODEOWNERS, `.gitlab/${CODEOWNERS}`, `docs/${CODEOWNERS}`],\n\n // https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-file-location\n github: [CODEOWNERS, `.github/${CODEOWNERS}`, `docs/${CODEOWNERS}`],\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { NotFoundError } from '@backstage/errors';\nimport { ScmIntegration } from '@backstage/integration';\nimport 'core-js/features/promise'; // NOTE: This can be removed when ES2021 is implemented\nimport { resolveCodeOwner } from './resolve';\nimport { scmCodeOwnersPaths } from './scm';\n\nexport async function readCodeOwners(\n reader: UrlReader,\n sourceUrl: string,\n codeownersPaths: string[],\n): Promise {\n const readOwnerLocation = async (path: string): Promise => {\n const url = `${sourceUrl}${path}`;\n const data = await reader.readUrl(url);\n const buffer = await data.buffer();\n return buffer.toString();\n };\n\n const candidates = codeownersPaths.map(readOwnerLocation);\n\n return Promise.any(candidates).catch((aggregateError: AggregateError) => {\n const hardError = aggregateError.errors.find(\n error => !(error instanceof NotFoundError),\n );\n\n if (hardError) {\n throw hardError;\n }\n\n return undefined;\n });\n}\n\nexport async function findCodeOwnerByTarget(\n reader: UrlReader,\n targetUrl: string,\n scmIntegration: ScmIntegration,\n): Promise {\n const codeownersPaths = scmCodeOwnersPaths[scmIntegration?.type ?? ''];\n\n const sourceUrl = scmIntegration?.resolveUrl({\n url: '/',\n base: targetUrl,\n });\n\n if (!sourceUrl || !codeownersPaths) {\n return undefined;\n }\n\n const contents = await readCodeOwners(reader, sourceUrl, codeownersPaths);\n\n if (!contents) {\n return undefined;\n }\n\n const owner = resolveCodeOwner(contents, targetUrl);\n\n return owner;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\nimport { findCodeOwnerByTarget } from './lib';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst ALLOWED_KINDS = ['API', 'Component', 'Domain', 'Resource', 'System'];\nconst ALLOWED_LOCATION_TYPES = ['url'];\n\n/** @public */\nexport class CodeOwnersProcessor implements CatalogProcessor {\n private readonly integrations: ScmIntegrationRegistry;\n private readonly logger: LoggerService;\n private readonly reader: UrlReader;\n\n static fromConfig(\n config: Config,\n options: { logger: LoggerService; reader: UrlReader },\n ) {\n const integrations = ScmIntegrations.fromConfig(config);\n\n return new CodeOwnersProcessor({\n ...options,\n integrations,\n });\n }\n\n constructor(options: {\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n reader: UrlReader;\n }) {\n this.integrations = options.integrations;\n this.logger = options.logger;\n this.reader = options.reader;\n }\n\n getProcessorName(): string {\n return 'CodeOwnersProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise {\n // Only continue if the owner is not set\n if (\n !entity ||\n !ALLOWED_KINDS.includes(entity.kind) ||\n !ALLOWED_LOCATION_TYPES.includes(location.type) ||\n (entity.spec && entity.spec.owner)\n ) {\n return entity;\n }\n\n const scmIntegration = this.integrations.byUrl(location.target);\n if (!scmIntegration) {\n return entity;\n }\n\n const owner = await findCodeOwnerByTarget(\n this.reader,\n location.target,\n scmIntegration,\n );\n\n if (!owner) {\n this.logger.debug(\n `CodeOwnerProcessor could not resolve owner for ${location.target}`,\n );\n return entity;\n }\n\n return {\n ...entity,\n spec: { ...entity.spec, owner },\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_EDIT_URL,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n ANNOTATION_SOURCE_LOCATION,\n ANNOTATION_VIEW_URL,\n Entity,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { identity, merge, pickBy } from 'lodash';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n} from '@backstage/plugin-catalog-node';\n\nconst commitHashRegExp = /\\b[0-9a-f]{40,}\\b/;\n/** @public */\nexport class AnnotateLocationEntityProcessor implements CatalogProcessor {\n constructor(\n private readonly options: {\n integrations: ScmIntegrationRegistry;\n },\n ) {}\n\n getProcessorName(): string {\n return 'AnnotateLocationEntityProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n _: CatalogProcessorEmit,\n originLocation: LocationSpec,\n ): Promise {\n const { integrations } = this.options;\n let viewUrl;\n let editUrl;\n let sourceLocation;\n\n if (location.type === 'url') {\n const scmIntegration = integrations.byUrl(location.target);\n\n viewUrl = location.target;\n\n if (!commitHashRegExp.test(location.target)) {\n editUrl = scmIntegration?.resolveEditUrl(location.target);\n }\n\n const sourceUrl = scmIntegration?.resolveUrl({\n url: './',\n base: location.target,\n });\n\n if (sourceUrl) {\n sourceLocation = stringifyLocationRef({\n type: 'url',\n target: sourceUrl,\n });\n }\n }\n\n return merge(\n {\n metadata: {\n annotations: pickBy(\n {\n [ANNOTATION_LOCATION]: stringifyLocationRef(location),\n [ANNOTATION_ORIGIN_LOCATION]:\n stringifyLocationRef(originLocation),\n [ANNOTATION_VIEW_URL]: viewUrl,\n [ANNOTATION_EDIT_URL]: editUrl,\n [ANNOTATION_SOURCE_LOCATION]: sourceLocation,\n },\n identity,\n ),\n },\n },\n entity,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiEntity,\n apiEntityV1alpha1Validator,\n ComponentEntity,\n componentEntityV1alpha1Validator,\n DomainEntity,\n domainEntityV1alpha1Validator,\n Entity,\n getCompoundEntityRef,\n GroupEntity,\n groupEntityV1alpha1Validator,\n locationEntityV1alpha1Validator,\n parseEntityRef,\n RELATION_API_CONSUMED_BY,\n RELATION_API_PROVIDED_BY,\n RELATION_CHILD_OF,\n RELATION_CONSUMES_API,\n RELATION_DEPENDENCY_OF,\n RELATION_DEPENDS_ON,\n RELATION_HAS_MEMBER,\n RELATION_HAS_PART,\n RELATION_MEMBER_OF,\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n RELATION_PARENT_OF,\n RELATION_PART_OF,\n RELATION_PROVIDES_API,\n ResourceEntity,\n resourceEntityV1alpha1Validator,\n SystemEntity,\n systemEntityV1alpha1Validator,\n UserEntity,\n userEntityV1alpha1Validator,\n} from '@backstage/catalog-model';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\n/** @public */\nexport class BuiltinKindsEntityProcessor implements CatalogProcessor {\n private readonly validators = [\n apiEntityV1alpha1Validator,\n componentEntityV1alpha1Validator,\n resourceEntityV1alpha1Validator,\n groupEntityV1alpha1Validator,\n locationEntityV1alpha1Validator,\n userEntityV1alpha1Validator,\n systemEntityV1alpha1Validator,\n domainEntityV1alpha1Validator,\n ];\n\n getProcessorName(): string {\n return 'BuiltinKindsEntityProcessor';\n }\n\n async validateEntityKind(entity: Entity): Promise {\n for (const validator of this.validators) {\n const results = await validator.check(entity);\n if (results) {\n return true;\n }\n }\n\n return false;\n }\n\n async postProcessEntity(\n entity: Entity,\n _location: LocationSpec,\n emit: CatalogProcessorEmit,\n ): Promise {\n const selfRef = getCompoundEntityRef(entity);\n\n /*\n * Utilities\n */\n\n function doEmit(\n targets: string | string[] | undefined,\n context: { defaultKind?: string; defaultNamespace: string },\n outgoingRelation: string,\n incomingRelation: string,\n ): void {\n if (!targets) {\n return;\n }\n for (const target of [targets].flat()) {\n const targetRef = parseEntityRef(target, context);\n emit(\n processingResult.relation({\n source: selfRef,\n type: outgoingRelation,\n target: {\n kind: targetRef.kind,\n namespace: targetRef.namespace,\n name: targetRef.name,\n },\n }),\n );\n emit(\n processingResult.relation({\n source: {\n kind: targetRef.kind,\n namespace: targetRef.namespace,\n name: targetRef.name,\n },\n type: incomingRelation,\n target: selfRef,\n }),\n );\n }\n }\n\n /*\n * Emit relations for the Component kind\n */\n\n if (entity.kind === 'Component') {\n const component = entity as ComponentEntity;\n doEmit(\n component.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n component.spec.subcomponentOf,\n { defaultKind: 'Component', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n doEmit(\n component.spec.providesApis,\n { defaultKind: 'API', defaultNamespace: selfRef.namespace },\n RELATION_PROVIDES_API,\n RELATION_API_PROVIDED_BY,\n );\n doEmit(\n component.spec.consumesApis,\n { defaultKind: 'API', defaultNamespace: selfRef.namespace },\n RELATION_CONSUMES_API,\n RELATION_API_CONSUMED_BY,\n );\n doEmit(\n component.spec.dependsOn,\n { defaultNamespace: selfRef.namespace },\n RELATION_DEPENDS_ON,\n RELATION_DEPENDENCY_OF,\n );\n doEmit(\n component.spec.system,\n { defaultKind: 'System', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the API kind\n */\n\n if (entity.kind === 'API') {\n const api = entity as ApiEntity;\n doEmit(\n api.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n api.spec.system,\n { defaultKind: 'System', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the Resource kind\n */\n\n if (entity.kind === 'Resource') {\n const resource = entity as ResourceEntity;\n doEmit(\n resource.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n resource.spec.dependsOn,\n { defaultNamespace: selfRef.namespace },\n RELATION_DEPENDS_ON,\n RELATION_DEPENDENCY_OF,\n );\n doEmit(\n resource.spec.dependencyOf,\n { defaultNamespace: selfRef.namespace },\n RELATION_DEPENDENCY_OF,\n RELATION_DEPENDS_ON,\n );\n doEmit(\n resource.spec.system,\n { defaultKind: 'System', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the User kind\n */\n\n if (entity.kind === 'User') {\n const user = entity as UserEntity;\n doEmit(\n user.spec.memberOf,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_MEMBER_OF,\n RELATION_HAS_MEMBER,\n );\n }\n\n /*\n * Emit relations for the Group kind\n */\n\n if (entity.kind === 'Group') {\n const group = entity as GroupEntity;\n doEmit(\n group.spec.parent,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_CHILD_OF,\n RELATION_PARENT_OF,\n );\n doEmit(\n group.spec.children,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_PARENT_OF,\n RELATION_CHILD_OF,\n );\n doEmit(\n group.spec.members,\n { defaultKind: 'User', defaultNamespace: selfRef.namespace },\n RELATION_HAS_MEMBER,\n RELATION_MEMBER_OF,\n );\n }\n\n /*\n * Emit relations for the System kind\n */\n\n if (entity.kind === 'System') {\n const system = entity as SystemEntity;\n doEmit(\n system.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n system.spec.domain,\n { defaultKind: 'Domain', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n /*\n * Emit relations for the Domain kind\n */\n\n if (entity.kind === 'Domain') {\n const domain = entity as DomainEntity;\n doEmit(\n domain.spec.owner,\n { defaultKind: 'Group', defaultNamespace: selfRef.namespace },\n RELATION_OWNED_BY,\n RELATION_OWNER_OF,\n );\n doEmit(\n domain.spec.subdomainOf,\n { defaultKind: 'Domain', defaultNamespace: selfRef.namespace },\n RELATION_PART_OF,\n RELATION_HAS_PART,\n );\n }\n\n return entity;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport g from 'glob';\nimport path from 'path';\nimport { promisify } from 'util';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n CatalogProcessorParser,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\nconst glob = promisify(g);\n\nconst LOCATION_TYPE = 'file';\n\n/** @public */\nexport class FileReaderProcessor implements CatalogProcessor {\n getProcessorName(): string {\n return 'FileReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n optional: boolean,\n emit: CatalogProcessorEmit,\n parser: CatalogProcessorParser,\n ): Promise {\n if (location.type !== LOCATION_TYPE) {\n return false;\n }\n\n try {\n const fileMatches = await glob(location.target);\n\n if (fileMatches.length > 0) {\n for (const fileMatch of fileMatches) {\n const data = await fs.readFile(fileMatch);\n const normalizedFilePath = path.normalize(fileMatch);\n\n // The normalize converts to native slashes; the glob library returns\n // forward slashes even on windows\n for await (const parseResult of parser({\n data: data,\n location: {\n type: LOCATION_TYPE,\n target: normalizedFilePath,\n },\n })) {\n emit(parseResult);\n emit(\n processingResult.refresh(\n `${LOCATION_TYPE}:${normalizedFilePath}`,\n ),\n );\n }\n }\n } else if (!optional) {\n const message = `${location.type} ${location.target} does not exist`;\n emit(processingResult.notFoundError(location, message));\n }\n } catch (e) {\n const message = `${location.type} ${location.target} could not be read, ${e}`;\n emit(processingResult.generalError(location, message));\n }\n\n return true;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { JsonValue } from '@backstage/types';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport yaml from 'yaml';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n PlaceholderResolver,\n PlaceholderResolverParams,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\n/** @public */\nexport type PlaceholderProcessorOptions = {\n resolvers: Record;\n reader: UrlReader;\n integrations: ScmIntegrationRegistry;\n};\n\n/**\n * Traverses raw entity JSON looking for occurrences of $-prefixed placeholders\n * that it then fills in with actual data.\n * @public\n */\nexport class PlaceholderProcessor implements CatalogProcessor {\n constructor(private readonly options: PlaceholderProcessorOptions) {}\n\n getProcessorName(): string {\n return 'PlaceholderProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n emit: CatalogProcessorEmit,\n ): Promise {\n const process = async (data: any): Promise<[any, boolean]> => {\n if (!data || !(data instanceof Object)) {\n // Scalars can't have placeholders\n return [data, false];\n }\n\n if (Array.isArray(data)) {\n // We're an array - process all entries recursively\n const items = await Promise.all(data.map(item => process(item)));\n return items.every(([, changed]) => !changed)\n ? [data, false]\n : [items.map(([item]) => item), true];\n }\n\n const keys = Object.keys(data);\n if (!keys.some(k => k.startsWith('$'))) {\n // We're an object but no placeholders at this level - process all\n // entries recursively\n const entries = await Promise.all(\n Object.entries(data).map(([k, v]) =>\n process(v).then(vp => [k, vp] as const),\n ),\n );\n return entries.every(([, [, changed]]) => !changed)\n ? [data, false]\n : [Object.fromEntries(entries.map(([k, [v]]) => [k, v])), true];\n } else if (keys.length !== 1) {\n // This was an object that had more than one key, some of which were\n // dollar prefixed. We only handle the case where there is exactly one\n // such key; anything else is left alone.\n return [data, false];\n }\n\n const resolverKey = keys[0].substring(1);\n const resolverValue = data[keys[0]];\n\n const resolver = this.options.resolvers[resolverKey];\n if (!resolver) {\n // If there was no such placeholder resolver, we err on the side of safety\n // and assume that this is something that's best left alone. For example, if\n // the input contains JSONSchema, there may be \"$ref\": \"#/definitions/node\"\n // nodes in the document.\n return [data, false];\n }\n\n const read = async (url: string): Promise => {\n const response = await this.options.reader.readUrl(url);\n const buffer = await response.buffer();\n return buffer;\n };\n\n const resolveUrl = (url: string, base: string): string =>\n this.options.integrations.resolveUrl({\n url,\n base,\n });\n\n return [\n await resolver({\n key: resolverKey,\n value: resolverValue,\n baseUrl: location.target,\n read,\n resolveUrl,\n emit,\n }),\n true,\n ];\n };\n\n const [result] = await process(entity);\n return result;\n }\n}\n\n/*\n * Resolvers\n */\n\nexport async function yamlPlaceholderResolver(\n params: PlaceholderResolverParams,\n): Promise {\n const { content, url } = await readTextLocation(params);\n\n params.emit(processingResult.refresh(`url:${url}`));\n\n let documents: yaml.Document.Parsed[];\n try {\n documents = yaml.parseAllDocuments(content).filter(d => d);\n } catch (e) {\n throw new Error(\n `Placeholder \\$${params.key} failed to parse YAML data at ${params.value}, ${e}`,\n );\n }\n\n if (documents.length !== 1) {\n throw new Error(\n `Placeholder \\$${params.key} expected to find exactly one document of data at ${params.value}, found ${documents.length}`,\n );\n }\n\n const document = documents[0];\n\n if (document.errors?.length) {\n throw new Error(\n `Placeholder \\$${params.key} found an error in the data at ${params.value}, ${document.errors[0]}`,\n );\n }\n\n return document.toJSON();\n}\n\nexport async function jsonPlaceholderResolver(\n params: PlaceholderResolverParams,\n): Promise {\n const { content, url } = await readTextLocation(params);\n\n params.emit(processingResult.refresh(`url:${url}`));\n\n try {\n return JSON.parse(content);\n } catch (e) {\n throw new Error(\n `Placeholder \\$${params.key} failed to parse JSON data at ${params.value}, ${e}`,\n );\n }\n}\n\nexport async function textPlaceholderResolver(\n params: PlaceholderResolverParams,\n): Promise {\n const { content, url } = await readTextLocation(params);\n\n params.emit(processingResult.refresh(`url:${url}`));\n\n return content;\n}\n\n/*\n * Helpers\n */\n\nasync function readTextLocation(\n params: PlaceholderResolverParams,\n): Promise<{ content: string; url: string }> {\n const newUrl = relativeUrl(params);\n\n try {\n const data = await params.read(newUrl);\n return { content: data.toString('utf-8'), url: newUrl };\n } catch (e) {\n throw new Error(\n `Placeholder \\$${params.key} could not read location ${params.value}, ${e}`,\n );\n }\n}\n\nfunction relativeUrl({\n key,\n value,\n baseUrl,\n resolveUrl,\n}: PlaceholderResolverParams): string {\n if (typeof value !== 'string') {\n throw new Error(\n `Placeholder \\$${key} expected a string value parameter, in the form of an absolute URL or a relative path`,\n );\n }\n\n try {\n return resolveUrl(value, baseUrl);\n } catch (e) {\n // The only remaining case that isn't support is a relative file path that should be\n // resolved using a relative file location. Accessing local file paths can lead to\n // path traversal attacks and access to any file on the host system. Implementing this\n // would require additional security measures.\n throw new Error(\n `Placeholder \\$${key} could not form a URL out of ${baseUrl} and ${value}, ${e}`,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { Entity } from '@backstage/catalog-model';\nimport { assertError } from '@backstage/errors';\nimport limiterFactory from 'p-limit';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport parseGitUrl from 'git-url-parse';\nimport {\n CatalogProcessor,\n CatalogProcessorCache,\n CatalogProcessorEmit,\n CatalogProcessorEntityResult,\n CatalogProcessorParser,\n CatalogProcessorResult,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst CACHE_KEY = 'v1';\n\n// WARNING: If you change this type, you likely need to bump the CACHE_KEY as well\ntype CacheItem = {\n etag: string;\n value: {\n type: 'entity';\n entity: Entity;\n location: LocationSpec;\n }[];\n};\n\n/** @public */\nexport class UrlReaderProcessor implements CatalogProcessor {\n constructor(\n private readonly options: {\n reader: UrlReader;\n logger: LoggerService;\n },\n ) {}\n\n getProcessorName() {\n return 'url-reader';\n }\n\n async readLocation(\n location: LocationSpec,\n optional: boolean,\n emit: CatalogProcessorEmit,\n parser: CatalogProcessorParser,\n cache: CatalogProcessorCache,\n ): Promise {\n if (location.type !== 'url') {\n return false;\n }\n\n const cacheItem = await cache.get(CACHE_KEY);\n\n try {\n const { response, etag: newEtag } = await this.doRead(\n location.target,\n cacheItem?.etag,\n );\n\n const parseResults: CatalogProcessorResult[] = [];\n for (const item of response) {\n for await (const parseResult of parser({\n data: item.data,\n location: { type: location.type, target: item.url },\n })) {\n parseResults.push(parseResult);\n emit(parseResult);\n }\n }\n\n const isOnlyEntities = parseResults.every(r => r.type === 'entity');\n if (newEtag && isOnlyEntities) {\n await cache.set(CACHE_KEY, {\n etag: newEtag,\n value: parseResults as CatalogProcessorEntityResult[],\n });\n }\n\n emit(processingResult.refresh(`${location.type}:${location.target}`));\n } catch (error) {\n assertError(error);\n const message = `Unable to read ${location.type}, ${error}`.substring(\n 0,\n 5000,\n );\n if (error.name === 'NotModifiedError' && cacheItem) {\n for (const parseResult of cacheItem.value) {\n emit(parseResult);\n }\n emit(processingResult.refresh(`${location.type}:${location.target}`));\n } else if (error.name === 'NotFoundError') {\n if (!optional) {\n emit(processingResult.notFoundError(location, message));\n }\n } else {\n emit(processingResult.generalError(location, message));\n }\n }\n\n return true;\n }\n\n private async doRead(\n location: string,\n etag?: string,\n ): Promise<{ response: { data: Buffer; url: string }[]; etag?: string }> {\n // Does it contain globs? I.e. does it contain asterisks or question marks\n // (no curly braces for now)\n\n const { filepath } = parseGitUrl(location);\n if (filepath?.match(/[*?]/)) {\n const limiter = limiterFactory(5);\n const response = await this.options.reader.search(location, { etag });\n const output = response.files.map(async file => ({\n url: file.url,\n data: await limiter(file.content),\n }));\n return { response: await Promise.all(output), etag: response.etag };\n }\n\n const data = await this.options.reader.readUrl(location, { etag });\n return {\n response: [{ url: location, data: await data.buffer() }],\n etag: data.etag,\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyLocationRef } from '@backstage/catalog-model';\nimport lodash from 'lodash';\nimport yaml from 'yaml';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessorParser,\n CatalogProcessorResult,\n processingResult,\n} from '@backstage/plugin-catalog-node';\n\n/** @public */\nexport function* parseEntityYaml(\n data: Buffer,\n location: LocationSpec,\n): Iterable {\n let documents: yaml.Document.Parsed[];\n try {\n documents = yaml.parseAllDocuments(data.toString('utf8')).filter(d => d);\n } catch (e) {\n const loc = stringifyLocationRef(location);\n const message = `Failed to parse YAML at ${loc}, ${e}`;\n yield processingResult.generalError(location, message);\n return;\n }\n\n for (const document of documents) {\n if (document.errors?.length) {\n const loc = stringifyLocationRef(location);\n const message = `YAML error at ${loc}, ${document.errors[0]}`;\n yield processingResult.generalError(location, message);\n } else {\n const json = document.toJSON();\n if (lodash.isPlainObject(json)) {\n yield processingResult.entity(location, json as Entity);\n } else if (json === null) {\n // Ignore null values, these happen if there is an empty document in the\n // YAML file, for example if --- is added to the end of the file.\n } else {\n const message = `Expected object at root, got ${typeof json}`;\n yield processingResult.generalError(location, message);\n }\n }\n }\n}\n\nexport const defaultEntityDataParser: CatalogProcessorParser =\n async function* defaultEntityDataParser({ data, location }) {\n for (const e of parseEntityYaml(data, location)) {\n yield e;\n }\n };\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Function that returns the catalog processing interval in seconds.\n * @public\n */\nexport type ProcessingIntervalFunction = () => number;\n\n/**\n * Creates a function that returns a random processing interval between minSeconds and maxSeconds.\n * @returns A {@link ProcessingIntervalFunction} that provides the next processing interval\n * @public\n */\nexport function createRandomProcessingInterval(options: {\n minSeconds: number;\n maxSeconds: number;\n}): ProcessingIntervalFunction {\n const { minSeconds, maxSeconds } = options;\n return () => {\n return Math.random() * (maxSeconds - minSeconds) + minSeconds;\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n entityEnvelopeSchemaValidator,\n entitySchemaValidator,\n LocationEntity,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\n\nexport function isLocationEntity(entity: Entity): entity is LocationEntity {\n return entity.kind === 'Location';\n}\n\nexport function getEntityLocationRef(entity: Entity): string {\n const ref = entity.metadata.annotations?.[ANNOTATION_LOCATION];\n if (!ref) {\n const entityRef = stringifyEntityRef(entity);\n throw new InputError(\n `Entity '${entityRef}' does not have the annotation ${ANNOTATION_LOCATION}`,\n );\n }\n return ref;\n}\n\nexport function getEntityOriginLocationRef(entity: Entity): string {\n const ref = entity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION];\n if (!ref) {\n const entityRef = stringifyEntityRef(entity);\n throw new InputError(\n `Entity '${entityRef}' does not have the annotation ${ANNOTATION_ORIGIN_LOCATION}`,\n );\n }\n return ref;\n}\n\nexport function toAbsoluteUrl(\n integrations: ScmIntegrationRegistry,\n base: LocationSpec,\n type: string,\n target: string,\n): string {\n if (base.type !== type) {\n return target;\n }\n try {\n if (type === 'file') {\n if (target.startsWith('.')) {\n return path.join(path.dirname(base.target), target);\n }\n return target;\n } else if (type === 'url') {\n return integrations.resolveUrl({ url: target, base: base.target });\n }\n return target;\n } catch (e) {\n return target;\n }\n}\n\nexport function isObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport const validateEntity = entitySchemaValidator();\n\nexport const validateEntityEnvelope = entityEnvelopeSchemaValidator();\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n LocationEntityV1alpha1,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n stringifyEntityRef,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\n\nexport function locationSpecToMetadataName(location: LocationSpec) {\n const hash = createHash('sha1')\n .update(`${location.type}:${location.target}`)\n .digest('hex');\n return `generated-${hash}`;\n}\n\n/** @public */\nexport function locationSpecToLocationEntity(opts: {\n location: LocationSpec;\n parentEntity?: Entity;\n}): LocationEntityV1alpha1 {\n const location = opts.location;\n const parentEntity = opts.parentEntity;\n\n let ownLocation: string;\n let originLocation: string;\n if (parentEntity) {\n const maybeOwnLocation =\n parentEntity.metadata.annotations?.[ANNOTATION_LOCATION];\n if (!maybeOwnLocation) {\n throw new Error(\n `Parent entity '${stringifyEntityRef(\n parentEntity,\n )}' of location '${stringifyLocationRef(\n location,\n )}' does not have a location annotation`,\n );\n }\n ownLocation = maybeOwnLocation;\n const maybeOriginLocation =\n parentEntity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION];\n if (!maybeOriginLocation) {\n throw new Error(\n `Parent entity '${stringifyEntityRef(\n parentEntity,\n )}' of location '${stringifyLocationRef(\n location,\n )}' does not have an origin location annotation`,\n );\n }\n originLocation = maybeOriginLocation;\n } else {\n ownLocation = stringifyLocationRef(location);\n originLocation = ownLocation;\n }\n\n const result: LocationEntityV1alpha1 = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Location',\n metadata: {\n name: locationSpecToMetadataName(location),\n annotations: {\n [ANNOTATION_LOCATION]: ownLocation,\n [ANNOTATION_ORIGIN_LOCATION]: originLocation,\n },\n },\n spec: {\n type: location.type,\n target: location.target,\n presence: location.presence,\n },\n };\n\n return result;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport path from 'path';\nimport { getEntityLocationRef } from '../../processing/util';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { locationSpecToLocationEntity } from '../../util/conversion';\n\nexport class ConfigLocationEntityProvider implements EntityProvider {\n constructor(private readonly config: Config) {}\n\n getProviderName(): string {\n return 'ConfigLocationProvider';\n }\n\n async connect(connection: EntityProviderConnection): Promise {\n const entities = this.getEntitiesFromConfig();\n await connection.applyMutation({\n type: 'full',\n entities,\n });\n\n if (this.config.subscribe) {\n let currentKey = JSON.stringify(entities);\n\n this.config.subscribe(() => {\n const newEntities = this.getEntitiesFromConfig();\n const newKey = JSON.stringify(newEntities);\n\n if (currentKey !== newKey) {\n currentKey = newKey;\n connection.applyMutation({\n type: 'full',\n entities: newEntities,\n });\n }\n });\n }\n }\n\n private getEntitiesFromConfig() {\n const locationConfigs =\n this.config.getOptionalConfigArray('catalog.locations') ?? [];\n\n return locationConfigs.map(location => {\n const type = location.getString('type');\n const target = location.getString('target');\n const entity = locationSpecToLocationEntity({\n location: {\n type,\n target: type === 'file' ? path.resolve(target) : target,\n },\n });\n const locationKey = getEntityLocationRef(entity);\n return { entity, locationKey };\n });\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Location } from '@backstage/catalog-client';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport {\n DbLocationsRow,\n DbRefreshStateRow,\n DbSearchRow,\n} from '../../database/tables';\nimport { getEntityLocationRef } from '../../processing/util';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { locationSpecToLocationEntity } from '../../util/conversion';\nimport { LocationInput, LocationStore } from '../../service/types';\nimport {\n ANNOTATION_ORIGIN_LOCATION,\n CompoundEntityRef,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\n\nexport class DefaultLocationStore implements LocationStore, EntityProvider {\n private _connection: EntityProviderConnection | undefined;\n\n constructor(private readonly db: Knex) {}\n\n getProviderName(): string {\n return 'DefaultLocationStore';\n }\n\n async createLocation(input: LocationInput): Promise {\n const location = await this.db.transaction(async tx => {\n // Attempt to find a previous location matching the input\n const previousLocations = await this.locations(tx);\n // TODO: when location id's are a compilation of input target we can remove this full\n // lookup of locations first and just grab the by that instead.\n const previousLocation = previousLocations.some(\n l => input.type === l.type && input.target === l.target,\n );\n if (previousLocation) {\n throw new ConflictError(\n `Location ${input.type}:${input.target} already exists`,\n );\n }\n\n const inner: DbLocationsRow = {\n id: uuid(),\n type: input.type,\n target: input.target,\n };\n\n await tx('locations').insert(inner);\n\n return inner;\n });\n const entity = locationSpecToLocationEntity({ location });\n await this.connection.applyMutation({\n type: 'delta',\n added: [{ entity, locationKey: getEntityLocationRef(entity) }],\n removed: [],\n });\n\n return location;\n }\n\n async listLocations(): Promise {\n return await this.locations();\n }\n\n async getLocation(id: string): Promise {\n const items = await this.db('locations')\n .where({ id })\n .select();\n\n if (!items.length) {\n throw new NotFoundError(`Found no location with ID ${id}`);\n }\n return items[0];\n }\n\n async deleteLocation(id: string): Promise {\n if (!this.connection) {\n throw new Error('location store is not initialized');\n }\n\n const deleted = await this.db.transaction(async tx => {\n const [location] = await tx('locations')\n .where({ id })\n .select();\n\n if (!location) {\n throw new NotFoundError(`Found no location with ID ${id}`);\n }\n\n await tx('locations').where({ id }).del();\n return location;\n });\n const entity = locationSpecToLocationEntity({ location: deleted });\n await this.connection.applyMutation({\n type: 'delta',\n added: [],\n removed: [{ entity, locationKey: getEntityLocationRef(entity) }],\n });\n }\n\n async getLocationByEntity(entityRef: CompoundEntityRef): Promise {\n const entityRefString = stringifyEntityRef(entityRef);\n\n const [entityRow] = await this.db('refresh_state')\n .where({ entity_ref: entityRefString })\n .select('entity_id')\n .limit(1);\n if (!entityRow) {\n throw new NotFoundError(`found no entity for ref ${entityRefString}`);\n }\n\n const [searchRow] = await this.db('search')\n .where({\n entity_id: entityRow.entity_id,\n key: `metadata.annotations.${ANNOTATION_ORIGIN_LOCATION}`,\n })\n .select('value')\n .limit(1);\n if (!searchRow?.value) {\n throw new NotFoundError(\n `found no origin annotation for ref ${entityRefString}`,\n );\n }\n\n const { type, target } = parseLocationRef(searchRow.value);\n const [locationRow] = await this.db('locations')\n .where({ type, target })\n .select()\n .limit(1);\n\n if (!locationRow) {\n throw new NotFoundError(\n `Found no location with type ${type} and target ${target}`,\n );\n }\n\n return locationRow;\n }\n\n private get connection(): EntityProviderConnection {\n if (!this._connection) {\n throw new Error('location store is not initialized');\n }\n\n return this._connection;\n }\n\n async connect(connection: EntityProviderConnection): Promise {\n this._connection = connection;\n\n const locations = await this.locations();\n\n const entities = locations.map(location => {\n const entity = locationSpecToLocationEntity({ location });\n return { entity, locationKey: getEntityLocationRef(entity) };\n });\n\n await this.connection.applyMutation({\n type: 'full',\n entities,\n });\n }\n\n private async locations(dbOrTx: Knex.Transaction | Knex = this.db) {\n const locations = await dbOrTx('locations').select();\n return (\n locations\n // TODO(blam): We should create a mutation to remove this location for everyone\n // eventually when it's all done and dusted\n .filter(({ type }) => type !== 'bootstrap')\n .map(item => ({\n id: item.id,\n target: item.target,\n type: item.type,\n }))\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport parseGitUrl from 'git-url-parse';\nimport { Entity } from '@backstage/catalog-model';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport {\n AnalyzeLocationRequest,\n AnalyzeLocationResponse,\n} from '@backstage/plugin-catalog-common';\nimport {\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class RepoLocationAnalyzer implements LocationAnalyzer {\n private readonly logger: LoggerService;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n private readonly analyzers: ScmLocationAnalyzer[];\n\n constructor(\n logger: LoggerService,\n scmIntegrations: ScmIntegrationRegistry,\n analyzers: ScmLocationAnalyzer[],\n ) {\n this.logger = logger;\n this.scmIntegrations = scmIntegrations;\n this.analyzers = analyzers;\n }\n async analyzeLocation(\n request: AnalyzeLocationRequest,\n ): Promise {\n const integration = this.scmIntegrations.byUrl(request.location.target);\n const { owner, name } = parseGitUrl(request.location.target);\n\n let annotationPrefix;\n switch (integration?.type) {\n case 'azure':\n annotationPrefix = 'dev.azure.com';\n break;\n case 'bitbucket':\n annotationPrefix = 'bitbucket.org';\n break;\n case 'github':\n annotationPrefix = 'github.com';\n break;\n case 'gitlab':\n annotationPrefix = 'gitlab.com';\n break;\n default:\n break;\n }\n\n const analyzer = this.analyzers.find(a =>\n a.supports(request.location.target),\n );\n if (analyzer) {\n const analyzerResult = await analyzer.analyze({\n url: request.location.target,\n });\n if (analyzerResult.existing.length > 0) {\n this.logger.debug(\n `entity for ${request.location.target} already exists.`,\n );\n return {\n existingEntityFiles: analyzerResult.existing,\n generateEntities: [],\n };\n }\n }\n\n const entity: Entity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Component',\n metadata: {\n name: name,\n },\n spec: { type: 'other', lifecycle: 'unknown' },\n };\n\n if (annotationPrefix) {\n entity.metadata.annotations = {\n [`${annotationPrefix}/project-slug`]: `${owner}/${name}`,\n };\n }\n\n this.logger.debug(`entity created for ${request.location.target}`);\n return {\n existingEntityFiles: [],\n generateEntities: [{ entity, fields: [] }],\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isDatabaseConflictError } from '@backstage/backend-plugin-api';\nimport { ConflictError, InputError } from '@backstage/errors';\nimport { DateTime } from 'luxon';\n\n/**\n * Takes a TIMESTAMP type column and converts it to a DateTime.\n *\n * Some engines return the SQL string form (e.g. 'YYYY-MM-DD hh:mm:ss'), some\n * return ISO string form (e.g. 'YYYY-MM-DDThh:mm:ss.SSSZ'), some return a js\n * Date object.\n */\nexport function timestampToDateTime(input: Date | string): DateTime {\n try {\n if (typeof input === 'object') {\n return DateTime.fromJSDate(input).toUTC();\n }\n\n const result = input.includes(' ')\n ? DateTime.fromSQL(input, { zone: 'utc' })\n : DateTime.fromISO(input, { zone: 'utc' });\n if (!result.isValid) {\n throw new TypeError('Not valid');\n }\n\n return result;\n } catch (e) {\n throw new InputError(`Failed to parse database timestamp ${input}`, e);\n }\n}\n\n/**\n * Rethrows an error, possibly translating it to a more precise error type.\n */\nexport function rethrowError(e: any): never {\n if (isDatabaseConflictError(e)) {\n throw new ConflictError(`Rejected due to a conflicting entity`, e);\n }\n\n throw e;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Counter,\n CounterConfiguration,\n Gauge,\n GaugeConfiguration,\n Histogram,\n HistogramConfiguration,\n register,\n Summary,\n SummaryConfiguration,\n} from 'prom-client';\n\nexport function createCounterMetric(\n config: CounterConfiguration,\n): Counter {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Counter(config);\n register.registerMetric(metric);\n }\n return metric as Counter;\n}\n\nexport function createGaugeMetric(\n config: GaugeConfiguration,\n): Gauge {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Gauge(config);\n register.registerMetric(metric);\n }\n return metric as Gauge;\n}\n\nexport function createSummaryMetric(\n config: SummaryConfiguration,\n): Summary {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Summary(config);\n register.registerMetric(metric);\n }\n\n return metric as Summary;\n}\n\nexport function createHistogramMetric(\n config: HistogramConfiguration,\n): Histogram {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Histogram(config);\n register.registerMetric(metric);\n }\n\n return metric as Histogram;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { createGaugeMetric } from '../util/metrics';\nimport { DbRefreshStateRow, DbRelationsRow, DbLocationsRow } from './tables';\nimport { metrics } from '@opentelemetry/api';\nimport { parseEntityRef } from '@backstage/catalog-model';\n\nexport function initDatabaseMetrics(knex: Knex) {\n const seenProm = new Set();\n const seen = new Set();\n const meter = metrics.getMeter('default');\n return {\n entities_count_prom: createGaugeMetric({\n name: 'catalog_entities_count',\n help: 'Total amount of entities in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n labelNames: ['kind'],\n async collect() {\n const result = await knex('refresh_state').select(\n 'entity_ref',\n );\n const results = result\n .map(row => row.entity_ref.split(':')[0])\n .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());\n\n results.forEach((value, key) => {\n seenProm.add(key);\n this.set({ kind: key }, value);\n });\n\n // Set all the entities that were not seenProm to 0 and delete them from the seenProm set.\n seenProm.forEach(key => {\n if (!results.has(key)) {\n this.set({ kind: key }, 0);\n seenProm.delete(key);\n }\n });\n },\n }),\n registered_locations_prom: createGaugeMetric({\n name: 'catalog_registered_locations_count',\n help: 'Total amount of registered locations in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex('locations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n relations_prom: createGaugeMetric({\n name: 'catalog_relations_count',\n help: 'Total amount of relations between entities. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex('relations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n entities_count: meter\n .createObservableGauge('catalog_entities_count', {\n description: 'Total amount of entities in the catalog',\n })\n .addCallback(async gauge => {\n const result = await knex('refresh_state').select(\n 'entity_ref',\n );\n const results = result\n .map(row => parseEntityRef(row.entity_ref).kind)\n .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());\n\n results.forEach((value, key) => {\n seen.add(key);\n gauge.observe(value, { kind: key });\n });\n\n // Set all the entities that were not seen to 0 and delete them from the seen set.\n seen.forEach(key => {\n if (!results.has(key)) {\n gauge.observe(0, { kind: key });\n seen.delete(key);\n }\n });\n }),\n registered_locations: meter\n .createObservableGauge('catalog_registered_locations_count', {\n description: 'Total amount of registered locations in the catalog',\n })\n .addCallback(async gauge => {\n const total = await knex('locations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }),\n relations: meter\n .createObservableGauge('catalog_relations_count', {\n description: 'Total amount of relations between entities',\n })\n .addCallback(async gauge => {\n const total = await knex('relations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }),\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Checks whether a refresh state exists for the given entity that has a\n * location key that does not match the provided location key.\n *\n * @returns The conflicting key if there is one.\n */\nexport async function checkLocationKeyConflict(options: {\n tx: Knex.Transaction;\n entityRef: string;\n locationKey?: string;\n}): Promise {\n const { tx, entityRef, locationKey } = options;\n\n const row = await tx('refresh_state')\n .select('location_key')\n .where('entity_ref', entityRef)\n .first();\n\n const conflictingKey = row?.location_key;\n\n // If there's no existing key we can't have a conflict\n if (!conflictingKey) {\n return undefined;\n }\n\n if (conflictingKey !== locationKey) {\n return conflictingKey;\n }\n return undefined;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\nimport { v4 as uuid } from 'uuid';\nimport {\n LoggerService,\n isDatabaseConflictError,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Attempts to insert a new refresh state row for the given entity, returning\n * true if successful and false if there was a conflict.\n */\nexport async function insertUnprocessedEntity(options: {\n tx: Knex.Transaction;\n entity: Entity;\n hash: string;\n locationKey?: string;\n logger: LoggerService;\n}): Promise {\n const { tx, entity, hash, logger, locationKey } = options;\n\n const entityRef = stringifyEntityRef(entity);\n const serializedEntity = JSON.stringify(entity);\n\n try {\n let query = tx('refresh_state').insert({\n entity_id: uuid(),\n entity_ref: entityRef,\n unprocessed_entity: serializedEntity,\n unprocessed_hash: hash,\n errors: '',\n location_key: locationKey,\n next_update_at: tx.fn.now(),\n last_discovery_at: tx.fn.now(),\n });\n\n // TODO(Rugvip): only tested towards MySQL, Postgres and SQLite.\n // We have to do this because the only way to detect if there was a conflict with\n // SQLite is to catch the error, while Postgres needs to ignore the conflict to not\n // break the ongoing transaction.\n if (tx.client.config.client.includes('pg')) {\n query = query.onConflict('entity_ref').ignore() as any; // type here does not match runtime\n }\n\n // Postgres gives as an object with rowCount, SQLite gives us an array\n const result: { rowCount?: number; length?: number } = await query;\n return result.rowCount === 1 || result.length === 1;\n } catch (error) {\n // SQLite, or MySQL reached this rather than the rowCount check above\n if (!isDatabaseConflictError(error)) {\n throw error;\n } else {\n logger.debug(`Unable to insert a new refresh state row, ${error}`);\n return false;\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Attempts to update an existing refresh state row, returning true if it was\n * updated and false if there was no entity with a matching ref and location key.\n *\n * Updating the entity will also cause it to be scheduled for immediate processing.\n */\nexport async function updateUnprocessedEntity(options: {\n tx: Knex.Transaction;\n entity: Entity;\n hash: string;\n locationKey?: string;\n}): Promise {\n const { tx, entity, hash, locationKey } = options;\n\n const entityRef = stringifyEntityRef(entity);\n const serializedEntity = JSON.stringify(entity);\n\n const refreshResult = await tx('refresh_state')\n .update({\n unprocessed_entity: serializedEntity,\n unprocessed_hash: hash,\n location_key: locationKey,\n last_discovery_at: tx.fn.now(),\n // We only get to this point if a processed entity actually had any changes, or\n // if an entity provider requested this mutation, meaning that we can safely\n // bump the deferred entities to the front of the queue for immediate processing.\n next_update_at: tx.fn.now(),\n })\n .where('entity_ref', entityRef)\n .andWhere(inner => {\n if (!locationKey) {\n return inner.whereNull('location_key');\n }\n return inner\n .where('location_key', locationKey)\n .orWhereNull('location_key');\n });\n\n return refreshResult === 1;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\n\nexport function generateStableHash(entity: Entity) {\n return createHash('sha1')\n .update(stableStringify({ ...entity }))\n .digest('hex');\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport const CATALOG_CONFLICTS_TOPIC = 'experimental.catalog.conflict';\n/** @public */\nexport const CATALOG_ERRORS_TOPIC = 'experimental.catalog.errors';\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { ConflictError } from '@backstage/errors';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport { ProcessingIntervalFunction } from '../processing';\nimport { rethrowError, timestampToDateTime } from './conversion';\nimport { initDatabaseMetrics } from './metrics';\nimport {\n DbRefreshKeysRow,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n} from './tables';\nimport {\n GetProcessableEntitiesResult,\n ListParentsOptions,\n ListParentsResult,\n ProcessingDatabase,\n RefreshStateItem,\n Transaction,\n UpdateEntityCacheOptions,\n UpdateProcessedEntityOptions,\n} from './types';\nimport { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict';\nimport { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity';\nimport { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity';\nimport { generateStableHash } from './util';\nimport {\n EventBroker,\n EventParams,\n EventsService,\n} from '@backstage/plugin-events-node';\nimport { DateTime } from 'luxon';\nimport { CATALOG_CONFLICTS_TOPIC } from '../constants';\nimport { CatalogConflictEventPayload } from '../catalog/types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nconst BATCH_SIZE = 50;\n\nexport class DefaultProcessingDatabase implements ProcessingDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n refreshInterval: ProcessingIntervalFunction;\n eventBroker?: EventBroker | EventsService;\n },\n ) {\n initDatabaseMetrics(options.database);\n }\n\n async updateProcessedEntity(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise<{ previous: { relations: DbRelationsRow[] } }> {\n const tx = txOpaque as Knex.Transaction;\n const {\n id,\n processedEntity,\n resultHash,\n errors,\n relations,\n deferredEntities,\n refreshKeys,\n locationKey,\n } = options;\n const configClient = tx.client.config.client;\n const refreshResult = await tx('refresh_state')\n .update({\n processed_entity: JSON.stringify(processedEntity),\n result_hash: resultHash,\n errors,\n location_key: locationKey,\n })\n .where('entity_id', id)\n .andWhere(inner => {\n if (!locationKey) {\n return inner.whereNull('location_key');\n }\n return inner\n .where('location_key', locationKey)\n .orWhereNull('location_key');\n });\n if (refreshResult === 0) {\n throw new ConflictError(\n `Conflicting write of processing result for ${id} with location key '${locationKey}'`,\n );\n }\n const sourceEntityRef = stringifyEntityRef(processedEntity);\n\n // Schedule all deferred entities for future processing.\n await this.addUnprocessedEntities(tx, {\n entities: deferredEntities,\n sourceEntityRef,\n });\n\n // Delete old relations\n // NOTE(freben): knex implemented support for returning() on update queries for sqlite, but at the current time of writing (Sep 2022) not for delete() queries.\n let previousRelationRows: DbRelationsRow[];\n if (configClient.includes('sqlite3') || configClient.includes('mysql')) {\n previousRelationRows = await tx('relations')\n .select('*')\n .where({ originating_entity_id: id });\n await tx('relations')\n .where({ originating_entity_id: id })\n .delete();\n } else {\n previousRelationRows = await tx('relations')\n .where({ originating_entity_id: id })\n .delete()\n .returning('*');\n }\n\n // Batch insert new relations\n const relationRows: DbRelationsRow[] = relations.map(\n ({ source, target, type }) => ({\n originating_entity_id: id,\n source_entity_ref: stringifyEntityRef(source),\n target_entity_ref: stringifyEntityRef(target),\n type,\n }),\n );\n\n await tx.batchInsert(\n 'relations',\n this.deduplicateRelations(relationRows),\n BATCH_SIZE,\n );\n\n // Delete old refresh keys\n await tx('refresh_keys')\n .where({ entity_id: id })\n .delete();\n\n // Insert the refresh keys for the processed entity\n await tx.batchInsert(\n 'refresh_keys',\n refreshKeys.map(k => ({\n entity_id: id,\n key: k.key,\n })),\n BATCH_SIZE,\n );\n\n return {\n previous: {\n relations: previousRelationRows,\n },\n };\n }\n\n async updateProcessedEntityErrors(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { id, errors, resultHash } = options;\n\n await tx('refresh_state')\n .update({\n errors,\n result_hash: resultHash,\n })\n .where('entity_id', id);\n }\n\n async updateEntityCache(\n txOpaque: Transaction,\n options: UpdateEntityCacheOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { id, state } = options;\n\n await tx('refresh_state')\n .update({ cache: JSON.stringify(state ?? {}) })\n .where('entity_id', id);\n }\n\n async getProcessableEntities(\n txOpaque: Transaction,\n request: { processBatchSize: number },\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n\n let itemsQuery = tx('refresh_state').select();\n\n // This avoids duplication of work because of race conditions and is\n // also fast because locked rows are ignored rather than blocking.\n // It's only available in MySQL and PostgreSQL\n if (['mysql', 'mysql2', 'pg'].includes(tx.client.config.client)) {\n itemsQuery = itemsQuery.forUpdate().skipLocked();\n }\n\n const items = await itemsQuery\n .where('next_update_at', '<=', tx.fn.now())\n .limit(request.processBatchSize)\n .orderBy('next_update_at', 'asc');\n\n const interval = this.options.refreshInterval();\n\n const nextUpdateAt = (refreshInterval: number) => {\n if (tx.client.config.client.includes('sqlite3')) {\n return tx.raw(`datetime('now', ?)`, [`${refreshInterval} seconds`]);\n }\n\n if (tx.client.config.client.includes('mysql')) {\n return tx.raw(`now() + interval ${refreshInterval} second`);\n }\n\n return tx.raw(`now() + interval '${refreshInterval} seconds'`);\n };\n\n await tx('refresh_state')\n .whereIn(\n 'entity_ref',\n items.map(i => i.entity_ref),\n )\n .update({\n next_update_at: nextUpdateAt(interval),\n });\n\n return {\n items: items.map(\n i =>\n ({\n id: i.entity_id,\n entityRef: i.entity_ref,\n unprocessedEntity: JSON.parse(i.unprocessed_entity) as Entity,\n processedEntity: i.processed_entity\n ? (JSON.parse(i.processed_entity) as Entity)\n : undefined,\n resultHash: i.result_hash || '',\n nextUpdateAt: timestampToDateTime(i.next_update_at),\n lastDiscoveryAt: timestampToDateTime(i.last_discovery_at),\n state: i.cache ? JSON.parse(i.cache) : undefined,\n errors: i.errors,\n locationKey: i.location_key,\n } as RefreshStateItem),\n ),\n };\n }\n\n async listParents(\n txOpaque: Transaction,\n options: ListParentsOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n\n const rows = await tx(\n 'refresh_state_references',\n )\n .where({ target_entity_ref: options.entityRef })\n .select();\n\n const entityRefs = rows.map(r => r.source_entity_ref!).filter(Boolean);\n\n return { entityRefs };\n }\n\n async transaction(fn: (tx: Transaction) => Promise): Promise {\n try {\n let result: T | undefined = undefined;\n\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n private deduplicateRelations(rows: DbRelationsRow[]): DbRelationsRow[] {\n return lodash.uniqBy(\n rows,\n r => `${r.source_entity_ref}:${r.target_entity_ref}:${r.type}`,\n );\n }\n\n /**\n * Add a set of deferred entities for processing.\n * The entities will be added at the front of the processing queue.\n */\n private async addUnprocessedEntities(\n txOpaque: Transaction,\n options: {\n sourceEntityRef: string;\n entities: DeferredEntity[];\n },\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n\n // Keeps track of the entities that we end up inserting to update refresh_state_references afterwards\n const stateReferences = new Array();\n\n // Upsert all of the unprocessed entities into the refresh_state table, by\n // their entity ref.\n for (const { entity, locationKey } of options.entities) {\n const entityRef = stringifyEntityRef(entity);\n const hash = generateStableHash(entity);\n\n const updated = await updateUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n });\n if (updated) {\n stateReferences.push(entityRef);\n continue;\n }\n\n const inserted = await insertUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n logger: this.options.logger,\n });\n if (inserted) {\n stateReferences.push(entityRef);\n continue;\n }\n\n // If the row can't be inserted, we have a conflict, but it could be either\n // because of a conflicting locationKey or a race with another instance, so check\n // whether the conflicting entity has the same entityRef but a different locationKey\n const conflictingKey = await checkLocationKeyConflict({\n tx,\n entityRef,\n locationKey,\n });\n if (conflictingKey) {\n this.options.logger.warn(\n `Detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`,\n );\n if (this.options.eventBroker && locationKey) {\n const eventParams: EventParams = {\n topic: CATALOG_CONFLICTS_TOPIC,\n eventPayload: {\n unprocessedEntity: entity,\n entityRef,\n newLocationKey: locationKey,\n existingLocationKey: conflictingKey,\n lastConflictAt: DateTime.now().toISO()!,\n },\n };\n await this.options.eventBroker?.publish(eventParams);\n }\n }\n }\n\n // Replace all references for the originating entity or source and then create new ones\n await tx('refresh_state_references')\n .andWhere({ source_entity_ref: options.sourceEntityRef })\n .delete();\n await tx.batchInsert(\n 'refresh_state_references',\n stateReferences.map(entityRef => ({\n source_entity_ref: options.sourceEntityRef,\n target_entity_ref: entityRef,\n })),\n BATCH_SIZE,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { Knex } from 'knex';\n\nexport async function applyDatabaseMigrations(knex: Knex): Promise {\n const migrationsDir = resolvePackagePath(\n '@backstage/plugin-catalog-backend',\n 'migrations',\n );\n\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport interface Stitcher {\n stitch(options: {\n entityRefs?: Iterable;\n entityIds?: Iterable;\n }): Promise;\n}\n\n/**\n * The strategies supported by the stitching process, in terms of when to\n * perform stitching.\n *\n * @remarks\n *\n * In immediate mode, stitching happens \"in-band\" (blocking) immediately when\n * each processing task finishes. When set to `'deferred'`, stitching is instead\n * deferred to happen on a separate asynchronous worker queue just like\n * processing.\n *\n * Deferred stitching should make performance smoother when ingesting large\n * amounts of entities, and reduce p99 processing times and repeated\n * over-stitching of hot spot entities when fan-out/fan-in in terms of relations\n * is very large. It does however also come with some performance cost due to\n * the queuing with how much wall-clock time some types of task take.\n */\nexport type StitchingStrategy =\n | {\n mode: 'immediate';\n }\n | {\n mode: 'deferred';\n pollingInterval: HumanDuration;\n stitchTimeout: HumanDuration;\n };\n\nexport function stitchingStrategyFromConfig(config: Config): StitchingStrategy {\n const strategyMode = config.getOptionalString(\n 'catalog.stitchingStrategy.mode',\n );\n\n if (strategyMode === undefined || strategyMode === 'immediate') {\n return {\n mode: 'immediate',\n };\n } else if (strategyMode === 'deferred') {\n // TODO(freben): Make parameters configurable\n return {\n mode: 'deferred',\n pollingInterval: { seconds: 1 },\n stitchTimeout: { seconds: 60 },\n };\n }\n\n throw new Error(\n `Invalid stitching strategy mode '${strategyMode}', expected one of 'immediate' or 'deferred'`,\n );\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Span, SpanOptions, SpanStatusCode, Tracer } from '@opentelemetry/api';\nimport { Entity } from '@backstage/catalog-model';\n\nexport const TRACER_ID = 'backstage-plugin-catalog-backend';\n\nfunction setAttributeIfDefined(span: Span, attribute: string, value?: string) {\n if (value !== null && value !== undefined) {\n span.setAttribute(attribute, value);\n }\n}\n\nexport function addEntityAttributes(span: Span, entity: Entity) {\n setAttributeIfDefined(span, 'backstage.entity.apiVersion', entity.apiVersion);\n setAttributeIfDefined(span, 'backstage.entity.kind', entity.kind);\n setAttributeIfDefined(\n span,\n 'backstage.entity.metadata.namespace',\n entity.metadata?.namespace,\n );\n setAttributeIfDefined(\n span,\n 'backstage.entity.metadata.name',\n entity.metadata?.name,\n );\n}\n\n// Adapted from https://github.com/open-telemetry/opentelemetry-js/blob/359fbcc40a859057a02b14e84599eac399b8dba7/api/src/trace/SugaredTracer.ts\n// While waiting for something like https://github.com/open-telemetry/opentelemetry-js/pull/3317 to land upstream\n\nconst onException = (e: Error, span: Span) => {\n span.recordException(e);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n });\n};\n\nfunction isPromiseLike(obj: PromiseLike | S): obj is PromiseLike {\n return (\n !!obj &&\n (typeof obj === 'object' || typeof obj === 'function') &&\n 'then' in obj &&\n typeof obj.then === 'function'\n );\n}\n\nfunction handleFn ReturnType>(\n span: Span,\n fn: F,\n): ReturnType {\n try {\n const ret = fn(span);\n\n // if fn is an async function attach a recordException and spanEnd callback to the promise\n if (isPromiseLike(ret)) {\n ret.then(\n () => {\n span.end();\n },\n e => {\n onException(e, span);\n span.end();\n },\n );\n } else {\n span.end();\n }\n\n return ret;\n } catch (e) {\n onException(e, span);\n span.end();\n throw e;\n }\n}\n\nexport function withActiveSpan ReturnType>(\n tracer: Tracer,\n name: string,\n fn: F,\n spanOptions: SpanOptions = {},\n): ReturnType {\n return tracer.startActiveSpan(name, spanOptions, (span: Span) => {\n return handleFn(span, fn);\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TRACER_ID, withActiveSpan } from '../util/opentelemetry';\nimport { trace } from '@opentelemetry/api';\n\nconst DEFAULT_POLLING_INTERVAL_MS = 1000;\nconst tracer = trace.getTracer(TRACER_ID);\n\ntype Options = {\n /**\n * The callback used to load in new tasks. The number of items returned\n * in the array must be at most `count` number of items, but may be lower.\n *\n * Any error thrown from this method fill be treated as an unhandled rejection.\n */\n loadTasks: (count: number) => Promise>;\n\n /**\n * The callback used to process a single item.\n *\n * Any error thrown from this method fill be treated as an unhandled rejection.\n */\n processTask: (item: T) => Promise;\n\n /**\n * The target minimum number of items to process in parallel. Once the number\n * of in-flight tasks reaches this count, more tasks will be loaded in.\n */\n lowWatermark: number;\n\n /**\n * The maximum number of items to process in parallel.\n */\n highWatermark: number;\n\n /**\n * The interval at which tasks are polled for in the background when\n * there aren't enough tasks to load to satisfy the low watermark.\n *\n * @default 1000\n */\n pollingIntervalMs?: number;\n};\n\n/**\n * Creates a task processing pipeline which continuously loads in tasks to\n * keep the number of parallel in-flight tasks between a low and high watermark.\n *\n * @param options - The options for the pipeline.\n * @returns A stop function which when called halts all processing.\n */\nexport function startTaskPipeline(options: Options) {\n const {\n loadTasks,\n processTask,\n lowWatermark,\n highWatermark,\n pollingIntervalMs = DEFAULT_POLLING_INTERVAL_MS,\n } = options;\n\n if (lowWatermark >= highWatermark) {\n throw new Error('lowWatermark must be lower than highWatermark');\n }\n\n // State is in an object so that it can be stably referenced from within\n // callbacks below\n const state = { inFlightCount: 0 };\n const abortController = new AbortController();\n const abortSignal = abortController.signal;\n\n const barrier = createBarrier({\n waitTimeoutMillis: pollingIntervalMs,\n signal: abortSignal,\n });\n\n async function pipelineLoop() {\n while (!abortSignal.aborted) {\n if (state.inFlightCount <= lowWatermark) {\n await withActiveSpan(tracer, 'TaskPipelineLoop', async span => {\n const loadCount = highWatermark - state.inFlightCount;\n const loadedItems = await Promise.resolve()\n .then(() => loadTasks(loadCount))\n .catch(() => {\n // Silently swallow errors and go back to sleep to try again; we\n // delegate to the loadTasks function itself to catch errors and log\n // if it so desires\n return [];\n });\n span.setAttribute('itemCount', loadedItems.length);\n if (loadedItems.length && !abortSignal.aborted) {\n state.inFlightCount += loadedItems.length;\n for (const item of loadedItems) {\n Promise.resolve()\n .then(() => processTask(item))\n .catch(() => {\n // Silently swallow errors and go back to sleep to try again; we\n // delegate to the processTask function itself to catch errors\n // and log if it so desires\n })\n .finally(() => {\n state.inFlightCount -= 1;\n barrier.release();\n });\n }\n }\n });\n }\n await barrier.wait();\n }\n }\n\n pipelineLoop().catch(error => {\n // This should be impossible, but if it did happen, it would signal a\n // programming error inside the loop (errors should definitely be caught\n // inside of it). Let's rethrow with more information, and let it be caught\n // by the process' uncaught exception handler, which will log the occurrence\n // at a high level.\n throw new Error(`Unexpected error in processing pipeline loop`, error);\n });\n\n return () => {\n abortController.abort();\n barrier.destroy();\n };\n}\n\n/**\n * Creates a barrier with a timeout, that can be awaited or prematurely\n * released either manually or by an abort signal.\n */\nexport function createBarrier(options: {\n waitTimeoutMillis: number;\n signal: AbortSignal;\n}): {\n wait: () => Promise;\n release: () => void;\n destroy: () => void;\n} {\n const { waitTimeoutMillis, signal } = options;\n const resolvers = new Set<() => void>();\n\n function wait() {\n if (signal.aborted || !(waitTimeoutMillis > 0)) {\n return Promise.resolve();\n }\n\n return new Promise(resolve => {\n const timeoutHandle = setTimeout(done, waitTimeoutMillis);\n\n function done() {\n resolvers.delete(done);\n clearTimeout(timeoutHandle);\n resolve();\n }\n\n resolvers.add(done);\n });\n }\n\n function release() {\n const resolversToCall = new Set(resolvers);\n resolvers.clear();\n for (const resolver of resolversToCall) {\n resolver();\n }\n }\n\n signal.addEventListener('abort', release);\n\n return {\n wait,\n release,\n destroy: () => signal.removeEventListener('abort', release),\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport splitToChunks from 'lodash/chunk';\nimport { v4 as uuid } from 'uuid';\nimport { StitchingStrategy } from '../../../stitching/types';\nimport { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables';\n\n/**\n * Marks a number of entities for stitching some time in the near\n * future.\n *\n * @remarks\n */\nexport async function markForStitching(options: {\n knex: Knex | Knex.Transaction;\n strategy: StitchingStrategy;\n entityRefs?: Iterable;\n entityIds?: Iterable;\n}): Promise {\n // Splitting to chunks just to cover pathological cases that upset the db\n const entityRefs = split(options.entityRefs);\n const entityIds = split(options.entityIds);\n const knex = options.knex;\n const mode = options.strategy.mode;\n\n if (mode === 'immediate') {\n for (const chunk of entityRefs) {\n await knex\n .table('final_entities')\n .update({\n hash: 'force-stitching',\n })\n .whereIn(\n 'entity_id',\n knex('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', chunk),\n );\n await knex\n .table('refresh_state')\n .update({\n result_hash: 'force-stitching',\n next_update_at: knex.fn.now(),\n })\n .whereIn('entity_ref', chunk);\n }\n\n for (const chunk of entityIds) {\n await knex\n .table('final_entities')\n .update({\n hash: 'force-stitching',\n })\n .whereIn('entity_id', chunk);\n await knex\n .table('refresh_state')\n .update({\n result_hash: 'force-stitching',\n next_update_at: knex.fn.now(),\n })\n .whereIn('entity_id', chunk);\n }\n } else if (mode === 'deferred') {\n // It's OK that this is shared across refresh state rows; it just needs to\n // be uniquely generated for every new stitch request.\n const ticket = uuid();\n\n for (const chunk of entityRefs) {\n await knex('refresh_state')\n .update({\n next_stitch_at: knex.fn.now(),\n next_stitch_ticket: ticket,\n })\n .whereIn('entity_ref', chunk);\n }\n\n for (const chunk of entityIds) {\n await knex('refresh_state')\n .update({\n next_stitch_at: knex.fn.now(),\n next_stitch_ticket: ticket,\n })\n .whereIn('entity_id', chunk);\n }\n } else {\n throw new Error(`Unknown stitching strategy mode ${mode}`);\n }\n}\n\nfunction split(input: Iterable | undefined): string[][] {\n if (!input) {\n return [];\n }\n return splitToChunks(Array.isArray(input) ? input : [...input], 200);\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport uniq from 'lodash/uniq';\nimport { StitchingStrategy } from '../../../stitching/types';\nimport { DbRefreshStateRow } from '../../tables';\nimport { markForStitching } from '../stitcher/markForStitching';\n\n/**\n * Finds and deletes all orphaned entities, i.e. entities that do not have any\n * incoming references to them, and also eagerly deletes all of their children\n * that would otherwise become orphaned.\n */\nexport async function deleteOrphanedEntities(options: {\n knex: Knex.Transaction | Knex;\n strategy: StitchingStrategy;\n}): Promise {\n const { knex, strategy } = options;\n\n let total = 0;\n\n // Limit iterations for sanity\n for (let i = 0; i < 100; ++i) {\n const candidates = await knex\n .with('orphans', ['entity_id', 'entity_ref'], orphans =>\n orphans\n .from('refresh_state')\n .select('refresh_state.entity_id', 'refresh_state.entity_ref')\n .leftOuterJoin(\n 'refresh_state_references',\n 'refresh_state_references.target_entity_ref',\n 'refresh_state.entity_ref',\n )\n .whereNull('refresh_state_references.target_entity_ref'),\n )\n .select({\n entityId: 'orphans.entity_id',\n relationSourceId: 'refresh_state.entity_id',\n })\n .from('orphans')\n .leftOuterJoin(\n 'relations',\n 'relations.target_entity_ref',\n 'orphans.entity_ref',\n )\n .leftOuterJoin(\n 'refresh_state',\n 'refresh_state.entity_ref',\n 'relations.source_entity_ref',\n );\n\n if (!candidates.length) {\n break;\n }\n\n const orphanIds: string[] = uniq(candidates.map(r => r.entityId));\n const orphanRelationIds: string[] = uniq(\n candidates.map(r => r.relationSourceId).filter(Boolean),\n );\n\n total += orphanIds.length;\n\n // Delete the orphans themselves\n await knex\n .table('refresh_state')\n .delete()\n .whereIn('entity_id', orphanIds);\n\n // Mark all of the things that the orphans had relations to for stitching\n await markForStitching({\n knex,\n strategy,\n entityIds: orphanRelationIds,\n });\n }\n\n return total;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_LOCATION,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { assertError, serializeError, stringifyError } from '@backstage/errors';\nimport { Hash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\nimport { Knex } from 'knex';\nimport { metrics, trace } from '@opentelemetry/api';\nimport { ProcessingDatabase, RefreshStateItem } from '../database/types';\nimport { createCounterMetric, createSummaryMetric } from '../util/metrics';\nimport { CatalogProcessingOrchestrator, EntityProcessingResult } from './types';\nimport { Stitcher, stitchingStrategyFromConfig } from '../stitching/types';\nimport { startTaskPipeline } from './TaskPipeline';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\nimport {\n addEntityAttributes,\n TRACER_ID,\n withActiveSpan,\n} from '../util/opentelemetry';\nimport { deleteOrphanedEntities } from '../database/operations/util/deleteOrphanedEntities';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { CATALOG_ERRORS_TOPIC } from '../constants';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst CACHE_TTL = 5;\n\nconst tracer = trace.getTracer(TRACER_ID);\n\nexport type ProgressTracker = ReturnType;\n\n// NOTE(freben): Perhaps surprisingly, this class does not implement the\n// CatalogProcessingEngine type. That type is externally visible and its name is\n// the way it is for historic reasons. This class has no particular reason to\n// implement that precise interface; nowadays there are several different\n// engines \"hiding\" behind the CatalogProcessingEngine interface, of which this\n// is just one.\nexport class DefaultCatalogProcessingEngine {\n private readonly config: Config;\n private readonly scheduler?: PluginTaskScheduler;\n private readonly logger: LoggerService;\n private readonly knex: Knex;\n private readonly processingDatabase: ProcessingDatabase;\n private readonly orchestrator: CatalogProcessingOrchestrator;\n private readonly stitcher: Stitcher;\n private readonly createHash: () => Hash;\n private readonly pollingIntervalMs: number;\n private readonly orphanCleanupIntervalMs: number;\n private readonly onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n private readonly tracker: ProgressTracker;\n private readonly eventBroker?: EventBroker | EventsService;\n\n private stopFunc?: () => void;\n\n constructor(options: {\n config: Config;\n scheduler?: PluginTaskScheduler;\n logger: LoggerService;\n knex: Knex;\n processingDatabase: ProcessingDatabase;\n orchestrator: CatalogProcessingOrchestrator;\n stitcher: Stitcher;\n createHash: () => Hash;\n pollingIntervalMs?: number;\n orphanCleanupIntervalMs?: number;\n onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n tracker?: ProgressTracker;\n eventBroker?: EventBroker | EventsService;\n }) {\n this.config = options.config;\n this.scheduler = options.scheduler;\n this.logger = options.logger;\n this.knex = options.knex;\n this.processingDatabase = options.processingDatabase;\n this.orchestrator = options.orchestrator;\n this.stitcher = options.stitcher;\n this.createHash = options.createHash;\n this.pollingIntervalMs = options.pollingIntervalMs ?? 1_000;\n this.orphanCleanupIntervalMs = options.orphanCleanupIntervalMs ?? 30_000;\n this.onProcessingError = options.onProcessingError;\n this.tracker = options.tracker ?? progressTracker();\n this.eventBroker = options.eventBroker;\n\n this.stopFunc = undefined;\n }\n\n async start() {\n if (this.stopFunc) {\n throw new Error('Processing engine is already started');\n }\n\n const stopPipeline = this.startPipeline();\n const stopCleanup = this.startOrphanCleanup();\n\n this.stopFunc = () => {\n stopPipeline();\n stopCleanup();\n };\n }\n\n async stop() {\n if (this.stopFunc) {\n this.stopFunc();\n this.stopFunc = undefined;\n }\n }\n\n private startPipeline(): () => void {\n return startTaskPipeline({\n lowWatermark: 5,\n highWatermark: 10,\n pollingIntervalMs: this.pollingIntervalMs,\n loadTasks: async count => {\n try {\n const { items } = await this.processingDatabase.transaction(\n async tx => {\n return this.processingDatabase.getProcessableEntities(tx, {\n processBatchSize: count,\n });\n },\n );\n return items;\n } catch (error) {\n this.logger.warn('Failed to load processing items', error);\n return [];\n }\n },\n processTask: async item => {\n await withActiveSpan(tracer, 'ProcessingRun', async span => {\n const track = this.tracker.processStart(item, this.logger);\n addEntityAttributes(span, item.unprocessedEntity);\n\n try {\n const {\n id,\n state,\n unprocessedEntity,\n entityRef,\n locationKey,\n resultHash: previousResultHash,\n } = item;\n const result = await this.orchestrator.process({\n entity: unprocessedEntity,\n state,\n });\n\n track.markProcessorsCompleted(result);\n\n if (result.ok) {\n const { ttl: _, ...stateWithoutTtl } = state ?? {};\n if (\n stableStringify(stateWithoutTtl) !==\n stableStringify(result.state)\n ) {\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: {\n ttl: CACHE_TTL,\n ...result.state,\n },\n });\n });\n }\n } else {\n const maybeTtl = state?.ttl;\n const ttl = Number.isInteger(maybeTtl) ? (maybeTtl as number) : 0;\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateEntityCache(tx, {\n id,\n state: ttl > 0 ? { ...state, ttl: ttl - 1 } : {},\n });\n });\n }\n\n const location =\n unprocessedEntity?.metadata?.annotations?.[ANNOTATION_LOCATION];\n if (result.errors.length) {\n this.eventBroker?.publish({\n topic: CATALOG_ERRORS_TOPIC,\n eventPayload: {\n entity: entityRef,\n location,\n errors: result.errors,\n },\n });\n }\n const errorsString = JSON.stringify(\n result.errors.map(e => serializeError(e)),\n );\n\n let hashBuilder = this.createHash().update(errorsString);\n\n if (result.ok) {\n const { entityRefs: parents } =\n await this.processingDatabase.transaction(tx =>\n this.processingDatabase.listParents(tx, {\n entityRef,\n }),\n );\n\n hashBuilder = hashBuilder\n .update(stableStringify({ ...result.completedEntity }))\n .update(stableStringify([...result.deferredEntities]))\n .update(stableStringify([...result.relations]))\n .update(stableStringify([...result.refreshKeys]))\n .update(stableStringify([...parents]));\n }\n\n const resultHash = hashBuilder.digest('hex');\n if (resultHash === previousResultHash) {\n // If nothing changed in our produced outputs, we cannot have any\n // significant effect on our surroundings; therefore, we just abort\n // without any updates / stitching.\n track.markSuccessfulWithNoChanges();\n return;\n }\n\n // If the result was marked as not OK, it signals that some part of the\n // processing pipeline threw an exception. This can happen both as part of\n // non-catastrophic things such as due to validation errors, as well as if\n // something fatal happens inside the processing for other reasons. In any\n // case, this means we can't trust that anything in the output is okay. So\n // just store the errors and trigger a stich so that they become visible to\n // the outside.\n if (!result.ok) {\n // notify the error listener if the entity can not be processed.\n Promise.resolve(undefined)\n .then(() =>\n this.onProcessingError?.({\n unprocessedEntity,\n errors: result.errors,\n }),\n )\n .catch(error => {\n this.logger.debug(\n `Processing error listener threw an exception, ${stringifyError(\n error,\n )}`,\n );\n });\n\n await this.processingDatabase.transaction(async tx => {\n await this.processingDatabase.updateProcessedEntityErrors(tx, {\n id,\n errors: errorsString,\n resultHash,\n });\n });\n\n await this.stitcher.stitch({\n entityRefs: [stringifyEntityRef(unprocessedEntity)],\n });\n\n track.markSuccessfulWithErrors();\n return;\n }\n\n result.completedEntity.metadata.uid = id;\n let oldRelationSources: Map;\n await this.processingDatabase.transaction(async tx => {\n const { previous } =\n await this.processingDatabase.updateProcessedEntity(tx, {\n id,\n processedEntity: result.completedEntity,\n resultHash,\n errors: errorsString,\n relations: result.relations,\n deferredEntities: result.deferredEntities,\n locationKey,\n refreshKeys: result.refreshKeys,\n });\n oldRelationSources = new Map(\n previous.relations.map(r => [\n `${r.source_entity_ref}:${r.type}`,\n r.source_entity_ref,\n ]),\n );\n });\n\n const newRelationSources = new Map(\n result.relations.map(relation => {\n const sourceEntityRef = stringifyEntityRef(relation.source);\n return [`${sourceEntityRef}:${relation.type}`, sourceEntityRef];\n }),\n );\n\n const setOfThingsToStitch = new Set([\n stringifyEntityRef(result.completedEntity),\n ]);\n newRelationSources.forEach((sourceEntityRef, uniqueKey) => {\n if (!oldRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n oldRelationSources!.forEach((sourceEntityRef, uniqueKey) => {\n if (!newRelationSources.has(uniqueKey)) {\n setOfThingsToStitch.add(sourceEntityRef);\n }\n });\n\n await this.stitcher.stitch({\n entityRefs: setOfThingsToStitch,\n });\n\n track.markSuccessfulWithChanges();\n } catch (error) {\n assertError(error);\n track.markFailed(error);\n }\n });\n },\n });\n }\n\n private startOrphanCleanup(): () => void {\n const orphanStrategy =\n this.config.getOptionalString('catalog.orphanStrategy') ?? 'keep';\n if (orphanStrategy !== 'delete') {\n return () => {};\n }\n\n const stitchingStrategy = stitchingStrategyFromConfig(this.config);\n\n const runOnce = async () => {\n try {\n const n = await deleteOrphanedEntities({\n knex: this.knex,\n strategy: stitchingStrategy,\n });\n if (n > 0) {\n this.logger.info(`Deleted ${n} orphaned entities`);\n }\n } catch (error) {\n this.logger.warn(`Failed to delete orphaned entities`, error);\n }\n };\n\n if (this.scheduler) {\n const abortController = new AbortController();\n\n this.scheduler.scheduleTask({\n id: 'catalog_orphan_cleanup',\n frequency: { milliseconds: this.orphanCleanupIntervalMs },\n timeout: { milliseconds: this.orphanCleanupIntervalMs * 0.8 },\n fn: runOnce,\n signal: abortController.signal,\n });\n\n return () => {\n abortController.abort();\n };\n }\n\n const intervalKey = setInterval(runOnce, this.orphanCleanupIntervalMs);\n return () => {\n clearInterval(intervalKey);\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction progressTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promProcessedEntities = createCounterMetric({\n name: 'catalog_processed_entities_count',\n help: 'Amount of entities processed, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingDuration = createSummaryMetric({\n name: 'catalog_processing_duration_seconds',\n help: 'Time spent executing the full processing flow, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessorsDuration = createSummaryMetric({\n name: 'catalog_processors_duration_seconds',\n help: 'Time spent executing catalog processors, DEPRECATED, use OpenTelemetry metrics instead',\n labelNames: ['result'],\n });\n const promProcessingQueueDelay = createSummaryMetric({\n name: 'catalog_processing_queue_delay_seconds',\n help: 'The amount of delay between being scheduled for processing, and the start of actually being processed, DEPRECATED, use OpenTelemetry metrics instead',\n });\n\n const meter = metrics.getMeter('default');\n const processedEntities = meter.createCounter(\n 'catalog.processed.entities.count',\n { description: 'Amount of entities processed' },\n );\n\n const processingDuration = meter.createHistogram(\n 'catalog.processing.duration',\n {\n description: 'Time spent executing the full processing flow',\n unit: 'seconds',\n },\n );\n\n const processorsDuration = meter.createHistogram(\n 'catalog.processors.duration',\n {\n description: 'Time spent executing catalog processors',\n unit: 'seconds',\n },\n );\n\n const processingQueueDelay = meter.createHistogram(\n 'catalog.processing.queue.delay',\n {\n description:\n 'The amount of delay between being scheduled for processing, and the start of actually being processed',\n unit: 'seconds',\n },\n );\n\n function processStart(item: RefreshStateItem, logger: LoggerService) {\n const startTime = process.hrtime();\n const endOverallTimer = promProcessingDuration.startTimer();\n const endProcessorsTimer = promProcessorsDuration.startTimer();\n\n logger.debug(`Processing ${item.entityRef}`);\n\n if (item.nextUpdateAt) {\n const seconds = -item.nextUpdateAt.diffNow().as('seconds');\n promProcessingQueueDelay.observe(seconds);\n processingQueueDelay.record(seconds);\n }\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n function markProcessorsCompleted(result: EntityProcessingResult) {\n endProcessorsTimer({ result: result.ok ? 'ok' : 'failed' });\n processorsDuration.record(endTime(), {\n result: result.ok ? 'ok' : 'failed',\n });\n }\n\n function markSuccessfulWithNoChanges() {\n endOverallTimer({ result: 'unchanged' });\n promProcessedEntities.inc({ result: 'unchanged' }, 1);\n\n processingDuration.record(endTime(), { result: 'unchanged' });\n processedEntities.add(1, { result: 'unchanged' });\n }\n\n function markSuccessfulWithErrors() {\n endOverallTimer({ result: 'errors' });\n promProcessedEntities.inc({ result: 'errors' }, 1);\n\n processingDuration.record(endTime(), { result: 'errors' });\n processedEntities.add(1, { result: 'errors' });\n }\n\n function markSuccessfulWithChanges() {\n endOverallTimer({ result: 'changed' });\n promProcessedEntities.inc({ result: 'changed' }, 1);\n\n processingDuration.record(endTime(), { result: 'changed' });\n processedEntities.add(1, { result: 'changed' });\n }\n\n function markFailed(error: Error) {\n promProcessedEntities.inc({ result: 'failed' }, 1);\n processedEntities.add(1, { result: 'failed' });\n logger.warn(`Processing of ${item.entityRef} failed`, error);\n }\n\n return {\n markProcessorsCompleted,\n markSuccessfulWithNoChanges,\n markSuccessfulWithErrors,\n markSuccessfulWithChanges,\n markFailed,\n };\n }\n\n return { processStart };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n stringifyEntityRef,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\nimport { Location } from '@backstage/catalog-client';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { LocationInput, LocationService, LocationStore } from './types';\nimport { locationSpecToMetadataName } from '../util/conversion';\nimport { InputError } from '@backstage/errors';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\n\nexport type DefaultLocationServiceOptions = {\n allowedLocationTypes: string[];\n};\n\nexport class DefaultLocationService implements LocationService {\n constructor(\n private readonly store: LocationStore,\n private readonly orchestrator: CatalogProcessingOrchestrator,\n private readonly options: DefaultLocationServiceOptions = {\n allowedLocationTypes: ['url'],\n },\n ) {}\n\n async createLocation(\n input: LocationInput,\n dryRun: boolean,\n ): Promise<{ location: Location; entities: Entity[]; exists?: boolean }> {\n if (!this.options.allowedLocationTypes.includes(input.type)) {\n throw new InputError(\n `Registered locations must be of an allowed type ${JSON.stringify(\n this.options.allowedLocationTypes,\n )}`,\n );\n }\n if (dryRun) {\n return this.dryRunCreateLocation(input);\n }\n const location = await this.store.createLocation(input);\n return { location, entities: [] };\n }\n\n listLocations(): Promise {\n return this.store.listLocations();\n }\n getLocation(id: string): Promise {\n return this.store.getLocation(id);\n }\n deleteLocation(id: string): Promise {\n return this.store.deleteLocation(id);\n }\n\n getLocationByEntity(\n entityRef: CompoundEntityRef | string,\n ): Promise {\n return this.store.getLocationByEntity(parseEntityRef(entityRef));\n }\n\n private async processEntities(\n unprocessedEntities: DeferredEntity[],\n ): Promise {\n const entities: Entity[] = [];\n while (unprocessedEntities.length) {\n const currentEntity = unprocessedEntities.pop();\n if (!currentEntity) {\n continue;\n }\n const processed = await this.orchestrator.process({\n entity: currentEntity.entity,\n state: {}, // we process without the existing cache\n });\n\n if (processed.ok) {\n if (\n entities.some(\n e =>\n stringifyEntityRef(e) ===\n stringifyEntityRef(processed.completedEntity),\n )\n ) {\n throw new InputError(\n `Duplicate nested entity: ${stringifyEntityRef(\n processed.completedEntity,\n )}`,\n );\n }\n unprocessedEntities.push(...processed.deferredEntities);\n entities.push(processed.completedEntity);\n } else {\n throw new InputError(processed.errors.map(String).join(', '));\n }\n }\n return entities;\n }\n\n private async dryRunCreateLocation(\n spec: LocationInput,\n ): Promise<{ location: Location; entities: Entity[]; exists?: boolean }> {\n // Run the existence check in parallel with the processing\n const existsPromise = this.store\n .listLocations()\n .then(locations =>\n locations.some(l => l.type === spec.type && l.target === spec.target),\n );\n\n const entity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Location',\n metadata: {\n name: locationSpecToMetadataName({\n type: spec.type,\n target: spec.target,\n }),\n namespace: 'default',\n annotations: {\n [ANNOTATION_LOCATION]: `${spec.type}:${spec.target}`,\n [ANNOTATION_ORIGIN_LOCATION]: `${spec.type}:${spec.target}`,\n },\n },\n spec: {\n type: spec.type,\n target: spec.target,\n },\n };\n const unprocessedEntities: DeferredEntity[] = [\n { entity, locationKey: `${spec.type}:${spec.target}` },\n ];\n const entities: Entity[] = await this.processEntities(unprocessedEntities);\n\n return {\n exists: await existsPromise,\n location: { ...spec, id: `${spec.type}:${spec.target}` },\n entities,\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError, NotAllowedError } from '@backstage/errors';\nimport { Request } from 'express';\nimport lodash from 'lodash';\nimport { z } from 'zod';\nimport {\n Cursor,\n QueryEntitiesCursorRequest,\n QueryEntitiesInitialRequest,\n QueryEntitiesRequest,\n} from '../catalog/types';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\n\nexport async function requireRequestBody(req: Request): Promise {\n const contentType = req.header('content-type');\n if (!contentType) {\n throw new InputError('Content-Type missing');\n } else if (!contentType.match(/^application\\/json($|;)/)) {\n throw new InputError('Illegal Content-Type');\n }\n\n const body = req.body;\n if (!body) {\n throw new InputError('Missing request body');\n } else if (!lodash.isPlainObject(body)) {\n throw new InputError('Expected body to be a JSON object');\n } else if (Object.keys(body).length === 0) {\n // Because of how express.json() translates the empty body to {}\n throw new InputError('Empty request body');\n }\n\n return body;\n}\n\nexport const locationInput = z\n .object({\n type: z.string(),\n target: z.string(),\n presence: z.literal('required').or(z.literal('optional')).optional(),\n })\n .strict(); // no unknown keys;\n\nexport async function validateRequestBody(\n req: Request,\n schema: z.Schema,\n): Promise {\n const body = await requireRequestBody(req);\n try {\n return await schema.parse(body);\n } catch (e) {\n throw new InputError(`Malformed request: ${e}`);\n }\n}\n\nexport function disallowReadonlyMode(readonly: boolean) {\n if (readonly) {\n throw new NotAllowedError('This operation not allowed in readonly mode');\n }\n}\n\nexport function isQueryEntitiesInitialRequest(\n input: QueryEntitiesRequest | undefined,\n): input is QueryEntitiesInitialRequest {\n if (!input) {\n return false;\n }\n return !isQueryEntitiesCursorRequest(input);\n}\n\nexport function isQueryEntitiesCursorRequest(\n input: QueryEntitiesRequest | undefined,\n): input is QueryEntitiesCursorRequest {\n if (!input) {\n return false;\n }\n return !!(input as QueryEntitiesCursorRequest).cursor;\n}\n\nconst entityFilterParser: z.ZodSchema = z.lazy(() =>\n z\n .object({\n key: z.string(),\n values: z.array(z.string()).optional(),\n })\n .or(z.object({ not: entityFilterParser }))\n .or(z.object({ anyOf: z.array(entityFilterParser) }))\n .or(z.object({ allOf: z.array(entityFilterParser) })),\n);\n\nexport const cursorParser: z.ZodSchema = z.object({\n orderFields: z.array(\n z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),\n ),\n fullTextFilter: z\n .object({\n term: z.string(),\n fields: z.array(z.string()).optional(),\n })\n .optional(),\n orderFieldValues: z.array(z.string().or(z.null())),\n filter: entityFilterParser.optional(),\n isPrevious: z.boolean(),\n query: z.string().optional(),\n firstSortFieldValues: z.array(z.string().or(z.null())).optional(),\n totalItems: z.number().optional(),\n});\n\nexport function encodeCursor(cursor: Cursor) {\n const json = JSON.stringify(cursor);\n return Buffer.from(json, 'utf8').toString('base64');\n}\n\nexport function decodeCursor(encodedCursor: string) {\n try {\n const data = Buffer.from(encodedCursor, 'base64').toString('utf8');\n const result = cursorParser.safeParse(JSON.parse(data));\n\n if (!result.success) {\n throw new InputError(`Malformed cursor: ${result.error}`);\n }\n return result.data;\n } catch (e) {\n throw new InputError(`Malformed cursor: ${e}`);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { chunk as lodashChunk, isEqual } from 'lodash';\nimport { z } from 'zod';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n EntityOrder,\n EntityPagination,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport {\n DbFinalEntitiesRow,\n DbPageInfo,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n DbSearchRow,\n} from '../database/tables';\nimport { Stitcher } from '../stitching/types';\n\nimport {\n isQueryEntitiesCursorRequest,\n isQueryEntitiesInitialRequest,\n} from './util';\nimport {\n EntitiesSearchFilter,\n EntityFilter,\n} from '@backstage/plugin-catalog-node';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst defaultSortField: EntityOrder = {\n field: 'metadata.uid',\n order: 'asc',\n};\n\nconst DEFAULT_LIMIT = 20;\n\nfunction parsePagination(input?: EntityPagination): EntityPagination {\n if (!input) {\n return {};\n }\n\n let { limit, offset } = input;\n\n if (input.after === undefined) {\n return { limit, offset };\n }\n\n let cursor;\n try {\n const json = Buffer.from(input.after, 'base64').toString('utf8');\n cursor = JSON.parse(json);\n } catch {\n throw new InputError('Malformed after cursor, could not be parsed');\n }\n\n if (cursor.limit !== undefined) {\n if (!Number.isInteger(cursor.limit)) {\n throw new InputError('Malformed after cursor, limit was not an number');\n }\n limit = cursor.limit;\n }\n\n if (cursor.offset !== undefined) {\n if (!Number.isInteger(cursor.offset)) {\n throw new InputError('Malformed after cursor, offset was not a number');\n }\n offset = cursor.offset;\n }\n\n return { limit, offset };\n}\n\nfunction stringifyPagination(\n input: Required>,\n): string {\n const { limit, offset } = input;\n const json = JSON.stringify({ limit, offset });\n const base64 = Buffer.from(json, 'utf8').toString('base64');\n return base64;\n}\n\nfunction addCondition(\n queryBuilder: Knex.QueryBuilder,\n db: Knex,\n filter: EntitiesSearchFilter,\n negate: boolean = false,\n entityIdField = 'entity_id',\n): void {\n const key = filter.key.toLowerCase();\n const values = filter.values?.map(v => v.toLowerCase());\n\n // NOTE(freben): This used to be a set of OUTER JOIN, which may seem to\n // make a lot of sense. However, it had abysmal performance on sqlite\n // when datasets grew large, so we're using IN instead.\n const matchQuery = db('search')\n .select('search.entity_id')\n .where({ key })\n .andWhere(function keyFilter() {\n if (values?.length === 1) {\n this.where({ value: values.at(0) });\n } else if (values) {\n this.andWhere('value', 'in', values);\n }\n });\n queryBuilder.andWhere(entityIdField, negate ? 'not in' : 'in', matchQuery);\n}\n\nfunction isEntitiesSearchFilter(\n filter: EntitiesSearchFilter | EntityFilter,\n): filter is EntitiesSearchFilter {\n return filter.hasOwnProperty('key');\n}\n\nfunction isOrEntityFilter(\n filter: { anyOf: EntityFilter[] } | EntityFilter,\n): filter is { anyOf: EntityFilter[] } {\n return filter.hasOwnProperty('anyOf');\n}\n\nfunction isNegationEntityFilter(\n filter: { not: EntityFilter } | EntityFilter,\n): filter is { not: EntityFilter } {\n return filter.hasOwnProperty('not');\n}\n\nfunction parseFilter(\n filter: EntityFilter,\n query: Knex.QueryBuilder,\n db: Knex,\n negate: boolean = false,\n entityIdField = 'entity_id',\n): Knex.QueryBuilder {\n if (isNegationEntityFilter(filter)) {\n return parseFilter(filter.not, query, db, !negate, entityIdField);\n }\n\n if (isEntitiesSearchFilter(filter)) {\n return query.andWhere(function filterFunction() {\n addCondition(this, db, filter, negate, entityIdField);\n });\n }\n\n return query[negate ? 'andWhereNot' : 'andWhere'](function filterFunction() {\n if (isOrEntityFilter(filter)) {\n for (const subFilter of filter.anyOf ?? []) {\n this.orWhere(subQuery =>\n parseFilter(subFilter, subQuery, db, false, entityIdField),\n );\n }\n } else {\n for (const subFilter of filter.allOf ?? []) {\n this.andWhere(subQuery =>\n parseFilter(subFilter, subQuery, db, false, entityIdField),\n );\n }\n }\n });\n}\n\nexport class DefaultEntitiesCatalog implements EntitiesCatalog {\n private readonly database: Knex;\n private readonly logger: LoggerService;\n private readonly stitcher: Stitcher;\n\n constructor(options: {\n database: Knex;\n logger: LoggerService;\n stitcher: Stitcher;\n }) {\n this.database = options.database;\n this.logger = options.logger;\n this.stitcher = options.stitcher;\n }\n\n async entities(request?: EntitiesRequest): Promise {\n const db = this.database;\n\n let entitiesQuery =\n db('final_entities').select('final_entities.*');\n\n request?.order?.forEach(({ field }, index) => {\n const alias = `order_${index}`;\n entitiesQuery = entitiesQuery.leftOuterJoin(\n { [alias]: 'search' },\n function search(inner) {\n inner\n .on(`${alias}.entity_id`, 'final_entities.entity_id')\n .andOn(`${alias}.key`, db.raw('?', [field]));\n },\n );\n });\n\n entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity');\n\n if (request?.filter) {\n entitiesQuery = parseFilter(\n request.filter,\n entitiesQuery,\n db,\n false,\n 'final_entities.entity_id',\n );\n }\n\n request?.order?.forEach(({ order }, index) => {\n if (db.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order, nulls: 'last' },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value \" while avoiding to give an order\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order: undefined, nulls: 'last' },\n { column: `order_${index}.value`, order },\n ]);\n }\n });\n entitiesQuery = entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort\n\n const { limit, offset } = parsePagination(request?.pagination);\n if (limit !== undefined) {\n entitiesQuery = entitiesQuery.limit(limit + 1);\n }\n if (offset !== undefined) {\n entitiesQuery = entitiesQuery.offset(offset);\n }\n\n let rows = await entitiesQuery;\n let pageInfo: DbPageInfo;\n if (limit === undefined || rows.length <= limit) {\n pageInfo = { hasNextPage: false };\n } else {\n rows = rows.slice(0, -1);\n pageInfo = {\n hasNextPage: true,\n endCursor: stringifyPagination({\n limit,\n offset: (offset ?? 0) + limit,\n }),\n };\n }\n\n let entities: Entity[] = rows.map(e => JSON.parse(e.final_entity!));\n\n if (request?.fields) {\n entities = entities.map(e => request.fields!(e));\n }\n\n // TODO(freben): This is added as a compatibility guarantee, until we can be\n // sure that all adopters have re-stitched their entities so that the new\n // targetRef field is present on them, and that they have stopped consuming\n // the now-removed old field\n // TODO(jhaals): Remove this in April 2022\n for (const entity of entities) {\n if (entity.relations) {\n for (const relation of entity.relations as any) {\n if (!relation.targetRef && relation.target) {\n // This is the case where an old-form entity, not yet stitched with\n // the updated code, was in the database\n relation.targetRef = stringifyEntityRef(relation.target);\n } else if (!relation.target && relation.targetRef) {\n // This is the case where a new-form entity, stitched with the\n // updated code, was in the database but we still want to produce\n // the old data shape as well for compatibility reasons\n relation.target = parseEntityRef(relation.targetRef);\n }\n }\n }\n }\n\n return {\n entities,\n pageInfo,\n };\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise {\n const lookup = new Map();\n\n for (const chunk of lodashChunk(request.entityRefs, 200)) {\n let query = this.database('final_entities')\n .innerJoin(\n 'refresh_state',\n 'refresh_state.entity_id',\n 'final_entities.entity_id',\n )\n .select({\n entityRef: 'refresh_state.entity_ref',\n entity: 'final_entities.final_entity',\n })\n .whereIn('refresh_state.entity_ref', chunk);\n\n if (request?.filter) {\n query = parseFilter(\n request.filter,\n query,\n this.database,\n false,\n 'refresh_state.entity_id',\n );\n }\n\n for (const row of await query) {\n lookup.set(row.entityRef, row.entity ? JSON.parse(row.entity) : null);\n }\n }\n\n let items = request.entityRefs.map(ref => lookup.get(ref) ?? null);\n\n if (request.fields) {\n items = items.map(e => e && request.fields!(e));\n }\n\n return { items };\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise {\n const db = this.database;\n\n const limit = request.limit ?? DEFAULT_LIMIT;\n\n const cursor: Omit & {\n orderFieldValues?: (string | null)[];\n } = {\n orderFields: [defaultSortField],\n isPrevious: false,\n ...parseCursorFromRequest(request),\n };\n\n const isFetchingBackwards = cursor.isPrevious;\n\n if (cursor.orderFields.length > 1) {\n this.logger.warn(`Only one sort field is supported, ignoring the rest`);\n }\n\n const sortField: EntityOrder = {\n ...defaultSortField,\n ...cursor.orderFields[0],\n };\n\n const [prevItemOrderFieldValue, prevItemUid] =\n cursor.orderFieldValues || [];\n\n const dbQuery = db('search')\n .join('final_entities', 'search.entity_id', 'final_entities.entity_id')\n .where('search.key', sortField.field);\n\n if (cursor.filter) {\n parseFilter(cursor.filter, dbQuery, db, false, 'search.entity_id');\n }\n\n const normalizedFullTextFilterTerm = cursor.fullTextFilter?.term?.trim();\n const textFilterFields = cursor.fullTextFilter?.fields ?? [sortField.field];\n if (normalizedFullTextFilterTerm) {\n if (\n textFilterFields.length === 1 &&\n textFilterFields[0] === sortField.field\n ) {\n // If there is one item, apply the like query to the top level query which is already\n // filtered based on the singular sortField.\n dbQuery.andWhereRaw(\n 'value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n } else {\n const matchQuery = db('search')\n .select('search.entity_id')\n .whereIn('key', textFilterFields)\n .andWhere(function keyFilter() {\n this.andWhereRaw(\n 'value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n });\n dbQuery.andWhere('search.entity_id', 'in', matchQuery);\n }\n }\n\n const countQuery = dbQuery.clone();\n\n const isOrderingDescending = sortField.order === 'desc';\n\n if (prevItemOrderFieldValue) {\n dbQuery.andWhere(function nested() {\n this.where(\n 'value',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n prevItemOrderFieldValue,\n )\n .orWhere('value', '=', prevItemOrderFieldValue)\n .andWhere(\n 'search.entity_id',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n prevItemUid,\n );\n });\n }\n\n dbQuery\n .orderBy([\n {\n column: 'value',\n order: isFetchingBackwards\n ? invertOrder(sortField.order)\n : sortField.order,\n },\n {\n column: 'search.entity_id',\n order: isFetchingBackwards\n ? invertOrder(sortField.order)\n : sortField.order,\n },\n ])\n // fetch an extra item to check if there are more items.\n .limit(isFetchingBackwards ? limit : limit + 1);\n\n countQuery.count('search.entity_id', { as: 'count' });\n\n const [rows, [{ count }]] = await Promise.all([\n limit > 0 ? dbQuery : [],\n // for performance reasons we invoke the countQuery\n // only on the first request.\n // The result is then embedded into the cursor\n // for subsequent requests.\n typeof cursor.totalItems === 'undefined'\n ? countQuery\n : [{ count: cursor.totalItems }],\n ]);\n\n const totalItems = Number(count);\n\n if (isFetchingBackwards) {\n rows.reverse();\n }\n const hasMoreResults =\n limit > 0 && (isFetchingBackwards || rows.length > limit);\n\n // discard the extra item only when fetching forward.\n if (rows.length > limit) {\n rows.length -= 1;\n }\n\n const isInitialRequest = cursor.firstSortFieldValues === undefined;\n\n const firstRow = rows[0];\n const lastRow = rows[rows.length - 1];\n\n const firstSortFieldValues = cursor.firstSortFieldValues || [\n firstRow?.value,\n firstRow?.entity_id,\n ];\n\n const nextCursor: Cursor | undefined = hasMoreResults\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(lastRow),\n firstSortFieldValues,\n isPrevious: false,\n totalItems,\n }\n : undefined;\n\n const prevCursor: Cursor | undefined =\n !isInitialRequest &&\n rows.length > 0 &&\n !isEqual(sortFieldsFromRow(firstRow), cursor.firstSortFieldValues)\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(firstRow),\n firstSortFieldValues: cursor.firstSortFieldValues,\n isPrevious: true,\n totalItems,\n }\n : undefined;\n\n const items = rows\n .map(e => JSON.parse(e.final_entity!))\n .map(e => (request.fields ? request.fields(e) : e));\n\n return {\n items,\n pageInfo: {\n ...(!!prevCursor && { prevCursor }),\n ...(!!nextCursor && { nextCursor }),\n },\n totalItems,\n };\n }\n\n async removeEntityByUid(uid: string): Promise {\n const dbConfig = this.database.client.config;\n\n // Clear the hashed state of the immediate parents of the deleted entity.\n // This makes sure that when they get reprocessed, their output is written\n // down again. The reason for wanting to do this, is that if the user\n // deletes entities that ARE still emitted by the parent, the parent\n // processing will still generate the same output hash as always, which\n // means it'll never try to write down the children again (it assumes that\n // they already exist). This means that without the code below, the database\n // never \"heals\" from accidental deletes.\n if (dbConfig.client.includes('mysql')) {\n // MySQL doesn't support the syntax we need to do this in a single query,\n // http://dev.mysql.com/doc/refman/5.6/en/update.html\n const results = await this.database('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from('refresh_state')\n .innerJoin(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n await this.database('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn(\n 'entity_id',\n results.map(key => key.entity_id),\n );\n } else {\n await this.database('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: this.database.fn.now(),\n })\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from('refresh_state')\n .innerJoin(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n }\n\n // Stitch the entities that the deleted one had relations to. If we do not\n // do this, the entities in the other end of the relations will still look\n // like they have a relation to the entity that was deleted, despite not\n // having any corresponding rows in the relations table.\n const relationPeers = await this.database\n .from('relations')\n .innerJoin('refresh_state', {\n 'refresh_state.entity_ref': 'relations.target_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.target_entity_ref' })\n .union(other =>\n other\n .from('relations')\n .innerJoin('refresh_state', {\n 'refresh_state.entity_ref': 'relations.source_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.source_entity_ref' }),\n );\n\n await this.database('refresh_state')\n .where('entity_id', uid)\n .delete();\n\n await this.stitcher.stitch({\n entityRefs: new Set(relationPeers.map(p => p.ref)),\n });\n }\n\n async entityAncestry(rootRef: string): Promise {\n const [rootRow] = await this.database('refresh_state')\n .leftJoin('final_entities', {\n 'refresh_state.entity_id': 'final_entities.entity_id',\n })\n .where('refresh_state.entity_ref', '=', rootRef)\n .select({\n entityJson: 'final_entities.final_entity',\n });\n\n if (!rootRow) {\n throw new NotFoundError(`No such entity ${rootRef}`);\n }\n\n const rootEntity = JSON.parse(rootRow.entityJson) as Entity;\n const seenEntityRefs = new Set();\n const todo = new Array();\n const items = new Array<{ entity: Entity; parentEntityRefs: string[] }>();\n\n for (\n let current: Entity | undefined = rootEntity;\n current;\n current = todo.pop()\n ) {\n const currentRef = stringifyEntityRef(current);\n seenEntityRefs.add(currentRef);\n\n const parentRows = await this.database(\n 'refresh_state_references',\n )\n .innerJoin('refresh_state', {\n 'refresh_state_references.source_entity_ref':\n 'refresh_state.entity_ref',\n })\n .innerJoin('final_entities', {\n 'refresh_state.entity_id': 'final_entities.entity_id',\n })\n .where('refresh_state_references.target_entity_ref', '=', currentRef)\n .select({\n parentEntityRef: 'refresh_state.entity_ref',\n parentEntityJson: 'final_entities.final_entity',\n });\n\n const parentRefs: string[] = [];\n for (const { parentEntityRef, parentEntityJson } of parentRows) {\n parentRefs.push(parentEntityRef);\n if (!seenEntityRefs.has(parentEntityRef)) {\n seenEntityRefs.add(parentEntityRef);\n todo.push(JSON.parse(parentEntityJson));\n }\n }\n\n items.push({\n entity: current,\n parentEntityRefs: parentRefs,\n });\n }\n\n return {\n rootEntityRef: stringifyEntityRef(rootEntity),\n items,\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise {\n const facets: EntityFacetsResponse['facets'] = {};\n const db = this.database;\n\n for (const facet of request.facets) {\n const dbQuery = db('search')\n .where('search.key', facet.toLocaleLowerCase('en-US'))\n .whereNotNull('search.original_value')\n .select({ value: 'search.original_value', count: db.raw('count(*)') })\n .groupBy('search.original_value');\n\n if (request?.filter) {\n parseFilter(request.filter, dbQuery, db, false, 'search.entity_id');\n }\n\n const result = await dbQuery;\n\n facets[facet] = result.map(data => ({\n value: String(data.value),\n count: Number(data.count),\n }));\n }\n\n return { facets };\n }\n}\n\nconst entityFilterParser: z.ZodSchema = z.lazy(() =>\n z\n .object({\n key: z.string(),\n values: z.array(z.string()).optional(),\n })\n .or(z.object({ not: entityFilterParser }))\n .or(z.object({ anyOf: z.array(entityFilterParser) }))\n .or(z.object({ allOf: z.array(entityFilterParser) })),\n);\n\nexport const cursorParser: z.ZodSchema = z.object({\n orderFields: z.array(\n z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }),\n ),\n orderFieldValues: z.array(z.string().or(z.null())),\n filter: entityFilterParser.optional(),\n isPrevious: z.boolean(),\n query: z.string().optional(),\n firstSortFieldValues: z.array(z.string().or(z.null())).optional(),\n totalItems: z.number().optional(),\n});\n\nfunction parseCursorFromRequest(\n request?: QueryEntitiesRequest,\n): Partial {\n if (isQueryEntitiesInitialRequest(request)) {\n const {\n filter,\n orderFields: sortFields = [defaultSortField],\n fullTextFilter,\n } = request;\n return { filter, orderFields: sortFields, fullTextFilter };\n }\n if (isQueryEntitiesCursorRequest(request)) {\n return request.cursor;\n }\n return {};\n}\n\nfunction invertOrder(order: EntityOrder['order']) {\n return order === 'asc' ? 'desc' : 'asc';\n}\n\nfunction sortFieldsFromRow(row: DbSearchRow) {\n return [row.value, row.entity_id];\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n stringifyEntityRef,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport { assertError } from '@backstage/errors';\nimport {\n CatalogProcessor,\n CatalogProcessorResult,\n DeferredEntity,\n EntityRelationSpec,\n} from '@backstage/plugin-catalog-node';\nimport { locationSpecToLocationEntity } from '../util/conversion';\nimport {\n getEntityLocationRef,\n getEntityOriginLocationRef,\n validateEntityEnvelope,\n} from './util';\nimport { RefreshKeyData } from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Helper class for aggregating all of the emitted data from processors.\n */\nexport class ProcessorOutputCollector {\n private readonly errors = new Array();\n private readonly relations = new Array();\n private readonly deferredEntities = new Array();\n private readonly refreshKeys = new Array();\n private done = false;\n\n constructor(\n private readonly logger: LoggerService,\n private readonly parentEntity: Entity,\n ) {}\n\n generic(): (i: CatalogProcessorResult) => void {\n return i => this.receive(this.logger, i);\n }\n\n forProcessor(\n processor: CatalogProcessor,\n ): (i: CatalogProcessorResult) => void {\n const logger = this.logger.child({\n processor: processor.getProcessorName(),\n });\n return i => this.receive(logger, i);\n }\n\n results() {\n this.done = true;\n return {\n errors: this.errors,\n relations: this.relations,\n refreshKeys: this.refreshKeys,\n deferredEntities: this.deferredEntities,\n };\n }\n\n private receive(logger: LoggerService, i: CatalogProcessorResult) {\n if (this.done) {\n logger.warn(\n `Item of type \"${\n i.type\n }\" was emitted after processing had completed. Stack trace: ${\n new Error().stack\n }`,\n );\n return;\n }\n\n if (i.type === 'entity') {\n let entity: Entity;\n const location = stringifyLocationRef(i.location);\n\n try {\n entity = validateEntityEnvelope(i.entity);\n } catch (e) {\n assertError(e);\n logger.debug(`Envelope validation failed at ${location}, ${e}`);\n this.errors.push(e);\n return;\n }\n\n // The processor contract says you should return the \"trunk\" (current)\n // entity, not emit it. But it happens that this is misunderstood or\n // accidentally forgotten. This can lead to circular references which at\n // best is wasteful, so we try to be helpful by ignoring such emitted\n // entities.\n const entityRef = stringifyEntityRef(entity);\n if (entityRef === stringifyEntityRef(this.parentEntity)) {\n logger.warn(\n `Ignored emitted entity ${entityRef} whose ref was identical to the one being processed. This commonly indicates mistakenly emitting the input entity instead of returning it.`,\n );\n return;\n }\n\n // Note that at this point, we have only validated the envelope part of\n // the entity data. Annotations are not part of that, so we have to be\n // defensive. If the annotations were malformed (e.g. were not a valid\n // object), we just skip over this step and let the full entity\n // validation at the next step of processing catch that.\n const annotations = entity.metadata.annotations || {};\n if (typeof annotations === 'object' && !Array.isArray(annotations)) {\n const originLocation = getEntityOriginLocationRef(this.parentEntity);\n entity = {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n ...annotations,\n [ANNOTATION_ORIGIN_LOCATION]: originLocation,\n [ANNOTATION_LOCATION]: location,\n },\n },\n };\n }\n\n this.deferredEntities.push({ entity, locationKey: location });\n } else if (i.type === 'location') {\n const entity = locationSpecToLocationEntity({\n location: i.location,\n parentEntity: this.parentEntity,\n });\n const locationKey = getEntityLocationRef(entity);\n this.deferredEntities.push({ entity, locationKey });\n } else if (i.type === 'relation') {\n this.relations.push(i.relation);\n } else if (i.type === 'error') {\n this.errors.push(i.error);\n } else if (i.type === 'refresh') {\n this.refreshKeys.push({ key: i.key });\n }\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport {\n CatalogProcessor,\n CatalogProcessorCache,\n} from '@backstage/plugin-catalog-node';\nimport { isObject } from './util';\n\nclass SingleProcessorSubCache implements CatalogProcessorCache {\n private newState?: JsonObject;\n\n constructor(private readonly existingState?: JsonObject) {}\n\n async get(\n key: string,\n ): Promise {\n return this.existingState?.[key] as ItemType | undefined;\n }\n\n async set(\n key: string,\n value: ItemType,\n ): Promise {\n if (!this.newState) {\n this.newState = {};\n }\n\n this.newState[key] = value;\n }\n\n collect(): JsonObject | undefined {\n return this.newState ?? this.existingState;\n }\n}\n\nclass SingleProcessorCache implements CatalogProcessorCache {\n private newState?: JsonObject;\n private subCaches: Map = new Map();\n\n constructor(private readonly existingState?: JsonObject) {}\n\n async get(\n key: string,\n ): Promise {\n return this.existingState?.[key] as ItemType | undefined;\n }\n\n async set(\n key: string,\n value: ItemType,\n ): Promise {\n if (!this.newState) {\n this.newState = {};\n }\n\n this.newState[key] = value;\n }\n\n withKey(key: string) {\n const existingSubCache = this.subCaches.get(key);\n if (existingSubCache) {\n return existingSubCache;\n }\n const existing = this.existingState?.[key];\n const subCache = new SingleProcessorSubCache(\n isObject(existing) ? existing : undefined,\n );\n this.subCaches.set(key, subCache);\n return subCache;\n }\n\n collect(): JsonObject | undefined {\n let obj = this.newState ?? this.existingState;\n for (const [key, subCache] of this.subCaches) {\n const subCacheValue = subCache.collect();\n if (subCacheValue) {\n obj = { ...obj, [key]: subCacheValue };\n }\n }\n return obj;\n }\n}\n\nexport class ProcessorCacheManager {\n private caches = new Map();\n\n constructor(private readonly existingState: JsonObject) {}\n\n forProcessor(\n processor: CatalogProcessor,\n key?: string,\n ): CatalogProcessorCache {\n // constructor name will be deprecated in the future when we make `getProcessorName` required in the implementation\n const name = processor.getProcessorName();\n const cache = this.caches.get(name);\n if (cache) {\n return key ? cache.withKey(key) : cache;\n }\n\n const existing = this.existingState[name];\n\n const newCache = new SingleProcessorCache(\n isObject(existing) ? existing : undefined,\n );\n this.caches.set(name, newCache);\n return key ? newCache.withKey(key) : newCache;\n }\n\n collect(): JsonObject {\n const result: JsonObject = {};\n for (const [key, value] of this.caches.entries()) {\n result[key] = value.collect();\n }\n\n return result;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Span, trace } from '@opentelemetry/api';\nimport {\n Entity,\n EntityPolicy,\n LocationEntity,\n parseLocationRef,\n stringifyEntityRef,\n stringifyLocationRef,\n} from '@backstage/catalog-model';\nimport {\n assertError,\n ConflictError,\n InputError,\n NotAllowedError,\n} from '@backstage/errors';\nimport { JsonValue } from '@backstage/types';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport {\n CatalogProcessingOrchestrator,\n EntityProcessingRequest,\n EntityProcessingResult,\n} from './types';\nimport { ProcessorOutputCollector } from './ProcessorOutputCollector';\nimport {\n getEntityLocationRef,\n getEntityOriginLocationRef,\n isLocationEntity,\n isObject,\n toAbsoluteUrl,\n validateEntity,\n validateEntityEnvelope,\n} from './util';\nimport { CatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { ProcessorCacheManager } from './ProcessorCacheManager';\nimport {\n addEntityAttributes,\n TRACER_ID,\n withActiveSpan,\n} from '../util/opentelemetry';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst tracer = trace.getTracer(TRACER_ID);\n\ntype Context = {\n entityRef: string;\n location: LocationSpec;\n originLocation: LocationSpec;\n collector: ProcessorOutputCollector;\n cache: ProcessorCacheManager;\n};\n\nfunction addProcessorAttributes(\n span: Span,\n stage: string,\n processor: CatalogProcessor,\n) {\n span.setAttribute('backstage.catalog.processor.stage', stage);\n span.setAttribute(\n 'backstage.catalog.processor.name',\n processor.getProcessorName(),\n );\n}\n\n/** @public */\nexport class DefaultCatalogProcessingOrchestrator\n implements CatalogProcessingOrchestrator\n{\n constructor(\n private readonly options: {\n processors: CatalogProcessor[];\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n parser: CatalogProcessorParser;\n policy: EntityPolicy;\n rulesEnforcer: CatalogRulesEnforcer;\n legacySingleProcessorValidation: boolean;\n },\n ) {}\n\n async process(\n request: EntityProcessingRequest,\n ): Promise {\n return this.processSingleEntity(request.entity, request.state);\n }\n\n private async processSingleEntity(\n unprocessedEntity: Entity,\n state: JsonValue | undefined,\n ): Promise {\n const collector = new ProcessorOutputCollector(\n this.options.logger,\n unprocessedEntity,\n );\n\n // Cache that is scoped to the entity and processor\n const cache = new ProcessorCacheManager(\n isObject(state) && isObject(state.cache) ? state.cache : {},\n );\n\n try {\n // This will be checked and mutated step by step below\n let entity: Entity = unprocessedEntity;\n\n // NOTE: At this early point, we can only rely on the envelope having to\n // be valid; full entity + kind validation happens after the (potentially\n // mutative) pre-steps. This means that the code below can't make a lot\n // of assumptions about the data despite it using the Entity type.\n try {\n validateEntityEnvelope(entity);\n } catch (e) {\n throw new InputError(\n `Entity envelope failed validation before processing`,\n e,\n );\n }\n\n // TODO: which one do we actually use for the location?\n // source-location? - maybe probably doesn't exist yet?\n const context: Context = {\n entityRef: stringifyEntityRef(entity),\n location: parseLocationRef(getEntityLocationRef(entity)),\n originLocation: parseLocationRef(getEntityOriginLocationRef(entity)),\n cache,\n collector,\n };\n\n // Run the steps\n entity = await this.runPreProcessStep(entity, context);\n entity = await this.runPolicyStep(entity);\n await this.runValidateStep(entity, context);\n if (isLocationEntity(entity)) {\n await this.runSpecialLocationStep(entity, context);\n }\n entity = await this.runPostProcessStep(entity, context);\n\n // Check that any emitted entities are permitted to originate from that\n // particular location according to the catalog rules\n const collectorResults = context.collector.results();\n for (const deferredEntity of collectorResults.deferredEntities) {\n if (\n !this.options.rulesEnforcer.isAllowed(\n deferredEntity.entity,\n context.originLocation,\n )\n ) {\n throw new NotAllowedError(\n `Entity ${stringifyEntityRef(\n deferredEntity.entity,\n )} at ${stringifyLocationRef(\n context.location,\n )}, originated at ${stringifyLocationRef(\n context.originLocation,\n )}, is not of an allowed kind for that location`,\n );\n }\n }\n\n return {\n ...collectorResults,\n completedEntity: entity,\n state: { cache: cache.collect() },\n ok: collectorResults.errors.length === 0,\n };\n } catch (error) {\n assertError(error);\n return {\n ok: false,\n errors: collector.results().errors.concat(error),\n };\n }\n }\n\n // Pre-process phase, used to populate entities with data that is required\n // during the main processing step\n private async runPreProcessStep(\n entity: Entity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute('backstage.catalog.processor.stage', 'preProcess');\n let res = entity;\n\n for (const processor of this.options.processors) {\n if (processor.preProcessEntity) {\n let innerRes = res;\n res = await withActiveSpan(tracer, 'ProcessingStep', async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'preProcessEntity', processor);\n try {\n innerRes = await processor.preProcessEntity!(\n innerRes,\n context.location,\n context.collector.forProcessor(processor),\n context.originLocation,\n context.cache.forProcessor(processor),\n );\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while preprocessing`,\n e,\n );\n }\n return innerRes;\n });\n }\n }\n\n return res;\n });\n }\n\n /**\n * Enforce entity policies making sure that entities conform to a general schema\n */\n private async runPolicyStep(entity: Entity): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute(\n 'backstage.catalog.processor.stage',\n 'enforcePolicy',\n );\n let policyEnforcedEntity: Entity | undefined;\n\n try {\n policyEnforcedEntity = await this.options.policy.enforce(entity);\n } catch (e) {\n throw new InputError(\n `Policy check failed for ${stringifyEntityRef(entity)}`,\n e,\n );\n }\n\n if (!policyEnforcedEntity) {\n throw new Error(\n `Policy unexpectedly returned no data for ${stringifyEntityRef(\n entity,\n )}`,\n );\n }\n\n return policyEnforcedEntity;\n });\n }\n\n /**\n * Validate the given entity\n */\n private async runValidateStep(\n entity: Entity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute('backstage.catalog.processor.stage', 'validate');\n // Double check that none of the previous steps tried to change something\n // related to the entity ref, which would break downstream\n if (stringifyEntityRef(entity) !== context.entityRef) {\n throw new ConflictError(\n 'Fatal: The entity kind, namespace, or name changed during processing',\n );\n }\n\n // Validate that the end result is a valid Entity at all\n try {\n validateEntity(entity);\n } catch (e) {\n throw new ConflictError(\n `Entity envelope for ${context.entityRef} failed validation after preprocessing`,\n e,\n );\n }\n\n let valid = false;\n\n for (const processor of this.options.processors) {\n if (processor.validateEntityKind) {\n try {\n const thisValid = await withActiveSpan(\n tracer,\n 'ProcessingStep',\n async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'validateEntityKind', processor);\n return await processor.validateEntityKind!(entity);\n },\n );\n if (thisValid) {\n valid = true;\n if (this.options.legacySingleProcessorValidation) {\n break;\n }\n }\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while validating the entity ${context.entityRef}`,\n e,\n );\n }\n }\n }\n\n if (!valid) {\n throw new InputError(\n `No processor recognized the entity ${context.entityRef} as valid, possibly caused by a foreign kind or apiVersion`,\n );\n }\n });\n }\n\n /**\n * Backwards compatible processing of location entities\n */\n private async runSpecialLocationStep(\n entity: LocationEntity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute(\n 'backstage.catalog.processor.stage',\n 'readLocation',\n );\n const { type = context.location.type, presence = 'required' } =\n entity.spec;\n const targets = new Array();\n if (entity.spec.target) {\n targets.push(entity.spec.target);\n }\n if (entity.spec.targets) {\n targets.push(...entity.spec.targets);\n }\n\n for (const maybeRelativeTarget of targets) {\n if (type === 'file' && maybeRelativeTarget.endsWith(path.sep)) {\n context.collector.generic()(\n processingResult.inputError(\n context.location,\n `LocationEntityProcessor cannot handle ${type} type location with target ${context.location.target} that ends with a path separator`,\n ),\n );\n continue;\n }\n const target = toAbsoluteUrl(\n this.options.integrations,\n context.location,\n type,\n maybeRelativeTarget,\n );\n\n let didRead = false;\n for (const processor of this.options.processors) {\n if (processor.readLocation) {\n try {\n const read = await withActiveSpan(\n tracer,\n 'ProcessingStep',\n async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'readLocation', processor);\n return await processor.readLocation!(\n {\n type,\n target,\n presence,\n },\n presence === 'optional',\n context.collector.forProcessor(processor),\n this.options.parser,\n context.cache.forProcessor(processor, target),\n );\n },\n );\n if (read) {\n didRead = true;\n break;\n }\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while reading ${type}:${target}`,\n e,\n );\n }\n }\n }\n if (!didRead) {\n throw new InputError(\n `No processor was able to handle reading of ${type}:${target}`,\n );\n }\n }\n });\n }\n\n /**\n * Main processing step of the entity\n */\n private async runPostProcessStep(\n entity: Entity,\n context: Context,\n ): Promise {\n return await withActiveSpan(tracer, 'ProcessingStage', async stageSpan => {\n addEntityAttributes(stageSpan, entity);\n stageSpan.setAttribute(\n 'backstage.catalog.processor.stage',\n 'postProcessEntity',\n );\n let res = entity;\n\n for (const processor of this.options.processors) {\n if (processor.postProcessEntity) {\n let innerRes = res;\n res = await withActiveSpan(tracer, 'ProcessingStep', async span => {\n addEntityAttributes(span, entity);\n addProcessorAttributes(span, 'postProcessEntity', processor);\n try {\n innerRes = await processor.postProcessEntity!(\n innerRes,\n context.location,\n context.collector.forProcessor(processor),\n context.cache.forProcessor(processor),\n );\n } catch (e) {\n throw new InputError(\n `Processor ${processor.constructor.name} threw an error while postprocessing`,\n e,\n );\n }\n return innerRes;\n });\n }\n }\n\n return res;\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { timestampToDateTime } from '../../conversion';\nimport { DbRefreshStateRow } from '../../tables';\n\n// TODO(freben): There is no retry counter or similar. If items start\n// perpetually crashing during stitching, they'll just get silently retried over\n// and over again, for better or worse. This will be visible in metrics though.\n\n/**\n * Finds entities that are marked for deferred stitching.\n *\n * @remarks\n *\n * This assumes that the stitching strategy is set to deferred.\n *\n * They are expected to already have the next_stitch_ticket set (by\n * markForStitching) so that their tickets can be returned with each item.\n *\n * All returned items have their next_stitch_at updated to be moved forward by\n * the given timeout duration. This has the effect that they will be picked up\n * for stitching again in the future, if it hasn't completed by that point for\n * some reason (restarts, crashes, etc).\n */\nexport async function getDeferredStitchableEntities(options: {\n knex: Knex | Knex.Transaction;\n batchSize: number;\n stitchTimeout: HumanDuration;\n}): Promise<\n Array<{\n entityRef: string;\n stitchTicket: string;\n stitchRequestedAt: DateTime; // the time BEFORE moving it forward by the timeout\n }>\n> {\n const { knex, batchSize, stitchTimeout } = options;\n\n let itemsQuery = knex('refresh_state').select(\n 'entity_ref',\n 'next_stitch_at',\n 'next_stitch_ticket',\n );\n\n // This avoids duplication of work because of race conditions and is\n // also fast because locked rows are ignored rather than blocking.\n // It's only available in MySQL and PostgreSQL\n if (['mysql', 'mysql2', 'pg'].includes(knex.client.config.client)) {\n itemsQuery = itemsQuery.forUpdate().skipLocked();\n }\n\n const items = await itemsQuery\n .whereNotNull('next_stitch_at')\n .whereNotNull('next_stitch_ticket')\n .where('next_stitch_at', '<=', knex.fn.now())\n .orderBy('next_stitch_at', 'asc')\n .limit(batchSize);\n\n if (!items.length) {\n return [];\n }\n\n await knex('refresh_state')\n .whereIn(\n 'entity_ref',\n items.map(i => i.entity_ref),\n )\n // avoid race condition where someone completes a stitch right between these statements\n .whereNotNull('next_stitch_ticket')\n .update({\n next_stitch_at: nowPlus(knex, stitchTimeout),\n });\n\n return items.map(i => ({\n entityRef: i.entity_ref,\n stitchTicket: i.next_stitch_ticket!,\n stitchRequestedAt: timestampToDateTime(i.next_stitch_at!),\n }));\n}\n\nfunction nowPlus(knex: Knex, duration: HumanDuration): Knex.Raw {\n const seconds = durationToMilliseconds(duration) / 1000;\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);\n } else if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`now() + interval ${seconds} second`);\n }\n return knex.raw(`now() + interval '${seconds} seconds'`);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DEFAULT_NAMESPACE, Entity } from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport { DbSearchRow } from '../../tables';\n\n// These are excluded in the generic loop, either because they do not make sense\n// to index, or because they are special-case always inserted whether they are\n// null or not\nconst SPECIAL_KEYS = [\n 'attachments',\n 'relations',\n 'status',\n 'metadata.name',\n 'metadata.namespace',\n 'metadata.uid',\n 'metadata.etag',\n];\n\n// The maximum length allowed for search values. These columns are indexed, and\n// database engines do not like to index on massive values. For example,\n// postgres will balk after 8191 byte line sizes.\nconst MAX_KEY_LENGTH = 200;\nconst MAX_VALUE_LENGTH = 200;\n\ntype Kv = {\n key: string;\n value: unknown;\n};\n\n// Helper for traversing through a nested structure and outputting a list of\n// path->value entries of the leaves.\n//\n// For example, this yaml structure\n//\n// a: 1\n// b:\n// c: null\n// e: [f, g]\n// h:\n// - i: 1\n// j: k\n// - i: 2\n// j: l\n//\n// will result in\n//\n// \"a\", 1\n// \"b.c\", null\n// \"b.e\": \"f\"\n// \"b.e.f\": true\n// \"b.e\": \"g\"\n// \"b.e.g\": true\n// \"h.i\": 1\n// \"h.j\": \"k\"\n// \"h.i\": 2\n// \"h.j\": \"l\"\nexport function traverse(root: unknown): Kv[] {\n const output: Kv[] = [];\n\n function visit(path: string, current: unknown) {\n if (SPECIAL_KEYS.includes(path)) {\n return;\n }\n\n // empty or scalar\n if (\n current === undefined ||\n current === null ||\n ['string', 'number', 'boolean'].includes(typeof current)\n ) {\n output.push({ key: path, value: current });\n return;\n }\n\n // unknown\n if (typeof current !== 'object') {\n return;\n }\n\n // array\n if (Array.isArray(current)) {\n for (const item of current) {\n // NOTE(freben): The reason that these are output in two different ways,\n // is to support use cases where you want to express that MORE than one\n // tag is present in a list. Since the EntityFilters structure is a\n // record, you can't have several entries of the same key. Therefore\n // you will have to match on\n //\n // { \"a.b\": [\"true\"], \"a.c\": [\"true\"] }\n //\n // rather than\n //\n // { \"a\": [\"b\", \"c\"] }\n //\n // because the latter means EITHER b or c has to be present.\n visit(path, item);\n if (typeof item === 'string') {\n output.push({ key: `${path}.${item}`, value: true });\n }\n }\n return;\n }\n\n // object\n for (const [key, value] of Object.entries(current!)) {\n visit(path ? `${path}.${key}` : key, value);\n }\n }\n\n visit('', root);\n\n return output;\n}\n\n// Translates a number of raw data rows to search table rows\nexport function mapToRows(input: Kv[], entityId: string): DbSearchRow[] {\n const result: DbSearchRow[] = [];\n\n for (const { key: rawKey, value: rawValue } of input) {\n const key = rawKey.toLocaleLowerCase('en-US');\n if (key.length > MAX_KEY_LENGTH) {\n continue;\n }\n if (rawValue === undefined || rawValue === null) {\n result.push({\n entity_id: entityId,\n key,\n original_value: null,\n value: null,\n });\n } else {\n const value = String(rawValue).toLocaleLowerCase('en-US');\n if (value.length <= MAX_VALUE_LENGTH) {\n result.push({\n entity_id: entityId,\n key,\n original_value: String(rawValue),\n value: value,\n });\n } else {\n result.push({\n entity_id: entityId,\n key,\n original_value: null,\n value: null,\n });\n }\n }\n }\n\n return result;\n}\n\n/**\n * Generates all of the search rows that are relevant for this entity.\n *\n * @param entityId - The uid of the entity\n * @param entity - The entity\n * @returns A list of entity search rows\n */\nexport function buildEntitySearch(\n entityId: string,\n entity: Entity,\n): DbSearchRow[] {\n // Visit the base structure recursively\n const raw = traverse(entity);\n\n // Start with some special keys that are always present because you want to\n // be able to easily search for null specifically\n raw.push({ key: 'metadata.name', value: entity.metadata.name });\n raw.push({ key: 'metadata.namespace', value: entity.metadata.namespace });\n raw.push({ key: 'metadata.uid', value: entity.metadata.uid });\n\n // Namespace not specified has the default value \"default\", so we want to\n // match on that as well\n if (!entity.metadata.namespace) {\n raw.push({ key: 'metadata.namespace', value: DEFAULT_NAMESPACE });\n }\n\n // Visit relations\n for (const relation of entity.relations ?? []) {\n raw.push({\n key: `relations.${relation.type}`,\n value: relation.targetRef,\n });\n }\n\n // This validates that there are no keys that vary only in casing, such\n // as `spec.foo` and `spec.Foo`.\n const keys = new Set(raw.map(r => r.key));\n const lowerKeys = new Set(raw.map(r => r.key.toLocaleLowerCase('en-US')));\n if (keys.size !== lowerKeys.size) {\n const difference = [];\n for (const key of keys) {\n const lower = key.toLocaleLowerCase('en-US');\n if (!lowerKeys.delete(lower)) {\n difference.push(lower);\n }\n }\n const badKeys = `'${difference.join(\"', '\")}'`;\n throw new InputError(\n `Entity has duplicate keys that vary only in casing, ${badKeys}`,\n );\n }\n\n return mapToRows(raw, entityId);\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Marks a single entity as having been stitched.\n *\n * @remarks\n *\n * This assumes that the stitching strategy is set to deferred.\n *\n * The timestamp and ticket are only reset if the ticket hasn't changed. If it\n * has, it means that a new stitch request has been made, and the entity should\n * be stitched once more some time in the future - or is indeed already being\n * stitched concurrently with ourselves.\n */\nexport async function markDeferredStitchCompleted(option: {\n knex: Knex | Knex.Transaction;\n entityRef: string;\n stitchTicket: string;\n}): Promise {\n const { knex, entityRef, stitchTicket } = option;\n\n await knex('refresh_state')\n .update({\n next_stitch_at: null,\n next_stitch_ticket: null,\n })\n .where('entity_ref', '=', entityRef)\n .andWhere('next_stitch_ticket', '=', stitchTicket);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nexport const BATCH_SIZE = 50;\n\nexport function generateStableHash(entity: Entity) {\n return createHash('sha1')\n .update(stableStringify({ ...entity }))\n .digest('hex');\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from '@backstage/catalog-client';\nimport {\n ANNOTATION_EDIT_URL,\n ANNOTATION_VIEW_URL,\n EntityRelation,\n} from '@backstage/catalog-model';\nimport { AlphaEntity, EntityStatusItem } from '@backstage/catalog-model/alpha';\nimport { SerializedError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport { StitchingStrategy } from '../../../stitching/types';\nimport {\n DbFinalEntitiesRow,\n DbRefreshStateRow,\n DbSearchRow,\n} from '../../tables';\nimport { buildEntitySearch } from './buildEntitySearch';\nimport { markDeferredStitchCompleted } from './markDeferredStitchCompleted';\nimport { BATCH_SIZE, generateStableHash } from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// See https://github.com/facebook/react/blob/f0cf832e1d0c8544c36aa8b310960885a11a847c/packages/react-dom-bindings/src/shared/sanitizeURL.js\nconst scriptProtocolPattern =\n // eslint-disable-next-line no-control-regex\n /^[\\u0000-\\u001F ]*j[\\r\\n\\t]*a[\\r\\n\\t]*v[\\r\\n\\t]*a[\\r\\n\\t]*s[\\r\\n\\t]*c[\\r\\n\\t]*r[\\r\\n\\t]*i[\\r\\n\\t]*p[\\r\\n\\t]*t[\\r\\n\\t]*\\:/i;\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport async function performStitching(options: {\n knex: Knex | Knex.Transaction;\n logger: LoggerService;\n strategy: StitchingStrategy;\n entityRef: string;\n stitchTicket?: string;\n}): Promise<'changed' | 'unchanged' | 'abandoned'> {\n const { knex, logger, entityRef } = options;\n const stitchTicket = options.stitchTicket ?? uuid();\n\n const entityResult = await knex('refresh_state')\n .where({ entity_ref: entityRef })\n .limit(1)\n .select('entity_id');\n if (!entityResult.length) {\n // Entity does no exist in refresh state table, no stitching required.\n return 'abandoned';\n }\n\n // Insert stitching ticket that will be compared before inserting the final entity.\n await knex('final_entities')\n .insert({\n entity_id: entityResult[0].entity_id,\n hash: '',\n stitch_ticket: stitchTicket,\n })\n .onConflict('entity_id')\n .merge(['stitch_ticket']);\n\n // Selecting from refresh_state and final_entities should yield exactly\n // one row (except in abnormal cases where the stitch was invoked for\n // something that didn't exist at all, in which case it's zero rows).\n // The join with the temporary incoming_references still gives one row.\n const [processedResult, relationsResult] = await Promise.all([\n knex\n .with('incoming_references', function incomingReferences(builder) {\n return builder\n .from('refresh_state_references')\n .where({ target_entity_ref: entityRef })\n .count({ count: '*' });\n })\n .select({\n entityId: 'refresh_state.entity_id',\n processedEntity: 'refresh_state.processed_entity',\n errors: 'refresh_state.errors',\n incomingReferenceCount: 'incoming_references.count',\n previousHash: 'final_entities.hash',\n })\n .from('refresh_state')\n .where({ 'refresh_state.entity_ref': entityRef })\n .crossJoin(knex.raw('incoming_references'))\n .leftOuterJoin('final_entities', {\n 'final_entities.entity_id': 'refresh_state.entity_id',\n }),\n knex\n .distinct({\n relationType: 'type',\n relationTarget: 'target_entity_ref',\n })\n .from('relations')\n .where({ source_entity_ref: entityRef })\n .orderBy('relationType', 'asc')\n .orderBy('relationTarget', 'asc'),\n ]);\n\n // If there were no rows returned, it would mean that there was no\n // matching row even in the refresh_state. This can happen for example\n // if we emit a relation to something that hasn't been ingested yet.\n // It's safe to ignore this stitch attempt in that case.\n if (!processedResult.length) {\n logger.debug(\n `Unable to stitch ${entityRef}, item does not exist in refresh state table`,\n );\n return 'abandoned';\n }\n\n const {\n entityId,\n processedEntity,\n errors,\n incomingReferenceCount,\n previousHash,\n } = processedResult[0];\n\n // If there was no processed entity in place, the target hasn't been\n // through the processing steps yet. It's safe to ignore this stitch\n // attempt in that case, since another stitch will be triggered when\n // that processing has finished.\n if (!processedEntity) {\n logger.debug(\n `Unable to stitch ${entityRef}, the entity has not yet been processed`,\n );\n return 'abandoned';\n }\n\n // Grab the processed entity and stitch all of the relevant data into\n // it\n const entity = JSON.parse(processedEntity) as AlphaEntity;\n const isOrphan = Number(incomingReferenceCount) === 0;\n let statusItems: EntityStatusItem[] = [];\n\n if (isOrphan) {\n logger.debug(`${entityRef} is an orphan`);\n entity.metadata.annotations = {\n ...entity.metadata.annotations,\n ['backstage.io/orphan']: 'true',\n };\n }\n if (errors) {\n const parsedErrors = JSON.parse(errors) as SerializedError[];\n if (Array.isArray(parsedErrors) && parsedErrors.length) {\n statusItems = parsedErrors.map(e => ({\n type: ENTITY_STATUS_CATALOG_PROCESSING_TYPE,\n level: 'error',\n message: `${e.name}: ${e.message}`,\n error: e,\n }));\n }\n }\n // We opt to do this check here as we otherwise can't guarantee that it will be run after all processors\n for (const annotation of [ANNOTATION_VIEW_URL, ANNOTATION_EDIT_URL]) {\n const value = entity.metadata.annotations?.[annotation];\n if (typeof value === 'string' && scriptProtocolPattern.test(value)) {\n entity.metadata.annotations![annotation] =\n 'https://backstage.io/annotation-rejected-for-security-reasons';\n }\n }\n\n // TODO: entityRef is lower case and should be uppercase in the final\n // result\n entity.relations = relationsResult\n .filter(row => row.relationType /* exclude null row, if relevant */)\n .map(row => ({\n type: row.relationType!,\n targetRef: row.relationTarget!,\n }));\n if (statusItems.length) {\n entity.status = {\n ...entity.status,\n items: [...(entity.status?.items ?? []), ...statusItems],\n };\n }\n\n // If the output entity was actually not changed, just abort\n const hash = generateStableHash(entity);\n if (hash === previousHash) {\n logger.debug(`Skipped stitching of ${entityRef}, no changes`);\n return 'unchanged';\n }\n\n entity.metadata.uid = entityId;\n if (!entity.metadata.etag) {\n // If the original data source did not have its own etag handling,\n // use the hash as a good-quality etag\n entity.metadata.etag = hash;\n }\n\n // This may throw if the entity is invalid, so we call it before\n // the final_entities write, even though we may end up not needing\n // to write the search index.\n const searchEntries = buildEntitySearch(entityId, entity);\n\n const amountOfRowsChanged = await knex('final_entities')\n .update({\n final_entity: JSON.stringify(entity),\n hash,\n last_updated_at: knex.fn.now(),\n })\n .where('entity_id', entityId)\n .where('stitch_ticket', stitchTicket)\n .onConflict('entity_id')\n .merge(['final_entity', 'hash', 'last_updated_at']);\n\n if (options.strategy.mode === 'deferred') {\n await markDeferredStitchCompleted({\n knex: knex,\n entityRef,\n stitchTicket,\n });\n }\n\n if (amountOfRowsChanged === 0) {\n logger.debug(`Entity ${entityRef} is already stitched, skipping write.`);\n return 'abandoned';\n }\n\n // TODO(freben): Search will probably need a similar safeguard against\n // race conditions like the final_entities ticket handling above.\n // Otherwise, it can be the case that:\n // A writes the entity ->\n // B writes the entity ->\n // B writes search ->\n // A writes search\n await knex('search').where({ entity_id: entityId }).delete();\n await knex.batchInsert('search', searchEntries, BATCH_SIZE);\n\n return 'changed';\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyError } from '@backstage/errors';\nimport { metrics } from '@opentelemetry/api';\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { DbRefreshStateRow } from '../database/tables';\nimport { createCounterMetric } from '../util/metrics';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// Helps wrap the timing and logging behaviors\nexport function progressTracker(knex: Knex, logger: LoggerService) {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promStitchedEntities = createCounterMetric({\n name: 'catalog_stitched_entities_count',\n help: 'Amount of entities stitched. DEPRECATED, use OpenTelemetry metrics instead',\n });\n\n const meter = metrics.getMeter('default');\n\n const stitchedEntities = meter.createCounter(\n 'catalog.stitched.entities.count',\n {\n description: 'Amount of entities stitched',\n },\n );\n\n const stitchingDuration = meter.createHistogram(\n 'catalog.stitching.duration',\n {\n description: 'Time spent executing the full stitching flow',\n unit: 'seconds',\n },\n );\n\n const stitchingQueueCount = meter.createObservableGauge(\n 'catalog.stitching.queue.length',\n { description: 'Number of entities currently in the stitching queue' },\n );\n stitchingQueueCount.addCallback(async result => {\n const total = await knex('refresh_state')\n .count({ count: '*' })\n .whereNotNull('next_stitch_at')\n .where('next_stitch_at', '<=', knex.fn.now());\n result.observe(Number(total[0].count));\n });\n\n const stitchingQueueDelay = meter.createHistogram(\n 'catalog.stitching.queue.delay',\n {\n description:\n 'The amount of delay between being scheduled for stitching, and the start of actually being stitched',\n unit: 'seconds',\n },\n );\n\n function stitchStart(item: {\n entityRef: string;\n stitchRequestedAt?: DateTime;\n }) {\n logger.debug(`Stitching ${item.entityRef}`);\n\n const startTime = process.hrtime();\n if (item.stitchRequestedAt) {\n stitchingQueueDelay.record(\n -item.stitchRequestedAt.diffNow().as('seconds'),\n );\n }\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n function markComplete(result: string) {\n promStitchedEntities.inc(1);\n stitchedEntities.add(1, { result });\n stitchingDuration.record(endTime(), { result });\n }\n\n function markFailed(error: Error) {\n promStitchedEntities.inc(1);\n stitchedEntities.add(1, { result: 'error' });\n stitchingDuration.record(endTime(), { result: 'error' });\n logger.error(\n `Failed to stitch ${item.entityRef}, ${stringifyError(error)}`,\n );\n }\n\n return {\n markComplete,\n markFailed,\n };\n }\n\n return { stitchStart };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\nimport { Knex } from 'knex';\nimport splitToChunks from 'lodash/chunk';\nimport { DateTime } from 'luxon';\nimport { getDeferredStitchableEntities } from '../database/operations/stitcher/getDeferredStitchableEntities';\nimport { markForStitching } from '../database/operations/stitcher/markForStitching';\nimport { performStitching } from '../database/operations/stitcher/performStitching';\nimport { DbRefreshStateRow } from '../database/tables';\nimport { startTaskPipeline } from '../processing/TaskPipeline';\nimport { progressTracker } from './progressTracker';\nimport {\n Stitcher,\n StitchingStrategy,\n stitchingStrategyFromConfig,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype DeferredStitchItem = Awaited<\n ReturnType\n>[0];\n\ntype StitchProgressTracker = ReturnType;\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport class DefaultStitcher implements Stitcher {\n private readonly knex: Knex;\n private readonly logger: LoggerService;\n private readonly strategy: StitchingStrategy;\n private readonly tracker: StitchProgressTracker;\n private stopFunc?: () => void;\n\n static fromConfig(\n config: Config,\n options: {\n knex: Knex;\n logger: LoggerService;\n },\n ): DefaultStitcher {\n return new DefaultStitcher({\n knex: options.knex,\n logger: options.logger,\n strategy: stitchingStrategyFromConfig(config),\n });\n }\n\n constructor(options: {\n knex: Knex;\n logger: LoggerService;\n strategy: StitchingStrategy;\n }) {\n this.knex = options.knex;\n this.logger = options.logger;\n this.strategy = options.strategy;\n this.tracker = progressTracker(options.knex, options.logger);\n }\n\n async stitch(options: {\n entityRefs?: Iterable;\n entityIds?: Iterable;\n }) {\n const { entityRefs, entityIds } = options;\n\n if (this.strategy.mode === 'deferred') {\n await markForStitching({\n knex: this.knex,\n strategy: this.strategy,\n entityRefs,\n entityIds,\n });\n return;\n }\n\n if (entityRefs) {\n for (const entityRef of entityRefs) {\n await this.#stitchOne({ entityRef });\n }\n }\n\n if (entityIds) {\n const chunks = splitToChunks(\n Array.isArray(entityIds) ? entityIds : [...entityIds],\n 100,\n );\n for (const chunk of chunks) {\n const rows = await this.knex('refresh_state')\n .select('entity_ref')\n .whereIn('entity_id', chunk);\n for (const row of rows) {\n await this.#stitchOne({ entityRef: row.entity_ref });\n }\n }\n }\n }\n\n async start() {\n if (this.strategy.mode === 'deferred') {\n if (this.stopFunc) {\n throw new Error('Processing engine is already started');\n }\n\n const { pollingInterval, stitchTimeout } = this.strategy;\n\n const stopPipeline = startTaskPipeline({\n lowWatermark: 2,\n highWatermark: 5,\n pollingIntervalMs: durationToMilliseconds(pollingInterval),\n loadTasks: async count => {\n return await this.#getStitchableEntities(count, stitchTimeout);\n },\n processTask: async item => {\n return await this.#stitchOne({\n entityRef: item.entityRef,\n stitchTicket: item.stitchTicket,\n stitchRequestedAt: item.stitchRequestedAt,\n });\n },\n });\n\n this.stopFunc = () => {\n stopPipeline();\n };\n }\n }\n\n async stop() {\n if (this.strategy.mode === 'deferred') {\n if (this.stopFunc) {\n this.stopFunc();\n this.stopFunc = undefined;\n }\n }\n }\n\n async #getStitchableEntities(count: number, stitchTimeout: HumanDuration) {\n try {\n return await getDeferredStitchableEntities({\n knex: this.knex,\n batchSize: count,\n stitchTimeout: stitchTimeout,\n });\n } catch (error) {\n this.logger.warn('Failed to load stitchable entities', error);\n return [];\n }\n }\n\n async #stitchOne(options: {\n entityRef: string;\n stitchTicket?: string;\n stitchRequestedAt?: DateTime;\n }) {\n const track = this.tracker.stitchStart({\n entityRef: options.entityRef,\n stitchRequestedAt: options.stitchRequestedAt,\n });\n\n try {\n const result = await performStitching({\n knex: this.knex,\n logger: this.logger,\n strategy: this.strategy,\n entityRef: options.entityRef,\n stitchTicket: options.stitchTicket,\n });\n track.markComplete(result);\n } catch (error) {\n track.markFailed(error);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { Request } from 'express';\nimport { z } from 'zod';\n\nconst schema = z.object({\n entityRefs: z.array(z.string()),\n fields: z.array(z.string()).optional(),\n});\n\nexport function entitiesBatchRequest(req: Request): z.infer {\n try {\n return schema.parse(req.body);\n } catch (error) {\n throw new InputError(\n `Malformed request body (did you remember to specify an application/json content type?), ${error.message}`,\n );\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EntitiesSearchFilter,\n EntityFilter,\n} from '@backstage/plugin-catalog-node';\n\n/**\n * Forms a full EntityFilter based on a single key-value(s) object.\n */\nexport function basicEntityFilter(\n items: Record,\n): EntityFilter {\n const filtersByKey: Record = {};\n\n for (const [key, value] of Object.entries(items)) {\n const values = [value].flat();\n\n const f =\n key in filtersByKey\n ? filtersByKey[key]\n : (filtersByKey[key] = { key, values: [] });\n\n f.values!.push(...values);\n }\n\n return { anyOf: [{ allOf: Object.values(filtersByKey) }] };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\n\n/**\n * Takes a single unknown parameter and makes sure that it's a string that can\n * be parsed as an integer.\n */\nexport function parseIntegerParam(\n param: unknown,\n ctx: string,\n): number | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n if (typeof param !== 'string') {\n throw new InputError(`Invalid ${ctx}, not an integer on string form`);\n }\n\n const parsed = parseInt(param, 10);\n if (!Number.isInteger(parsed) || String(parsed) !== param) {\n throw new InputError(`Invalid ${ctx}, not an integer`);\n }\n\n return parsed;\n}\n\n/**\n * Takes a single unknown parameter and makes sure that it's a string.\n */\nexport function parseStringParam(\n param: unknown,\n ctx: string,\n): string | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n if (typeof param !== 'string') {\n throw new InputError(`Invalid ${ctx}, not a string`);\n }\n\n return param;\n}\n\n/**\n * Takes a single unknown parameter and makes sure that it's a single string or\n * an array of strings, and returns as an array.\n */\nexport function parseStringsParam(\n param: unknown,\n ctx: string,\n): string[] | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n const array = [param].flat();\n if (array.some(p => typeof p !== 'string')) {\n throw new InputError(`Invalid ${ctx}, not a string`);\n }\n\n return array as string[];\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { parseStringsParam } from './common';\nimport {\n EntitiesSearchFilter,\n EntityFilter,\n} from '@backstage/plugin-catalog-node';\n\n/**\n * Parses the filtering part of a query, like\n * /entities?filter=metadata.namespace=default,kind=Component\n */\nexport function parseEntityFilterParams(\n params: Record,\n): EntityFilter | undefined {\n // Each filter string is on the form a=b,c=d\n const filterStrings = parseStringsParam(params.filter, 'filter');\n if (!filterStrings) {\n return undefined;\n }\n\n // Outer array: \"any of the inner ones\"\n // Inner arrays: \"all of these must match\"\n const filters = filterStrings.map(parseEntityFilterString).filter(Boolean);\n if (!filters.length) {\n return undefined;\n }\n\n return { anyOf: filters.map(f => ({ allOf: f! })) };\n}\n\n/**\n * Parses a single filter string as seen in a filter query, for example\n * metadata.namespace=default,kind=Component\n */\nexport function parseEntityFilterString(\n filterString: string,\n): EntitiesSearchFilter[] | undefined {\n const statements = filterString\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n if (!statements.length) {\n return undefined;\n }\n\n const filtersByKey: Record = {};\n\n for (const statement of statements) {\n const equalsIndex = statement.indexOf('=');\n\n const key =\n equalsIndex === -1\n ? statement\n : statement.substring(0, equalsIndex).trim();\n const value =\n equalsIndex === -1\n ? undefined\n : statement.substring(equalsIndex + 1).trim();\n if (!key) {\n throw new InputError(\n `Invalid filter, '${statement}' is not a valid statement (expected a string on the form a=b or a= or a)`,\n );\n }\n\n const f =\n key in filtersByKey ? filtersByKey[key] : (filtersByKey[key] = { key });\n\n if (value !== undefined) {\n f.values = f.values || [];\n f.values.push(value);\n }\n }\n\n return Object.values(filtersByKey);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport lodash from 'lodash';\nimport { RecursivePartial } from '../../util/RecursivePartial';\nimport { parseStringsParam } from './common';\n\nfunction getPathArrayAndValue(input: Entity, field: string) {\n return field.split('.').reduce(\n ([pathArray, inputSubset], pathPart, index, fieldParts) => {\n if (lodash.hasIn(inputSubset, pathPart)) {\n return [pathArray.concat(pathPart), inputSubset[pathPart]];\n } else if (fieldParts[index + 1] !== undefined) {\n fieldParts[index + 1] = `${pathPart}.${fieldParts[index + 1]}`;\n return [pathArray, inputSubset];\n }\n\n return [pathArray, undefined];\n },\n [[] as string[], input as any],\n );\n}\n\nexport function parseEntityTransformParams(\n params: Record,\n extra?: string[],\n): ((entity: Entity) => Entity) | undefined {\n const queryFields = parseStringsParam(params.fields, 'fields');\n\n const fields = Array.from(\n new Set(\n [...(extra ?? []), ...(queryFields?.map(s => s.split(',')) ?? [])]\n .flat()\n .map(s => s.trim())\n .filter(Boolean),\n ),\n );\n\n if (!fields.length) {\n return undefined;\n }\n\n const arrayTypeField = fields.find(f => f.includes('['));\n if (arrayTypeField) {\n throw new InputError(\n `Invalid field \"${arrayTypeField}\", array type fields are not supported`,\n );\n }\n\n return input => {\n const output: RecursivePartial = {};\n\n for (const field of fields) {\n const [pathArray, value] = getPathArrayAndValue(input, field);\n\n if (value !== undefined) {\n lodash.set(output, pathArray, value);\n }\n }\n\n return output as Entity;\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { EntityOrder } from '../../catalog/types';\nimport { parseStringsParam } from './common';\n\nexport function parseEntityOrderFieldParams(\n params: Record,\n): EntityOrder[] | undefined {\n const orderFieldStrings = parseStringsParam(params.orderField, 'orderField');\n if (!orderFieldStrings) {\n return undefined;\n }\n\n return orderFieldStrings.map(orderFieldString => {\n const [field, order] = orderFieldString.split(',');\n\n if (order !== undefined && !isOrder(order)) {\n throw new InputError('Invalid order field order, must be asc or desc');\n }\n return { field, order };\n });\n}\n\nexport function isOrder(order: string): order is 'asc' | 'desc' {\n return ['asc', 'desc'].includes(order);\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n QueryEntitiesCursorRequest,\n QueryEntitiesInitialRequest,\n QueryEntitiesRequest,\n} from '../../catalog/types';\nimport { decodeCursor } from '../util';\nimport { parseEntityFilterParams } from './parseEntityFilterParams';\nimport { parseEntityOrderFieldParams } from './parseEntityOrderFieldParams';\nimport { parseEntityTransformParams } from './parseEntityTransformParams';\nimport { spec } from '../../schema/openapi.generated';\nimport { internal } from '@backstage/backend-openapi-utils';\n\nexport function parseQueryEntitiesParams(\n params: internal.QuerySchema,\n): Omit {\n const fields = parseEntityTransformParams(params);\n\n if (params.cursor) {\n const decodedCursor = decodeCursor(params.cursor);\n const response: Omit = {\n cursor: decodedCursor,\n fields,\n };\n return response;\n }\n\n const filter = parseEntityFilterParams(params);\n const orderFields = parseEntityOrderFieldParams(params);\n\n const response: Omit = {\n fields,\n filter,\n orderFields,\n fullTextFilter: {\n term: params.fullTextFilterTerm || '',\n fields: params.fullTextFilterFields,\n },\n };\n\n return response;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { parseStringsParam } from './common';\n\n/**\n * Parses the facets part of a facet query, like\n * /entity-facets?filter=metadata.namespace=default,kind=Component&facet=metadata.namespace\n */\nexport function parseEntityFacetParams(\n params: Record,\n): string[] {\n // Each facet string is on the form a.b.c\n const facetStrings = parseStringsParam(params.facet, 'facet');\n if (facetStrings) {\n const filtered = facetStrings.filter(Boolean);\n if (filtered.length) {\n return filtered;\n }\n }\n\n throw new InputError('Missing facet parameter');\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { EntityOrder } from '../../catalog/types';\nimport { parseStringsParam } from './common';\n\nexport function parseEntityOrderParams(\n params: Record,\n): EntityOrder[] | undefined {\n return parseStringsParam(params.order, 'order')?.map(item => {\n const match = item.match(/^(asc|desc):(.+)$/);\n if (!match) {\n throw new InputError(\n `Invalid order parameter \"${item}\", expected \":\"`,\n );\n }\n\n return {\n order: match[1] as 'asc' | 'desc',\n field: match[2],\n };\n });\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ******************************************************************\n// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *\n// ******************************************************************\nimport { createValidatedOpenApiRouter } from '@backstage/backend-openapi-utils';\n\nexport const spec = {\n openapi: '3.0.3',\n info: {\n title: 'catalog',\n version: '1',\n description:\n 'The Backstage backend plugin that provides the Backstage catalog',\n license: {\n name: 'Apache-2.0',\n url: 'http://www.apache.org/licenses/LICENSE-2.0.html',\n },\n contact: {},\n },\n servers: [\n {\n url: '/',\n },\n ],\n components: {\n examples: {},\n headers: {},\n parameters: {\n kind: {\n name: 'kind',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n namespace: {\n name: 'namespace',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n name: {\n name: 'name',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n uid: {\n name: 'uid',\n in: 'path',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n cursor: {\n name: 'cursor',\n in: 'query',\n description: 'Cursor to a set page of results.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n minLength: 1,\n },\n },\n after: {\n name: 'after',\n in: 'query',\n description: 'Pointer to the previous page of results.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n minLength: 1,\n },\n },\n fields: {\n name: 'fields',\n in: 'query',\n description: 'Restrict to just these fields in the response.',\n required: false,\n allowReserved: true,\n explode: false,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n examples: {\n 'Get name and the entire relations collection': {\n value: ['metadata.name', 'relations'],\n },\n 'Get kind, name and namespace': {\n value: ['kind', 'metadata.name', 'metadata.namespace'],\n },\n },\n },\n filter: {\n name: 'filter',\n in: 'query',\n description: 'Filter for just the entities defined by this filter.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n examples: {\n 'Get groups': {\n value: ['kind=group'],\n },\n 'Get orphaned components': {\n value: [\n 'kind=component,metadata.annotations.backstage.io/orphan=true',\n ],\n },\n },\n },\n offset: {\n name: 'offset',\n in: 'query',\n description: 'Number of records to skip in the query page.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'integer',\n minimum: 0,\n },\n },\n limit: {\n name: 'limit',\n in: 'query',\n description: 'Number of records to return in the response.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'integer',\n minimum: 0,\n },\n },\n orderField: {\n name: 'orderField',\n in: 'query',\n description: 'The fields to sort returned results by.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n description: 'A two-item tuple of [field, order].',\n },\n },\n explode: true,\n style: 'form',\n examples: {\n 'Order ascending by name': {\n value: ['metadata.name,asc'],\n },\n 'Order descending by owner': {\n value: ['spec.owner,desc'],\n },\n },\n },\n },\n requestBodies: {},\n responses: {\n ErrorResponse: {\n description: 'An error response from the backend.',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Error',\n },\n },\n },\n },\n },\n schemas: {\n Error: {\n type: 'object',\n properties: {\n error: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n },\n message: {\n type: 'string',\n },\n stack: {\n type: 'string',\n },\n code: {\n type: 'string',\n },\n },\n required: ['name', 'message'],\n },\n request: {\n type: 'object',\n properties: {\n method: {\n type: 'string',\n },\n url: {\n type: 'string',\n },\n },\n required: ['method', 'url'],\n },\n response: {\n type: 'object',\n properties: {\n statusCode: {\n type: 'number',\n },\n },\n required: ['statusCode'],\n },\n },\n required: ['error', 'response'],\n additionalProperties: {},\n },\n JsonObject: {\n type: 'object',\n properties: {},\n description: 'A type representing all allowed JSON object values.',\n additionalProperties: {},\n },\n MapStringString: {\n type: 'object',\n properties: {},\n additionalProperties: {\n type: 'string',\n },\n description: 'Construct a type with a set of properties K of type T',\n },\n EntityLink: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n description:\n 'An optional value to categorize links into specific groups',\n },\n icon: {\n type: 'string',\n description:\n 'An optional semantic key that represents a visual icon.',\n },\n title: {\n type: 'string',\n description: 'An optional descriptive title for the link.',\n },\n url: {\n type: 'string',\n description: 'The url to the external site, document, etc.',\n },\n },\n required: ['url'],\n description:\n 'A link to external information that is related to the entity.',\n additionalProperties: false,\n },\n EntityMeta: {\n type: 'object',\n properties: {\n links: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityLink',\n },\n description: 'A list of external hyperlinks related to the entity.',\n },\n tags: {\n type: 'array',\n items: {\n type: 'string',\n },\n description:\n 'A list of single-valued strings, to for example classify catalog entities in\\nvarious ways.',\n },\n annotations: {\n $ref: '#/components/schemas/MapStringString',\n },\n labels: {\n $ref: '#/components/schemas/MapStringString',\n },\n description: {\n type: 'string',\n description:\n 'A short (typically relatively few words, on one line) description of the\\nentity.',\n },\n title: {\n type: 'string',\n description:\n 'A display name of the entity, to be presented in user interfaces instead\\nof the `name` property above, when available.\\nThis field is sometimes useful when the `name` is cumbersome or ends up\\nbeing perceived as overly technical. The title generally does not have\\nas stringent format requirements on it, so it may contain special\\ncharacters and be more explanatory. Do keep it very short though, and\\navoid situations where a title can be confused with the name of another\\nentity, or where two entities share a title.\\nNote that this is only for display purposes, and may be ignored by some\\nparts of the code. Entity references still always make use of the `name`\\nproperty, not the title.',\n },\n namespace: {\n type: 'string',\n description: 'The namespace that the entity belongs to.',\n },\n name: {\n type: 'string',\n description:\n 'The name of the entity.\\nMust be unique within the catalog at any given point in time, for any\\ngiven namespace + kind pair. This value is part of the technical\\nidentifier of the entity, and as such it will appear in URLs, database\\ntables, entity references, and similar. It is subject to restrictions\\nregarding what characters are allowed.\\nIf you want to use a different, more human readable string with fewer\\nrestrictions on it in user interfaces, see the `title` field below.',\n },\n etag: {\n type: 'string',\n description:\n 'An opaque string that changes for each update operation to any part of\\nthe entity, including metadata.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, and the server will then reject the\\noperation if it does not match the current stored value.',\n },\n uid: {\n type: 'string',\n description:\n 'A globally unique ID for the entity.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, but the server is free to reject requests\\nthat do so in such a way that it breaks semantics.',\n },\n },\n required: ['name'],\n description: 'Metadata fields common to all versions/kinds of entity.',\n additionalProperties: {},\n },\n EntityRelation: {\n type: 'object',\n properties: {\n targetRef: {\n type: 'string',\n description: 'The entity ref of the target of this relation.',\n },\n type: {\n type: 'string',\n description: 'The type of the relation.',\n },\n },\n required: ['targetRef', 'type'],\n description:\n 'A relation of a specific type to another entity in the catalog.',\n additionalProperties: false,\n },\n Entity: {\n type: 'object',\n properties: {\n relations: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityRelation',\n },\n description:\n 'The relations that this entity has with other entities.',\n },\n spec: {\n $ref: '#/components/schemas/JsonObject',\n },\n metadata: {\n $ref: '#/components/schemas/EntityMeta',\n },\n kind: {\n type: 'string',\n description: 'The high level entity type being described.',\n },\n apiVersion: {\n type: 'string',\n description:\n 'The version of specification format for this particular entity that\\nthis is written against.',\n },\n },\n required: ['metadata', 'kind', 'apiVersion'],\n description:\n \"The parts of the format that's common to all versions/kinds of entity.\",\n },\n NullableEntity: {\n type: 'object',\n properties: {\n relations: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityRelation',\n },\n description:\n 'The relations that this entity has with other entities.',\n },\n spec: {\n $ref: '#/components/schemas/JsonObject',\n },\n metadata: {\n $ref: '#/components/schemas/EntityMeta',\n },\n kind: {\n type: 'string',\n description: 'The high level entity type being described.',\n },\n apiVersion: {\n type: 'string',\n description:\n 'The version of specification format for this particular entity that\\nthis is written against.',\n },\n },\n required: ['metadata', 'kind', 'apiVersion'],\n description:\n \"The parts of the format that's common to all versions/kinds of entity.\",\n nullable: true,\n },\n EntityAncestryResponse: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n parentEntityRefs: {\n items: {\n type: 'string',\n },\n type: 'array',\n },\n entity: {\n $ref: '#/components/schemas/Entity',\n },\n },\n required: ['parentEntityRefs', 'entity'],\n },\n },\n rootEntityRef: {\n type: 'string',\n },\n },\n required: ['items', 'rootEntityRef'],\n additionalProperties: false,\n },\n EntitiesBatchResponse: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/NullableEntity',\n },\n description:\n 'The list of entities, in the same order as the refs in the request. Entries\\nthat are null signify that no entity existed with that ref.',\n },\n },\n required: ['items'],\n additionalProperties: false,\n },\n EntityFacet: {\n type: 'object',\n properties: {\n value: {\n type: 'string',\n },\n count: {\n type: 'number',\n },\n },\n required: ['value', 'count'],\n additionalProperties: false,\n },\n EntityFacetsResponse: {\n type: 'object',\n properties: {\n facets: {\n type: 'object',\n additionalProperties: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityFacet',\n },\n },\n },\n },\n required: ['facets'],\n additionalProperties: false,\n },\n Location: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n },\n type: {\n type: 'string',\n },\n id: {\n type: 'string',\n },\n },\n required: ['target', 'type', 'id'],\n description: 'Entity location for a specific entity.',\n additionalProperties: false,\n },\n LocationSpec: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n },\n type: {\n type: 'string',\n },\n },\n required: ['target', 'type'],\n description: 'Holds the entity location information.',\n additionalProperties: false,\n },\n AnalyzeLocationExistingEntity: {\n type: 'object',\n properties: {\n entity: {\n $ref: '#/components/schemas/Entity',\n },\n isRegistered: {\n type: 'boolean',\n },\n location: {\n $ref: '#/components/schemas/LocationSpec',\n },\n },\n required: ['entity', 'isRegistered', 'location'],\n description:\n \"If the folder pointed to already contained catalog info yaml files, they are\\nread and emitted like this so that the frontend can inform the user that it\\nlocated them and can make sure to register them as well if they weren't\\nalready\",\n additionalProperties: false,\n },\n RecursivePartialEntityRelation: {\n type: 'object',\n properties: {\n targetRef: {\n type: 'string',\n description: 'The entity ref of the target of this relation.',\n },\n type: {\n type: 'string',\n description: 'The type of the relation.',\n },\n },\n description:\n 'A relation of a specific type to another entity in the catalog.',\n additionalProperties: false,\n },\n RecursivePartialEntityMeta: {\n allOf: [\n {\n $ref: '#/components/schemas/JsonObject',\n },\n {\n type: 'object',\n properties: {\n links: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/EntityLink',\n },\n description:\n 'A list of external hyperlinks related to the entity.',\n },\n tags: {\n type: 'array',\n items: {\n type: 'string',\n },\n description:\n 'A list of single-valued strings, to for example classify catalog entities in\\nvarious ways.',\n },\n annotations: {\n $ref: '#/components/schemas/MapStringString',\n },\n labels: {\n $ref: '#/components/schemas/MapStringString',\n },\n description: {\n type: 'string',\n description:\n 'A short (typically relatively few words, on one line) description of the\\nentity.',\n },\n title: {\n type: 'string',\n description:\n 'A display name of the entity, to be presented in user interfaces instead\\nof the `name` property above, when available.\\nThis field is sometimes useful when the `name` is cumbersome or ends up\\nbeing perceived as overly technical. The title generally does not have\\nas stringent format requirements on it, so it may contain special\\ncharacters and be more explanatory. Do keep it very short though, and\\navoid situations where a title can be confused with the name of another\\nentity, or where two entities share a title.\\nNote that this is only for display purposes, and may be ignored by some\\nparts of the code. Entity references still always make use of the `name`\\nproperty, not the title.',\n },\n namespace: {\n type: 'string',\n description: 'The namespace that the entity belongs to.',\n },\n name: {\n type: 'string',\n description:\n 'The name of the entity.\\nMust be unique within the catalog at any given point in time, for any\\ngiven namespace + kind pair. This value is part of the technical\\nidentifier of the entity, and as such it will appear in URLs, database\\ntables, entity references, and similar. It is subject to restrictions\\nregarding what characters are allowed.\\nIf you want to use a different, more human readable string with fewer\\nrestrictions on it in user interfaces, see the `title` field below.',\n },\n etag: {\n type: 'string',\n description:\n 'An opaque string that changes for each update operation to any part of\\nthe entity, including metadata.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, and the server will then reject the\\noperation if it does not match the current stored value.',\n },\n uid: {\n type: 'string',\n description:\n 'A globally unique ID for the entity.\\nThis field can not be set by the user at creation time, and the server\\nwill reject an attempt to do so. The field will be populated in read\\noperations. The field can (optionally) be specified when performing\\nupdate or delete operations, but the server is free to reject requests\\nthat do so in such a way that it breaks semantics.',\n },\n },\n description:\n 'Metadata fields common to all versions/kinds of entity.',\n },\n ],\n additionalProperties: false,\n },\n RecursivePartialEntity: {\n type: 'object',\n properties: {\n apiVersion: {\n type: 'string',\n description:\n 'The version of specification format for this particular entity that\\nthis is written against.',\n },\n kind: {\n type: 'string',\n description: 'The high level entity type being described.',\n },\n metadata: {\n $ref: '#/components/schemas/RecursivePartialEntityMeta',\n },\n spec: {\n $ref: '#/components/schemas/JsonObject',\n },\n relations: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/RecursivePartialEntityRelation',\n },\n description:\n 'The relations that this entity has with other entities.',\n },\n },\n description: 'Makes all keys of an entire hierarchy optional.',\n additionalProperties: false,\n },\n AnalyzeLocationEntityField: {\n type: 'object',\n properties: {\n description: {\n type: 'string',\n description:\n 'A text to show to the user to inform about the choices made. Like, it could say\\n\"Found a CODEOWNERS file that covers this target, so we suggest leaving this\\nfield empty; which would currently make it owned by X\" where X is taken from the\\ncodeowners file.',\n },\n value: {\n type: 'string',\n nullable: true,\n },\n state: {\n type: 'string',\n enum: [\n 'analysisSuggestedValue',\n 'analysisSuggestedNoValue',\n 'needsUserInput',\n ],\n description:\n 'The outcome of the analysis for this particular field',\n },\n field: {\n type: 'string',\n description:\n 'e.g. \"spec.owner\"? The frontend needs to know how to \"inject\" the field into the\\nentity again if the user wants to change it',\n },\n },\n required: ['description', 'value', 'state', 'field'],\n additionalProperties: false,\n },\n AnalyzeLocationGenerateEntity: {\n type: 'object',\n properties: {\n fields: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/AnalyzeLocationEntityField',\n },\n },\n entity: {\n $ref: '#/components/schemas/RecursivePartialEntity',\n },\n },\n required: ['fields', 'entity'],\n description:\n \"This is some form of representation of what the analyzer could deduce.\\nWe should probably have a chat about how this can best be conveyed to\\nthe frontend. It'll probably contain a (possibly incomplete) entity, plus\\nenough info for the frontend to know what form data to show to the user\\nfor overriding/completing the info.\",\n additionalProperties: false,\n },\n AnalyzeLocationResponse: {\n type: 'object',\n properties: {\n generateEntities: {\n items: {\n $ref: '#/components/schemas/AnalyzeLocationGenerateEntity',\n },\n type: 'array',\n },\n existingEntityFiles: {\n items: {\n $ref: '#/components/schemas/AnalyzeLocationExistingEntity',\n },\n type: 'array',\n },\n },\n required: ['generateEntities', 'existingEntityFiles'],\n additionalProperties: false,\n },\n LocationInput: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n },\n target: {\n type: 'string',\n },\n },\n required: ['type', 'target'],\n additionalProperties: false,\n },\n EntitiesQueryResponse: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/Entity',\n },\n description: 'The list of entities paginated by a specific filter.',\n },\n totalItems: {\n type: 'number',\n },\n pageInfo: {\n type: 'object',\n properties: {\n nextCursor: {\n type: 'string',\n description: 'The cursor for the next batch of entities.',\n },\n prevCursor: {\n type: 'string',\n description: 'The cursor for the previous batch of entities.',\n },\n },\n },\n },\n required: ['items', 'totalItems', 'pageInfo'],\n additionalProperties: false,\n },\n },\n securitySchemes: {\n JWT: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n },\n },\n },\n paths: {\n '/refresh': {\n post: {\n operationId: 'RefreshEntity',\n description: 'Refresh the entity related to entityRef.',\n responses: {\n '200': {\n description: 'Refreshed',\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n authorizationToken: {\n type: 'string',\n },\n entityRef: {\n type: 'string',\n description:\n 'The reference to a single entity that should be refreshed',\n },\n },\n required: ['entityRef'],\n description:\n 'Options for requesting a refresh of entities in the catalog.',\n additionalProperties: false,\n },\n },\n },\n },\n },\n },\n '/entities': {\n get: {\n operationId: 'GetEntities',\n description: 'Get all entities matching a given filter.',\n responses: {\n '200': {\n description: '',\n content: {\n 'application/json': {\n schema: {\n type: 'array',\n items: {\n $ref: '#/components/schemas/Entity',\n },\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/fields',\n },\n {\n $ref: '#/components/parameters/limit',\n },\n {\n $ref: '#/components/parameters/filter',\n },\n {\n $ref: '#/components/parameters/offset',\n },\n {\n $ref: '#/components/parameters/after',\n },\n {\n name: 'order',\n in: 'query',\n allowReserved: true,\n required: false,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n },\n ],\n },\n },\n '/entities/by-uid/{uid}': {\n get: {\n operationId: 'GetEntityByUid',\n description: 'Get a single entity by the UID.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Entity',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/uid',\n },\n ],\n },\n delete: {\n operationId: 'DeleteEntityByUid',\n description: 'Delete a single entity by UID.',\n responses: {\n '204': {\n description: 'Deleted successfully.',\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/uid',\n },\n ],\n },\n },\n '/entities/by-name/{kind}/{namespace}/{name}': {\n get: {\n operationId: 'GetEntityByName',\n description: 'Get an entity by an entity ref.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Entity',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/kind',\n },\n {\n $ref: '#/components/parameters/namespace',\n },\n {\n $ref: '#/components/parameters/name',\n },\n ],\n },\n },\n '/entities/by-name/{kind}/{namespace}/{name}/ancestry': {\n get: {\n operationId: 'GetEntityAncestryByName',\n description: \"Get an entity's ancestry by entity ref.\",\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntityAncestryResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/kind',\n },\n {\n $ref: '#/components/parameters/namespace',\n },\n {\n $ref: '#/components/parameters/name',\n },\n ],\n },\n },\n '/entities/by-refs': {\n post: {\n operationId: 'GetEntitiesByRefs',\n description:\n 'Get a batch set of entities given an array of entityRefs.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntitiesBatchResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n requestBody: {\n required: false,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n required: ['entityRefs'],\n properties: {\n entityRefs: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n fields: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n },\n },\n examples: {\n 'Fetch Backstage entities': {\n value: {\n entityRefs: [\n 'component:default/backstage',\n 'api:default/backstage',\n ],\n },\n },\n 'Fetch annotations for backstage entity': {\n value: {\n entityRefs: ['component:default/backstage'],\n fields: ['metadata.annotations'],\n },\n },\n },\n },\n },\n },\n parameters: [\n {\n $ref: '#/components/parameters/filter',\n },\n ],\n },\n },\n '/entities/by-query': {\n get: {\n operationId: 'GetEntitiesByQuery',\n description: 'Search for entities by a given query.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntitiesQueryResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n $ref: '#/components/parameters/fields',\n },\n {\n $ref: '#/components/parameters/limit',\n },\n {\n $ref: '#/components/parameters/orderField',\n },\n {\n $ref: '#/components/parameters/cursor',\n },\n {\n $ref: '#/components/parameters/filter',\n },\n {\n name: 'fullTextFilterTerm',\n in: 'query',\n description: 'Text search term.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n {\n name: 'fullTextFilterFields',\n in: 'query',\n description:\n 'A comma separated list of fields to sort returned results by.',\n required: false,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n explode: false,\n style: 'form',\n },\n ],\n },\n },\n '/entity-facets': {\n get: {\n operationId: 'GetEntityFacets',\n description: 'Get all entity facets that match the given filters.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/EntityFacetsResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'query',\n name: 'facet',\n required: true,\n allowReserved: true,\n schema: {\n type: 'array',\n items: {\n type: 'string',\n },\n },\n examples: {\n 'Entities by kind': {\n value: ['kind'],\n },\n 'Entities by spec type': {\n value: ['spec.type'],\n },\n },\n },\n {\n $ref: '#/components/parameters/filter',\n },\n ],\n },\n },\n '/locations': {\n post: {\n operationId: 'CreateLocation',\n description: 'Create a location for a given target.',\n responses: {\n '201': {\n description: 'Created',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n exists: {\n type: 'boolean',\n },\n entities: {\n items: {\n $ref: '#/components/schemas/Entity',\n },\n type: 'array',\n },\n location: {\n $ref: '#/components/schemas/Location',\n },\n },\n required: ['entities', 'location'],\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'query',\n name: 'dryRun',\n required: false,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n },\n type: {\n type: 'string',\n },\n },\n required: ['target', 'type'],\n },\n },\n },\n },\n },\n get: {\n operationId: 'GetLocations',\n description: 'Get all locations',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n data: {\n $ref: '#/components/schemas/Location',\n },\n },\n required: ['data'],\n },\n },\n },\n },\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n },\n },\n '/locations/{id}': {\n get: {\n operationId: 'GetLocation',\n description: 'Get a location by id.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Location',\n },\n },\n },\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'path',\n name: 'id',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n },\n delete: {\n operationId: 'DeleteLocation',\n description: 'Delete a location by id.',\n responses: {\n '204': {\n description: 'No content',\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'path',\n name: 'id',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n },\n },\n '/locations/by-entity/{kind}/{namespace}/{name}': {\n get: {\n operationId: 'getLocationByEntity',\n description: 'Get a location for entity.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/Location',\n },\n },\n },\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [\n {\n in: 'path',\n name: 'kind',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n {\n in: 'path',\n name: 'namespace',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n {\n in: 'path',\n name: 'name',\n required: true,\n allowReserved: true,\n schema: {\n type: 'string',\n },\n },\n ],\n },\n },\n '/analyze-location': {\n post: {\n operationId: 'AnalyzeLocation',\n description: 'Validate a given location.',\n responses: {\n '200': {\n description: 'Ok',\n content: {\n 'application/json': {\n schema: {\n $ref: '#/components/schemas/AnalyzeLocationResponse',\n },\n },\n },\n },\n '400': {\n $ref: '#/components/responses/ErrorResponse',\n },\n default: {\n $ref: '#/components/responses/ErrorResponse',\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n catalogFileName: {\n type: 'string',\n },\n location: {\n $ref: '#/components/schemas/LocationInput',\n },\n },\n required: ['location'],\n },\n },\n },\n },\n },\n },\n '/validate-entity': {\n post: {\n operationId: 'ValidateEntity',\n description:\n 'Validate that a passed in entity has no errors in schema.',\n responses: {\n '200': {\n description: 'Ok',\n },\n '400': {\n description: 'Validation errors.',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n errors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n },\n message: {\n type: 'string',\n },\n },\n required: ['name', 'message'],\n additionalProperties: {},\n },\n },\n },\n required: ['errors'],\n },\n },\n },\n },\n },\n security: [\n {},\n {\n JWT: [],\n },\n ],\n parameters: [],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n location: {\n type: 'string',\n },\n entity: {\n type: 'object',\n additionalProperties: {},\n },\n },\n required: ['location', 'entity'],\n },\n },\n },\n },\n },\n },\n },\n} as const;\nexport const createOpenApiRouter = async (\n options?: Parameters['1'],\n) => createValidatedOpenApiRouter(spec, options);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { EntityPagination } from '../../catalog/types';\n\n/**\n * Parses the pagination related parameters out of a query, e.g.\n * /entities?offset=100&limit=10\n */\nexport function parseEntityPaginationParams({\n limit,\n offset,\n after,\n}: {\n offset?: number;\n limit?: number;\n after?: string;\n}): EntityPagination | undefined {\n if (offset === undefined && limit === undefined && after === undefined) {\n return undefined;\n }\n\n if (offset !== undefined && offset < 0) {\n throw new InputError(`Invalid offset, must be zero or greater`);\n }\n if (limit !== undefined && limit <= 0) {\n throw new InputError(`Invalid limit, must be greater than zero`);\n }\n if (after !== undefined && !after) {\n throw new InputError(`Invalid after, must not be empty`);\n }\n\n return {\n ...(offset !== undefined ? { offset } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(after !== undefined ? { after } : {}),\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n parseLocationRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError, serializeError } from '@backstage/errors';\nimport express from 'express';\nimport yn from 'yn';\nimport { z } from 'zod';\nimport { EntitiesCatalog } from '../catalog/types';\nimport { CatalogProcessingOrchestrator } from '../processing/types';\nimport { validateEntityEnvelope } from '../processing/util';\nimport {\n basicEntityFilter,\n entitiesBatchRequest,\n parseEntityFilterParams,\n parseEntityTransformParams,\n parseQueryEntitiesParams,\n} from './request';\nimport { parseEntityFacetParams } from './request/parseEntityFacetParams';\nimport { parseEntityOrderParams } from './request/parseEntityOrderParams';\nimport { LocationService, RefreshService } from './types';\nimport {\n disallowReadonlyMode,\n encodeCursor,\n locationInput,\n validateRequestBody,\n} from './util';\nimport { createOpenApiRouter } from '../schema/openapi.generated';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { parseEntityPaginationParams } from './request/parseEntityPaginationParams';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { LocationAnalyzer } from '@backstage/plugin-catalog-node';\n\nimport { DefaultAuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\n/**\n * Options used by {@link createRouter}.\n *\n * @public\n */\nexport interface RouterOptions {\n entitiesCatalog?: EntitiesCatalog;\n locationAnalyzer?: LocationAnalyzer;\n locationService: LocationService;\n orchestrator?: CatalogProcessingOrchestrator;\n refreshService?: RefreshService;\n scheduler?: PluginTaskScheduler;\n logger: LoggerService;\n config: Config;\n permissionIntegrationRouter?: express.Router;\n auth: AuthService;\n httpAuth: HttpAuthService;\n}\n\n/**\n * Creates a catalog router.\n *\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = await createOpenApiRouter({\n validatorOptions: {\n // We want the spec to be up to date with the expected value, but the return type needs\n // to be controlled by the router implementation not the request validator.\n ignorePaths: /^\\/validate-entity\\/?$/,\n },\n });\n const {\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n config,\n logger,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n } = options;\n\n const auditLogger = new DefaultAuditLogger({\n logger,\n authService: auth,\n httpAuthService: httpAuth,\n });\n const readonlyEnabled =\n config.getOptionalBoolean('catalog.readonly') || false;\n if (readonlyEnabled) {\n logger.info('Catalog is running in readonly mode');\n }\n\n if (refreshService) {\n // TODO: Potentially find a way to track the ancestor that gets refreshed to refresh this entity (as well as the child of that ancestor?)\n router.post('/refresh', async (req, res) => {\n const { authorizationToken, ...restBody } = req.body;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityRefresh',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n metadata: {\n entityRef: restBody.entityRef,\n },\n request: req,\n message: `Refresh attempt for ${restBody.entityRef} initiated by ${actorId}`,\n });\n\n const credentials = authorizationToken\n ? await auth.authenticate(authorizationToken)\n : await httpAuth.credentials(req);\n\n await refreshService.refresh({\n ...restBody,\n credentials,\n });\n await auditLogger.auditLog({\n eventName: 'CatalogEntityRefresh',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n metadata: {\n entityRef: restBody.entityRef,\n },\n response: {\n status: 200,\n },\n request: req,\n message: `Refresh attempt for ${restBody.entityRef} triggered by ${actorId}`,\n });\n res.status(200).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityRefresh',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n metadata: {\n entityRef: restBody.entityRef,\n },\n request: req,\n message: `Refresh attempt for ${restBody.entityRef} by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (permissionIntegrationRouter) {\n router.use(permissionIntegrationRouter);\n }\n\n if (entitiesCatalog) {\n router\n .get('/entities', async (req, res) => {\n const actorId = await auditLogger.getActorId(\n req as unknown as express.Request,\n );\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req as unknown as express.Request,\n message: `Entity fetch attempt initiated by ${actorId}`,\n });\n const { entities, pageInfo } = await entitiesCatalog.entities({\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query),\n order: parseEntityOrderParams(req.query),\n pagination: parseEntityPaginationParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n // Add a Link header to the next page\n if (pageInfo.hasNextPage) {\n const url = new URL(`http://ignored${req.url}`);\n url.searchParams.delete('offset');\n url.searchParams.set('after', pageInfo.endCursor);\n res.setHeader('link', `<${url.pathname}${url.search}>; rel=\"next\"`);\n }\n\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req as unknown as express.Request,\n // Let's not log out the entities since this can make the log very big due to it not being paged?\n response: {\n status: 200,\n },\n message: `Entity fetch attempt by ${actorId} succeeded`,\n });\n\n // TODO(freben): encode the pageInfo in the response\n res.json(entities);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetch',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req as unknown as express.Request,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Entity fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entities/by-query', async (req, res) => {\n const actorId = await auditLogger.getActorId(\n req as unknown as express.Request,\n );\n try {\n await auditLogger.auditLog({\n eventName: 'QueriedCatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req as unknown as express.Request,\n message: `Queried entity fetch attempt initiated by ${actorId}`,\n });\n const { items, pageInfo, totalItems } =\n await entitiesCatalog.queryEntities({\n limit: req.query.limit,\n ...parseQueryEntitiesParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n\n res.json({\n items,\n totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n });\n await auditLogger.auditLog({\n eventName: 'QueriedCatalogEntityFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req as unknown as express.Request,\n metadata: {\n totalEntities: totalItems,\n pageInfo: {\n ...(pageInfo.nextCursor && {\n nextCursor: encodeCursor(pageInfo.nextCursor),\n }),\n ...(pageInfo.prevCursor && {\n prevCursor: encodeCursor(pageInfo.prevCursor),\n }),\n },\n },\n // Let's not log out the entities since this can make the log very big\n response: {\n status: 200,\n },\n message: `Queried entity fetch attempt by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'QueriedCatalogEntityFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req as unknown as express.Request,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Queried entity fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByUid',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n uid: uid,\n },\n message: `Fetch attempt for entity with uid ${uid} initiated by ${actorId}`,\n });\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(`No entity with uid ${uid}`);\n }\n res.status(200).json(entities[0]);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByUid',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n uid: uid,\n entityRef: stringifyEntityRef(entities[0]),\n },\n response: {\n status: 200,\n },\n message: `Fetch attempt for entity with uid ${uid} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByUid',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n metadata: {\n uid: uid,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt for entity with uid ${uid} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .delete('/entities/by-uid/:uid', async (req, res) => {\n const { uid } = req.params;\n const actorId = await auditLogger.getActorId(req);\n let entityRef: string | undefined;\n try {\n // Get the entityRef of the UID so users can more easily identity the entity\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({ 'metadata.uid': uid }),\n credentials: await httpAuth.credentials(req),\n });\n if (entities.length) {\n entityRef = stringifyEntityRef(entities[0]);\n }\n await auditLogger.auditLog({\n eventName: 'CatalogEntityDeletion',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n uid: uid,\n entityRef: entityRef,\n },\n message: `Deletion attempt for entity with uid ${uid} initiated by ${actorId}`,\n });\n await entitiesCatalog.removeEntityByUid(uid, {\n credentials: await httpAuth.credentials(req),\n });\n await auditLogger.auditLog({\n eventName: 'CatalogEntityDeletion',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n uid: uid,\n entityRef: entityRef,\n },\n response: {\n status: 204,\n },\n message: `Deletion attempt for entity with uid ${uid} by ${actorId} succeeded`,\n });\n res.status(204).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityDeletion',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Deletion attempt for entity with uid ${uid} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByName',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n message: `Fetch attempt for entity with entityRef ${entityRef} initiated by ${actorId}`,\n });\n const { entities } = await entitiesCatalog.entities({\n filter: basicEntityFilter({\n kind: kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n }),\n credentials: await httpAuth.credentials(req),\n });\n if (!entities.length) {\n throw new NotFoundError(\n `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`,\n );\n }\n res.status(200).json(entities[0]);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByName',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n response: {\n status: 200,\n },\n message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFetchByName',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt for entity with entityRef ${entityRef} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get(\n '/entities/by-name/:kind/:namespace/:name/ancestry',\n async (req, res) => {\n const { kind, namespace, name } = req.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityAncestryFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n message: `Fetch attempt for entity ancestor of entity ${entityRef} initiated by ${actorId}`,\n });\n const response = await entitiesCatalog.entityAncestry(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityAncestryFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n rootEntityRef: response.rootEntityRef,\n ancestry: response.items.map(ancestryLink => {\n return {\n entityRef: stringifyEntityRef(ancestryLink.entity),\n parentEntityRefs: ancestryLink.parentEntityRefs,\n };\n }),\n },\n response: {\n status: 200,\n },\n message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityAncestryFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n metadata: {\n entityRef: entityRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt for entity ancestor of entity ${entityRef} by ${actorId} failed`,\n });\n throw err;\n }\n },\n )\n .post('/entities/by-refs', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityBatchFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n message: `Batch entity fetch attempt initiated by ${actorId}`,\n });\n const request = entitiesBatchRequest(req);\n const response = await entitiesCatalog.entitiesBatch({\n entityRefs: request.entityRefs,\n filter: parseEntityFilterParams(req.query),\n fields: parseEntityTransformParams(req.query, request.fields),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityBatchFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n metadata: {\n ...request,\n },\n response: {\n status: 200,\n },\n message: `Batch entity fetch attempt by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityBatchFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Batch entity fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/entity-facets', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFacetFetch',\n actorId,\n status: 'succeeded',\n stage: 'initiation',\n request: req,\n message: `Entity facet fetch attempt initiated by ${actorId}`,\n });\n const response = await entitiesCatalog.facets({\n filter: parseEntityFilterParams(req.query),\n facets: parseEntityFacetParams(req.query),\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(response);\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFacetFetch',\n actorId,\n status: 'succeeded',\n stage: 'completion',\n request: req,\n response: { status: 200 },\n message: `Entity facet fetch attempt by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityFacetFetch',\n actorId,\n status: 'failed',\n stage: 'completion',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Entity facet fetch attempt by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (locationService) {\n router\n .post('/locations', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n const actorId = await auditLogger.getActorId(req);\n const location = await validateRequestBody(req, locationInput);\n const dryRun = yn(req.query.dryRun, { default: false });\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationCreation',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n location: location,\n isDryRun: dryRun,\n },\n request: req,\n message: `Creation attempt of location entity for ${location.target} initiated by ${actorId}`,\n });\n\n // when in dryRun addLocation is effectively a read operation so we don't\n // need to disallow readonly\n if (!dryRun) {\n disallowReadonlyMode(readonlyEnabled);\n }\n\n const output = await locationService.createLocation(\n location,\n dryRun,\n {\n credentials,\n },\n );\n await auditLogger.auditLog({\n eventName: 'CatalogLocationCreation',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n location: output.location,\n isDryRun: dryRun,\n },\n request: req,\n response: {\n status: 201,\n },\n message: `Creation of location entity for ${location.target} initiated by ${actorId} succeeded`,\n });\n res.status(201).json(output);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationCreation',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n location: location,\n isDryRun: dryRun,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Creation of location entity for ${location.target} initiated by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/locations', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetch',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n request: req,\n message: `Fetch attempt of locations initiated by ${actorId}`,\n });\n const locations = await locationService.listLocations({\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(locations.map(l => ({ data: l })));\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetch',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n request: req,\n response: {\n status: 200,\n },\n message: `Fetch attempt of locations by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetch',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Fetch attempt of locations by ${actorId} failed`,\n });\n throw err;\n }\n })\n\n .get('/locations/:id', async (req, res) => {\n const { id } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchById',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n id: id,\n },\n request: req,\n message: `Fetch attempt of location with id: ${id} initiated by ${actorId}`,\n });\n const output = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n res.status(200).json(output);\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchById',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n id: id,\n },\n response: {\n status: 200,\n body: output,\n },\n request: req,\n message: `Fetch attempt of location with id: ${id} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchById',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n id: id,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Fetch attempt of location with id: ${id} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .delete('/locations/:id', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n const { id } = req.params;\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationDeletion',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n id: id,\n },\n request: req,\n message: `Deletion attempt of location with id: ${id} initiated by ${actorId}`,\n });\n disallowReadonlyMode(readonlyEnabled);\n // Grabbing the information of the location begin deleted\n const location = await locationService.getLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n await locationService.deleteLocation(id, {\n credentials: await httpAuth.credentials(req),\n });\n await auditLogger.auditLog({\n eventName: 'CatalogLocationDeletion',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n location,\n },\n response: {\n status: 204,\n },\n request: req,\n message: `Deletion attempt of location with id: ${id} by ${actorId} succeeded`,\n });\n res.status(204).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationDeletion',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n id: id,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Deletion attempt of location with id: ${id} by ${actorId} failed`,\n });\n throw err;\n }\n })\n .get('/locations/by-entity/:kind/:namespace/:name', async (req, res) => {\n const { kind, namespace, name } = req.params;\n const actorId = await auditLogger.getActorId(req);\n const locationRef = `${kind}:${namespace}/${name}`;\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchByEntityRef',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n metadata: {\n locationRef: locationRef,\n },\n request: req,\n message: `Fetch attempt for location ${locationRef} initiated by ${actorId}`,\n });\n\n const output = await locationService.getLocationByEntity(\n { kind, namespace, name },\n { credentials: await httpAuth.credentials(req) },\n );\n res.status(200).json(output);\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchByEntityRef',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n metadata: {\n locationRef: locationRef,\n },\n response: {\n status: 200,\n body: output,\n },\n request: req,\n message: `Fetch attempt for location ${locationRef} by ${actorId} succeeded`,\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationFetchByEntityRef',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n metadata: {\n locationRef: locationRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Fetch attempt for location ${locationRef} by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (locationAnalyzer) {\n router.post('/analyze-location', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationAnalyze',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n request: req,\n message: `Analyze location for location initiated by ${actorId}`,\n });\n const body = await validateRequestBody(\n req,\n z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n }),\n );\n const schema = z.object({\n location: locationInput,\n catalogFilename: z.string().optional(),\n });\n const parsedBody = schema.parse(body);\n try {\n const output = await locationAnalyzer.analyzeLocation(parsedBody);\n res.status(200).json(output);\n await auditLogger.auditLog({\n eventName: 'CatalogLocationAnalyze',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n request: req,\n response: {\n status: 200,\n body: output,\n },\n message: `Analyze location for location by ${actorId} succeeded`,\n });\n } catch (err) {\n if (\n // Catch errors from parse-url library.\n err.name === 'Error' &&\n 'subject_url' in err\n ) {\n throw new InputError('The given location.target is not a URL');\n }\n throw err;\n }\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogLocationAnalyze',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n actorId,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n request: req,\n message: `Analyze location for location by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n\n if (orchestrator) {\n router.post('/validate-entity', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n\n try {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'succeeded',\n stage: 'initiation',\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId}`,\n });\n const bodySchema = z.object({\n entity: z.unknown(),\n location: z.string(),\n });\n\n let body: z.infer;\n let entity: Entity;\n let location: { type: string; target: string };\n try {\n body = await validateRequestBody(req, bodySchema);\n entity = validateEntityEnvelope(body.entity);\n location = parseLocationRef(body.location);\n if (location.type !== 'url')\n throw new TypeError(\n `Invalid location ref ${body.location}, only 'url:' is supported, e.g. url:https://host/path`,\n );\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId} failed`,\n });\n return res.status(400).json({\n errors: [serializeError(err)],\n });\n }\n\n const processingResult = await orchestrator.process({\n entity: {\n ...entity,\n metadata: {\n ...entity.metadata,\n annotations: {\n [ANNOTATION_LOCATION]: body.location,\n [ANNOTATION_ORIGIN_LOCATION]: body.location,\n ...entity.metadata.annotations,\n },\n },\n },\n });\n\n if (!processingResult.ok) {\n const errors = processingResult.errors.map(e => serializeError(e));\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: errors,\n response: {\n status: 400,\n },\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId} failed`,\n });\n return res.status(400).json({\n errors,\n });\n }\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'succeeded',\n stage: 'completion',\n actorId,\n response: {\n status: 200,\n },\n request: req,\n message: `Entity validation for entity by ${actorId} succeeded`,\n });\n return res.status(200).end();\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'CatalogEntityValidate',\n status: 'failed',\n stage: 'completion',\n level: 'error',\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n actorId,\n request: req,\n message: `Entity validation for entity initiated by ${actorId} failed`,\n });\n throw err;\n }\n });\n }\n router.use(errorHandler());\n return router;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { RefreshOptions, RefreshService } from './types';\n\nexport class DefaultRefreshService implements RefreshService {\n private database: DefaultCatalogDatabase;\n\n constructor(options: { database: DefaultCatalogDatabase }) {\n this.database = options.database;\n }\n\n async refresh(options: RefreshOptions) {\n await this.database.transaction(async tx => {\n const { entityRefs } = await this.database.listAncestors(tx, {\n entityRef: options.entityRef,\n });\n const locationAncestor = entityRefs.find(ref =>\n ref.startsWith('location:'),\n );\n\n // TODO: Refreshes are currently scheduled(as soon as possible) for execution and will therefore happen in the future.\n // There's room for improvements here where the refresh could potentially hang or return an ID so that the user can check progress.\n if (locationAncestor) {\n await this.database.refresh(tx, {\n entityRef: locationAncestor,\n });\n }\n await this.database.refresh(tx, {\n entityRef: options.entityRef,\n });\n });\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotAllowedError } from '@backstage/errors';\nimport { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { RefreshOptions, RefreshService } from './types';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\n\nexport class AuthorizedRefreshService implements RefreshService {\n constructor(\n private readonly service: RefreshService,\n private readonly permissionApi: PermissionsService,\n ) {}\n\n async refresh(options: RefreshOptions) {\n const authorizeDecision = (\n await this.permissionApi.authorize(\n [\n {\n permission: catalogEntityRefreshPermission,\n resourceRef: options.entityRef,\n },\n ],\n { credentials: options.credentials },\n )\n )[0];\n if (authorizeDecision.result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError();\n }\n await this.service.refresh(options);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Entity } from '@backstage/catalog-model';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { minimatch } from 'minimatch';\n\n/**\n * Rules to apply to catalog entities.\n *\n * An undefined list of matchers means match all, an empty list of matchers means match none.\n */\nexport type CatalogRule = {\n allow: Array<{\n kind: string;\n }>;\n locations?: Array<{\n exact?: string;\n type: string;\n pattern?: string;\n }>;\n};\n\n/**\n * Decides whether an entity from a given location is allowed to enter the\n * catalog, according to some rule set.\n */\nexport type CatalogRulesEnforcer = {\n isAllowed(entity: Entity, location: LocationSpec): boolean;\n};\n\n/**\n * Implements the default catalog rule set, consuming the config keys\n * `catalog.rules` and `catalog.locations.[].rules`.\n */\nexport class DefaultCatalogRulesEnforcer implements CatalogRulesEnforcer {\n /**\n * Default rules used by the catalog.\n *\n * Denies any location from specifying user or group entities.\n */\n static readonly defaultRules: CatalogRule[] = [\n {\n allow: ['Component', 'API', 'Location'].map(kind => ({ kind })),\n },\n ];\n\n /**\n * Loads catalog rules from config.\n *\n * This reads `catalog.rules` and defaults to the default rules if no value is present.\n * The value of the config should be a list of config objects, each with a single `allow`\n * field which in turn is a list of entity kinds to allow.\n *\n * If there is no matching rule to allow an ingested entity, it will be rejected by the catalog.\n *\n * It also reads in rules from `catalog.locations`, where each location can have a list\n * of rules for that specific location, specified in a `rules` field.\n *\n * For example:\n *\n * ```yaml\n * catalog:\n * rules:\n * - allow: [Component, API]\n * - allow: [Template]\n * locations:\n * - type: url\n * pattern: https://github.com/org/*\\/blob/master/template.yaml\n * - allow: [Location]\n * locations:\n * - type: url\n * pattern: https://github.com/org/repo/blob/master/location.yaml\n *\n * locations:\n * - type: url\n * target: https://github.com/org/repo/blob/master/users.yaml\n * rules:\n * - allow: [User, Group]\n * - type: url\n * target: https://github.com/org/repo/blob/master/systems.yaml\n * rules:\n * - allow: [System]\n * ```\n */\n static fromConfig(config: Config) {\n const rules = new Array();\n\n if (config.has('catalog.rules')) {\n const globalRules = config\n .getConfigArray('catalog.rules')\n .map(ruleConf => ({\n allow: ruleConf.getStringArray('allow').map(kind => ({ kind })),\n locations: ruleConf\n .getOptionalConfigArray('locations')\n ?.map(locationConfig => {\n const location = {\n pattern: locationConfig.getOptionalString('pattern'),\n type: locationConfig.getString('type'),\n exact: locationConfig.getOptionalString('exact'),\n };\n if (location.pattern && location.exact) {\n throw new Error(\n 'A catalog rule location cannot have both exact and pattern values',\n );\n }\n return location;\n }),\n }));\n rules.push(...globalRules);\n } else {\n rules.push(...DefaultCatalogRulesEnforcer.defaultRules);\n }\n\n if (config.has('catalog.locations')) {\n const locationRules = config\n .getConfigArray('catalog.locations')\n .flatMap(locConf => {\n if (!locConf.has('rules')) {\n return [];\n }\n const type = locConf.getString('type');\n const exact = resolveTarget(type, locConf.getString('target'));\n\n return locConf.getConfigArray('rules').map(ruleConf => ({\n allow: ruleConf.getStringArray('allow').map(kind => ({ kind })),\n locations: [{ type, exact }],\n }));\n });\n\n rules.push(...locationRules);\n }\n\n return new DefaultCatalogRulesEnforcer(rules);\n }\n\n constructor(private readonly rules: CatalogRule[]) {}\n\n /**\n * Checks whether a specific entity/location combination is allowed\n * according to the configured rules.\n */\n isAllowed(entity: Entity, location: LocationSpec) {\n for (const rule of this.rules) {\n if (!this.matchLocation(location, rule.locations)) {\n continue;\n }\n\n if (this.matchEntity(entity, rule.allow)) {\n return true;\n }\n }\n\n return false;\n }\n\n private matchLocation(\n location: LocationSpec,\n matchers?: { exact?: string; type: string; pattern?: string }[],\n ): boolean {\n if (!matchers) {\n return true;\n }\n\n for (const matcher of matchers) {\n if (matcher.type !== location?.type) {\n continue;\n }\n if (matcher.exact && matcher.exact !== location?.target) {\n continue;\n }\n if (\n matcher.pattern &&\n !minimatch(location?.target, matcher.pattern, {\n nocase: true,\n dot: true,\n })\n ) {\n continue;\n }\n return true;\n }\n\n return false;\n }\n\n private matchEntity(entity: Entity, matchers?: { kind: string }[]): boolean {\n if (!matchers) {\n return true;\n }\n\n for (const matcher of matchers) {\n if (entity?.kind?.toLowerCase() !== matcher.kind.toLowerCase()) {\n continue;\n }\n\n return true;\n }\n\n return false;\n }\n}\n\nfunction resolveTarget(type: string, target: string): string {\n if (type !== 'file') {\n return target;\n }\n\n return path.resolve(target);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n entityEnvelopeSchemaValidator,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { ProviderDatabase } from '../database/types';\nimport {\n EntityProvider,\n EntityProviderConnection,\n EntityProviderRefreshOptions,\n EntityProviderMutation,\n} from '@backstage/plugin-catalog-node';\n\nclass Connection implements EntityProviderConnection {\n readonly validateEntityEnvelope = entityEnvelopeSchemaValidator();\n\n constructor(\n private readonly config: {\n id: string;\n providerDatabase: ProviderDatabase;\n },\n ) {}\n\n async applyMutation(mutation: EntityProviderMutation): Promise {\n const db = this.config.providerDatabase;\n\n if (mutation.type === 'full') {\n this.check(mutation.entities.map(e => e.entity));\n await db.transaction(async tx => {\n await db.replaceUnprocessedEntities(tx, {\n sourceKey: this.config.id,\n type: 'full',\n items: mutation.entities,\n });\n });\n } else if (mutation.type === 'delta') {\n this.check(mutation.added.map(e => e.entity));\n this.check(\n mutation.removed\n .map(e => ('entity' in e ? e.entity : undefined))\n .filter((e): e is Entity => Boolean(e)),\n );\n await db.transaction(async tx => {\n await db.replaceUnprocessedEntities(tx, {\n sourceKey: this.config.id,\n type: 'delta',\n added: mutation.added,\n removed: mutation.removed.map(r =>\n 'entityRef' in r\n ? r\n : {\n entityRef: stringifyEntityRef(r.entity),\n locationKey: r.locationKey,\n },\n ),\n });\n });\n }\n }\n\n async refresh(options: EntityProviderRefreshOptions): Promise {\n const db = this.config.providerDatabase;\n\n await db.transaction(async (tx: any) => {\n return db.refreshByRefreshKeys(tx, {\n keys: options.keys,\n });\n });\n }\n\n private check(entities: Entity[]) {\n for (const entity of entities) {\n try {\n this.validateEntityEnvelope(entity);\n } catch (e) {\n throw new TypeError(`Malformed entity envelope, ${e}`);\n }\n }\n }\n}\n\nexport async function connectEntityProviders(\n db: ProviderDatabase,\n providers: EntityProvider[],\n) {\n await Promise.all(\n providers.map(async provider => {\n const connection = new Connection({\n id: provider.getProviderName(),\n providerDatabase: db,\n });\n return provider.connect(connection);\n }),\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { EntitiesSearchFilter } from '@backstage/plugin-catalog-node';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport {\n makeCreatePermissionRule,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\n\n/**\n * Convenience type for {@link @backstage/plugin-permission-node#PermissionRule}\n * instances with the correct resource type, resource, and filter to work with\n * the catalog.\n *\n * @alpha\n */\nexport type CatalogPermissionRule<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule;\n\n/**\n * Helper function for creating correctly-typed\n * {@link @backstage/plugin-permission-node#PermissionRule}s for the\n * catalog-backend.\n *\n * @alpha\n */\nexport const createCatalogPermissionRule = makeCreatePermissionRule<\n Entity,\n EntitiesSearchFilter,\n typeof RESOURCE_TYPE_CATALOG_ENTITY\n>();\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for the presence of an annotation on a given entity.\n *\n * If a value is given, it filters for the annotation value, too.\n *\n * @alpha\n */\nexport const hasAnnotation = createCatalogPermissionRule({\n name: 'HAS_ANNOTATION',\n description: 'Allow entities with the specified annotation',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n annotation: z.string().describe('Name of the annotation to match on'),\n value: z\n .string()\n .optional()\n .describe('Value of the annotation to match on'),\n }),\n apply: (resource, { annotation, value }) =>\n !!resource.metadata.annotations?.hasOwnProperty(annotation) &&\n (value === undefined\n ? true\n : resource.metadata.annotations?.[annotation] === value),\n toQuery: ({ annotation, value }) =>\n value === undefined\n ? {\n key: `metadata.annotations.${annotation}`,\n }\n : {\n key: `metadata.annotations.${annotation}`,\n values: [value],\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified kind.\n * @alpha\n */\nexport const isEntityKind = createCatalogPermissionRule({\n name: 'IS_ENTITY_KIND',\n description: 'Allow entities matching a specified kind',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n kinds: z\n .array(z.string())\n .describe('List of kinds to match at least one of'),\n }),\n apply(resource, { kinds }) {\n const resourceKind = resource.kind.toLocaleLowerCase('en-US');\n return kinds.some(kind => kind.toLocaleLowerCase('en-US') === resourceKind);\n },\n toQuery({ kinds }) {\n return {\n key: 'kind',\n values: kinds.map(kind => kind.toLocaleLowerCase('en-US')),\n };\n },\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified owner.\n *\n * @alpha\n */\nexport const isEntityOwner = createCatalogPermissionRule({\n name: 'IS_ENTITY_OWNER',\n description: 'Allow entities owned by a specified claim',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n claims: z\n .array(z.string())\n .describe(\n `List of claims to match at least one on within ${RELATION_OWNED_BY}`,\n ),\n }),\n apply: (resource, { claims }) => {\n if (!resource.relations) {\n return false;\n }\n\n return resource.relations\n .filter(relation => relation.type === RELATION_OWNED_BY)\n .some(relation => claims.includes(relation.targetRef));\n },\n toQuery: ({ claims }) => ({\n key: 'relations.ownedBy',\n values: claims,\n }),\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { z } from 'zod';\nimport { createCatalogPermissionRule } from './util';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified label in its metadata.\n * @alpha\n */\nexport const hasLabel = createCatalogPermissionRule({\n name: 'HAS_LABEL',\n description: 'Allow entities with the specified label',\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n label: z.string().describe('Name of the label to match on'),\n }),\n apply: (resource, { label }) =>\n !!resource.metadata.labels?.hasOwnProperty(label),\n toQuery: ({ label }) => ({\n key: `metadata.labels.${label}`,\n }),\n});\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { get } from 'lodash';\nimport { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha';\nimport { createCatalogPermissionRule } from './util';\nimport { z } from 'zod';\n\nexport const createPropertyRule = (propertyType: 'metadata' | 'spec') =>\n createCatalogPermissionRule({\n name: `HAS_${propertyType.toUpperCase()}`,\n description: `Allow entities with the specified ${propertyType} subfield`,\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n paramsSchema: z.object({\n key: z\n .string()\n .describe(`Property within the entities ${propertyType} to match on`),\n value: z\n .string()\n .optional()\n .describe(`Value of the given property to match on`),\n }),\n apply: (resource, { key, value }) => {\n const foundValue = get(resource[propertyType], key);\n\n if (Array.isArray(foundValue)) {\n if (value !== undefined) {\n return foundValue.includes(value);\n }\n return foundValue.length > 0;\n }\n if (value !== undefined) {\n return value === foundValue;\n }\n return !!foundValue;\n },\n toQuery: ({ key, value }) => ({\n key: `${propertyType}.${key}`,\n ...(value !== undefined && { values: [value] }),\n }),\n });\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPropertyRule } from './createPropertyRule';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with the specified metadata subfield. Also matches on\n * values if value is provided.\n *\n * The key argument to the `apply` and `toQuery` methods can be nested, such as\n * 'field.nestedfield'.\n * @alpha\n */\nexport const hasMetadata = createPropertyRule('metadata');\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPropertyRule } from './createPropertyRule';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with the specified spec subfield. Also matches on values\n * if value is provided.\n *\n * The key argument to the `apply` and `toQuery` methods can be nested, such as\n * 'field.nestedfield'.\n * @alpha\n */\nexport const hasSpec = createPropertyRule('spec');\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { hasAnnotation } from './hasAnnotation';\nimport { isEntityKind } from './isEntityKind';\nimport { isEntityOwner } from './isEntityOwner';\nimport { hasLabel } from './hasLabel';\nimport { hasMetadata } from './hasMetadata';\nimport { hasSpec } from './hasSpec';\n\n/**\n * These permission rules can be used to conditionally filter catalog entities\n * or describe a user's access to the entities.\n *\n * @alpha\n */\nexport const permissionRules = {\n hasAnnotation,\n hasLabel,\n hasMetadata,\n hasSpec,\n isEntityKind,\n isEntityOwner,\n};\n\nexport type { CatalogPermissionRule } from './util';\nexport { createCatalogPermissionRule } from './util';\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n catalogEntityDeletePermission,\n catalogEntityReadPermission,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { ConditionTransformer } from '@backstage/plugin-permission-node';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport { basicEntityFilter } from './request';\nimport { isQueryEntitiesCursorRequest } from './util';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\nexport class AuthorizedEntitiesCatalog implements EntitiesCatalog {\n constructor(\n private readonly entitiesCatalog: EntitiesCatalog,\n private readonly permissionApi: PermissionsService,\n private readonly transformConditions: ConditionTransformer,\n ) {}\n\n async entities(request: EntitiesRequest): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n entities: [],\n pageInfo: { hasNextPage: false },\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entities({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entities(request);\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: new Array(request.entityRefs.length).fill(null),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entitiesBatch({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entitiesBatch(request);\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: [],\n pageInfo: {},\n totalItems: 0,\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n\n let permissionedRequest: QueryEntitiesRequest;\n let requestFilter: EntityFilter | undefined;\n\n if (isQueryEntitiesCursorRequest(request)) {\n requestFilter = request.cursor.filter;\n\n permissionedRequest = {\n ...request,\n cursor: {\n ...request.cursor,\n filter: request.cursor.filter\n ? { allOf: [permissionFilter, request.cursor.filter] }\n : permissionFilter,\n },\n };\n } else {\n permissionedRequest = {\n ...request,\n filter: request.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n };\n requestFilter = request.filter;\n }\n\n const response = await this.entitiesCatalog.queryEntities(\n permissionedRequest,\n );\n\n const prevCursor: Cursor | undefined = response.pageInfo.prevCursor && {\n ...response.pageInfo.prevCursor,\n filter: requestFilter,\n };\n\n const nextCursor: Cursor | undefined = response.pageInfo.nextCursor && {\n ...response.pageInfo.nextCursor,\n filter: requestFilter,\n };\n\n return {\n ...response,\n pageInfo: {\n prevCursor,\n nextCursor,\n },\n };\n }\n\n return this.entitiesCatalog.queryEntities(request);\n }\n\n async removeEntityByUid(\n uid: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizeResponse = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityDeletePermission }],\n { credentials: options.credentials },\n )\n )[0];\n if (authorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n if (authorizeResponse.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeResponse.conditions,\n );\n const { entities } = await this.entitiesCatalog.entities({\n credentials: options.credentials,\n filter: {\n allOf: [permissionFilter, basicEntityFilter({ 'metadata.uid': uid })],\n },\n });\n if (entities.length === 0) {\n throw new NotAllowedError();\n }\n }\n return this.entitiesCatalog.removeEntityByUid(uid, {\n credentials: options.credentials,\n });\n }\n\n async entityAncestry(\n entityRef: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const rootEntityAuthorizeResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogEntityReadPermission, resourceRef: entityRef }],\n { credentials: options.credentials },\n )\n )[0];\n if (rootEntityAuthorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n const ancestryResult = await this.entitiesCatalog.entityAncestry(\n entityRef,\n { credentials: options.credentials },\n );\n const authorizeResponse = await this.permissionApi.authorize(\n ancestryResult.items.map(item => ({\n permission: catalogEntityReadPermission,\n resourceRef: stringifyEntityRef(item.entity),\n })),\n { credentials: options.credentials },\n );\n const unauthorizedAncestryItems = ancestryResult.items.filter(\n (_, index) => authorizeResponse[index].result === AuthorizeResult.DENY,\n );\n if (unauthorizedAncestryItems.length === 0) {\n return ancestryResult;\n }\n const rootUnauthorizedEntityRefs = unauthorizedAncestryItems.map(\n ancestryItem => stringifyEntityRef(ancestryItem.entity),\n );\n const allUnauthorizedEntityRefs = new Set(\n rootUnauthorizedEntityRefs.flatMap(rootEntityRef =>\n this.findParents(\n rootEntityRef,\n ancestryResult.items,\n new Set(rootUnauthorizedEntityRefs),\n ),\n ),\n );\n return {\n rootEntityRef: ancestryResult.rootEntityRef,\n items: ancestryResult.items.filter(\n ancestryItem =>\n !allUnauthorizedEntityRefs.has(\n stringifyEntityRef(ancestryItem.entity),\n ),\n ),\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n facets: Object.fromEntries(request.facets.map(f => [f, []])),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.facets({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.facets(request);\n }\n\n private findParents(\n entityRef: string,\n allAncestryItems: { entity: Entity; parentEntityRefs: string[] }[],\n seenEntityRefs: Set,\n ): string[] {\n const entity = allAncestryItems.find(\n ancestryItem => stringifyEntityRef(ancestryItem.entity) === entityRef,\n );\n if (!entity) return [];\n\n const newSeenEntityRefs = new Set(seenEntityRefs);\n entity.parentEntityRefs.forEach(parentRef =>\n newSeenEntityRefs.add(parentRef),\n );\n\n return [\n entityRef,\n ...entity.parentEntityRefs.flatMap(parentRef =>\n seenEntityRefs.has(parentRef)\n ? []\n : this.findParents(parentRef, allAncestryItems, newSeenEntityRefs),\n ),\n ];\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Location } from '@backstage/catalog-client';\nimport { CompoundEntityRef, Entity } from '@backstage/catalog-model';\nimport { NotAllowedError, NotFoundError } from '@backstage/errors';\nimport {\n catalogLocationCreatePermission,\n catalogLocationDeletePermission,\n catalogLocationReadPermission,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { LocationInput, LocationService } from './types';\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\nexport class AuthorizedLocationService implements LocationService {\n constructor(\n private readonly locationService: LocationService,\n private readonly permissionApi: PermissionsService,\n ) {}\n\n async createLocation(\n spec: LocationInput,\n dryRun: boolean,\n options: {\n credentials: BackstageCredentials;\n },\n ): Promise<{\n location: Location;\n entities: Entity[];\n exists?: boolean | undefined;\n }> {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationCreatePermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n return this.locationService.createLocation(spec, dryRun, options);\n }\n\n async listLocations(options: {\n credentials: BackstageCredentials;\n }): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationReadPermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n return [];\n }\n\n return this.locationService.listLocations(options);\n }\n\n async getLocation(\n id: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationReadPermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotFoundError(`Found no location with ID ${id}`);\n }\n\n return this.locationService.getLocation(id, options);\n }\n\n async deleteLocation(\n id: string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationDeletePermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n return this.locationService.deleteLocation(id, options);\n }\n\n async getLocationByEntity(\n entityRef: CompoundEntityRef | string,\n options: { credentials: BackstageCredentials },\n ): Promise {\n const authorizationResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogLocationReadPermission }],\n { credentials: options.credentials },\n )\n )[0];\n\n if (authorizationResponse.result === AuthorizeResult.DENY) {\n throw new NotFoundError();\n }\n return this.locationService.getLocationByEntity(entityRef, options);\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport {\n DbFinalEntitiesRow,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n} from '../../tables';\n\n/**\n * Given a number of entity refs originally created by a given entity provider\n * (source key), remove those entities from the refresh state, and at the same\n * time recursively remove every child that is a direct or indirect result of\n * processing those entities, if they would have otherwise become orphaned by\n * the removal of their parents.\n */\nexport async function deleteWithEagerPruningOfChildren(options: {\n knex: Knex | Knex.Transaction;\n entityRefs: string[];\n sourceKey: string;\n}): Promise {\n const { knex, entityRefs, sourceKey } = options;\n\n // Split up the operation by (large) chunks, so that we do not hit database\n // limits for the number of permitted bindings on a precompiled statement\n let removedCount = 0;\n for (const refs of lodash.chunk(entityRefs, 1000)) {\n const { orphanEntityRefs } =\n await findDescendantsThatWouldHaveBeenOrphanedByDeletion({\n knex: options.knex,\n refs,\n sourceKey,\n });\n\n // Chunk again - these can be many more than the outer chunk size\n for (const refsToDelete of lodash.chunk(orphanEntityRefs, 1000)) {\n await markEntitiesAffectedByDeletionForStitching({\n knex: options.knex,\n entityRefs: refsToDelete,\n });\n await knex\n .delete()\n .from('refresh_state')\n .whereIn('entity_ref', refsToDelete);\n }\n\n // Delete the references that originate only from this entity provider. Note\n // that there may be more than one entity provider making a \"claim\" for a\n // given root entity, if they emit with the same location key.\n await knex('refresh_state_references')\n .where('source_key', '=', sourceKey)\n .whereIn('target_entity_ref', refs)\n .delete();\n\n removedCount += orphanEntityRefs.length;\n }\n\n return removedCount;\n}\n\nasync function findDescendantsThatWouldHaveBeenOrphanedByDeletion(options: {\n knex: Knex | Knex.Transaction;\n refs: string[];\n sourceKey: string;\n}): Promise<{ orphanEntityRefs: string[] }> {\n const { knex, refs, sourceKey } = options;\n\n const orphans: string[] =\n // First find all nodes that can be reached downwards from the roots\n // (deletion targets), including the roots themselves, by traversing\n // down the refresh_state_references table. Note that this query\n // starts with a condition that source_key = our source key, and\n // target_entity_ref is one of the deletion targets. This has two\n // effects: it won't match attempts at deleting something that didn't\n // originate from us in the first place, and also won't match non-root\n // entities (source_key would be null for those).\n //\n // KeyA - R1 - R2 Legend:\n // \\ -----------------------------------------\n // R3 Key* Source key\n // / R* Entity ref\n // KeyA - R4 - R5 lines Individual references; sources to\n // / the left and targets to the right\n // KeyB --- R6\n //\n // The scenario is that KeyA wants to delete R1.\n //\n // The query starts with the KeyA-R1 reference, and then traverses\n // down to also find R2 and R3. It uses union instead of union all,\n // because it wants to find the set of unique descendants even if\n // the tree has unexpected loops etc.\n await knex\n .withRecursive('descendants', ['entity_ref'], initial =>\n initial\n .select('target_entity_ref')\n .from('refresh_state_references')\n .where('source_key', '=', sourceKey)\n .whereIn('target_entity_ref', refs)\n .union(recursive =>\n recursive\n .select('refresh_state_references.target_entity_ref')\n .from('descendants')\n .join(\n 'refresh_state_references',\n 'descendants.entity_ref',\n 'refresh_state_references.source_entity_ref',\n ),\n ),\n )\n // Then for each descendant, traverse all the way back upwards through\n // the refresh_state_references table to get an exhaustive list of all\n // references that are part of keeping that particular descendant\n // alive.\n //\n // Continuing the scenario from above, starting from R3, it goes\n // upwards to find every pair along every relation line.\n //\n // Top branch: R2-R3, R1-R2, KeyA-R1\n // Middle branch: R5-R3, R4-R5, KeyA-R4\n // Bottom branch: R6-R5, KeyB-R6\n //\n // Note that this all applied to the subject R3. The exact same thing\n // will be done starting from each other descendant (R2 and R1). They\n // only have one and two references to find, respectively.\n //\n // This query also uses union instead of union all, to get the set of\n // distinct relations even if the tree has unexpected loops etc.\n .withRecursive(\n 'ancestors',\n ['source_key', 'source_entity_ref', 'target_entity_ref', 'subject'],\n initial =>\n initial\n .select(\n 'refresh_state_references.source_key',\n 'refresh_state_references.source_entity_ref',\n 'refresh_state_references.target_entity_ref',\n 'descendants.entity_ref',\n )\n .from('descendants')\n .join(\n 'refresh_state_references',\n 'refresh_state_references.target_entity_ref',\n 'descendants.entity_ref',\n )\n .union(recursive =>\n recursive\n .select(\n 'refresh_state_references.source_key',\n 'refresh_state_references.source_entity_ref',\n 'refresh_state_references.target_entity_ref',\n 'ancestors.subject',\n )\n .from('ancestors')\n .join(\n 'refresh_state_references',\n 'refresh_state_references.target_entity_ref',\n 'ancestors.source_entity_ref',\n ),\n ),\n )\n // Finally, from that list of ancestor relations per descendant, pick\n // out the ones that are roots (have a source_key). Specifically, find\n // ones that seem to be be either (1) from another source, or (2)\n // aren't part of the deletion targets. Those are markers that tell us\n // that the corresponding descendant should be kept alive and NOT\n // subject to eager deletion, because there's \"something else\" (not\n // targeted for deletion) that has references down through the tree to\n // it.\n //\n // Continuing the scenario from above, for R3 we have\n //\n // KeyA-R1, KeyA-R4, KeyB-R6\n //\n // This tells us that R3 should be kept alive for two reasons: it's\n // referenced by a node that isn't being deleted (R4), and also by\n // another source (KeyB). What about R1 and R2? They both have\n //\n // KeyA-R1\n //\n // So those should be deleted, since they are definitely only being\n // kept alive by something that's about to be deleted.\n //\n // Final shape of the tree:\n //\n // R3\n // /\n // KeyA - R4 - R5\n // /\n // KeyB --- R6\n .with('retained', ['entity_ref'], notPartOfDeletion =>\n notPartOfDeletion\n .select('subject')\n .from('ancestors')\n .whereNotNull('ancestors.source_key')\n .where(foreignKeyOrRef =>\n foreignKeyOrRef\n .where('ancestors.source_key', '!=', sourceKey)\n .orWhereNotIn('ancestors.target_entity_ref', refs),\n ),\n )\n // Return all descendants minus the retained ones\n .select('descendants.entity_ref AS entity_ref')\n .from('descendants')\n .leftOuterJoin(\n 'retained',\n 'retained.entity_ref',\n 'descendants.entity_ref',\n )\n .whereNull('retained.entity_ref')\n .then(rows => rows.map(row => row.entity_ref));\n\n return { orphanEntityRefs: orphans };\n}\n\nasync function markEntitiesAffectedByDeletionForStitching(options: {\n knex: Knex | Knex.Transaction;\n entityRefs: string[];\n}) {\n const { knex, entityRefs } = options;\n\n // We want to re-stitch anything that has a relation pointing to the\n // soon-to-be-deleted entity. In many circumstances we also re-stitch children\n // in the refresh_state_references graph because their orphan state might\n // change, but not here - this code by its very definition is meant to not\n // leave any orphans behind, so we can simplify away that.\n const affectedIds = await knex\n .select('refresh_state.entity_id AS entity_id')\n .from('relations')\n .join(\n 'refresh_state',\n 'relations.source_entity_ref',\n 'refresh_state.entity_ref',\n )\n .whereIn('relations.target_entity_ref', entityRefs)\n .then(rows => rows.map(row => row.entity_id));\n\n for (const ids of lodash.chunk(affectedIds, 1000)) {\n await knex\n .table('final_entities')\n .update({\n hash: 'force-stitching',\n })\n .whereIn('entity_id', ids);\n await knex\n .table('refresh_state')\n .update({\n result_hash: 'force-stitching',\n next_update_at: knex.fn.now(),\n })\n .whereIn('entity_id', ids);\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Schedules a future refresh of entities, by so called \"refresh keys\" that may\n * be associated with one or more entities. Note that this does not mean that\n * the refresh happens immediately, but rather that their scheduling time gets\n * moved up the queue and will get picked up eventually by the regular\n * processing loop.\n */\nexport async function refreshByRefreshKeys(options: {\n tx: Knex.Transaction;\n keys: string[];\n}): Promise {\n const { tx, keys } = options;\n\n await tx('refresh_state')\n .whereIn('entity_id', function selectEntityRefs(inner) {\n inner\n .whereIn('key', keys)\n .select({\n entity_id: 'refresh_keys.entity_id',\n })\n .from('refresh_keys');\n })\n .update({ next_update_at: tx.fn.now() });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport { v4 as uuid } from 'uuid';\nimport { rethrowError } from './conversion';\nimport { deleteWithEagerPruningOfChildren } from './operations/provider/deleteWithEagerPruningOfChildren';\nimport { refreshByRefreshKeys } from './operations/provider/refreshByRefreshKeys';\nimport { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict';\nimport { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity';\nimport { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity';\nimport { DbRefreshStateReferencesRow, DbRefreshStateRow } from './tables';\nimport {\n ProviderDatabase,\n RefreshByKeyOptions,\n ReplaceUnprocessedEntitiesOptions,\n Transaction,\n} from './types';\nimport { generateStableHash } from './util';\nimport {\n LoggerService,\n isDatabaseConflictError,\n} from '@backstage/backend-plugin-api';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nconst BATCH_SIZE = 50;\n\nexport class DefaultProviderDatabase implements ProviderDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n },\n ) {}\n\n async transaction(fn: (tx: Transaction) => Promise): Promise {\n try {\n let result: T | undefined = undefined;\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the\n // transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n async replaceUnprocessedEntities(\n txOpaque: Transaction,\n options: ReplaceUnprocessedEntitiesOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { toAdd, toUpsert, toRemove } = await this.createDelta(tx, options);\n\n if (toRemove.length) {\n const removedCount = await deleteWithEagerPruningOfChildren({\n knex: tx,\n entityRefs: toRemove,\n sourceKey: options.sourceKey,\n });\n this.options.logger.debug(\n `removed, ${removedCount} entities: ${JSON.stringify(toRemove)}`,\n );\n }\n\n if (toAdd.length) {\n // The reason for this chunking, rather than just massively batch\n // inserting the entire payload, is that we fall back to the individual\n // upsert mechanism below on conflicts. That path is massively slower than\n // the fast batch path, so we don't want to end up accidentally having to\n // for example item-by-item upsert tens of thousands of entities in a\n // large initial delivery dump. The implication is that the size of these\n // chunks needs to weigh the benefit of fast successful inserts, against\n // the drawback of super slow but more rare fallbacks. There's quickly\n // diminishing returns though with turning up this value way high.\n for (const chunk of lodash.chunk(toAdd, 50)) {\n try {\n await tx.batchInsert(\n 'refresh_state',\n chunk.map(item => ({\n entity_id: uuid(),\n entity_ref: stringifyEntityRef(item.deferred.entity),\n unprocessed_entity: JSON.stringify(item.deferred.entity),\n unprocessed_hash: item.hash,\n errors: '',\n location_key: item.deferred.locationKey,\n next_update_at: tx.fn.now(),\n last_discovery_at: tx.fn.now(),\n })),\n BATCH_SIZE,\n );\n await tx.batchInsert(\n 'refresh_state_references',\n chunk.map(item => ({\n source_key: options.sourceKey,\n target_entity_ref: stringifyEntityRef(item.deferred.entity),\n })),\n BATCH_SIZE,\n );\n } catch (error) {\n if (!isDatabaseConflictError(error)) {\n throw error;\n } else {\n this.options.logger.debug(\n `Fast insert path failed, falling back to slow path, ${error}`,\n );\n toUpsert.push(...chunk);\n }\n }\n }\n }\n\n if (toUpsert.length) {\n for (const {\n deferred: { entity, locationKey },\n hash,\n } of toUpsert) {\n const entityRef = stringifyEntityRef(entity);\n\n try {\n let ok = await updateUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n });\n if (!ok) {\n ok = await insertUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n logger: this.options.logger,\n });\n }\n\n await tx('refresh_state_references')\n .where('target_entity_ref', entityRef)\n .andWhere({ source_key: options.sourceKey })\n .delete();\n\n if (ok) {\n await tx(\n 'refresh_state_references',\n ).insert({\n source_key: options.sourceKey,\n target_entity_ref: entityRef,\n });\n } else {\n const conflictingKey = await checkLocationKeyConflict({\n tx,\n entityRef,\n locationKey,\n });\n if (conflictingKey) {\n this.options.logger.warn(\n `Source ${options.sourceKey} detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`,\n );\n }\n }\n } catch (error) {\n this.options.logger.error(\n `Failed to add '${entityRef}' from source '${options.sourceKey}', ${error}`,\n );\n }\n }\n }\n }\n\n async refreshByRefreshKeys(\n txOpaque: Transaction,\n options: RefreshByKeyOptions,\n ) {\n const tx = txOpaque as Knex.Transaction;\n await refreshByRefreshKeys({ tx, keys: options.keys });\n }\n\n private async createDelta(\n tx: Knex.Transaction,\n options: ReplaceUnprocessedEntitiesOptions,\n ): Promise<{\n toAdd: { deferred: DeferredEntity; hash: string }[];\n toUpsert: { deferred: DeferredEntity; hash: string }[];\n toRemove: string[];\n }> {\n if (options.type === 'delta') {\n return {\n toAdd: [],\n toUpsert: options.added.map(e => ({\n deferred: e,\n hash: generateStableHash(e.entity),\n })),\n toRemove: options.removed.map(e => e.entityRef),\n };\n }\n\n // Grab all of the existing references from the same source, and their locationKeys as well\n const oldRefs = await tx(\n 'refresh_state_references',\n )\n .leftJoin('refresh_state', {\n target_entity_ref: 'entity_ref',\n })\n .where({ source_key: options.sourceKey })\n .select({\n target_entity_ref: 'refresh_state_references.target_entity_ref',\n location_key: 'refresh_state.location_key',\n unprocessed_hash: 'refresh_state.unprocessed_hash',\n });\n\n const items = options.items.map(deferred => ({\n deferred,\n ref: stringifyEntityRef(deferred.entity),\n hash: generateStableHash(deferred.entity),\n }));\n\n const oldRefsSet = new Map(\n oldRefs.map(r => [\n r.target_entity_ref,\n {\n locationKey: r.location_key,\n oldEntityHash: r.unprocessed_hash,\n },\n ]),\n );\n const newRefsSet = new Set(items.map(item => item.ref));\n\n const toAdd = new Array<{ deferred: DeferredEntity; hash: string }>();\n const toUpsert = new Array<{ deferred: DeferredEntity; hash: string }>();\n const toRemove = oldRefs\n .map(row => row.target_entity_ref)\n .filter(ref => !newRefsSet.has(ref));\n\n for (const item of items) {\n const oldRef = oldRefsSet.get(item.ref);\n const upsertItem = { deferred: item.deferred, hash: item.hash };\n if (!oldRef) {\n // Add any entity that does not exist in the database\n toAdd.push(upsertItem);\n } else if (\n (oldRef?.locationKey ?? undefined) !==\n (item.deferred.locationKey ?? undefined)\n ) {\n // Remove and then re-add any entity that exists, but with a different location key\n toRemove.push(item.ref);\n toAdd.push(upsertItem);\n } else if (oldRef.oldEntityHash !== item.hash) {\n // Entities with modifications should be pushed through too\n toUpsert.push(upsertItem);\n }\n }\n\n return { toAdd, toUpsert, toRemove };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport {\n CatalogDatabase,\n ListAncestorsOptions,\n ListAncestorsResult,\n RefreshOptions,\n Transaction,\n} from './types';\nimport { DbRefreshStateReferencesRow, DbRefreshStateRow } from './tables';\nimport { rethrowError } from './conversion';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst MAX_ANCESTOR_DEPTH = 32;\n\nexport class DefaultCatalogDatabase implements CatalogDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n },\n ) {}\n\n async transaction(fn: (tx: Transaction) => Promise): Promise {\n try {\n let result: T | undefined = undefined;\n\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n async listAncestors(\n txOpaque: Transaction,\n options: ListAncestorsOptions,\n ): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { entityRef } = options;\n const entityRefs = new Array();\n\n let currentRef = entityRef.toLocaleLowerCase('en-US');\n for (let depth = 1; depth <= MAX_ANCESTOR_DEPTH; depth += 1) {\n const rows = await tx(\n 'refresh_state_references',\n )\n .where({ target_entity_ref: currentRef })\n .select();\n\n if (rows.length === 0) {\n if (depth === 1) {\n throw new NotFoundError(`Entity ${currentRef} not found`);\n }\n throw new NotFoundError(\n `Entity ${entityRef} has a broken parent reference chain at ${currentRef}`,\n );\n }\n\n const parentRef = rows.find(r => r.source_entity_ref)?.source_entity_ref;\n if (!parentRef) {\n // We've reached the top of the tree which is the entityProvider.\n // In this case we refresh the entity itself.\n return { entityRefs };\n }\n entityRefs.push(parentRef);\n currentRef = parentRef;\n }\n throw new Error(\n `Unable receive ancestors for ${entityRef}, reached maximum depth of ${MAX_ANCESTOR_DEPTH}`,\n );\n }\n\n async refresh(txOpaque: Transaction, options: RefreshOptions): Promise {\n const tx = txOpaque as Knex.Transaction;\n const { entityRef } = options;\n\n const updateResult = await tx('refresh_state')\n .where({ entity_ref: entityRef.toLocaleLowerCase('en-US') })\n .update({ next_update_at: tx.fn.now() });\n if (updateResult === 0) {\n throw new NotFoundError(`Failed to schedule ${entityRef} for refresh`);\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n PluginDatabaseManager,\n UrlReader,\n} from '@backstage/backend-common';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport {\n DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n parseEntityRef,\n SchemaValidEntityPolicy,\n stringifyEntityRef,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash, { keyBy } from 'lodash';\n\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntitiesSearchFilter,\n EntityProvider,\n PlaceholderResolver,\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n CodeOwnersProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../modules';\nimport { ConfigLocationEntityProvider } from '../modules/core/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../modules/core/DefaultLocationStore';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../modules/core/PlaceholderProcessor';\nimport { defaultEntityDataParser } from '../modules/util/parse';\nimport {\n CatalogProcessingEngine,\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { createRouter } from './createRouter';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport {\n Permission,\n PermissionAuthorizer,\n PermissionRuleParams,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { basicEntityFilter } from './request';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API.\n *\n * @public\n */\nexport type CatalogPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule;\n\n/** @public */\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: PluginDatabaseManager;\n config: Config;\n reader: UrlReader;\n permissions: PermissionsService | PermissionAuthorizer;\n scheduler?: PluginTaskScheduler;\n discovery?: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n *\n * @public\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record;\n private fieldFormatValidators: Partial;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n CodeOwnersProcessor.fromConfig(config, { logger, reader }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n discovery = HostDiscovery.fromConfig(config),\n } = this.env;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...this.env,\n discovery,\n });\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n createConditionTransformer(this.permissionRules),\n );\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources: async (resourceRefs: string[]) => {\n const { entities } = await unauthorizedEntitiesCatalog.entities({\n credentials: await auth.getOwnServiceCredentials(),\n filter: {\n anyOf: resourceRefs.map(resourceRef => {\n const { kind, namespace, name } = parseEntityRef(resourceRef);\n\n return basicEntityFilter({\n kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n });\n }),\n },\n });\n\n const entitiesByRef = keyBy(entities, stringifyEntityRef);\n\n return resourceRefs.map(\n resourceRef =>\n entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],\n );\n },\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers);\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n });\n\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n // These are only added unless the user replaced them all\n if (!this.processorsReplace) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["codeowners","parseGitUrl","NotFoundError","ScmIntegrations","stringifyLocationRef","merge","pickBy","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION","ANNOTATION_VIEW_URL","ANNOTATION_EDIT_URL","ANNOTATION_SOURCE_LOCATION","identity","apiEntityV1alpha1Validator","componentEntityV1alpha1Validator","resourceEntityV1alpha1Validator","groupEntityV1alpha1Validator","locationEntityV1alpha1Validator","userEntityV1alpha1Validator","systemEntityV1alpha1Validator","domainEntityV1alpha1Validator","getCompoundEntityRef","parseEntityRef","processingResult","RELATION_OWNED_BY","RELATION_OWNER_OF","RELATION_PART_OF","RELATION_HAS_PART","RELATION_PROVIDES_API","RELATION_API_PROVIDED_BY","RELATION_CONSUMES_API","RELATION_API_CONSUMED_BY","RELATION_DEPENDS_ON","RELATION_DEPENDENCY_OF","RELATION_MEMBER_OF","RELATION_HAS_MEMBER","RELATION_CHILD_OF","RELATION_PARENT_OF","promisify","g","fs","path","yaml","assertError","limiterFactory","lodash","defaultEntityDataParser","stringifyEntityRef","InputError","entitySchemaValidator","entityEnvelopeSchemaValidator","createHash","ConflictError","uuid","parseLocationRef","DateTime","isDatabaseConflictError","register","Counter","Gauge","Summary","metrics","generateStableHash","stableStringify","BATCH_SIZE","errors","resolvePackagePath","SpanStatusCode","tracer","trace","splitToChunks","uniq","progressTracker","serializeError","stringifyError","z","NotAllowedError","entityFilterParser","lodashChunk","isEqual","durationToMilliseconds","DEFAULT_NAMESPACE","ENTITY_STATUS_CATALOG_PROCESSING_TYPE","response","createValidatedOpenApiRouter","DefaultAuditLogger","yn","errorHandler","catalogEntityRefreshPermission","AuthorizeResult","minimatch","makeCreatePermissionRule","RESOURCE_TYPE_CATALOG_ENTITY","get","catalogEntityReadPermission","catalogEntityDeletePermission","catalogLocationCreatePermission","catalogLocationReadPermission","catalogLocationDeletePermission","catalogPermissions","catalogPermissionRules","HostDiscovery","createLegacyAuthAdapters","toPermissionEvaluator","createConditionTransformer","createPermissionIntegrationRouter","keyBy","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","config","readDurationFromConfig"],"mappings":"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"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js b/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js -index 917485c..5ddc4f2 100644 ---- a/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js -+++ b/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js -@@ -32,6 +32,7 @@ require('zod'); - require('@backstage/types'); - require('yn'); - require('@backstage/backend-openapi-utils'); -+require('@janus-idp/backstage-plugin-audit-log-node'); - require('@backstage/plugin-permission-common'); - require('minimatch'); - require('@backstage/config'); -diff --git a/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js.map b/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js.map -index e1a6db3..35e1b77 100644 ---- a/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js.map -+++ b/node_modules/@backstage/plugin-catalog-backend/dist/index.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"index.cjs.js","sources":["../src/modules/core/AnnotateScmSlugEntityProcessor.ts","../src/modules/core/LocationEntityProcessor.ts","../src/modules/core/transformLegacyPolicyToProcessor.ts","../src/search/DefaultCatalogCollator.ts","../src/deprecated.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport parseGitUrl from 'git-url-parse';\nimport { identity, merge, pickBy } from 'lodash';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\n\nconst GITHUB_ACTIONS_ANNOTATION = 'github.com/project-slug';\nconst GITLAB_ACTIONS_ANNOTATION = 'gitlab.com/project-slug';\nconst AZURE_ACTIONS_ANNOTATION = 'dev.azure.com/project-repo';\n\n/** @public */\nexport class AnnotateScmSlugEntityProcessor implements CatalogProcessor {\n constructor(\n private readonly opts: {\n scmIntegrationRegistry: ScmIntegrationRegistry;\n kinds?: string[];\n },\n ) {}\n\n getProcessorName(): string {\n return 'AnnotateScmSlugEntityProcessor';\n }\n\n static fromConfig(\n config: Config,\n options?: { kinds?: string[] },\n ): AnnotateScmSlugEntityProcessor {\n return new AnnotateScmSlugEntityProcessor({\n scmIntegrationRegistry: ScmIntegrations.fromConfig(config),\n kinds: options?.kinds,\n });\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise {\n const applicableKinds = (this.opts.kinds ?? ['Component']).map(k =>\n k.toLocaleLowerCase('en-US'),\n );\n if (\n !applicableKinds.includes(entity.kind.toLocaleLowerCase('en-US')) ||\n location.type !== 'url'\n ) {\n return entity;\n }\n\n const scmIntegration = this.opts.scmIntegrationRegistry.byUrl(\n location.target,\n );\n\n if (!scmIntegration) {\n return entity;\n }\n\n let annotation;\n switch (scmIntegration.type) {\n case 'github':\n annotation = GITHUB_ACTIONS_ANNOTATION;\n break;\n case 'gitlab':\n annotation = GITLAB_ACTIONS_ANNOTATION;\n break;\n case 'azure':\n annotation = AZURE_ACTIONS_ANNOTATION;\n break;\n default:\n return entity;\n }\n\n let projectSlug = entity.metadata.annotations?.[annotation];\n if (!projectSlug) {\n const gitUrl = parseGitUrl(location.target);\n projectSlug = `${gitUrl.owner}/${gitUrl.name}`;\n }\n\n return merge(\n {\n metadata: {\n annotations: pickBy(\n {\n [annotation]: projectSlug,\n },\n identity,\n ),\n },\n },\n entity,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, LocationEntity } from '@backstage/catalog-model';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n processingResult,\n CatalogProcessor,\n CatalogProcessorEmit,\n} from '@backstage/plugin-catalog-node';\n\nexport function toAbsoluteUrl(\n integrations: ScmIntegrationRegistry,\n base: LocationSpec,\n target: string,\n): string {\n try {\n if (base.type === 'file') {\n if (target.startsWith('.')) {\n return path.join(path.dirname(base.target), target);\n }\n return target;\n }\n return integrations.resolveUrl({ url: target, base: base.target });\n } catch (e) {\n return target;\n }\n}\n\n/**\n * @public\n * @deprecated This processor should no longer be used\n */\nexport type LocationEntityProcessorOptions = {\n integrations: ScmIntegrationRegistry;\n};\n\n/**\n * Legacy processor, should not be used.\n *\n * @remarks\n *\n * In the old catalog architecture, this processor translated Location entities\n * into URLs that should be fetched. This is no longer needed since the engine\n * handles this internally.\n *\n * @public\n * @deprecated This processor should no longer be used\n */\nexport class LocationEntityProcessor implements CatalogProcessor {\n constructor(private readonly options: LocationEntityProcessorOptions) {}\n\n getProcessorName(): string {\n return 'LocationEntityProcessor';\n }\n\n async postProcessEntity(\n entity: Entity,\n location: LocationSpec,\n emit: CatalogProcessorEmit,\n ): Promise {\n if (entity.kind === 'Location') {\n const locationEntity = entity as LocationEntity;\n\n const type = locationEntity.spec.type || location.type;\n if (type === 'file' && location.target.endsWith(path.sep)) {\n emit(\n processingResult.inputError(\n location,\n `LocationEntityProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`,\n ),\n );\n }\n\n const targets = new Array();\n if (locationEntity.spec.target) {\n targets.push(locationEntity.spec.target);\n }\n if (locationEntity.spec.targets) {\n targets.push(...locationEntity.spec.targets);\n }\n\n for (const maybeRelativeTarget of targets) {\n const target = toAbsoluteUrl(\n this.options.integrations,\n location,\n maybeRelativeTarget,\n );\n emit(processingResult.location({ type, target }));\n }\n }\n\n return entity;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { EntityPolicy } from '@backstage/catalog-model';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\n\n/**\n * Transform a given entity policy to an entity processor.\n * @param policy - The policy to transform\n * @returns A new entity processor that uses the entity policy.\n * @public\n */\nexport function transformLegacyPolicyToProcessor(\n policy: EntityPolicy,\n): CatalogProcessor {\n return {\n getProcessorName() {\n return policy.constructor.name;\n },\n async preProcessEntity(entity) {\n // If enforcing the policy fails, throw the policy error.\n const result = await policy.enforce(entity);\n if (!result) {\n return entity;\n }\n return result;\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n Entity,\n isUserEntity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n CatalogApi,\n CatalogClient,\n GetEntitiesRequest,\n} from '@backstage/catalog-client';\nimport { catalogEntityReadPermission } from '@backstage/plugin-catalog-common/alpha';\nimport { CatalogEntityDocument } from '@backstage/plugin-catalog-common';\nimport { Permission } from '@backstage/plugin-permission-common';\n\n/**\n * @public\n * @deprecated Upgrade to a more recent `@backstage/plugin-search-backend-node` and\n * use `DefaultCatalogCollatorFactory` instead.\n */\nexport class DefaultCatalogCollator {\n protected discovery: PluginEndpointDiscovery;\n protected locationTemplate: string;\n protected filter?: GetEntitiesRequest['filter'];\n protected readonly catalogClient: CatalogApi;\n public readonly type: string = 'software-catalog';\n public readonly visibilityPermission: Permission =\n catalogEntityReadPermission;\n protected tokenManager: TokenManager;\n\n static fromConfig(\n _config: Config,\n options: {\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n filter?: GetEntitiesRequest['filter'];\n },\n ) {\n return new DefaultCatalogCollator({\n ...options,\n });\n }\n\n constructor(options: {\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n locationTemplate?: string;\n filter?: GetEntitiesRequest['filter'];\n catalogClient?: CatalogApi;\n }) {\n const { discovery, locationTemplate, filter, catalogClient, tokenManager } =\n options;\n\n this.discovery = discovery;\n this.locationTemplate =\n locationTemplate || '/catalog/:namespace/:kind/:name';\n this.filter = filter;\n this.catalogClient =\n catalogClient || new CatalogClient({ discoveryApi: discovery });\n this.tokenManager = tokenManager;\n }\n\n protected applyArgsToFormat(\n format: string,\n args: Record,\n ): string {\n let formatted = format;\n for (const [key, value] of Object.entries(args)) {\n formatted = formatted.replace(`:${key}`, value);\n }\n return formatted.toLowerCase();\n }\n\n private getDocumentText(entity: Entity): string {\n let documentText = entity.metadata.description || '';\n if (isUserEntity(entity)) {\n if (entity.spec?.profile?.displayName && documentText) {\n // combine displayName and description\n const displayName = entity.spec?.profile?.displayName;\n documentText = displayName.concat(' : ', documentText);\n } else {\n documentText = entity.spec?.profile?.displayName || documentText;\n }\n }\n return documentText;\n }\n\n async execute() {\n const { token } = await this.tokenManager.getToken();\n const response = await this.catalogClient.getEntities(\n {\n filter: this.filter,\n },\n { token },\n );\n return response.items.map((entity: Entity): CatalogEntityDocument => {\n return {\n title: entity.metadata.title\n ? `${entity.metadata.title} (${entity.metadata.name})`\n : entity.metadata.name,\n location: this.applyArgsToFormat(this.locationTemplate, {\n namespace: entity.metadata.namespace || 'default',\n kind: entity.kind,\n name: entity.metadata.name,\n }),\n text: this.getDocumentText(entity),\n componentType: entity.spec?.type?.toString() || 'other',\n type: entity.spec?.type?.toString() || 'other',\n namespace: entity.metadata.namespace || 'default',\n kind: entity.kind,\n lifecycle: (entity.spec?.lifecycle as string) || '',\n owner: (entity.spec?.owner as string) || '',\n authorization: {\n resourceRef: stringifyEntityRef(entity),\n },\n };\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type AnalyzeLocationEntityField as _AnalyzeLocationEntityField,\n type AnalyzeLocationExistingEntity as _AnalyzeLocationExistingEntity,\n type AnalyzeLocationGenerateEntity as _AnalyzeLocationGenerateEntity,\n type AnalyzeLocationRequest as _AnalyzeLocationRequest,\n type AnalyzeLocationResponse as _AnalyzeLocationResponse,\n type LocationSpec as _LocationSpec,\n} from '@backstage/plugin-catalog-common';\nimport {\n locationSpecToMetadataName as _locationSpecToMetadataName,\n locationSpecToLocationEntity as _locationSpecToLocationEntity,\n processingResult as _processingResult,\n type EntitiesSearchFilter as _EntitiesSearchFilter,\n type EntityFilter as _EntityFilter,\n type DeferredEntity as _DeferredEntity,\n type EntityRelationSpec as _EntityRelationSpec,\n type CatalogProcessor as _CatalogProcessor,\n type CatalogProcessorParser as _CatalogProcessorParser,\n type CatalogProcessorCache as _CatalogProcessorCache,\n type CatalogProcessorEmit as _CatalogProcessorEmit,\n type CatalogProcessorLocationResult as _CatalogProcessorLocationResult,\n type CatalogProcessorEntityResult as _CatalogProcessorEntityResult,\n type CatalogProcessorRelationResult as _CatalogProcessorRelationResult,\n type CatalogProcessorErrorResult as _CatalogProcessorErrorResult,\n type CatalogProcessorRefreshKeysResult as _CatalogProcessorRefreshKeysResult,\n type CatalogProcessorResult as _CatalogProcessorResult,\n type EntityProvider as _EntityProvider,\n type EntityProviderConnection as _EntityProviderConnection,\n type EntityProviderMutation as _EntityProviderMutation,\n type AnalyzeOptions as _AnalyzeOptions,\n type PlaceholderResolver as _PlaceholderResolver,\n type PlaceholderResolverParams as _PlaceholderResolverParams,\n type PlaceholderResolverRead as _PlaceholderResolverRead,\n type PlaceholderResolverResolveUrl as _PlaceholderResolverResolveUrl,\n type LocationAnalyzer as _LocationAnalyzer,\n type ScmLocationAnalyzer as _ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n defaultCatalogCollatorEntityTransformer as _defaultCatalogCollatorEntityTransformer,\n DefaultCatalogCollatorFactory as _DefaultCatalogCollatorFactory,\n type CatalogCollatorEntityTransformer as _CatalogCollatorEntityTransformer,\n type DefaultCatalogCollatorFactoryOptions as _DefaultCatalogCollatorFactoryOptions,\n} from '@backstage/plugin-search-backend-module-catalog';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport const locationSpecToMetadataName = _locationSpecToMetadataName;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport const locationSpecToLocationEntity = _locationSpecToLocationEntity;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport const processingResult = _processingResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntitiesSearchFilter = _EntitiesSearchFilter;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityFilter = _EntityFilter;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type DeferredEntity = _DeferredEntity;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityRelationSpec = _EntityRelationSpec;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessor = _CatalogProcessor;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorParser = _CatalogProcessorParser;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorCache = _CatalogProcessorCache;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorEmit = _CatalogProcessorEmit;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorLocationResult = _CatalogProcessorLocationResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorEntityResult = _CatalogProcessorEntityResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorRelationResult = _CatalogProcessorRelationResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorErrorResult = _CatalogProcessorErrorResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorRefreshKeysResult =\n _CatalogProcessorRefreshKeysResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorResult = _CatalogProcessorResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityProvider = _EntityProvider;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityProviderConnection = _EntityProviderConnection;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityProviderMutation = _EntityProviderMutation;\n\n/**\n * Holds the entity location information.\n *\n * @remarks\n *\n * `presence` flag: when using repo importer plugin, location is being created before the component yaml file is merged to the main branch.\n * This flag is then set to indicate that the file can be not present.\n * default value: 'required'.\n *\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type LocationSpec = _LocationSpec;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type AnalyzeOptions = _AnalyzeOptions;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type LocationAnalyzer = _LocationAnalyzer;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type ScmLocationAnalyzer = _ScmLocationAnalyzer;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolver = _PlaceholderResolver;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolverParams = _PlaceholderResolverParams;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolverRead = _PlaceholderResolverRead;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolverResolveUrl = _PlaceholderResolverResolveUrl;\n\n/**\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationRequest = _AnalyzeLocationRequest;\n/**\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationResponse = _AnalyzeLocationResponse;\n\n/**\n * If the folder pointed to already contained catalog info yaml files, they are\n * read and emitted like this so that the frontend can inform the user that it\n * located them and can make sure to register them as well if they weren't\n * already\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationExistingEntity = _AnalyzeLocationExistingEntity;\n/**\n * This is some form of representation of what the analyzer could deduce.\n * We should probably have a chat about how this can best be conveyed to\n * the frontend. It'll probably contain a (possibly incomplete) entity, plus\n * enough info for the frontend to know what form data to show to the user\n * for overriding/completing the info.\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationGenerateEntity = _AnalyzeLocationGenerateEntity;\n\n/**\n *\n * This is where I get really vague. Something like this perhaps? Or it could be\n * something like a json-schema that contains enough info for the frontend to\n * be able to present a form and explanations\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationEntityField = _AnalyzeLocationEntityField;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport const DefaultCatalogCollatorFactory = _DefaultCatalogCollatorFactory;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport const defaultCatalogCollatorEntityTransformer =\n _defaultCatalogCollatorEntityTransformer;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport type DefaultCatalogCollatorFactoryOptions =\n _DefaultCatalogCollatorFactoryOptions;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport type CatalogCollatorEntityTransformer =\n _CatalogCollatorEntityTransformer;\n"],"names":["ScmIntegrations","parseGitUrl","merge","pickBy","identity","path","processingResult","catalogEntityReadPermission","catalogClient","CatalogClient","isUserEntity","stringifyEntityRef","_locationSpecToMetadataName","_locationSpecToLocationEntity","_processingResult","_DefaultCatalogCollatorFactory","_defaultCatalogCollatorEntityTransformer"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"index.cjs.js","sources":["../src/modules/core/AnnotateScmSlugEntityProcessor.ts","../src/modules/core/LocationEntityProcessor.ts","../src/modules/core/transformLegacyPolicyToProcessor.ts","../src/search/DefaultCatalogCollator.ts","../src/deprecated.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport parseGitUrl from 'git-url-parse';\nimport { identity, merge, pickBy } from 'lodash';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\n\nconst GITHUB_ACTIONS_ANNOTATION = 'github.com/project-slug';\nconst GITLAB_ACTIONS_ANNOTATION = 'gitlab.com/project-slug';\nconst AZURE_ACTIONS_ANNOTATION = 'dev.azure.com/project-repo';\n\n/** @public */\nexport class AnnotateScmSlugEntityProcessor implements CatalogProcessor {\n constructor(\n private readonly opts: {\n scmIntegrationRegistry: ScmIntegrationRegistry;\n kinds?: string[];\n },\n ) {}\n\n getProcessorName(): string {\n return 'AnnotateScmSlugEntityProcessor';\n }\n\n static fromConfig(\n config: Config,\n options?: { kinds?: string[] },\n ): AnnotateScmSlugEntityProcessor {\n return new AnnotateScmSlugEntityProcessor({\n scmIntegrationRegistry: ScmIntegrations.fromConfig(config),\n kinds: options?.kinds,\n });\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise {\n const applicableKinds = (this.opts.kinds ?? ['Component']).map(k =>\n k.toLocaleLowerCase('en-US'),\n );\n if (\n !applicableKinds.includes(entity.kind.toLocaleLowerCase('en-US')) ||\n location.type !== 'url'\n ) {\n return entity;\n }\n\n const scmIntegration = this.opts.scmIntegrationRegistry.byUrl(\n location.target,\n );\n\n if (!scmIntegration) {\n return entity;\n }\n\n let annotation;\n switch (scmIntegration.type) {\n case 'github':\n annotation = GITHUB_ACTIONS_ANNOTATION;\n break;\n case 'gitlab':\n annotation = GITLAB_ACTIONS_ANNOTATION;\n break;\n case 'azure':\n annotation = AZURE_ACTIONS_ANNOTATION;\n break;\n default:\n return entity;\n }\n\n let projectSlug = entity.metadata.annotations?.[annotation];\n if (!projectSlug) {\n const gitUrl = parseGitUrl(location.target);\n projectSlug = `${gitUrl.owner}/${gitUrl.name}`;\n }\n\n return merge(\n {\n metadata: {\n annotations: pickBy(\n {\n [annotation]: projectSlug,\n },\n identity,\n ),\n },\n },\n entity,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, LocationEntity } from '@backstage/catalog-model';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport path from 'path';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport {\n processingResult,\n CatalogProcessor,\n CatalogProcessorEmit,\n} from '@backstage/plugin-catalog-node';\n\nexport function toAbsoluteUrl(\n integrations: ScmIntegrationRegistry,\n base: LocationSpec,\n target: string,\n): string {\n try {\n if (base.type === 'file') {\n if (target.startsWith('.')) {\n return path.join(path.dirname(base.target), target);\n }\n return target;\n }\n return integrations.resolveUrl({ url: target, base: base.target });\n } catch (e) {\n return target;\n }\n}\n\n/**\n * @public\n * @deprecated This processor should no longer be used\n */\nexport type LocationEntityProcessorOptions = {\n integrations: ScmIntegrationRegistry;\n};\n\n/**\n * Legacy processor, should not be used.\n *\n * @remarks\n *\n * In the old catalog architecture, this processor translated Location entities\n * into URLs that should be fetched. This is no longer needed since the engine\n * handles this internally.\n *\n * @public\n * @deprecated This processor should no longer be used\n */\nexport class LocationEntityProcessor implements CatalogProcessor {\n constructor(private readonly options: LocationEntityProcessorOptions) {}\n\n getProcessorName(): string {\n return 'LocationEntityProcessor';\n }\n\n async postProcessEntity(\n entity: Entity,\n location: LocationSpec,\n emit: CatalogProcessorEmit,\n ): Promise {\n if (entity.kind === 'Location') {\n const locationEntity = entity as LocationEntity;\n\n const type = locationEntity.spec.type || location.type;\n if (type === 'file' && location.target.endsWith(path.sep)) {\n emit(\n processingResult.inputError(\n location,\n `LocationEntityProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`,\n ),\n );\n }\n\n const targets = new Array();\n if (locationEntity.spec.target) {\n targets.push(locationEntity.spec.target);\n }\n if (locationEntity.spec.targets) {\n targets.push(...locationEntity.spec.targets);\n }\n\n for (const maybeRelativeTarget of targets) {\n const target = toAbsoluteUrl(\n this.options.integrations,\n location,\n maybeRelativeTarget,\n );\n emit(processingResult.location({ type, target }));\n }\n }\n\n return entity;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { EntityPolicy } from '@backstage/catalog-model';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\n\n/**\n * Transform a given entity policy to an entity processor.\n * @param policy - The policy to transform\n * @returns A new entity processor that uses the entity policy.\n * @public\n */\nexport function transformLegacyPolicyToProcessor(\n policy: EntityPolicy,\n): CatalogProcessor {\n return {\n getProcessorName() {\n return policy.constructor.name;\n },\n async preProcessEntity(entity) {\n // If enforcing the policy fails, throw the policy error.\n const result = await policy.enforce(entity);\n if (!result) {\n return entity;\n }\n return result;\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PluginEndpointDiscovery,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n Entity,\n isUserEntity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n CatalogApi,\n CatalogClient,\n GetEntitiesRequest,\n} from '@backstage/catalog-client';\nimport { catalogEntityReadPermission } from '@backstage/plugin-catalog-common/alpha';\nimport { CatalogEntityDocument } from '@backstage/plugin-catalog-common';\nimport { Permission } from '@backstage/plugin-permission-common';\n\n/**\n * @public\n * @deprecated Upgrade to a more recent `@backstage/plugin-search-backend-node` and\n * use `DefaultCatalogCollatorFactory` instead.\n */\nexport class DefaultCatalogCollator {\n protected discovery: PluginEndpointDiscovery;\n protected locationTemplate: string;\n protected filter?: GetEntitiesRequest['filter'];\n protected readonly catalogClient: CatalogApi;\n public readonly type: string = 'software-catalog';\n public readonly visibilityPermission: Permission =\n catalogEntityReadPermission;\n protected tokenManager: TokenManager;\n\n static fromConfig(\n _config: Config,\n options: {\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n filter?: GetEntitiesRequest['filter'];\n },\n ) {\n return new DefaultCatalogCollator({\n ...options,\n });\n }\n\n constructor(options: {\n discovery: PluginEndpointDiscovery;\n tokenManager: TokenManager;\n locationTemplate?: string;\n filter?: GetEntitiesRequest['filter'];\n catalogClient?: CatalogApi;\n }) {\n const { discovery, locationTemplate, filter, catalogClient, tokenManager } =\n options;\n\n this.discovery = discovery;\n this.locationTemplate =\n locationTemplate || '/catalog/:namespace/:kind/:name';\n this.filter = filter;\n this.catalogClient =\n catalogClient || new CatalogClient({ discoveryApi: discovery });\n this.tokenManager = tokenManager;\n }\n\n protected applyArgsToFormat(\n format: string,\n args: Record,\n ): string {\n let formatted = format;\n for (const [key, value] of Object.entries(args)) {\n formatted = formatted.replace(`:${key}`, value);\n }\n return formatted.toLowerCase();\n }\n\n private getDocumentText(entity: Entity): string {\n let documentText = entity.metadata.description || '';\n if (isUserEntity(entity)) {\n if (entity.spec?.profile?.displayName && documentText) {\n // combine displayName and description\n const displayName = entity.spec?.profile?.displayName;\n documentText = displayName.concat(' : ', documentText);\n } else {\n documentText = entity.spec?.profile?.displayName || documentText;\n }\n }\n return documentText;\n }\n\n async execute() {\n const { token } = await this.tokenManager.getToken();\n const response = await this.catalogClient.getEntities(\n {\n filter: this.filter,\n },\n { token },\n );\n return response.items.map((entity: Entity): CatalogEntityDocument => {\n return {\n title: entity.metadata.title\n ? `${entity.metadata.title} (${entity.metadata.name})`\n : entity.metadata.name,\n location: this.applyArgsToFormat(this.locationTemplate, {\n namespace: entity.metadata.namespace || 'default',\n kind: entity.kind,\n name: entity.metadata.name,\n }),\n text: this.getDocumentText(entity),\n componentType: entity.spec?.type?.toString() || 'other',\n type: entity.spec?.type?.toString() || 'other',\n namespace: entity.metadata.namespace || 'default',\n kind: entity.kind,\n lifecycle: (entity.spec?.lifecycle as string) || '',\n owner: (entity.spec?.owner as string) || '',\n authorization: {\n resourceRef: stringifyEntityRef(entity),\n },\n };\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type AnalyzeLocationEntityField as _AnalyzeLocationEntityField,\n type AnalyzeLocationExistingEntity as _AnalyzeLocationExistingEntity,\n type AnalyzeLocationGenerateEntity as _AnalyzeLocationGenerateEntity,\n type AnalyzeLocationRequest as _AnalyzeLocationRequest,\n type AnalyzeLocationResponse as _AnalyzeLocationResponse,\n type LocationSpec as _LocationSpec,\n} from '@backstage/plugin-catalog-common';\nimport {\n locationSpecToMetadataName as _locationSpecToMetadataName,\n locationSpecToLocationEntity as _locationSpecToLocationEntity,\n processingResult as _processingResult,\n type EntitiesSearchFilter as _EntitiesSearchFilter,\n type EntityFilter as _EntityFilter,\n type DeferredEntity as _DeferredEntity,\n type EntityRelationSpec as _EntityRelationSpec,\n type CatalogProcessor as _CatalogProcessor,\n type CatalogProcessorParser as _CatalogProcessorParser,\n type CatalogProcessorCache as _CatalogProcessorCache,\n type CatalogProcessorEmit as _CatalogProcessorEmit,\n type CatalogProcessorLocationResult as _CatalogProcessorLocationResult,\n type CatalogProcessorEntityResult as _CatalogProcessorEntityResult,\n type CatalogProcessorRelationResult as _CatalogProcessorRelationResult,\n type CatalogProcessorErrorResult as _CatalogProcessorErrorResult,\n type CatalogProcessorRefreshKeysResult as _CatalogProcessorRefreshKeysResult,\n type CatalogProcessorResult as _CatalogProcessorResult,\n type EntityProvider as _EntityProvider,\n type EntityProviderConnection as _EntityProviderConnection,\n type EntityProviderMutation as _EntityProviderMutation,\n type AnalyzeOptions as _AnalyzeOptions,\n type PlaceholderResolver as _PlaceholderResolver,\n type PlaceholderResolverParams as _PlaceholderResolverParams,\n type PlaceholderResolverRead as _PlaceholderResolverRead,\n type PlaceholderResolverResolveUrl as _PlaceholderResolverResolveUrl,\n type LocationAnalyzer as _LocationAnalyzer,\n type ScmLocationAnalyzer as _ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n defaultCatalogCollatorEntityTransformer as _defaultCatalogCollatorEntityTransformer,\n DefaultCatalogCollatorFactory as _DefaultCatalogCollatorFactory,\n type CatalogCollatorEntityTransformer as _CatalogCollatorEntityTransformer,\n type DefaultCatalogCollatorFactoryOptions as _DefaultCatalogCollatorFactoryOptions,\n} from '@backstage/plugin-search-backend-module-catalog';\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport const locationSpecToMetadataName = _locationSpecToMetadataName;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport const locationSpecToLocationEntity = _locationSpecToLocationEntity;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport const processingResult = _processingResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntitiesSearchFilter = _EntitiesSearchFilter;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityFilter = _EntityFilter;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type DeferredEntity = _DeferredEntity;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityRelationSpec = _EntityRelationSpec;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessor = _CatalogProcessor;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorParser = _CatalogProcessorParser;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorCache = _CatalogProcessorCache;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorEmit = _CatalogProcessorEmit;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorLocationResult = _CatalogProcessorLocationResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorEntityResult = _CatalogProcessorEntityResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorRelationResult = _CatalogProcessorRelationResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorErrorResult = _CatalogProcessorErrorResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorRefreshKeysResult =\n _CatalogProcessorRefreshKeysResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type CatalogProcessorResult = _CatalogProcessorResult;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityProvider = _EntityProvider;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityProviderConnection = _EntityProviderConnection;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type EntityProviderMutation = _EntityProviderMutation;\n\n/**\n * Holds the entity location information.\n *\n * @remarks\n *\n * `presence` flag: when using repo importer plugin, location is being created before the component yaml file is merged to the main branch.\n * This flag is then set to indicate that the file can be not present.\n * default value: 'required'.\n *\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type LocationSpec = _LocationSpec;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type AnalyzeOptions = _AnalyzeOptions;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type LocationAnalyzer = _LocationAnalyzer;\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type ScmLocationAnalyzer = _ScmLocationAnalyzer;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolver = _PlaceholderResolver;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolverParams = _PlaceholderResolverParams;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolverRead = _PlaceholderResolverRead;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-catalog-node` instead\n */\nexport type PlaceholderResolverResolveUrl = _PlaceholderResolverResolveUrl;\n\n/**\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationRequest = _AnalyzeLocationRequest;\n/**\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationResponse = _AnalyzeLocationResponse;\n\n/**\n * If the folder pointed to already contained catalog info yaml files, they are\n * read and emitted like this so that the frontend can inform the user that it\n * located them and can make sure to register them as well if they weren't\n * already\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationExistingEntity = _AnalyzeLocationExistingEntity;\n/**\n * This is some form of representation of what the analyzer could deduce.\n * We should probably have a chat about how this can best be conveyed to\n * the frontend. It'll probably contain a (possibly incomplete) entity, plus\n * enough info for the frontend to know what form data to show to the user\n * for overriding/completing the info.\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationGenerateEntity = _AnalyzeLocationGenerateEntity;\n\n/**\n *\n * This is where I get really vague. Something like this perhaps? Or it could be\n * something like a json-schema that contains enough info for the frontend to\n * be able to present a form and explanations\n * @public\n * @deprecated use the same type from `@backstage/plugin-catalog-common` instead\n */\nexport type AnalyzeLocationEntityField = _AnalyzeLocationEntityField;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport const DefaultCatalogCollatorFactory = _DefaultCatalogCollatorFactory;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport const defaultCatalogCollatorEntityTransformer =\n _defaultCatalogCollatorEntityTransformer;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport type DefaultCatalogCollatorFactoryOptions =\n _DefaultCatalogCollatorFactoryOptions;\n\n/**\n * @public\n * @deprecated import from `@backstage/plugin-search-backend-module-catalog` instead\n */\nexport type CatalogCollatorEntityTransformer =\n _CatalogCollatorEntityTransformer;\n"],"names":["ScmIntegrations","parseGitUrl","merge","pickBy","identity","path","processingResult","catalogEntityReadPermission","catalogClient","CatalogClient","isUserEntity","stringifyEntityRef","_locationSpecToMetadataName","_locationSpecToLocationEntity","_processingResult","_DefaultCatalogCollatorFactory","_defaultCatalogCollatorEntityTransformer"],"mappings":"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"} -\ No newline at end of file diff --git a/patches/@backstage+plugin-catalog-backend-module-msgraph+0.5.30.patch b/patches/@backstage+plugin-catalog-backend-module-msgraph+0.5.30.patch deleted file mode 100644 index d5a1c85a40..0000000000 --- a/patches/@backstage+plugin-catalog-backend-module-msgraph+0.5.30.patch +++ /dev/null @@ -1,1175 +0,0 @@ -diff --git a/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/alpha.cjs.js b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/alpha.cjs.js -index 8190355..60c0887 100644 ---- a/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/alpha.cjs.js -+++ b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/alpha.cjs.js -@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); - - var backendPluginApi = require('@backstage/backend-plugin-api'); - var alpha = require('@backstage/plugin-catalog-node/alpha'); --var MicrosoftGraphOrgEntityProvider = require('./cjs/MicrosoftGraphOrgEntityProvider-mdJJRFUn.cjs.js'); -+var MicrosoftGraphOrgEntityProvider = require('./cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js'); - require('@backstage/plugin-catalog-node'); - require('@azure/identity'); - require('node-fetch'); -diff --git a/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js -new file mode 100644 -index 0000000..70c1293 ---- /dev/null -+++ b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js -@@ -0,0 +1,1136 @@ -+'use strict'; -+ -+var catalogModel = require('@backstage/catalog-model'); -+var lodash = require('lodash'); -+var uuid = require('uuid'); -+var identity = require('@azure/identity'); -+var fetch = require('node-fetch'); -+var qs = require('qs'); -+var backendTasks = require('@backstage/backend-tasks'); -+var limiterFactory = require('p-limit'); -+ -+function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } -+ -+function _interopNamespaceCompat(e) { -+ if (e && typeof e === 'object' && 'default' in e) return e; -+ var n = Object.create(null); -+ if (e) { -+ Object.keys(e).forEach(function (k) { -+ if (k !== 'default') { -+ var d = Object.getOwnPropertyDescriptor(e, k); -+ Object.defineProperty(n, k, d.get ? d : { -+ enumerable: true, -+ get: function () { return e[k]; } -+ }); -+ } -+ }); -+ } -+ n.default = e; -+ return Object.freeze(n); -+} -+ -+var uuid__namespace = /*#__PURE__*/_interopNamespaceCompat(uuid); -+var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch); -+var qs__default = /*#__PURE__*/_interopDefaultCompat(qs); -+var limiterFactory__default = /*#__PURE__*/_interopDefaultCompat(limiterFactory); -+ -+class MicrosoftGraphClient { -+ /** -+ * @param baseUrl - baseUrl of Graph API {@link MicrosoftGraphProviderConfig.target} -+ * @param tokenCredential - instance of `TokenCredential` that is used to acquire token for Graph API calls -+ * -+ */ -+ constructor(baseUrl, tokenCredential) { -+ this.baseUrl = baseUrl; -+ this.tokenCredential = tokenCredential; -+ } -+ /** -+ * Factory method that instantiate `msal` client and return -+ * an instance of `MicrosoftGraphClient` -+ * -+ * @public -+ * -+ * @param config - Configuration for Interacting with Graph API -+ */ -+ static create(config) { -+ const options = { -+ authorityHost: config.authority, -+ tenantId: config.tenantId -+ }; -+ const credential = config.clientId && config.clientSecret ? new identity.ClientSecretCredential( -+ config.tenantId, -+ config.clientId, -+ config.clientSecret, -+ options -+ ) : new identity.DefaultAzureCredential(options); -+ return new MicrosoftGraphClient(config.target, credential); -+ } -+ /** -+ * Get a collection of resource from Graph API and -+ * return an `AsyncIterable` of that resource -+ * -+ * @public -+ * @param path - Resource in Microsoft Graph -+ * @param query - OData Query {@link ODataQuery} -+ * @param queryMode - Mode to use while querying. Some features are only available at "advanced". -+ */ -+ async *requestCollection(path, query, queryMode) { -+ const appliedQueryMode = query?.search ? "advanced" : queryMode ?? "basic"; -+ if (appliedQueryMode === "advanced" && (query?.filter || query?.select)) { -+ query.count = true; -+ } -+ const headers = appliedQueryMode === "advanced" ? { -+ // Eventual consistency is required for advanced querying capabilities -+ // like "$search" or parts of "$filter". -+ // If a new user/group is not found, it'll eventually be imported on a subsequent read -+ ConsistencyLevel: "eventual" -+ } : {}; -+ let response = await this.requestApi(path, query, headers); -+ for (; ; ) { -+ if (response.status !== 200) { -+ await this.handleError(path, response); -+ } -+ const result = await response.json(); -+ const elements = result.value; -+ yield* elements; -+ if (!result["@odata.nextLink"]) { -+ return; -+ } -+ response = await this.requestRaw(result["@odata.nextLink"], headers); -+ } -+ } -+ /** -+ * Abstract on top of {@link MicrosoftGraphClient.requestRaw} -+ * -+ * @public -+ * @param path - Resource in Microsoft Graph -+ * @param query - OData Query {@link ODataQuery} -+ * @param headers - optional HTTP headers -+ */ -+ async requestApi(path, query, headers) { -+ const queryString = qs__default.default.stringify( -+ { -+ $search: query?.search, -+ $filter: query?.filter, -+ $select: query?.select?.join(","), -+ $expand: query?.expand, -+ $count: query?.count, -+ $top: query?.top -+ }, -+ { -+ addQueryPrefix: true, -+ // Microsoft Graph doesn't like an encoded query string -+ encode: false -+ } -+ ); -+ return await this.requestRaw( -+ `${this.baseUrl}/${path}${queryString}`, -+ headers -+ ); -+ } -+ /** -+ * Makes a HTTP call to Graph API with token -+ * -+ * @param url - HTTP Endpoint of Graph API -+ * @param headers - optional HTTP headers -+ */ -+ async requestRaw(url, headers, retryCount = 2) { -+ const urlObj = new URL(url); -+ const token = await this.tokenCredential.getToken( -+ `${urlObj.protocol}//${urlObj.hostname}/.default` -+ ); -+ if (!token) { -+ throw new Error("Failed to obtain token from Azure Identity"); -+ } -+ try { -+ return await fetch__default.default(url, { -+ headers: { -+ ...headers, -+ Authorization: `Bearer ${token.token}` -+ } -+ }); -+ } catch (e) { -+ if (e?.code === "ETIMEDOUT" && retryCount > 0) { -+ return this.requestRaw(url, headers, retryCount - 1); -+ } -+ throw e; -+ } -+ } -+ /** -+ * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto} -+ * of `User` from Graph API with size limit -+ * -+ * @param userId - The unique identifier for the `User` resource -+ * @param maxSize - Maximum pixel height of the photo -+ * -+ */ -+ async getUserPhotoWithSizeLimit(userId, maxSize) { -+ return await this.getPhotoWithSizeLimit("users", userId, maxSize); -+ } -+ async getUserPhoto(userId, sizeId) { -+ return await this.getPhoto("users", userId, sizeId); -+ } -+ /** -+ * Get a collection of -+ * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User} -+ * from Graph API and return as `AsyncIterable` -+ * -+ * @public -+ * @param query - OData Query {@link ODataQuery} -+ * @param queryMode - Mode to use while querying. Some features are only available at "advanced". -+ */ -+ async *getUsers(query, queryMode) { -+ yield* this.requestCollection( -+ `users`, -+ query, -+ queryMode -+ ); -+ } -+ /** -+ * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto} -+ * of `Group` from Graph API with size limit -+ * -+ * @param groupId - The unique identifier for the `Group` resource -+ * @param maxSize - Maximum pixel height of the photo -+ * -+ */ -+ async getGroupPhotoWithSizeLimit(groupId, maxSize) { -+ return await this.getPhotoWithSizeLimit("groups", groupId, maxSize); -+ } -+ async getGroupPhoto(groupId, sizeId) { -+ return await this.getPhoto("groups", groupId, sizeId); -+ } -+ /** -+ * Get a collection of -+ * {@link https://docs.microsoft.com/en-us/graph/api/resources/group | Group} -+ * from Graph API and return as `AsyncIterable` -+ * -+ * @public -+ * @param query - OData Query {@link ODataQuery} -+ * @param queryMode - Mode to use while querying. Some features are only available at "advanced". -+ */ -+ async *getGroups(query, queryMode) { -+ yield* this.requestCollection( -+ `groups`, -+ query, -+ queryMode -+ ); -+ } -+ /** -+ * Get a collection of -+ * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User} -+ * belonging to a `Group` from Graph API and return as `AsyncIterable` -+ * @public -+ * @param groupId - The unique identifier for the `Group` resource -+ * -+ */ -+ async *getGroupMembers(groupId, query, queryMode) { -+ yield* this.requestCollection( -+ `groups/${groupId}/members`, -+ query, -+ queryMode -+ ); -+ } -+ /** -+ * Get a collection of -+ * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User} -+ * belonging to a `Group` from Graph API and return as `AsyncIterable` -+ * @public -+ * @param groupId - The unique identifier for the `Group` resource -+ * @param query - OData Query {@link ODataQuery} -+ * @param queryMode - Mode to use while querying. Some features are only available at "advanced". -+ */ -+ async *getGroupUserMembers(groupId, query, queryMode) { -+ yield* this.requestCollection( -+ `groups/${groupId}/members/microsoft.graph.user/`, -+ query, -+ queryMode -+ ); -+ } -+ /** -+ * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/organization | Organization} -+ * from Graph API -+ * @public -+ * @param tenantId - The unique identifier for the `Organization` resource -+ * -+ */ -+ async getOrganization(tenantId) { -+ const response = await this.requestApi(`organization/${tenantId}`); -+ if (response.status !== 200) { -+ await this.handleError(`organization/${tenantId}`, response); -+ } -+ return await response.json(); -+ } -+ /** -+ * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto} -+ * from Graph API -+ * -+ * @param entityName - type of parent resource, either `User` or `Group` -+ * @param id - The unique identifier for the {@link entityName | entityName} resource -+ * @param maxSize - Maximum pixel height of the photo -+ * -+ */ -+ async getPhotoWithSizeLimit(entityName, id, maxSize) { -+ const response = await this.requestApi(`${entityName}/${id}/photos`); -+ if (response.status === 404) { -+ return void 0; -+ } else if (response.status !== 200) { -+ await this.handleError(`${entityName} photos`, response); -+ } -+ const result = await response.json(); -+ const photos = result.value; -+ let selectedPhoto = void 0; -+ for (const p of photos) { -+ if (!selectedPhoto || p.height >= selectedPhoto.height && p.height <= maxSize) { -+ selectedPhoto = p; -+ } -+ } -+ if (!selectedPhoto) { -+ return void 0; -+ } -+ return await this.getPhoto(entityName, id, selectedPhoto.id); -+ } -+ async getPhoto(entityName, id, sizeId) { -+ const path = sizeId ? `${entityName}/${id}/photos/${sizeId}/$value` : `${entityName}/${id}/photo/$value`; -+ const response = await this.requestApi(path); -+ if (response.status === 404) { -+ return void 0; -+ } else if (response.status !== 200) { -+ await this.handleError("photo", response); -+ } -+ return `data:image/jpeg;base64,${Buffer.from( -+ await response.arrayBuffer() -+ ).toString("base64")}`; -+ } -+ async handleError(path, response) { -+ const result = await response.json(); -+ const error = result.error; -+ throw new Error( -+ `Error while reading ${path} from Microsoft Graph: ${error.code} - ${error.message}` -+ ); -+ } -+} -+ -+const DEFAULT_PROVIDER_ID = "default"; -+const DEFAULT_TARGET = "https://graph.microsoft.com/v1.0"; -+function readMicrosoftGraphConfig(config) { -+ const providers = []; -+ const providerConfigs = config.getOptionalConfigArray("providers") ?? []; -+ for (const providerConfig of providerConfigs) { -+ const target = lodash.trimEnd( -+ providerConfig.getOptionalString("target") ?? DEFAULT_TARGET, -+ "/" -+ ); -+ const authority = providerConfig.getOptionalString("authority"); -+ const tenantId = providerConfig.getString("tenantId"); -+ const clientId = providerConfig.getOptionalString("clientId"); -+ const clientSecret = providerConfig.getOptionalString("clientSecret"); -+ const userExpand = providerConfig.getOptionalString("userExpand"); -+ const userFilter = providerConfig.getOptionalString("userFilter"); -+ const userSelect = providerConfig.getOptionalStringArray("userSelect"); -+ const userGroupMemberFilter = providerConfig.getOptionalString( -+ "userGroupMemberFilter" -+ ); -+ const userGroupMemberSearch = providerConfig.getOptionalString( -+ "userGroupMemberSearch" -+ ); -+ const groupExpand = providerConfig.getOptionalString("groupExpand"); -+ const groupFilter = providerConfig.getOptionalString("groupFilter"); -+ const groupSearch = providerConfig.getOptionalString("groupSearch"); -+ if (userFilter && userGroupMemberFilter) { -+ throw new Error( -+ `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.` -+ ); -+ } -+ if (userFilter && userGroupMemberSearch) { -+ throw new Error( -+ `userGroupMemberSearch cannot be specified when userFilter is defined.` -+ ); -+ } -+ const groupSelect = providerConfig.getOptionalStringArray("groupSelect"); -+ const queryMode = providerConfig.getOptionalString("queryMode"); -+ if (queryMode !== void 0 && queryMode !== "basic" && queryMode !== "advanced") { -+ throw new Error(`queryMode must be one of: basic, advanced`); -+ } -+ if (clientId && !clientSecret) { -+ throw new Error( -+ `clientSecret must be provided when clientId is defined.` -+ ); -+ } -+ if (clientSecret && !clientId) { -+ throw new Error( -+ `clientId must be provided when clientSecret is defined.` -+ ); -+ } -+ providers.push({ -+ id: target, -+ target, -+ authority, -+ tenantId, -+ clientId, -+ clientSecret, -+ userExpand, -+ userFilter, -+ userSelect, -+ userGroupMemberFilter, -+ userGroupMemberSearch, -+ groupExpand, -+ groupFilter, -+ groupSearch, -+ groupSelect, -+ queryMode -+ }); -+ } -+ return providers; -+} -+function readProviderConfigs(config) { -+ const providersConfig = config.getOptionalConfig( -+ "catalog.providers.microsoftGraphOrg" -+ ); -+ if (!providersConfig) { -+ return []; -+ } -+ if (providersConfig.has("clientId")) { -+ return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)]; -+ } -+ return providersConfig.keys().map((id) => { -+ const providerConfig = providersConfig.getConfig(id); -+ return readProviderConfig(id, providerConfig); -+ }); -+} -+function readProviderConfig(id, config) { -+ const target = lodash.trimEnd( -+ config.getOptionalString("target") ?? DEFAULT_TARGET, -+ "/" -+ ); -+ const authority = config.getOptionalString("authority"); -+ const tenantId = config.getString("tenantId"); -+ const clientId = config.getOptionalString("clientId"); -+ const clientSecret = config.getOptionalString("clientSecret"); -+ const userExpand = config.getOptionalString("user.expand"); -+ const userFilter = config.getOptionalString("user.filter"); -+ const userSelect = config.getOptionalStringArray("user.select"); -+ const loadUserPhotos = config.getOptionalBoolean("user.loadPhotos"); -+ const groupExpand = config.getOptionalString("group.expand"); -+ const groupFilter = config.getOptionalString("group.filter"); -+ const groupSearch = config.getOptionalString("group.search"); -+ const groupSelect = config.getOptionalStringArray("group.select"); -+ const queryMode = config.getOptionalString("queryMode"); -+ if (queryMode !== void 0 && queryMode !== "basic" && queryMode !== "advanced") { -+ throw new Error(`queryMode must be one of: basic, advanced`); -+ } -+ const userGroupMemberFilter = config.getOptionalString( -+ "userGroupMember.filter" -+ ); -+ const userGroupMemberSearch = config.getOptionalString( -+ "userGroupMember.search" -+ ); -+ if (userFilter && userGroupMemberFilter) { -+ throw new Error( -+ `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.` -+ ); -+ } -+ if (userFilter && userGroupMemberSearch) { -+ throw new Error( -+ `userGroupMemberSearch cannot be specified when userFilter is defined.` -+ ); -+ } -+ if (clientId && !clientSecret) { -+ throw new Error(`clientSecret must be provided when clientId is defined.`); -+ } -+ if (clientSecret && !clientId) { -+ throw new Error(`clientId must be provided when clientSecret is defined.`); -+ } -+ const schedule = config.has("schedule") ? backendTasks.readTaskScheduleDefinitionFromConfig(config.getConfig("schedule")) : void 0; -+ return { -+ id, -+ target, -+ authority, -+ clientId, -+ clientSecret, -+ tenantId, -+ userExpand, -+ userFilter, -+ userSelect, -+ loadUserPhotos, -+ groupExpand, -+ groupFilter, -+ groupSearch, -+ groupSelect, -+ queryMode, -+ userGroupMemberFilter, -+ userGroupMemberSearch, -+ schedule -+ }; -+} -+ -+const MICROSOFT_EMAIL_ANNOTATION = "microsoft.com/email"; -+const MICROSOFT_GRAPH_TENANT_ID_ANNOTATION = "graph.microsoft.com/tenant-id"; -+const MICROSOFT_GRAPH_GROUP_ID_ANNOTATION = "graph.microsoft.com/group-id"; -+const MICROSOFT_GRAPH_USER_ID_ANNOTATION = "graph.microsoft.com/user-id"; -+ -+function normalizeEntityName(name) { -+ let cleaned = name.trim().toLocaleLowerCase().replace(/[^a-zA-Z0-9_\-\.]/g, "_"); -+ while (cleaned.endsWith("_")) { -+ cleaned = cleaned.substring(0, cleaned.length - 1); -+ } -+ while (cleaned.includes("__")) { -+ cleaned = cleaned.replace("__", "_"); -+ } -+ return cleaned; -+} -+ -+async function defaultOrganizationTransformer(organization) { -+ if (!organization.id || !organization.displayName) { -+ return void 0; -+ } -+ const name = normalizeEntityName(organization.displayName); -+ return { -+ apiVersion: "backstage.io/v1alpha1", -+ kind: "Group", -+ metadata: { -+ name, -+ description: organization.displayName, -+ annotations: { -+ [MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]: organization.id -+ } -+ }, -+ spec: { -+ type: "root", -+ profile: { -+ displayName: organization.displayName -+ }, -+ children: [] -+ } -+ }; -+} -+function extractGroupName(group) { -+ if (group.securityEnabled) { -+ return group.displayName; -+ } -+ return group.mailNickname || group.displayName; -+} -+async function defaultGroupTransformer(group, groupPhoto) { -+ if (!group.id || !group.displayName) { -+ return void 0; -+ } -+ const name = normalizeEntityName(extractGroupName(group)); -+ const entity = { -+ apiVersion: "backstage.io/v1alpha1", -+ kind: "Group", -+ metadata: { -+ name, -+ annotations: { -+ [MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]: group.id -+ } -+ }, -+ spec: { -+ type: "team", -+ profile: {}, -+ children: [] -+ } -+ }; -+ if (group.description) { -+ entity.metadata.description = group.description; -+ } -+ if (group.displayName) { -+ entity.spec.profile.displayName = group.displayName; -+ } -+ if (group.mail) { -+ entity.spec.profile.email = group.mail; -+ } -+ if (groupPhoto) { -+ entity.spec.profile.picture = groupPhoto; -+ } -+ return entity; -+} -+async function defaultUserTransformer(user, userPhoto) { -+ if (!user.id || !user.displayName) { -+ return void 0; -+ } -+ const name = user.mail ? normalizeEntityName(user.mail) : normalizeEntityName(user.userPrincipalName); -+ const entity = { -+ apiVersion: "backstage.io/v1alpha1", -+ kind: "User", -+ metadata: { -+ name, -+ annotations: { -+ [MICROSOFT_GRAPH_USER_ID_ANNOTATION]: user.id -+ } -+ }, -+ spec: { -+ profile: { -+ displayName: user.displayName -+ // TODO: Additional fields? -+ // jobTitle: user.jobTitle || undefined, -+ // officeLocation: user.officeLocation || undefined, -+ // mobilePhone: user.mobilePhone || undefined, -+ }, -+ memberOf: [] -+ } -+ }; -+ if (user.mail) { -+ entity.metadata.annotations[MICROSOFT_EMAIL_ANNOTATION] = user.mail; -+ entity.spec.profile.email = user.mail; -+ } -+ if (userPhoto) { -+ entity.spec.profile.picture = userPhoto; -+ } -+ return entity; -+} -+ -+function buildOrgHierarchy(groups) { -+ const groupsByName = new Map(groups.map((g) => [g.metadata.name, g])); -+ for (const group of groups) { -+ const selfName = group.metadata.name; -+ const parentName = group.spec.parent; -+ if (parentName) { -+ const parent = groupsByName.get(parentName); -+ if (parent && !parent.spec.children.includes(selfName)) { -+ parent.spec.children.push(selfName); -+ } -+ } -+ } -+ for (const group of groups) { -+ const selfName = group.metadata.name; -+ for (const childName of group.spec.children) { -+ const child = groupsByName.get(childName); -+ if (child && !child.spec.parent) { -+ child.spec.parent = selfName; -+ } -+ } -+ } -+} -+function buildMemberOf(groups, users) { -+ const groupsByName = new Map(groups.map((g) => [g.metadata.name, g])); -+ users.forEach((user) => { -+ const transitiveMemberOf = /* @__PURE__ */ new Set(); -+ const todo = [ -+ ...user.spec.memberOf ?? [], -+ ...groups.filter((g) => g.spec.members?.includes(user.metadata.name)).map((g) => g.metadata.name) -+ ]; -+ for (; ; ) { -+ const current = todo.pop(); -+ if (!current) { -+ break; -+ } -+ if (!transitiveMemberOf.has(current)) { -+ transitiveMemberOf.add(current); -+ const group = groupsByName.get(current); -+ if (group?.spec.parent) { -+ todo.push(group.spec.parent); -+ } -+ } -+ } -+ user.spec.memberOf = [...transitiveMemberOf]; -+ }); -+} -+ -+const PAGE_SIZE = 999; -+async function readMicrosoftGraphUsers(client, options) { -+ const users = client.getUsers( -+ { -+ filter: options.userFilter, -+ expand: options.userExpand, -+ select: options.userSelect, -+ top: PAGE_SIZE -+ }, -+ options.queryMode -+ ); -+ return { -+ users: await transformUsers( -+ client, -+ users, -+ options.logger, -+ options.loadUserPhotos, -+ options.transformer -+ ) -+ }; -+} -+async function readMicrosoftGraphUsersInGroups(client, options) { -+ const limiter = limiterFactory__default.default(10); -+ const userGroupMemberPromises = []; -+ const userGroupMembers = /* @__PURE__ */ new Map(); -+ for await (const group of client.getGroups( -+ { -+ expand: options.groupExpand, -+ filter: options.userGroupMemberFilter, -+ search: options.userGroupMemberSearch, -+ select: ["id", "displayName"], -+ top: PAGE_SIZE -+ }, -+ options.queryMode -+ )) { -+ userGroupMemberPromises.push( -+ limiter(async () => { -+ let groupMemberCount = 0; -+ for await (const user of client.getGroupUserMembers( -+ group.id, -+ { -+ expand: options.userExpand, -+ filter: options.userFilter, -+ select: options.userSelect, -+ top: PAGE_SIZE -+ }, -+ options.queryMode -+ )) { -+ userGroupMembers.set(user.id, user); -+ groupMemberCount++; -+ } -+ options.logger.debug("Read users from group", { -+ groupId: group.id, -+ groupName: group.displayName, -+ memberCount: groupMemberCount -+ }); -+ }) -+ ); -+ } -+ await Promise.all(userGroupMemberPromises); -+ options.logger.info("Read users from group membership", { -+ groupCount: userGroupMemberPromises.length, -+ userCount: userGroupMembers.size -+ }); -+ return { -+ users: await transformUsers( -+ client, -+ userGroupMembers.values(), -+ options.logger, -+ options.loadUserPhotos, -+ options.transformer -+ ) -+ }; -+} -+async function readMicrosoftGraphOrganization(client, tenantId, options) { -+ const organization = await client.getOrganization(tenantId); -+ const transformer = options?.transformer ?? defaultOrganizationTransformer; -+ const rootGroup = await transformer(organization); -+ return { rootGroup }; -+} -+async function readMicrosoftGraphGroups(client, tenantId, options) { -+ const groups = []; -+ const groupMember = /* @__PURE__ */ new Map(); -+ const groupMemberOf = /* @__PURE__ */ new Map(); -+ const limiter = limiterFactory__default.default(10); -+ const { rootGroup } = await readMicrosoftGraphOrganization(client, tenantId, { -+ transformer: options?.organizationTransformer -+ }); -+ if (rootGroup) { -+ groupMember.set(rootGroup.metadata.name, /* @__PURE__ */ new Set()); -+ groups.push(rootGroup); -+ } -+ const transformer = options?.groupTransformer ?? defaultGroupTransformer; -+ const promises = []; -+ for await (const group of client.getGroups( -+ { -+ expand: options?.groupExpand, -+ filter: options?.groupFilter, -+ search: options?.groupSearch, -+ select: options?.groupSelect, -+ top: PAGE_SIZE -+ }, -+ options?.queryMode -+ )) { -+ promises.push( -+ limiter(async () => { -+ const entity = await transformer( -+ group -+ /* , groupPhoto*/ -+ ); -+ if (!entity) { -+ return; -+ } -+ for await (const member of client.getGroupMembers(group.id, { -+ top: PAGE_SIZE -+ })) { -+ if (!member.id) { -+ continue; -+ } -+ if (member["@odata.type"] === "#microsoft.graph.user") { -+ ensureItem(groupMemberOf, member.id, group.id); -+ } -+ if (member["@odata.type"] === "#microsoft.graph.group") { -+ ensureItem(groupMember, group.id, member.id); -+ } -+ } -+ groups.push(entity); -+ }) -+ ); -+ } -+ await Promise.all(promises); -+ return { -+ groups, -+ rootGroup, -+ groupMember, -+ groupMemberOf -+ }; -+} -+function resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf) { -+ const groupMap = /* @__PURE__ */ new Map(); -+ for (const group of groups) { -+ if (group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]) { -+ groupMap.set( -+ group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION], -+ group -+ ); -+ } -+ if (group.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]) { -+ groupMap.set( -+ group.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION], -+ group -+ ); -+ } -+ } -+ const parentGroups = /* @__PURE__ */ new Map(); -+ groupMember.forEach( -+ (members, groupId) => members.forEach((m) => ensureItem(parentGroups, m, groupId)) -+ ); -+ if (rootGroup) { -+ const tenantId = rootGroup.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]; -+ groups.forEach((group) => { -+ const groupId = group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]; -+ if (!groupId) { -+ return; -+ } -+ if (retrieveItems(parentGroups, groupId).size === 0) { -+ ensureItem(parentGroups, groupId, tenantId); -+ ensureItem(groupMember, tenantId, groupId); -+ } -+ }); -+ } -+ groups.forEach((group) => { -+ const id = group.metadata.annotations[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ?? group.metadata.annotations[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]; -+ retrieveItems(groupMember, id).forEach((m) => { -+ const childGroup = groupMap.get(m); -+ if (childGroup) { -+ group.spec.children.push(catalogModel.stringifyEntityRef(childGroup)); -+ } -+ }); -+ retrieveItems(parentGroups, id).forEach((p) => { -+ const parentGroup = groupMap.get(p); -+ if (parentGroup) { -+ group.spec.parent = catalogModel.stringifyEntityRef(parentGroup); -+ } -+ }); -+ }); -+ buildOrgHierarchy(groups); -+ users.forEach((user) => { -+ const id = user.metadata.annotations[MICROSOFT_GRAPH_USER_ID_ANNOTATION]; -+ retrieveItems(groupMemberOf, id).forEach((p) => { -+ const parentGroup = groupMap.get(p); -+ if (parentGroup) { -+ if (!user.spec.memberOf) { -+ user.spec.memberOf = []; -+ } -+ user.spec.memberOf.push(catalogModel.stringifyEntityRef(parentGroup)); -+ } -+ }); -+ }); -+ buildMemberOf(groups, users); -+} -+async function readMicrosoftGraphOrg(client, tenantId, options) { -+ let users = []; -+ if (options.userGroupMemberFilter || options.userGroupMemberSearch) { -+ const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups( -+ client, -+ { -+ queryMode: options.queryMode, -+ userExpand: options.userExpand, -+ userFilter: options.userFilter, -+ userSelect: options.userSelect, -+ userGroupMemberFilter: options.userGroupMemberFilter, -+ userGroupMemberSearch: options.userGroupMemberSearch, -+ loadUserPhotos: options.loadUserPhotos, -+ transformer: options.userTransformer, -+ logger: options.logger -+ } -+ ); -+ users = usersInGroups; -+ } else { -+ const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, { -+ queryMode: options.queryMode, -+ userExpand: options.userExpand, -+ userFilter: options.userFilter, -+ userSelect: options.userSelect, -+ loadUserPhotos: options.loadUserPhotos, -+ transformer: options.userTransformer, -+ logger: options.logger -+ }); -+ users = usersWithFilter; -+ } -+ const { groups, rootGroup, groupMember, groupMemberOf } = await readMicrosoftGraphGroups(client, tenantId, { -+ queryMode: options.queryMode, -+ groupExpand: options.groupExpand, -+ groupFilter: options.groupFilter, -+ groupSearch: options.groupSearch, -+ groupSelect: options.groupSelect, -+ groupTransformer: options.groupTransformer, -+ organizationTransformer: options.organizationTransformer -+ }); -+ resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf); -+ users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name)); -+ groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name)); -+ return { users, groups }; -+} -+async function transformUsers(client, users, logger, loadUserPhotos = true, transformer) { -+ const limiter = limiterFactory__default.default(10); -+ const resolvedTransformer = transformer ?? defaultUserTransformer; -+ const promises = []; -+ const entities = []; -+ for await (const user of users) { -+ promises.push( -+ limiter(async () => { -+ let userPhoto; -+ try { -+ if (loadUserPhotos) { -+ userPhoto = await client.getUserPhotoWithSizeLimit( -+ user.id, -+ // We are limiting the photo size, as users with full resolution photos -+ // can make the Backstage API slow -+ 120 -+ ); -+ } -+ } catch (e) { -+ logger.warn(`Unable to load user photo for`, { -+ user: user.id, -+ error: e -+ }); -+ } -+ const entity = await resolvedTransformer(user, userPhoto); -+ if (entity) { -+ entities.push(entity); -+ } -+ }) -+ ); -+ } -+ await Promise.all(promises); -+ logger.debug("Finished transforming users", { -+ microsoftUserCount: promises.length, -+ backstageUserCount: entities.length -+ }); -+ return entities; -+} -+function ensureItem(target, key, value) { -+ let set = target.get(key); -+ if (!set) { -+ set = /* @__PURE__ */ new Set(); -+ target.set(key, set); -+ } -+ set.add(value); -+} -+function retrieveItems(target, key) { -+ return target.get(key) ?? /* @__PURE__ */ new Set(); -+} -+ -+class MicrosoftGraphOrgEntityProvider { -+ constructor(options) { -+ this.options = options; -+ } -+ connection; -+ scheduleFn; -+ static fromConfig(configRoot, options) { -+ if ("id" in options) { -+ return [ -+ MicrosoftGraphOrgEntityProvider.fromLegacyConfig(configRoot, options) -+ ]; -+ } -+ if (!options.schedule && !options.scheduler) { -+ throw new Error("Either schedule or scheduler must be provided."); -+ } -+ function getTransformer(id, transformers) { -+ if (["undefined", "function"].includes(typeof transformers)) { -+ return transformers; -+ } -+ return transformers[id]; -+ } -+ return readProviderConfigs(configRoot).map((providerConfig) => { -+ if (!options.schedule && !providerConfig.schedule) { -+ throw new Error( -+ `No schedule provided neither via code nor config for MicrosoftGraphOrgEntityProvider:${providerConfig.id}.` -+ ); -+ } -+ const taskRunner = options.schedule ?? options.scheduler.createScheduledTaskRunner(providerConfig.schedule); -+ const provider = new MicrosoftGraphOrgEntityProvider({ -+ id: providerConfig.id, -+ provider: providerConfig, -+ logger: options.logger, -+ userTransformer: getTransformer( -+ providerConfig.id, -+ options.userTransformer -+ ), -+ groupTransformer: getTransformer( -+ providerConfig.id, -+ options.groupTransformer -+ ), -+ organizationTransformer: getTransformer( -+ providerConfig.id, -+ options.organizationTransformer -+ ), -+ providerConfigTransformer: getTransformer( -+ providerConfig.id, -+ options.providerConfigTransformer -+ ) -+ }); -+ if (taskRunner !== "manual") { -+ provider.schedule(taskRunner); -+ } -+ return provider; -+ }); -+ } -+ /** -+ * @deprecated Exists for backwards compatibility only and will be removed in the future. -+ */ -+ static fromLegacyConfig(configRoot, options) { -+ options.logger.warn( -+ 'Deprecated msgraph config "catalog.processors.microsoftGraphOrg" used. Use "catalog.providers.microsoftGraphOrg" instead. More info at https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/CHANGELOG.md#040-next1' -+ ); -+ const config = configRoot.getOptionalConfig( -+ "catalog.processors.microsoftGraphOrg" -+ ); -+ const providers = config ? readMicrosoftGraphConfig(config) : []; -+ const provider = providers.find((p) => options.target.startsWith(p.target)); -+ if (!provider) { -+ throw new Error( -+ `There is no Microsoft Graph Org provider that matches "${options.target}". Please add a configuration entry for it under "catalog.processors.microsoftGraphOrg.providers".` -+ ); -+ } -+ const logger = options.logger.child({ -+ target: options.target -+ }); -+ const result = new MicrosoftGraphOrgEntityProvider({ -+ id: options.id, -+ userTransformer: options.userTransformer, -+ groupTransformer: options.groupTransformer, -+ organizationTransformer: options.organizationTransformer, -+ providerConfigTransformer: options.providerConfigTransformer, -+ logger, -+ provider -+ }); -+ if (options.schedule !== "manual") { -+ result.schedule(options.schedule); -+ } -+ return result; -+ } -+ /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */ -+ getProviderName() { -+ return `MicrosoftGraphOrgEntityProvider:${this.options.id}`; -+ } -+ /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */ -+ async connect(connection) { -+ this.connection = connection; -+ await this.scheduleFn?.(); -+ } -+ /** -+ * Runs one complete ingestion loop. Call this method regularly at some -+ * appropriate cadence. -+ */ -+ async read(options) { -+ if (!this.connection) { -+ throw new Error("Not initialized"); -+ } -+ const logger = options?.logger ?? this.options.logger; -+ const provider = this.options.providerConfigTransformer ? await this.options.providerConfigTransformer(this.options.provider) : this.options.provider; -+ const { markReadComplete } = trackProgress(logger); -+ const client = MicrosoftGraphClient.create(this.options.provider); -+ const { users, groups } = await readMicrosoftGraphOrg( -+ client, -+ provider.tenantId, -+ { -+ userExpand: provider.userExpand, -+ userFilter: provider.userFilter, -+ userSelect: provider.userSelect, -+ loadUserPhotos: provider.loadUserPhotos, -+ userGroupMemberFilter: provider.userGroupMemberFilter, -+ userGroupMemberSearch: provider.userGroupMemberSearch, -+ groupExpand: provider.groupExpand, -+ groupFilter: provider.groupFilter, -+ groupSearch: provider.groupSearch, -+ groupSelect: provider.groupSelect, -+ queryMode: provider.queryMode, -+ groupTransformer: this.options.groupTransformer, -+ userTransformer: this.options.userTransformer, -+ organizationTransformer: this.options.organizationTransformer, -+ logger -+ } -+ ); -+ const { markCommitComplete } = markReadComplete({ users, groups }); -+ await this.connection.applyMutation({ -+ type: "full", -+ entities: [...users, ...groups].map((entity) => ({ -+ locationKey: `msgraph-org-provider:${this.options.id}`, -+ entity: withLocations(this.options.id, entity) -+ })) -+ }); -+ markCommitComplete(); -+ } -+ schedule(taskRunner) { -+ this.scheduleFn = async () => { -+ const id = `${this.getProviderName()}:refresh`; -+ await taskRunner.run({ -+ id, -+ fn: async () => { -+ const logger = this.options.logger.child({ -+ class: MicrosoftGraphOrgEntityProvider.prototype.constructor.name, -+ taskId: id, -+ taskInstanceId: uuid__namespace.v4() -+ }); -+ try { -+ await this.read({ logger }); -+ } catch (error) { -+ logger.error( -+ `${this.getProviderName()} refresh failed, ${error}`, -+ error -+ ); -+ } -+ } -+ }); -+ }; -+ } -+} -+function trackProgress(logger) { -+ let timestamp = Date.now(); -+ let summary; -+ logger.info("Reading msgraph users and groups"); -+ function markReadComplete(read) { -+ summary = `${read.users.length} msgraph users and ${read.groups.length} msgraph groups`; -+ const readDuration = ((Date.now() - timestamp) / 1e3).toFixed(1); -+ timestamp = Date.now(); -+ logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`); -+ return { markCommitComplete }; -+ } -+ function markCommitComplete() { -+ const commitDuration = ((Date.now() - timestamp) / 1e3).toFixed(1); -+ logger.info(`Committed ${summary} in ${commitDuration} seconds.`); -+ } -+ return { markReadComplete }; -+} -+function withLocations(providerId, entity) { -+ const uid = entity.metadata.annotations?.[MICROSOFT_GRAPH_USER_ID_ANNOTATION] || entity.metadata.annotations?.[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] || entity.metadata.annotations?.[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION] || entity.metadata.name; -+ const location = `msgraph:${providerId}/${encodeURIComponent(uid)}`; -+ return lodash.merge( -+ { -+ metadata: { -+ annotations: { -+ [catalogModel.ANNOTATION_LOCATION]: location, -+ [catalogModel.ANNOTATION_ORIGIN_LOCATION]: location -+ } -+ } -+ }, -+ entity -+ ); -+} -+ -+exports.MICROSOFT_EMAIL_ANNOTATION = MICROSOFT_EMAIL_ANNOTATION; -+exports.MICROSOFT_GRAPH_GROUP_ID_ANNOTATION = MICROSOFT_GRAPH_GROUP_ID_ANNOTATION; -+exports.MICROSOFT_GRAPH_TENANT_ID_ANNOTATION = MICROSOFT_GRAPH_TENANT_ID_ANNOTATION; -+exports.MICROSOFT_GRAPH_USER_ID_ANNOTATION = MICROSOFT_GRAPH_USER_ID_ANNOTATION; -+exports.MicrosoftGraphClient = MicrosoftGraphClient; -+exports.MicrosoftGraphOrgEntityProvider = MicrosoftGraphOrgEntityProvider; -+exports.defaultGroupTransformer = defaultGroupTransformer; -+exports.defaultOrganizationTransformer = defaultOrganizationTransformer; -+exports.defaultUserTransformer = defaultUserTransformer; -+exports.normalizeEntityName = normalizeEntityName; -+exports.readMicrosoftGraphConfig = readMicrosoftGraphConfig; -+exports.readMicrosoftGraphOrg = readMicrosoftGraphOrg; -+exports.readProviderConfig = readProviderConfig; -+exports.readProviderConfigs = readProviderConfigs; -+//# sourceMappingURL=MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js.map -diff --git a/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js.map b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js.map -new file mode 100644 -index 0000000..b8dbe27 ---- /dev/null -+++ b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js.map -@@ -0,0 +1 @@ -+{"version":3,"file":"MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js","sources":["../../src/microsoftGraph/client.ts","../../src/microsoftGraph/config.ts","../../src/microsoftGraph/constants.ts","../../src/microsoftGraph/helper.ts","../../src/microsoftGraph/defaultTransformers.ts","../../src/microsoftGraph/org.ts","../../src/microsoftGraph/read.ts","../../src/processors/MicrosoftGraphOrgEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n TokenCredential,\n DefaultAzureCredential,\n ClientSecretCredential,\n} from '@azure/identity';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport fetch, { Response } from 'node-fetch';\nimport qs from 'qs';\nimport { MicrosoftGraphProviderConfig } from './config';\n\n/**\n * OData (Open Data Protocol) Query\n *\n * {@link https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview}\n * {@link https://docs.microsoft.com/en-us/graph/query-parameters}\n * @public\n */\nexport type ODataQuery = {\n /**\n * search resources within a collection matching a free-text search expression.\n */\n search?: string;\n /**\n * filter a collection of resources\n */\n filter?: string;\n /**\n * specifies the related resources or media streams to be included in line with retrieved resources\n */\n expand?: string;\n /**\n * request a specific set of properties for each entity or complex type\n */\n select?: string[];\n /**\n * Retrieves the total count of matching resources.\n */\n count?: boolean;\n /**\n * Maximum number of records to receive in one batch.\n */\n top?: number;\n};\n\n/**\n * Extends the base msgraph types to include the odata type.\n *\n * @public\n */\nexport type GroupMember =\n | (MicrosoftGraph.Group & { '@odata.type': '#microsoft.graph.user' })\n | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.group' });\n\n/**\n * A HTTP Client that communicates with Microsoft Graph API.\n * Simplify Authentication and API calls to get `User` and `Group` from Microsoft Graph\n *\n * Uses `msal-node` for authentication\n *\n * @public\n */\nexport class MicrosoftGraphClient {\n /**\n * Factory method that instantiate `msal` client and return\n * an instance of `MicrosoftGraphClient`\n *\n * @public\n *\n * @param config - Configuration for Interacting with Graph API\n */\n static create(config: MicrosoftGraphProviderConfig): MicrosoftGraphClient {\n const options = {\n authorityHost: config.authority,\n tenantId: config.tenantId,\n };\n\n const credential =\n config.clientId && config.clientSecret\n ? new ClientSecretCredential(\n config.tenantId,\n config.clientId,\n config.clientSecret,\n options,\n )\n : new DefaultAzureCredential(options);\n\n return new MicrosoftGraphClient(config.target, credential);\n }\n\n /**\n * @param baseUrl - baseUrl of Graph API {@link MicrosoftGraphProviderConfig.target}\n * @param tokenCredential - instance of `TokenCredential` that is used to acquire token for Graph API calls\n *\n */\n constructor(\n private readonly baseUrl: string,\n private readonly tokenCredential: TokenCredential,\n ) {}\n\n /**\n * Get a collection of resource from Graph API and\n * return an `AsyncIterable` of that resource\n *\n * @public\n * @param path - Resource in Microsoft Graph\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *requestCollection(\n path: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable {\n // upgrade to advanced query mode transparently when \"search\" is used\n // to stay backwards compatible.\n const appliedQueryMode = query?.search ? 'advanced' : queryMode ?? 'basic';\n\n // not needed for \"search\"\n // as of https://docs.microsoft.com/en-us/graph/aad-advanced-queries?tabs=http\n // even though a few other places say the opposite\n // - https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=http#request-headers\n // - https://docs.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0#properties\n if (appliedQueryMode === 'advanced' && (query?.filter || query?.select)) {\n query.count = true;\n }\n const headers: Record =\n appliedQueryMode === 'advanced'\n ? {\n // Eventual consistency is required for advanced querying capabilities\n // like \"$search\" or parts of \"$filter\".\n // If a new user/group is not found, it'll eventually be imported on a subsequent read\n ConsistencyLevel: 'eventual',\n }\n : {};\n\n let response = await this.requestApi(path, query, headers);\n\n for (;;) {\n if (response.status !== 200) {\n await this.handleError(path, response);\n }\n\n const result = await response.json();\n\n // Graph API return array of collections\n const elements: T[] = result.value;\n\n yield* elements;\n\n // Follow cursor to the next page if one is available\n if (!result['@odata.nextLink']) {\n return;\n }\n\n response = await this.requestRaw(result['@odata.nextLink'], headers);\n }\n }\n\n /**\n * Abstract on top of {@link MicrosoftGraphClient.requestRaw}\n *\n * @public\n * @param path - Resource in Microsoft Graph\n * @param query - OData Query {@link ODataQuery}\n * @param headers - optional HTTP headers\n */\n async requestApi(\n path: string,\n query?: ODataQuery,\n headers?: Record,\n ): Promise {\n const queryString = qs.stringify(\n {\n $search: query?.search,\n $filter: query?.filter,\n $select: query?.select?.join(','),\n $expand: query?.expand,\n $count: query?.count,\n $top: query?.top,\n },\n {\n addQueryPrefix: true,\n // Microsoft Graph doesn't like an encoded query string\n encode: false,\n },\n );\n\n return await this.requestRaw(\n `${this.baseUrl}/${path}${queryString}`,\n headers,\n );\n }\n\n /**\n * Makes a HTTP call to Graph API with token\n *\n * @param url - HTTP Endpoint of Graph API\n * @param headers - optional HTTP headers\n */\n async requestRaw(\n url: string,\n headers?: Record,\n retryCount = 2,\n ): Promise {\n // Make sure that we always have a valid access token (might be cached)\n const urlObj = new URL(url);\n const token = await this.tokenCredential.getToken(\n `${urlObj.protocol}//${urlObj.hostname}/.default`,\n );\n\n if (!token) {\n throw new Error('Failed to obtain token from Azure Identity');\n }\n\n try {\n return await fetch(url, {\n headers: {\n ...headers,\n Authorization: `Bearer ${token.token}`,\n },\n });\n } catch (e: any) {\n if (e?.code === 'ETIMEDOUT' && retryCount > 0) {\n return this.requestRaw(url, headers, retryCount - 1);\n }\n throw e;\n }\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * of `User` from Graph API with size limit\n *\n * @param userId - The unique identifier for the `User` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n async getUserPhotoWithSizeLimit(\n userId: string,\n maxSize: number,\n ): Promise {\n return await this.getPhotoWithSizeLimit('users', userId, maxSize);\n }\n\n async getUserPhoto(\n userId: string,\n sizeId?: string,\n ): Promise {\n return await this.getPhoto('users', userId, sizeId);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * from Graph API and return as `AsyncIterable`\n *\n * @public\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *getUsers(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable {\n yield* this.requestCollection(\n `users`,\n query,\n queryMode,\n );\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * of `Group` from Graph API with size limit\n *\n * @param groupId - The unique identifier for the `Group` resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n async getGroupPhotoWithSizeLimit(\n groupId: string,\n maxSize: number,\n ): Promise {\n return await this.getPhotoWithSizeLimit('groups', groupId, maxSize);\n }\n\n async getGroupPhoto(\n groupId: string,\n sizeId?: string,\n ): Promise {\n return await this.getPhoto('groups', groupId, sizeId);\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/group | Group}\n * from Graph API and return as `AsyncIterable`\n *\n * @public\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *getGroups(\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable {\n yield* this.requestCollection(\n `groups`,\n query,\n queryMode,\n );\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * belonging to a `Group` from Graph API and return as `AsyncIterable`\n * @public\n * @param groupId - The unique identifier for the `Group` resource\n *\n */\n async *getGroupMembers(\n groupId: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable {\n yield* this.requestCollection(\n `groups/${groupId}/members`,\n query,\n queryMode,\n );\n }\n\n /**\n * Get a collection of\n * {@link https://docs.microsoft.com/en-us/graph/api/resources/user | User}\n * belonging to a `Group` from Graph API and return as `AsyncIterable`\n * @public\n * @param groupId - The unique identifier for the `Group` resource\n * @param query - OData Query {@link ODataQuery}\n * @param queryMode - Mode to use while querying. Some features are only available at \"advanced\".\n */\n async *getGroupUserMembers(\n groupId: string,\n query?: ODataQuery,\n queryMode?: 'basic' | 'advanced',\n ): AsyncIterable {\n yield* this.requestCollection(\n `groups/${groupId}/members/microsoft.graph.user/`,\n query,\n queryMode,\n );\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/organization | Organization}\n * from Graph API\n * @public\n * @param tenantId - The unique identifier for the `Organization` resource\n *\n */\n async getOrganization(\n tenantId: string,\n ): Promise {\n const response = await this.requestApi(`organization/${tenantId}`);\n\n if (response.status !== 200) {\n await this.handleError(`organization/${tenantId}`, response);\n }\n\n return await response.json();\n }\n\n /**\n * Get {@link https://docs.microsoft.com/en-us/graph/api/resources/profilephoto | profilePhoto}\n * from Graph API\n *\n * @param entityName - type of parent resource, either `User` or `Group`\n * @param id - The unique identifier for the {@link entityName | entityName} resource\n * @param maxSize - Maximum pixel height of the photo\n *\n */\n private async getPhotoWithSizeLimit(\n entityName: string,\n id: string,\n maxSize: number,\n ): Promise {\n const response = await this.requestApi(`${entityName}/${id}/photos`);\n\n if (response.status === 404) {\n return undefined;\n } else if (response.status !== 200) {\n await this.handleError(`${entityName} photos`, response);\n }\n\n const result = await response.json();\n const photos = result.value as MicrosoftGraph.ProfilePhoto[];\n let selectedPhoto: MicrosoftGraph.ProfilePhoto | undefined = undefined;\n\n // Find the biggest picture that is smaller than the max size\n for (const p of photos) {\n if (\n !selectedPhoto ||\n (p.height! >= selectedPhoto.height! && p.height! <= maxSize)\n ) {\n selectedPhoto = p;\n }\n }\n\n if (!selectedPhoto) {\n return undefined;\n }\n\n return await this.getPhoto(entityName, id, selectedPhoto.id!);\n }\n\n private async getPhoto(\n entityName: string,\n id: string,\n sizeId?: string,\n ): Promise {\n const path = sizeId\n ? `${entityName}/${id}/photos/${sizeId}/$value`\n : `${entityName}/${id}/photo/$value`;\n const response = await this.requestApi(path);\n\n if (response.status === 404) {\n return undefined;\n } else if (response.status !== 200) {\n await this.handleError('photo', response);\n }\n\n return `data:image/jpeg;base64,${Buffer.from(\n await response.arrayBuffer(),\n ).toString('base64')}`;\n }\n\n private async handleError(path: string, response: Response): Promise {\n const result = await response.json();\n const error = result.error as MicrosoftGraph.PublicError;\n\n throw new Error(\n `Error while reading ${path} from Microsoft Graph: ${error.code} - ${error.message}`,\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n readTaskScheduleDefinitionFromConfig,\n TaskScheduleDefinition,\n} from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\nimport { trimEnd } from 'lodash';\n\nconst DEFAULT_PROVIDER_ID = 'default';\nconst DEFAULT_TARGET = 'https://graph.microsoft.com/v1.0';\n\n/**\n * The configuration parameters for a single Microsoft Graph provider.\n *\n * @public\n */\nexport type MicrosoftGraphProviderConfig = {\n /**\n * Identifier of the provider which will be used i.e. at the location key for ingested entities.\n */\n id: string;\n\n /**\n * The prefix of the target that this matches on, e.g.\n * \"https://graph.microsoft.com/v1.0\", with no trailing slash.\n */\n target: string;\n /**\n * The auth authority used.\n *\n * E.g. \"https://login.microsoftonline.com\"\n */\n authority?: string;\n /**\n * The tenant whose org data we are interested in.\n */\n tenantId: string;\n /**\n * The OAuth client ID to use for authenticating requests.\n * If specified, ClientSecret must also be specified\n */\n clientId?: string;\n /**\n * The OAuth client secret to use for authenticating requests.\n * If specified, ClientId must also be specified\n */\n clientSecret?: string;\n /**\n * The filter to apply to extract users.\n *\n * E.g. \"accountEnabled eq true and userType eq 'member'\"\n */\n userFilter?: string;\n /**\n * The fields to be fetched on query.\n *\n * E.g. [\"id\", \"displayName\", \"description\"]\n */\n userSelect?: string[];\n /**\n * The \"expand\" argument to apply to users.\n *\n * E.g. \"manager\".\n */\n userExpand?: string;\n /**\n * The filter to apply to extract users by groups memberships.\n *\n * E.g. \"displayName eq 'Backstage Users'\"\n */\n userGroupMemberFilter?: string;\n /**\n * The search criteria to apply to extract users by groups memberships.\n *\n * E.g. \"\\\"displayName:-team\\\"\" would only match groups which contain '-team'\n */\n userGroupMemberSearch?: string;\n /**\n * The \"expand\" argument to apply to groups.\n *\n * E.g. \"member\".\n */\n groupExpand?: string;\n /**\n * The filter to apply to extract groups.\n *\n * E.g. \"securityEnabled eq false and mailEnabled eq true\"\n */\n groupFilter?: string;\n /**\n * The search criteria to apply to extract groups.\n *\n * E.g. \"\\\"displayName:-team\\\"\" would only match groups which contain '-team'\n */\n groupSearch?: string;\n\n /**\n * The fields to be fetched on query.\n *\n * E.g. [\"id\", \"displayName\", \"description\"]\n */\n groupSelect?: string[];\n\n /**\n * By default, the Microsoft Graph API only provides the basic feature set\n * for querying. Certain features are limited to advanced query capabilities\n * (see https://docs.microsoft.com/en-us/graph/aad-advanced-queries)\n * and need to be enabled.\n *\n * Some features like `$expand` are not available for advanced queries, though.\n */\n queryMode?: 'basic' | 'advanced';\n\n /**\n * Set to false to not load user photos.\n * This can be useful for huge organizations.\n */\n loadUserPhotos?: boolean;\n\n /**\n * Schedule configuration for refresh tasks.\n */\n schedule?: TaskScheduleDefinition;\n};\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the msgraph config hierarchy\n *\n * @public\n * @deprecated Replaced by not exported `readProviderConfigs` and kept for backwards compatibility only.\n */\nexport function readMicrosoftGraphConfig(\n config: Config,\n): MicrosoftGraphProviderConfig[] {\n const providers: MicrosoftGraphProviderConfig[] = [];\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n\n for (const providerConfig of providerConfigs) {\n const target = trimEnd(\n providerConfig.getOptionalString('target') ?? DEFAULT_TARGET,\n '/',\n );\n const authority = providerConfig.getOptionalString('authority');\n\n const tenantId = providerConfig.getString('tenantId');\n const clientId = providerConfig.getOptionalString('clientId');\n const clientSecret = providerConfig.getOptionalString('clientSecret');\n\n const userExpand = providerConfig.getOptionalString('userExpand');\n const userFilter = providerConfig.getOptionalString('userFilter');\n const userSelect = providerConfig.getOptionalStringArray('userSelect');\n const userGroupMemberFilter = providerConfig.getOptionalString(\n 'userGroupMemberFilter',\n );\n const userGroupMemberSearch = providerConfig.getOptionalString(\n 'userGroupMemberSearch',\n );\n const groupExpand = providerConfig.getOptionalString('groupExpand');\n const groupFilter = providerConfig.getOptionalString('groupFilter');\n const groupSearch = providerConfig.getOptionalString('groupSearch');\n\n if (userFilter && userGroupMemberFilter) {\n throw new Error(\n `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,\n );\n }\n if (userFilter && userGroupMemberSearch) {\n throw new Error(\n `userGroupMemberSearch cannot be specified when userFilter is defined.`,\n );\n }\n\n const groupSelect = providerConfig.getOptionalStringArray('groupSelect');\n const queryMode = providerConfig.getOptionalString('queryMode');\n if (\n queryMode !== undefined &&\n queryMode !== 'basic' &&\n queryMode !== 'advanced'\n ) {\n throw new Error(`queryMode must be one of: basic, advanced`);\n }\n\n if (clientId && !clientSecret) {\n throw new Error(\n `clientSecret must be provided when clientId is defined.`,\n );\n }\n\n if (clientSecret && !clientId) {\n throw new Error(\n `clientId must be provided when clientSecret is defined.`,\n );\n }\n\n providers.push({\n id: target,\n target,\n authority,\n tenantId,\n clientId,\n clientSecret,\n userExpand,\n userFilter,\n userSelect,\n userGroupMemberFilter,\n userGroupMemberSearch,\n groupExpand,\n groupFilter,\n groupSearch,\n groupSelect,\n queryMode,\n });\n }\n\n return providers;\n}\n\n/**\n * Parses all configured providers.\n *\n * @param config - The root of the msgraph config hierarchy\n *\n * @public\n */\nexport function readProviderConfigs(\n config: Config,\n): MicrosoftGraphProviderConfig[] {\n const providersConfig = config.getOptionalConfig(\n 'catalog.providers.microsoftGraphOrg',\n );\n if (!providersConfig) {\n return [];\n }\n\n if (providersConfig.has('clientId')) {\n // simple/single config variant\n return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];\n }\n\n return providersConfig.keys().map(id => {\n const providerConfig = providersConfig.getConfig(id);\n\n return readProviderConfig(id, providerConfig);\n });\n}\n\n/**\n * Parses a single configured provider by id.\n *\n * @param id - the id of the provider to parse\n * @param config - The root of the msgraph config hierarchy\n *\n * @public\n */\nexport function readProviderConfig(\n id: string,\n config: Config,\n): MicrosoftGraphProviderConfig {\n const target = trimEnd(\n config.getOptionalString('target') ?? DEFAULT_TARGET,\n '/',\n );\n const authority = config.getOptionalString('authority');\n\n const tenantId = config.getString('tenantId');\n const clientId = config.getOptionalString('clientId');\n const clientSecret = config.getOptionalString('clientSecret');\n\n const userExpand = config.getOptionalString('user.expand');\n const userFilter = config.getOptionalString('user.filter');\n const userSelect = config.getOptionalStringArray('user.select');\n const loadUserPhotos = config.getOptionalBoolean('user.loadPhotos');\n\n const groupExpand = config.getOptionalString('group.expand');\n const groupFilter = config.getOptionalString('group.filter');\n const groupSearch = config.getOptionalString('group.search');\n const groupSelect = config.getOptionalStringArray('group.select');\n\n const queryMode = config.getOptionalString('queryMode');\n if (\n queryMode !== undefined &&\n queryMode !== 'basic' &&\n queryMode !== 'advanced'\n ) {\n throw new Error(`queryMode must be one of: basic, advanced`);\n }\n\n const userGroupMemberFilter = config.getOptionalString(\n 'userGroupMember.filter',\n );\n const userGroupMemberSearch = config.getOptionalString(\n 'userGroupMember.search',\n );\n\n if (userFilter && userGroupMemberFilter) {\n throw new Error(\n `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,\n );\n }\n if (userFilter && userGroupMemberSearch) {\n throw new Error(\n `userGroupMemberSearch cannot be specified when userFilter is defined.`,\n );\n }\n\n if (clientId && !clientSecret) {\n throw new Error(`clientSecret must be provided when clientId is defined.`);\n }\n\n if (clientSecret && !clientId) {\n throw new Error(`clientId must be provided when clientSecret is defined.`);\n }\n\n const schedule = config.has('schedule')\n ? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule'))\n : undefined;\n\n return {\n id,\n target,\n authority,\n clientId,\n clientSecret,\n tenantId,\n userExpand,\n userFilter,\n userSelect,\n loadUserPhotos,\n groupExpand,\n groupFilter,\n groupSearch,\n groupSelect,\n queryMode,\n userGroupMemberFilter,\n userGroupMemberSearch,\n schedule,\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The (primary) user email. Also used by the Microsoft auth provider to resolve the User entity.\n *\n * @public\n */\nexport const MICROSOFT_EMAIL_ANNOTATION = 'microsoft.com/email';\n\n/**\n * The tenant id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_TENANT_ID_ANNOTATION =\n 'graph.microsoft.com/tenant-id';\n\n/**\n * The group id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_GROUP_ID_ANNOTATION =\n 'graph.microsoft.com/group-id';\n\n/**\n * The user id used by the Microsoft Graph API\n *\n * @public\n */\nexport const MICROSOFT_GRAPH_USER_ID_ANNOTATION = 'graph.microsoft.com/user-id';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Takes an input string and cleans it up to become suitable as an entity name.\n *\n * @public\n */\nexport function normalizeEntityName(name: string): string {\n let cleaned = name\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-zA-Z0-9_\\-\\.]/g, '_');\n\n // invalid to end with _\n while (cleaned.endsWith('_')) {\n cleaned = cleaned.substring(0, cleaned.length - 1);\n }\n\n // cleans up format for groups like 'my group (Reader)'\n while (cleaned.includes('__')) {\n // replaceAll from node.js >= 15\n cleaned = cleaned.replace('__', '_');\n }\n\n return cleaned;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n MICROSOFT_EMAIL_ANNOTATION,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n} from './constants';\nimport { normalizeEntityName } from './helper';\nimport { GroupEntity, UserEntity } from '@backstage/catalog-model';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\n\n/**\n * The default implementation of the transformation from a graph organization\n * entry to a Group entity.\n *\n * @public\n */\nexport async function defaultOrganizationTransformer(\n organization: MicrosoftGraph.Organization,\n): Promise {\n if (!organization.id || !organization.displayName) {\n return undefined;\n }\n\n const name = normalizeEntityName(organization.displayName!);\n return {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Group',\n metadata: {\n name: name,\n description: organization.displayName!,\n annotations: {\n [MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]: organization.id!,\n },\n },\n spec: {\n type: 'root',\n profile: {\n displayName: organization.displayName!,\n },\n children: [],\n },\n };\n}\n\nfunction extractGroupName(group: MicrosoftGraph.Group): string {\n if (group.securityEnabled) {\n return group.displayName as string;\n }\n return (group.mailNickname || group.displayName) as string;\n}\n\n/**\n * The default implementation of the transformation from a graph group entry to\n * a Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n group: MicrosoftGraph.Group,\n groupPhoto?: string,\n): Promise {\n if (!group.id || !group.displayName) {\n return undefined;\n }\n\n const name = normalizeEntityName(extractGroupName(group));\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Group',\n metadata: {\n name: name,\n annotations: {\n [MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]: group.id,\n },\n },\n spec: {\n type: 'team',\n profile: {},\n children: [],\n },\n };\n\n if (group.description) {\n entity.metadata.description = group.description;\n }\n if (group.displayName) {\n entity.spec.profile!.displayName = group.displayName;\n }\n if (group.mail) {\n entity.spec.profile!.email = group.mail;\n }\n if (groupPhoto) {\n entity.spec.profile!.picture = groupPhoto;\n }\n\n return entity;\n}\n\n/**\n * The default implementation of the transformation from a graph user entry to\n * a User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n user: MicrosoftGraph.User,\n userPhoto?: string,\n): Promise {\n if (!user.id || !user.displayName) {\n return undefined;\n }\n\n const name = user.mail\n ? normalizeEntityName(user.mail)\n : normalizeEntityName(user.userPrincipalName!);\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'User',\n metadata: {\n name,\n annotations: {\n [MICROSOFT_GRAPH_USER_ID_ANNOTATION]: user.id!,\n },\n },\n spec: {\n profile: {\n displayName: user.displayName!,\n\n // TODO: Additional fields?\n // jobTitle: user.jobTitle || undefined,\n // officeLocation: user.officeLocation || undefined,\n // mobilePhone: user.mobilePhone || undefined,\n },\n memberOf: [],\n },\n };\n\n if (user.mail) {\n entity.metadata.annotations![MICROSOFT_EMAIL_ANNOTATION] = user.mail;\n entity.spec.profile!.email = user.mail;\n }\n\n if (userPhoto) {\n entity.spec.profile!.picture = userPhoto;\n }\n\n return entity;\n}","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GroupEntity, UserEntity } from '@backstage/catalog-model';\n\n// TODO: Copied from plugin-catalog-backend, but we could also export them from\n// there. Or move them to catalog-model.\n\nexport function buildOrgHierarchy(groups: GroupEntity[]) {\n const groupsByName = new Map(groups.map(g => [g.metadata.name, g]));\n\n //\n // Make sure that g.parent.children contain g\n //\n\n for (const group of groups) {\n const selfName = group.metadata.name;\n const parentName = group.spec.parent;\n if (parentName) {\n const parent = groupsByName.get(parentName);\n if (parent && !parent.spec.children.includes(selfName)) {\n parent.spec.children.push(selfName);\n }\n }\n }\n\n //\n // Make sure that g.children.parent is g\n //\n\n for (const group of groups) {\n const selfName = group.metadata.name;\n for (const childName of group.spec.children) {\n const child = groupsByName.get(childName);\n if (child && !child.spec.parent) {\n child.spec.parent = selfName;\n }\n }\n }\n}\n\n// Ensure that users have their transitive group memberships. Requires that\n// the groups were previously processed with buildOrgHierarchy()\nexport function buildMemberOf(groups: GroupEntity[], users: UserEntity[]) {\n const groupsByName = new Map(groups.map(g => [g.metadata.name, g]));\n\n users.forEach(user => {\n const transitiveMemberOf = new Set();\n\n const todo = [\n ...(user.spec.memberOf ?? []),\n ...groups\n .filter(g => g.spec.members?.includes(user.metadata.name))\n .map(g => g.metadata.name),\n ];\n\n for (;;) {\n const current = todo.pop();\n if (!current) {\n break;\n }\n\n if (!transitiveMemberOf.has(current)) {\n transitiveMemberOf.add(current);\n const group = groupsByName.get(current);\n if (group?.spec.parent) {\n todo.push(group.spec.parent);\n }\n }\n }\n\n user.spec.memberOf = [...transitiveMemberOf];\n });\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport limiterFactory from 'p-limit';\nimport { MicrosoftGraphClient } from './client';\nimport {\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n} from './constants';\nimport { buildMemberOf, buildOrgHierarchy } from './org';\nimport {\n GroupTransformer,\n OrganizationTransformer,\n UserTransformer,\n} from './types';\nimport {\n defaultGroupTransformer,\n defaultOrganizationTransformer,\n defaultUserTransformer,\n} from './defaultTransformers';\nimport * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst PAGE_SIZE = 999;\n\nexport async function readMicrosoftGraphUsers(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n loadUserPhotos?: boolean;\n transformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const users = client.getUsers(\n {\n filter: options.userFilter,\n expand: options.userExpand,\n select: options.userSelect,\n top: PAGE_SIZE,\n },\n options.queryMode,\n );\n\n return {\n users: await transformUsers(\n client,\n users,\n options.logger,\n options.loadUserPhotos,\n options.transformer,\n ),\n };\n}\n\nexport async function readMicrosoftGraphUsersInGroups(\n client: MicrosoftGraphClient,\n options: {\n queryMode?: 'basic' | 'advanced';\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n loadUserPhotos?: boolean;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n groupExpand?: string;\n transformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n}> {\n const limiter = limiterFactory(10);\n\n const userGroupMemberPromises: Promise[] = [];\n const userGroupMembers = new Map();\n\n for await (const group of client.getGroups(\n {\n expand: options.groupExpand,\n filter: options.userGroupMemberFilter,\n search: options.userGroupMemberSearch,\n select: ['id', 'displayName'],\n top: PAGE_SIZE,\n },\n options.queryMode,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n userGroupMemberPromises.push(\n limiter(async () => {\n let groupMemberCount = 0;\n for await (const user of client.getGroupUserMembers(\n group.id!,\n {\n expand: options.userExpand,\n filter: options.userFilter,\n select: options.userSelect,\n top: PAGE_SIZE,\n },\n options.queryMode,\n )) {\n userGroupMembers.set(user.id!, user);\n groupMemberCount++;\n }\n options.logger.debug('Read users from group', {\n groupId: group.id,\n groupName: group.displayName,\n memberCount: groupMemberCount,\n });\n }),\n );\n }\n\n // Wait for all group members\n await Promise.all(userGroupMemberPromises);\n\n options.logger.info('Read users from group membership', {\n groupCount: userGroupMemberPromises.length,\n userCount: userGroupMembers.size,\n });\n\n return {\n users: await transformUsers(\n client,\n userGroupMembers.values(),\n options.logger,\n options.loadUserPhotos,\n options.transformer,\n ),\n };\n}\n\nexport async function readMicrosoftGraphOrganization(\n client: MicrosoftGraphClient,\n tenantId: string,\n options?: { transformer?: OrganizationTransformer },\n): Promise<{\n rootGroup?: GroupEntity; // With all relations empty\n}> {\n // For now we expect a single root organization\n const organization = await client.getOrganization(tenantId);\n const transformer = options?.transformer ?? defaultOrganizationTransformer;\n const rootGroup = await transformer(organization);\n\n return { rootGroup };\n}\n\nexport async function readMicrosoftGraphGroups(\n client: MicrosoftGraphClient,\n tenantId: string,\n options?: {\n queryMode?: 'basic' | 'advanced';\n groupExpand?: string;\n groupFilter?: string;\n groupSearch?: string;\n groupSelect?: string[];\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n rootGroup: GroupEntity | undefined; // With all relations empty\n groupMember: Map>;\n groupMemberOf: Map>;\n}> {\n const groups: GroupEntity[] = [];\n const groupMember: Map> = new Map();\n const groupMemberOf: Map> = new Map();\n const limiter = limiterFactory(10);\n\n const { rootGroup } = await readMicrosoftGraphOrganization(client, tenantId, {\n transformer: options?.organizationTransformer,\n });\n if (rootGroup) {\n groupMember.set(rootGroup.metadata.name, new Set());\n groups.push(rootGroup);\n }\n\n const transformer = options?.groupTransformer ?? defaultGroupTransformer;\n const promises: Promise[] = [];\n\n for await (const group of client.getGroups(\n {\n expand: options?.groupExpand,\n filter: options?.groupFilter,\n search: options?.groupSearch,\n select: options?.groupSelect,\n top: PAGE_SIZE,\n },\n options?.queryMode,\n )) {\n // Process all groups in parallel, otherwise it can take quite some time\n promises.push(\n limiter(async () => {\n // TODO: Loading groups photos doesn't work right now as Microsoft Graph\n // doesn't allows this yet: https://microsoftgraph.uservoice.com/forums/920506-microsoft-graph-feature-requests/suggestions/37884922-allow-application-to-set-or-update-a-group-s-photo\n /* const groupPhoto = await client.getGroupPhotoWithSizeLimit(\n group.id!,\n // We are limiting the photo size, as groups with full resolution photos\n // can make the Backstage API slow\n 120,\n );*/\n\n const entity = await transformer(group /* , groupPhoto*/);\n\n if (!entity) {\n return;\n }\n\n for await (const member of client.getGroupMembers(group.id!, {\n top: PAGE_SIZE,\n })) {\n if (!member.id) {\n continue;\n }\n\n if (member['@odata.type'] === '#microsoft.graph.user') {\n ensureItem(groupMemberOf, member.id, group.id!);\n }\n\n if (member['@odata.type'] === '#microsoft.graph.group') {\n ensureItem(groupMember, group.id!, member.id);\n }\n }\n\n groups.push(entity);\n }),\n );\n }\n\n // Wait for all group members and photos to be loaded\n await Promise.all(promises);\n\n return {\n groups,\n rootGroup,\n groupMember,\n groupMemberOf,\n };\n}\n\nexport function resolveRelations(\n rootGroup: GroupEntity | undefined,\n groups: GroupEntity[],\n users: UserEntity[],\n groupMember: Map>,\n groupMemberOf: Map>,\n) {\n // Build reference lookup tables, we reference them by the id the the graph\n const groupMap: Map = new Map(); // by group-id or tenant-id\n\n for (const group of groups) {\n if (group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION]) {\n groupMap.set(\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION],\n group,\n );\n }\n if (group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION]) {\n groupMap.set(\n group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION],\n group,\n );\n }\n }\n\n // Resolve all member relationships into the reverse direction\n const parentGroups = new Map>();\n\n groupMember.forEach((members, groupId) =>\n members.forEach(m => ensureItem(parentGroups, m, groupId)),\n );\n\n // Make sure every group (except root) has at least one parent. If the parent is missing, add the root.\n if (rootGroup) {\n const tenantId =\n rootGroup.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];\n\n groups.forEach(group => {\n const groupId =\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION];\n\n if (!groupId) {\n return;\n }\n\n if (retrieveItems(parentGroups, groupId).size === 0) {\n ensureItem(parentGroups, groupId, tenantId);\n ensureItem(groupMember, tenantId, groupId);\n }\n });\n }\n\n groups.forEach(group => {\n const id =\n group.metadata.annotations![MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ??\n group.metadata.annotations![MICROSOFT_GRAPH_TENANT_ID_ANNOTATION];\n\n retrieveItems(groupMember, id).forEach(m => {\n const childGroup = groupMap.get(m);\n if (childGroup) {\n group.spec.children.push(stringifyEntityRef(childGroup));\n }\n });\n\n retrieveItems(parentGroups, id).forEach(p => {\n const parentGroup = groupMap.get(p);\n if (parentGroup) {\n // TODO: Only having a single parent group might not match every companies model, but fine for now.\n group.spec.parent = stringifyEntityRef(parentGroup);\n }\n });\n });\n\n // Make sure that all groups have proper parents and children\n buildOrgHierarchy(groups);\n\n // Set relations for all users\n users.forEach(user => {\n const id = user.metadata.annotations![MICROSOFT_GRAPH_USER_ID_ANNOTATION];\n\n retrieveItems(groupMemberOf, id).forEach(p => {\n const parentGroup = groupMap.get(p);\n if (parentGroup) {\n if (!user.spec.memberOf) {\n user.spec.memberOf = [];\n }\n user.spec.memberOf.push(stringifyEntityRef(parentGroup));\n }\n });\n });\n\n // Make sure all transitive memberships are available\n buildMemberOf(groups, users);\n}\n\n/**\n * Reads an entire org as Group and User entities.\n *\n * @public\n */\nexport async function readMicrosoftGraphOrg(\n client: MicrosoftGraphClient,\n tenantId: string,\n options: {\n userExpand?: string;\n userFilter?: string;\n userSelect?: string[];\n loadUserPhotos?: boolean;\n userGroupMemberSearch?: string;\n userGroupMemberFilter?: string;\n groupExpand?: string;\n groupSearch?: string;\n groupFilter?: string;\n groupSelect?: string[];\n queryMode?: 'basic' | 'advanced';\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n logger: LoggerService;\n },\n): Promise<{ users: UserEntity[]; groups: GroupEntity[] }> {\n let users: UserEntity[] = [];\n\n if (options.userGroupMemberFilter || options.userGroupMemberSearch) {\n const { users: usersInGroups } = await readMicrosoftGraphUsersInGroups(\n client,\n {\n queryMode: options.queryMode,\n userExpand: options.userExpand,\n userFilter: options.userFilter,\n userSelect: options.userSelect,\n userGroupMemberFilter: options.userGroupMemberFilter,\n userGroupMemberSearch: options.userGroupMemberSearch,\n loadUserPhotos: options.loadUserPhotos,\n transformer: options.userTransformer,\n logger: options.logger,\n },\n );\n users = usersInGroups;\n } else {\n const { users: usersWithFilter } = await readMicrosoftGraphUsers(client, {\n queryMode: options.queryMode,\n userExpand: options.userExpand,\n userFilter: options.userFilter,\n userSelect: options.userSelect,\n loadUserPhotos: options.loadUserPhotos,\n transformer: options.userTransformer,\n logger: options.logger,\n });\n users = usersWithFilter;\n }\n const { groups, rootGroup, groupMember, groupMemberOf } =\n await readMicrosoftGraphGroups(client, tenantId, {\n queryMode: options.queryMode,\n groupExpand: options.groupExpand,\n groupFilter: options.groupFilter,\n groupSearch: options.groupSearch,\n groupSelect: options.groupSelect,\n groupTransformer: options.groupTransformer,\n organizationTransformer: options.organizationTransformer,\n });\n\n resolveRelations(rootGroup, groups, users, groupMember, groupMemberOf);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\nasync function transformUsers(\n client: MicrosoftGraphClient,\n users: Iterable | AsyncIterable,\n logger: LoggerService,\n loadUserPhotos = true,\n transformer?: UserTransformer,\n) {\n const limiter = limiterFactory(10);\n\n const resolvedTransformer = transformer ?? defaultUserTransformer;\n const promises: Promise[] = [];\n const entities: UserEntity[] = [];\n\n // Process all users in parallel, otherwise it can take quite some time\n for await (const user of users) {\n promises.push(\n limiter(async () => {\n let userPhoto;\n try {\n if (loadUserPhotos) {\n userPhoto = await client.getUserPhotoWithSizeLimit(\n user.id!,\n // We are limiting the photo size, as users with full resolution photos\n // can make the Backstage API slow\n 120,\n );\n }\n } catch (e) {\n logger.warn(`Unable to load user photo for`, {\n user: user.id,\n error: e,\n });\n }\n\n const entity = await resolvedTransformer(user, userPhoto);\n\n if (entity) {\n entities.push(entity);\n }\n }),\n );\n }\n\n // Wait for all users and photos to be downloaded\n await Promise.all(promises);\n\n logger.debug('Finished transforming users', {\n microsoftUserCount: promises.length,\n backstageUserCount: entities.length,\n });\n return entities;\n}\n\nfunction ensureItem(\n target: Map>,\n key: string,\n value: string,\n) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n set!.add(value);\n}\n\nfunction retrieveItems(\n target: Map>,\n key: string,\n): Set {\n return target.get(key) ?? new Set();\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks';\nimport {\n ANNOTATION_LOCATION,\n ANNOTATION_ORIGIN_LOCATION,\n Entity,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport * as uuid from 'uuid';\nimport {\n GroupTransformer,\n MICROSOFT_GRAPH_GROUP_ID_ANNOTATION,\n MICROSOFT_GRAPH_TENANT_ID_ANNOTATION,\n MICROSOFT_GRAPH_USER_ID_ANNOTATION,\n MicrosoftGraphClient,\n MicrosoftGraphProviderConfig,\n ProviderConfigTransformer,\n OrganizationTransformer,\n readMicrosoftGraphConfig,\n readMicrosoftGraphOrg,\n UserTransformer,\n} from '../microsoftGraph';\nimport { readProviderConfigs } from '../microsoftGraph/config';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Options for {@link MicrosoftGraphOrgEntityProvider}.\n *\n * @public\n */\nexport type MicrosoftGraphOrgEntityProviderOptions =\n | MicrosoftGraphOrgEntityProviderLegacyOptions\n | {\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-tasks#PluginTaskScheduler.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule?: 'manual' | TaskRunner;\n\n /**\n * Scheduler used to schedule refreshes based on\n * the schedule config.\n */\n scheduler?: PluginTaskScheduler;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n userTransformer?: UserTransformer | Record;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n groupTransformer?: GroupTransformer | Record;\n\n /**\n * The function that transforms an organization entry in msgraph to an entity.\n * Optionally, you can pass separate transformers per provider ID.\n */\n organizationTransformer?:\n | OrganizationTransformer\n | Record;\n\n /**\n * The function that transforms provider config dynamically.\n */\n providerConfigTransformer?:\n | ProviderConfigTransformer\n | Record;\n };\n\n/**\n * Legacy options for {@link MicrosoftGraphOrgEntityProvider}\n * based on `catalog.processors.microsoftGraphOrg`.\n *\n * @public\n * @deprecated This interface exists for backwards compatibility only and will be removed in the future.\n */\nexport interface MicrosoftGraphOrgEntityProviderLegacyOptions {\n /**\n * A unique, stable identifier for this provider.\n *\n * @example \"production\"\n */\n id: string;\n\n /**\n * The target that this provider should consume.\n *\n * Should exactly match the \"target\" field of one of the provider\n * configuration entries.\n */\n target: string;\n\n /**\n * The logger to use.\n */\n logger: LoggerService;\n\n /**\n * The refresh schedule to use.\n *\n * @remarks\n *\n * If you pass in 'manual', you are responsible for calling the `read` method\n * manually at some interval.\n *\n * But more commonly you will pass in the result of\n * {@link @backstage/backend-tasks#PluginTaskScheduler.createScheduledTaskRunner}\n * to enable automatic scheduling of tasks.\n */\n schedule: 'manual' | TaskRunner;\n\n /**\n * The function that transforms a user entry in msgraph to an entity.\n */\n userTransformer?: UserTransformer;\n\n /**\n * The function that transforms a group entry in msgraph to an entity.\n */\n groupTransformer?: GroupTransformer;\n\n /**\n * The function that transforms an organization entry in msgraph to an entity.\n */\n organizationTransformer?: OrganizationTransformer;\n\n /**\n * The function that transforms provider config dynamically.\n */\n providerConfigTransformer?: ProviderConfigTransformer;\n}\n\n/**\n * Reads user and group entries out of Microsoft Graph, and provides them as\n * User and Group entities for the catalog.\n *\n * @public\n */\nexport class MicrosoftGraphOrgEntityProvider implements EntityProvider {\n private connection?: EntityProviderConnection;\n private scheduleFn?: () => Promise;\n\n static fromConfig(\n configRoot: Config,\n options: MicrosoftGraphOrgEntityProviderOptions,\n ): MicrosoftGraphOrgEntityProvider[] {\n if ('id' in options) {\n return [\n MicrosoftGraphOrgEntityProvider.fromLegacyConfig(configRoot, options),\n ];\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n function getTransformer(\n id: string,\n transformers?: T | Record,\n ): T | undefined {\n if (['undefined', 'function'].includes(typeof transformers)) {\n return transformers as T;\n }\n\n return (transformers as Record)[id];\n }\n\n return readProviderConfigs(configRoot).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for MicrosoftGraphOrgEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n const provider = new MicrosoftGraphOrgEntityProvider({\n id: providerConfig.id,\n provider: providerConfig,\n logger: options.logger,\n userTransformer: getTransformer(\n providerConfig.id,\n options.userTransformer,\n ),\n groupTransformer: getTransformer(\n providerConfig.id,\n options.groupTransformer,\n ),\n organizationTransformer: getTransformer(\n providerConfig.id,\n options.organizationTransformer,\n ),\n providerConfigTransformer: getTransformer(\n providerConfig.id,\n options.providerConfigTransformer,\n ),\n });\n\n if (taskRunner !== 'manual') {\n provider.schedule(taskRunner);\n }\n\n return provider;\n });\n }\n\n /**\n * @deprecated Exists for backwards compatibility only and will be removed in the future.\n */\n private static fromLegacyConfig(\n configRoot: Config,\n options: MicrosoftGraphOrgEntityProviderLegacyOptions,\n ): MicrosoftGraphOrgEntityProvider {\n options.logger.warn(\n 'Deprecated msgraph config \"catalog.processors.microsoftGraphOrg\" used. Use \"catalog.providers.microsoftGraphOrg\" instead. More info at https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/CHANGELOG.md#040-next1',\n );\n const config = configRoot.getOptionalConfig(\n 'catalog.processors.microsoftGraphOrg',\n );\n const providers = config ? readMicrosoftGraphConfig(config) : [];\n const provider = providers.find(p => options.target.startsWith(p.target));\n\n if (!provider) {\n throw new Error(\n `There is no Microsoft Graph Org provider that matches \"${options.target}\". Please add a configuration entry for it under \"catalog.processors.microsoftGraphOrg.providers\".`,\n );\n }\n\n const logger = options.logger.child({\n target: options.target,\n });\n\n const result = new MicrosoftGraphOrgEntityProvider({\n id: options.id,\n userTransformer: options.userTransformer,\n groupTransformer: options.groupTransformer,\n organizationTransformer: options.organizationTransformer,\n providerConfigTransformer: options.providerConfigTransformer,\n logger,\n provider,\n });\n\n if (options.schedule !== 'manual') {\n result.schedule(options.schedule);\n }\n\n return result;\n }\n\n constructor(\n private options: {\n id: string;\n provider: MicrosoftGraphProviderConfig;\n logger: LoggerService;\n userTransformer?: UserTransformer;\n groupTransformer?: GroupTransformer;\n organizationTransformer?: OrganizationTransformer;\n providerConfigTransformer?: ProviderConfigTransformer;\n },\n ) {}\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName() {\n return `MicrosoftGraphOrgEntityProvider:${this.options.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection) {\n this.connection = connection;\n await this.scheduleFn?.();\n }\n\n /**\n * Runs one complete ingestion loop. Call this method regularly at some\n * appropriate cadence.\n */\n async read(options?: { logger?: LoggerService }) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n const logger = options?.logger ?? this.options.logger;\n const provider = this.options.providerConfigTransformer\n ? await this.options.providerConfigTransformer(this.options.provider)\n : this.options.provider;\n const { markReadComplete } = trackProgress(logger);\n const client = MicrosoftGraphClient.create(this.options.provider);\n const { users, groups } = await readMicrosoftGraphOrg(\n client,\n provider.tenantId,\n {\n userExpand: provider.userExpand,\n userFilter: provider.userFilter,\n userSelect: provider.userSelect,\n loadUserPhotos: provider.loadUserPhotos,\n userGroupMemberFilter: provider.userGroupMemberFilter,\n userGroupMemberSearch: provider.userGroupMemberSearch,\n groupExpand: provider.groupExpand,\n groupFilter: provider.groupFilter,\n groupSearch: provider.groupSearch,\n groupSelect: provider.groupSelect,\n queryMode: provider.queryMode,\n groupTransformer: this.options.groupTransformer,\n userTransformer: this.options.userTransformer,\n organizationTransformer: this.options.organizationTransformer,\n logger: logger,\n },\n );\n\n const { markCommitComplete } = markReadComplete({ users, groups });\n\n await this.connection.applyMutation({\n type: 'full',\n entities: [...users, ...groups].map(entity => ({\n locationKey: `msgraph-org-provider:${this.options.id}`,\n entity: withLocations(this.options.id, entity),\n })),\n });\n\n markCommitComplete();\n }\n\n private schedule(taskRunner: TaskRunner) {\n this.scheduleFn = async () => {\n const id = `${this.getProviderName()}:refresh`;\n await taskRunner.run({\n id,\n fn: async () => {\n const logger = this.options.logger.child({\n class: MicrosoftGraphOrgEntityProvider.prototype.constructor.name,\n taskId: id,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.read({ logger });\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n}\n\n// Helps wrap the timing and logging behaviors\nfunction trackProgress(logger: LoggerService) {\n let timestamp = Date.now();\n let summary: string;\n\n logger.info('Reading msgraph users and groups');\n\n function markReadComplete(read: { users: unknown[]; groups: unknown[] }) {\n summary = `${read.users.length} msgraph users and ${read.groups.length} msgraph groups`;\n const readDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n timestamp = Date.now();\n logger.info(`Read ${summary} in ${readDuration} seconds. Committing...`);\n return { markCommitComplete };\n }\n\n function markCommitComplete() {\n const commitDuration = ((Date.now() - timestamp) / 1000).toFixed(1);\n logger.info(`Committed ${summary} in ${commitDuration} seconds.`);\n }\n\n return { markReadComplete };\n}\n\n// Makes sure that emitted entities have a proper location based on their uuid\nexport function withLocations(providerId: string, entity: Entity): Entity {\n const uid =\n entity.metadata.annotations?.[MICROSOFT_GRAPH_USER_ID_ANNOTATION] ||\n entity.metadata.annotations?.[MICROSOFT_GRAPH_GROUP_ID_ANNOTATION] ||\n entity.metadata.annotations?.[MICROSOFT_GRAPH_TENANT_ID_ANNOTATION] ||\n entity.metadata.name;\n const location = `msgraph:${providerId}/${encodeURIComponent(uid)}`;\n return merge(\n {\n metadata: {\n annotations: {\n [ANNOTATION_LOCATION]: location,\n [ANNOTATION_ORIGIN_LOCATION]: location,\n },\n },\n },\n entity,\n ) as Entity;\n}\n"],"names":["ClientSecretCredential","DefaultAzureCredential","qs","fetch","trimEnd","readTaskScheduleDefinitionFromConfig","limiterFactory","stringifyEntityRef","uuid","merge","ANNOTATION_LOCATION","ANNOTATION_ORIGIN_LOCATION"],"mappings":"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"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/index.cjs.js b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/index.cjs.js -index 8942c5b..9226f0c 100644 ---- a/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/index.cjs.js -+++ b/node_modules/@backstage/plugin-catalog-backend-module-msgraph/dist/index.cjs.js -@@ -1,6 +1,6 @@ - 'use strict'; - --var MicrosoftGraphOrgEntityProvider = require('./cjs/MicrosoftGraphOrgEntityProvider-mdJJRFUn.cjs.js'); -+var MicrosoftGraphOrgEntityProvider = require('./cjs/MicrosoftGraphOrgEntityProvider-BkGFhBQB.cjs.js'); - var pluginCatalogNode = require('@backstage/plugin-catalog-node'); - require('@backstage/catalog-model'); - require('lodash'); diff --git a/patches/@backstage+plugin-scaffolder-backend+1.23.0.patch b/patches/@backstage+plugin-scaffolder-backend+1.23.0.patch deleted file mode 100644 index d4f6566f7d..0000000000 --- a/patches/@backstage+plugin-scaffolder-backend+1.23.0.patch +++ /dev/null @@ -1,1845 +0,0 @@ -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/README.md b/node_modules/@backstage/plugin-scaffolder-backend/README.md -index d760b0f..2f87dec 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/README.md -+++ b/node_modules/@backstage/plugin-scaffolder-backend/README.md -@@ -63,3 +63,101 @@ you will not have any templates available to use. These need to be [added to the - - To get up and running and try out some templates quickly, you can or copy the - catalog locations from the [create-app template](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs). -+ -+### Audit Logging -+ -+This package supports audit logging for the endpoints and scaffolder task executions. Audit logs will provide the following information: -+ -+- `eventName`: The event associated with the audit log, see the [audited events](#audit-log-events) for the list of events that are audited -+- `actor`: An object containing information about the actor who triggered the event being audited. Contains the following fields: -+ - `actorId`: The name/id/`entityRef` of the associated backstage user or service. Can be `null` if default auth policy is disabled, and endpoints are accessed with an unauthenticated user. -+ - `ip`: The IP address of the actor (optional) -+ - `hostname`: The hostname of the actor (optional) -+ - `client`: The user agent of the actor (optional) -+- `stage`: The stage the event was at when the audit log was generated. In the case of the scaffolder-backend, it is either `initiation` or `completion` -+- `status`: Whether the event `succeeded` or `failed` -+- `meta`: An optional object containing event specific data. Ex: `taskId` for a task might be a field in this metadata object -+- `request`: An optional field that contains information about the HTTP request sent to an endpoint. Contains the following fields: -+ - `method`: The HTTP method of the request -+ - `query`: The `query` fields of the request -+ - `params`: The `params` fields of the request -+ - `body`: The request `body`. Note: the `secrets` provided when creating a task are redacted and will appear as `***` -+ - `url`: The endpoint url of the request. -+- `response`: An optional field that contains information about the HTTP response sent from an endpoint. Contains the following fields: -+ - `status`: The status code of the HTTP response -+ - `body`: The contents of the request body -+- `isAuditLog`: A flag set to `true` to differentiate audit logs from normal logs. Always `true` for audit logs. -+- `errors`: A list of errors containing the `name`, `message` and potentially the `stack` field of the error. Only appears when `status` is `failed`. -+ -+#### Audit Log Events -+ -+The following are the events that are audit logged: -+ -+- `ScaffolderParameterSchemaFetch`: Tracks `GET` requests to the `/v2/templates/:namespace/:kind/:name/parameter-schema` endpoint which return template parameter schemas -+- `ScaffolderInstalledActionsFetch`: Tracks `GET` requests to the `/v2/actions` endpoint which grabs the list of installed actions -+- `ScaffolderTaskCreation`: Tracks `POST` requests to the `/v2/tasks` endpoint which creates tasks that the scaffolder executes -+- `ScaffolderTaskListFetch`: Tracks `GET` requests to the `/v2/tasks` endpoint which fetches details of all tasks in the scaffolder. -+- `ScaffolderTaskFetch`: Tracks `GET` requests to the `/v2/tasks/:taskId` endpoint which fetches details of a specified task `:taskId` -+- `ScaffolderTaskCancellation`: Tracks `POST` requests to the `/v2/tasks/:taskId/cancel` endpoint which cancels a running task -+- `ScaffolderTaskStream`: Tracks `GET` requests to the `/v2/tasks/:taskId/eventstream` endpoint which returns an event stream of the task logs of task `:taskId` -+- `ScaffolderTaskEventFetch`: Tracks `GET` requests to the `/v2/tasks/:taskId/events` endpoint which returns a snapshot of the task logs of task `:taskId` -+- `ScaffolderTaskDryRun`: Tracks `POST` requests to the `/v2/dry-run` endpoint which creates a dry-run task. All audit logs for events associated with dry runs have the `meta.isDryLog` flag set to `true`. -+- `ScaffolderStaleTaskCancellation`: Tracks automated cancellation of stale tasks -+- `ScaffolderTaskExecution`: Tracks the `initiation` and `completion` of a real scaffolder task execution (will not occur during dry runs) -+- `ScaffolderTaskStepExecution`: Tracks `initiation` and `completion` of a scaffolder task step execution -+- `ScaffolderTaskStepSkip`: Tracks steps skipped due to `if` conditionals not being met -+- `ScaffolderTaskStepIteration`: Tracks the step execution of each iteration of a task step that contains the `each` field. -+ -+#### Example Audit Log Output -+ -+The following is an example audit log when a user creates a task with the `POST /v2/tasks` endpoint: -+ -+Example cURL Request being used: -+ -+```bash -+curl -X POST localhost:7007/api/scaffolder/v2/tasks \ -+ -H "Authorization: Bearer ${BACKSTAGE_TOKEN}" \ -+ -H "Content-Type: application/json" \ --data '{"templateRef":"template:default/test-template", "values": {"username": "user", "password": "******"}, "secrets": { "password": "secret" }}' -+``` -+ -+Example of a prettified version of the Audit Log of the scaffolder task being successfully created: -+ -+```json -+{ -+ "actor": { -+ "actorId": "user:development/guest", -+ "hostname": "localhost", -+ "ip": "::1", -+ "userAgent": "curl/8.2.1" -+ }, -+ "eventName": "ScaffolderTaskCreation", -+ "isAuditLog": true, -+ "level": "info", -+ "message": "Scaffolding task for template:default/test-template with taskId: b06058bf-4d56-4309-b7ab-3d6ed7fe49a9 successfully created by user:development/guest", -+ "meta": { -+ "taskId": "b06058bf-4d56-4309-b7ab-3d6ed7fe49a9", -+ "templateRef": "template:default/test-template" -+ }, -+ "plugin": "scaffolder", -+ "request": { -+ "body": { -+ "secrets": { "password": "***" }, -+ "templateRef": "template:default/test-template", -+ "values": { "password": "******", "username": "user" } -+ }, -+ "method": "POST", -+ "params": {}, -+ "query": {}, -+ "url": "/api/scaffolder/v2/tasks" -+ }, -+ "response": { -+ "body": { "id": "b06058bf-4d56-4309-b7ab-3d6ed7fe49a9" }, -+ "status": 201 -+ }, -+ "service": "backstage", -+ "stage": "completion", -+ "status": "succeeded", -+ "timestamp": "2024-05-22 15:15:55", -+ "type": "plugin" -+} -+``` -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js b/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js -index 3117c72..d544866 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js -@@ -48,6 +48,7 @@ require('winston-transport'); - require('triple-beam'); - require('url'); - require('os'); -+require('@janus-idp/backstage-plugin-audit-log-node'); - - const templateConditionExports = pluginPermissionNode.createConditionExports({ - pluginId: "scaffolder", -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js.map b/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js.map -index cfa4dd5..51d99c4 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js.map -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"alpha.cjs.js","sources":["../src/service/conditionExports.ts","../src/ScaffolderPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport { createConditionExports } from '@backstage/plugin-permission-node';\nimport { scaffolderTemplateRules, scaffolderActionRules } from './rules';\n\nconst templateConditionExports = createConditionExports({\n pluginId: 'scaffolder',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n rules: scaffolderTemplateRules,\n});\n\nconst actionsConditionExports = createConditionExports({\n pluginId: 'scaffolder',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n rules: scaffolderActionRules,\n});\n\n/**\n * `createScaffolderTemplateConditionalDecision` can be used when authoring policies to\n * create conditional decisions. It requires a permission of type\n * `ResourcePermission<'scaffolder-template'>` to be passed as the first parameter.\n * It's recommended that you use the provided `isResourcePermission` and\n * `isPermission` helper methods to narrow the type of the permission passed to\n * the handle method as shown below.\n *\n * ```\n * // MyAuthorizationPolicy.ts\n * ...\n * import { createScaffolderPolicyDecision } from '@backstage/plugin-scaffolder-backend';\n * import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common';\n *\n * class MyAuthorizationPolicy implements PermissionPolicy {\n * async handle(request, user) {\n * ...\n *\n * if (isResourcePermission(request.permission, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE)) {\n * return createScaffolderConditionalDecision(\n * request.permission,\n * { anyOf: [...insert conditions here...] }\n * );\n * }\n *\n * ...\n * }\n *\n * ```\n *\n * @alpha\n */\nexport const createScaffolderTemplateConditionalDecision =\n templateConditionExports.createConditionalDecision;\n\n/**\n * These conditions are used when creating conditional decisions for scaffolder\n * templates that are returned by authorization policies.\n *\n * @alpha\n */\nexport const scaffolderTemplateConditions = templateConditionExports.conditions;\n\n/**\n * @alpha\n */\nexport const createScaffolderActionConditionalDecision =\n actionsConditionExports.createConditionalDecision;\n\n/**\n *\n * These conditions are used when creating conditional decisions for scaffolder\n * actions that are returned by authorization policies.\n *\n * @alpha\n */\nexport const scaffolderActionConditions = actionsConditionExports.conditions;\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createBackendPlugin,\n coreServices,\n} from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport {\n TaskBroker,\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n AutocompleteHandler,\n scaffolderActionsExtensionPoint,\n scaffolderAutocompleteExtensionPoint,\n scaffolderTaskBrokerExtensionPoint,\n scaffolderTemplatingExtensionPoint,\n scaffolderWorkspaceProviderExtensionPoint,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport {\n createCatalogRegisterAction,\n createCatalogWriteAction,\n createDebugLogAction,\n createFetchCatalogEntityAction,\n createFetchPlainAction,\n createFetchPlainFileAction,\n createFetchTemplateAction,\n createFilesystemDeleteAction,\n createFilesystemRenameAction,\n createWaitAction,\n} from './scaffolder';\nimport { createRouter } from './service/router';\n\n/**\n * Scaffolder plugin\n *\n * @alpha\n */\nexport const scaffolderPlugin = createBackendPlugin({\n pluginId: 'scaffolder',\n register(env) {\n const addedActions = new Array>();\n env.registerExtensionPoint(scaffolderActionsExtensionPoint, {\n addActions(...newActions: TemplateAction[]) {\n addedActions.push(...newActions);\n },\n });\n\n let taskBroker: TaskBroker | undefined;\n env.registerExtensionPoint(scaffolderTaskBrokerExtensionPoint, {\n setTaskBroker(newTaskBroker) {\n if (taskBroker) {\n throw new Error('Task broker may only be set once');\n }\n taskBroker = newTaskBroker;\n },\n });\n\n const additionalTemplateFilters: Record = {};\n const additionalTemplateGlobals: Record = {};\n env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, {\n addTemplateFilters(newFilters) {\n Object.assign(additionalTemplateFilters, newFilters);\n },\n addTemplateGlobals(newGlobals) {\n Object.assign(additionalTemplateGlobals, newGlobals);\n },\n });\n\n const autocompleteHandlers: Record = {};\n env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, {\n addAutocompleteProvider(provider) {\n autocompleteHandlers[provider.id] = provider.handler;\n },\n });\n\n const additionalWorkspaceProviders: Record = {};\n env.registerExtensionPoint(scaffolderWorkspaceProviderExtensionPoint, {\n addProviders(provider) {\n Object.assign(additionalWorkspaceProviders, provider);\n },\n });\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n lifecycle: coreServices.rootLifecycle,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n auth: coreServices.auth,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n catalogClient: catalogServiceRef,\n },\n async init({\n logger,\n config,\n lifecycle,\n reader,\n database,\n auth,\n discovery,\n httpRouter,\n httpAuth,\n catalogClient,\n permissions,\n }) {\n const log = loggerToWinstonLogger(logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n const actions = [\n // actions provided from other modules\n ...addedActions,\n\n // built-in actions for the scaffolder\n createFetchPlainAction({\n reader,\n integrations,\n }),\n createFetchPlainFileAction({\n reader,\n integrations,\n }),\n createFetchTemplateAction({\n integrations,\n reader,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n }),\n createDebugLogAction(),\n createWaitAction(),\n // todo(blam): maybe these should be a -catalog module?\n createCatalogRegisterAction({ catalogClient, integrations, auth }),\n createFetchCatalogEntityAction({ catalogClient, auth }),\n createCatalogWriteAction(),\n createFilesystemDeleteAction(),\n createFilesystemRenameAction(),\n ];\n\n const actionIds = actions.map(action => action.id).join(', ');\n\n log.info(\n `Starting scaffolder with the following actions enabled ${actionIds}`,\n );\n\n const router = await createRouter({\n logger: log,\n config,\n database,\n catalogClient,\n reader,\n lifecycle,\n actions,\n taskBroker,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n httpAuth,\n discovery,\n permissions,\n autocompleteHandlers,\n additionalWorkspaceProviders,\n });\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createConditionExports","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","scaffolderTemplateRules","RESOURCE_TYPE_SCAFFOLDER_ACTION","scaffolderActionRules","createBackendPlugin","scaffolderActionsExtensionPoint","scaffolderTaskBrokerExtensionPoint","scaffolderTemplatingExtensionPoint","scaffolderAutocompleteExtensionPoint","scaffolderWorkspaceProviderExtensionPoint","coreServices","catalogServiceRef","loggerToWinstonLogger","ScmIntegrations","createFetchPlainAction","createFetchPlainFileAction","createFetchTemplateAction","createDebugLogAction","createWaitAction","createCatalogRegisterAction","createFetchCatalogEntityAction","createCatalogWriteAction","createFilesystemDeleteAction","createFilesystemRenameAction","router","createRouter"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"alpha.cjs.js","sources":["../src/service/conditionExports.ts","../src/ScaffolderPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport { createConditionExports } from '@backstage/plugin-permission-node';\nimport { scaffolderTemplateRules, scaffolderActionRules } from './rules';\n\nconst templateConditionExports = createConditionExports({\n pluginId: 'scaffolder',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n rules: scaffolderTemplateRules,\n});\n\nconst actionsConditionExports = createConditionExports({\n pluginId: 'scaffolder',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n rules: scaffolderActionRules,\n});\n\n/**\n * `createScaffolderTemplateConditionalDecision` can be used when authoring policies to\n * create conditional decisions. It requires a permission of type\n * `ResourcePermission<'scaffolder-template'>` to be passed as the first parameter.\n * It's recommended that you use the provided `isResourcePermission` and\n * `isPermission` helper methods to narrow the type of the permission passed to\n * the handle method as shown below.\n *\n * ```\n * // MyAuthorizationPolicy.ts\n * ...\n * import { createScaffolderPolicyDecision } from '@backstage/plugin-scaffolder-backend';\n * import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common';\n *\n * class MyAuthorizationPolicy implements PermissionPolicy {\n * async handle(request, user) {\n * ...\n *\n * if (isResourcePermission(request.permission, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE)) {\n * return createScaffolderConditionalDecision(\n * request.permission,\n * { anyOf: [...insert conditions here...] }\n * );\n * }\n *\n * ...\n * }\n *\n * ```\n *\n * @alpha\n */\nexport const createScaffolderTemplateConditionalDecision =\n templateConditionExports.createConditionalDecision;\n\n/**\n * These conditions are used when creating conditional decisions for scaffolder\n * templates that are returned by authorization policies.\n *\n * @alpha\n */\nexport const scaffolderTemplateConditions = templateConditionExports.conditions;\n\n/**\n * @alpha\n */\nexport const createScaffolderActionConditionalDecision =\n actionsConditionExports.createConditionalDecision;\n\n/**\n *\n * These conditions are used when creating conditional decisions for scaffolder\n * actions that are returned by authorization policies.\n *\n * @alpha\n */\nexport const scaffolderActionConditions = actionsConditionExports.conditions;\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createBackendPlugin,\n coreServices,\n} from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport {\n TaskBroker,\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n AutocompleteHandler,\n scaffolderActionsExtensionPoint,\n scaffolderAutocompleteExtensionPoint,\n scaffolderTaskBrokerExtensionPoint,\n scaffolderTemplatingExtensionPoint,\n scaffolderWorkspaceProviderExtensionPoint,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport {\n createCatalogRegisterAction,\n createCatalogWriteAction,\n createDebugLogAction,\n createFetchCatalogEntityAction,\n createFetchPlainAction,\n createFetchPlainFileAction,\n createFetchTemplateAction,\n createFilesystemDeleteAction,\n createFilesystemRenameAction,\n createWaitAction,\n} from './scaffolder';\nimport { createRouter } from './service/router';\n\n/**\n * Scaffolder plugin\n *\n * @alpha\n */\nexport const scaffolderPlugin = createBackendPlugin({\n pluginId: 'scaffolder',\n register(env) {\n const addedActions = new Array>();\n env.registerExtensionPoint(scaffolderActionsExtensionPoint, {\n addActions(...newActions: TemplateAction[]) {\n addedActions.push(...newActions);\n },\n });\n\n let taskBroker: TaskBroker | undefined;\n env.registerExtensionPoint(scaffolderTaskBrokerExtensionPoint, {\n setTaskBroker(newTaskBroker) {\n if (taskBroker) {\n throw new Error('Task broker may only be set once');\n }\n taskBroker = newTaskBroker;\n },\n });\n\n const additionalTemplateFilters: Record = {};\n const additionalTemplateGlobals: Record = {};\n env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, {\n addTemplateFilters(newFilters) {\n Object.assign(additionalTemplateFilters, newFilters);\n },\n addTemplateGlobals(newGlobals) {\n Object.assign(additionalTemplateGlobals, newGlobals);\n },\n });\n\n const autocompleteHandlers: Record = {};\n env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, {\n addAutocompleteProvider(provider) {\n autocompleteHandlers[provider.id] = provider.handler;\n },\n });\n\n const additionalWorkspaceProviders: Record = {};\n env.registerExtensionPoint(scaffolderWorkspaceProviderExtensionPoint, {\n addProviders(provider) {\n Object.assign(additionalWorkspaceProviders, provider);\n },\n });\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n lifecycle: coreServices.rootLifecycle,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n auth: coreServices.auth,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n catalogClient: catalogServiceRef,\n },\n async init({\n logger,\n config,\n lifecycle,\n reader,\n database,\n auth,\n discovery,\n httpRouter,\n httpAuth,\n catalogClient,\n permissions,\n }) {\n const log = loggerToWinstonLogger(logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n const actions = [\n // actions provided from other modules\n ...addedActions,\n\n // built-in actions for the scaffolder\n createFetchPlainAction({\n reader,\n integrations,\n }),\n createFetchPlainFileAction({\n reader,\n integrations,\n }),\n createFetchTemplateAction({\n integrations,\n reader,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n }),\n createDebugLogAction(),\n createWaitAction(),\n // todo(blam): maybe these should be a -catalog module?\n createCatalogRegisterAction({ catalogClient, integrations, auth }),\n createFetchCatalogEntityAction({ catalogClient, auth }),\n createCatalogWriteAction(),\n createFilesystemDeleteAction(),\n createFilesystemRenameAction(),\n ];\n\n const actionIds = actions.map(action => action.id).join(', ');\n\n log.info(\n `Starting scaffolder with the following actions enabled ${actionIds}`,\n );\n\n const router = await createRouter({\n logger: log,\n config,\n database,\n catalogClient,\n reader,\n lifecycle,\n actions,\n taskBroker,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n httpAuth,\n discovery,\n permissions,\n autocompleteHandlers,\n additionalWorkspaceProviders,\n });\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createConditionExports","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","scaffolderTemplateRules","RESOURCE_TYPE_SCAFFOLDER_ACTION","scaffolderActionRules","createBackendPlugin","scaffolderActionsExtensionPoint","scaffolderTaskBrokerExtensionPoint","scaffolderTemplatingExtensionPoint","scaffolderAutocompleteExtensionPoint","scaffolderWorkspaceProviderExtensionPoint","coreServices","catalogServiceRef","loggerToWinstonLogger","ScmIntegrations","createFetchPlainAction","createFetchPlainFileAction","createFetchTemplateAction","createDebugLogAction","createWaitAction","createCatalogRegisterAction","createFetchCatalogEntityAction","createCatalogWriteAction","createFilesystemDeleteAction","createFilesystemRenameAction","router","createRouter"],"mappings":"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"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.d.ts b/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.d.ts -index 7507d13..915a60c 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.d.ts -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/alpha.d.ts -@@ -44,7 +44,7 @@ declare const createScaffolderTemplateConditionalDecision: (permission: _backsta - * @alpha - */ - declare const scaffolderTemplateConditions: _backstage_plugin_permission_node.Conditions<{ -- hasTag: _backstage_plugin_permission_node.PermissionRule<_backstage_plugin_scaffolder_common.TemplateParametersV1beta3 | _backstage_plugin_scaffolder_common.TemplateEntityStepV1beta3, {}, "scaffolder-template", { -+ hasTag: _backstage_plugin_permission_node.PermissionRule<_backstage_plugin_scaffolder_common.TemplateEntityStepV1beta3 | _backstage_plugin_scaffolder_common.TemplateParametersV1beta3, {}, "scaffolder-template", { - tag: string; - }>; - }>; -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js b/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js -index 9da0063..fdf1e04 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js -@@ -44,6 +44,7 @@ var Transport = require('winston-transport'); - var tripleBeam = require('triple-beam'); - var url = require('url'); - var os = require('os'); -+var backstagePluginAuditLogNode = require('@janus-idp/backstage-plugin-audit-log-node'); - - function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } - -@@ -1965,17 +1966,18 @@ class DefaultWorkspaceService { - - class TaskManager { - // Runs heartbeat internally -- constructor(task, storage, signal, logger, workspaceService, auth) { -+ constructor(task, storage, signal, logger, workspaceService, auditLogger, auth) { - this.task = task; - this.storage = storage; - this.signal = signal; - this.logger = logger; - this.workspaceService = workspaceService; -+ this.auditLogger = auditLogger; - this.auth = auth; - } - isDone = false; - heartbeatTimeoutId; -- static create(task, storage, abortSignal, logger, auth, config, additionalWorkspaceProviders) { -+ static create(task, storage, abortSignal, logger, auditLogger, auth, config, additionalWorkspaceProviders) { - const workspaceService = DefaultWorkspaceService.create( - task, - storage, -@@ -1988,11 +1990,15 @@ class TaskManager { - abortSignal, - logger, - workspaceService, -+ auditLogger, - auth - ); - agent.startTimeout(); - return agent; - } -+ get taskId() { -+ return this.task.taskId; -+ } - get spec() { - return this.task.spec; - } -@@ -2054,6 +2060,34 @@ class TaskManager { - if (this.heartbeatTimeoutId) { - clearTimeout(this.heartbeatTimeoutId); - } -+ const commonAuditFields = { -+ eventName: "ScaffolderTaskExecution", -+ actorId: "scaffolder-backend", -+ stage: "completion", -+ metadata: { -+ taskId: this.task.taskId, -+ taskParameters: this.task.spec.parameters -+ } -+ }; -+ if (result === "failed") { -+ await this.auditLogger?.auditLog({ -+ ...commonAuditFields, -+ status: "failed", -+ level: "error", -+ errors: [metadata?.error], -+ message: `Scaffolding task with taskId: ${this.task.taskId} failed` -+ }); -+ } else { -+ await this.auditLogger?.auditLog({ -+ ...commonAuditFields, -+ status: "succeeded", -+ metadata: { -+ ...commonAuditFields.metadata, -+ ...metadata -+ }, -+ message: `Scaffolding task with taskId: ${this.task.taskId} completed successfully` -+ }); -+ } - } - startTimeout() { - this.heartbeatTimeoutId = setTimeout(async () => { -@@ -2091,9 +2125,10 @@ function defer() { - return { promise, resolve }; - } - class StorageTaskBroker { -- constructor(storage, logger, config, auth, additionalWorkspaceProviders) { -+ constructor(storage, logger, auditLogger, config, auth, additionalWorkspaceProviders) { - this.storage = storage; - this.logger = logger; -+ this.auditLogger = auditLogger; - this.config = config; - this.auth = auth; - this.additionalWorkspaceProviders = additionalWorkspaceProviders; -@@ -2130,9 +2165,7 @@ class StorageTaskBroker { - }); - } - async recoverTasks() { -- const enabled = (this.config && this.config.getOptionalBoolean( -- "scaffolder.EXPERIMENTAL_recoverTasks" -- )) ?? false; -+ const enabled = this.config?.getOptionalBoolean("scaffolder.EXPERIMENTAL_recoverTasks") ?? false; - if (enabled) { - const defaultTimeout = { seconds: 30 }; - const timeout = readDuration$1( -@@ -2168,6 +2201,7 @@ class StorageTaskBroker { - this.storage, - abortController.signal, - this.logger, -+ this.auditLogger, - this.auth, - this.config, - this.additionalWorkspaceProviders -@@ -2224,6 +2258,16 @@ class StorageTaskBroker { - await Promise.all( - tasks.map(async (task) => { - try { -+ this.auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderStaleTaskCancellation", -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId: task.taskId -+ }, -+ message: `Attempting to cancel Stale scaffolding task ${task.taskId} because the task worker lost connection to the task broker` -+ }); - await this.storage.completeTask({ - taskId: task.taskId, - status: "failed", -@@ -2231,8 +2275,35 @@ class StorageTaskBroker { - message: "The task was cancelled because the task worker lost connection to the task broker" - } - }); -+ this.auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderStaleTaskCancellation", -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ taskId: task.taskId -+ }, -+ message: `Stale scaffolding task ${task.taskId} successfully cancelled` -+ }); - } catch (error) { -- this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`); -+ this.auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderStaleTaskCancellation", -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ taskId: task.taskId -+ }, -+ errors: [ -+ { -+ name: error.name, -+ message: error.message, -+ stack: error.stack -+ } -+ ], -+ message: `Failed to cancel stale scaffolding task ${task.taskId}` -+ }); - } - }) - ); -@@ -2533,9 +2604,10 @@ class NunjucksWorkflowRunner { - this.defaultTemplateFilters = createDefaultFilters({ - integrations: this.options.integrations - }); -+ this.tracker = scaffoldingTracker(this.options.auditLogger); - } - defaultTemplateFilters; -- tracker = scaffoldingTracker(); -+ tracker; - isSingleTemplateString(input) { - const { parser, nodes } = nunjucks__default.default; - const parsed = parser.parse( -@@ -2587,37 +2659,66 @@ class NunjucksWorkflowRunner { - async executeStep(task, step, context, renderTemplate, taskTrack, workspacePath, decision) { - const stepTrack = await this.tracker.stepStart(task, step); - if (task.cancelSignal.aborted) { -- throw new Error(`Step ${step.name} has been cancelled.`); -+ throw new Error( -+ `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.` -+ ); - } - try { -+ const action = this.options.actionRegistry.get(step.action); -+ const { taskLogger, streamLogger } = createStepLogger({ -+ task, -+ step, -+ rootLogger: this.options.logger -+ }); -+ const redactedSecrets = Object.fromEntries( -+ Object.entries(task.secrets ?? {}).map((secret) => [secret[0], "***"]) -+ ); -+ const stepInputs = (step.input && this.render( -+ step.input, -+ { -+ ...context, -+ secrets: redactedSecrets -+ }, -+ renderTemplate -+ )) ?? {}; -+ const commonStepAuditMetadata = { -+ templateRef: task.spec.templateInfo?.entityRef || "", -+ taskId: task.taskId, -+ stepId: step.id, -+ stepName: step.name, -+ stepAction: step.action, -+ stepInputs, -+ stepConditional: step.if, -+ stepEach: step.each, -+ isDryRun: task.isDryRun || false -+ }; - if (step.if) { - const ifResult = this.render(step.if, context, renderTemplate); - if (!isTruthy(ifResult)) { - await stepTrack.skipFalsy(); -+ await this.options.auditLogger.auditLog({ -+ eventName: "ScaffolderTaskStepSkip", -+ actorId: "scaffolder-backend", -+ stage: "completion", -+ status: "succeeded", -+ metadata: commonStepAuditMetadata, -+ message: `Skipped step ${step.name} (id: ${step.id}) of task ${task.taskId}` -+ }); - return; - } - } -- const action = this.options.actionRegistry.get(step.action); -- const { taskLogger, streamLogger } = createStepLogger({ -- task, -- step, -- rootLogger: this.options.logger -+ await this.options.auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderTaskStepExecution", -+ stage: "initiation", -+ status: "succeeded", -+ metadata: commonStepAuditMetadata, -+ message: `Started ${step.name} (id: ${step.id}) of task ${task.taskId} triggering the ${step.action} action` - }); - if (task.isDryRun) { -- const redactedSecrets = Object.fromEntries( -- Object.entries(task.secrets ?? {}).map((secret) => [secret[0], "***"]) -- ); -- const debugInput = (step.input && this.render( -- step.input, -- { -- ...context, -- secrets: redactedSecrets -- }, -- renderTemplate -- )) ?? {}; - taskLogger.info( - `Running ${action.id} in dry-run mode with inputs (secrets redacted): ${JSON.stringify( -- debugInput, -+ stepInputs, - void 0, - 2 - )}` -@@ -2678,6 +2779,7 @@ class NunjucksWorkflowRunner { - const tmpDirs = new Array(); - const stepOutput = {}; - const prevTaskState = await task.getTaskState?.(); -+ let iterationCount = 0; - for (const iteration of iterations) { - if (iteration.each) { - taskLogger.info( -@@ -2687,6 +2789,22 @@ class NunjucksWorkflowRunner { - 0 - )}` - ); -+ await this.options.auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderTaskStepIteration", -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ ...commonStepAuditMetadata, -+ stepInputs: void 0, -+ stepAction: `${step.action}[${iteration.each.key}]`, -+ stepIterationInputs: iteration.input, -+ stepIterationCount: ++iterationCount, -+ stepIterationValue: iteration.each.value, -+ totalIterations: iterations.length -+ }, -+ message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} started` -+ }); - } - await action.handler({ - input: iteration.input, -@@ -2746,18 +2864,38 @@ class NunjucksWorkflowRunner { - signal: task.cancelSignal, - getInitiatorCredentials: () => task.getInitiatorCredentials() - }); -+ if (iteration.each) { -+ await this.options.auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderTaskStepIteration", -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ ...commonStepAuditMetadata, -+ stepInputs: void 0, -+ stepAction: `${step.action}[${iteration.each.key}]`, -+ stepIterationCount: iterationCount, -+ stepIterationValue: iteration.each.value, -+ stepIterationInputs: iteration.input, -+ totalIterations: iterations.length -+ }, -+ message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded` -+ }); -+ } - } - for (const tmpDir of tmpDirs) { - await fs__default.default.remove(tmpDir); - } - context.steps[step.id] = { output: stepOutput }; - if (task.cancelSignal.aborted) { -- throw new Error(`Step ${step.name} has been cancelled.`); -+ throw new Error( -+ `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.` -+ ); - } - await stepTrack.markSuccessful(); - } catch (err) { - await taskTrack.markFailed(step, err); -- await stepTrack.markFailed(); -+ await stepTrack.markFailed(err); - throw err; - } finally { - await task.serializeWorkspace?.({ path: workspacePath }); -@@ -2814,7 +2952,7 @@ class NunjucksWorkflowRunner { - } - } - } --function scaffoldingTracker() { -+function scaffoldingTracker(auditLogger) { - const taskCount = createCounterMetric({ - name: "scaffolder_task_count", - help: "Count of task runs", -@@ -2908,6 +3046,21 @@ function scaffoldingTracker() { - result: "ok" - }); - stepTimer({ result: "ok" }); -+ await auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderTaskStepExecution", -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ templateRef: template, -+ taskId: task.taskId, -+ stepId: step.id, -+ stepName: step.name, -+ stepAction: step.action, -+ isDryRun: task.isDryRun || false -+ }, -+ message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded` -+ }); - } - async function markCancelled() { - stepCount.inc({ -@@ -2917,13 +3070,36 @@ function scaffoldingTracker() { - }); - stepTimer({ result: "cancelled" }); - } -- async function markFailed() { -+ async function markFailed(err) { - stepCount.inc({ - template, - step: step.name, - result: "failed" - }); - stepTimer({ result: "failed" }); -+ await auditLogger.auditLog({ -+ actorId: "scaffolder-backend", -+ eventName: "ScaffolderTaskStepExecution", -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ templateRef: template, -+ taskId: task.taskId, -+ stepId: step.id, -+ stepName: step.name, -+ stepAction: step.action, -+ isDryRun: task.isDryRun || false -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} failed` -+ }); - } - async function skipFalsy() { - await task.emitLog( -@@ -2950,6 +3126,7 @@ class TaskWorker { - this.options = options; - this.stopWorkers = false; - this.logger = options.logger; -+ this.auditLogger = options.auditLogger; - this.taskQueue = new PQueue__default.default({ - concurrency: options.concurrentTasksLimit - }); -@@ -2957,6 +3134,7 @@ class TaskWorker { - taskQueue; - logger; - stopWorkers; -+ auditLogger; - static async create(options) { - const { - taskBroker, -@@ -2968,12 +3146,14 @@ class TaskWorker { - concurrentTasksLimit = 10, - // from 1 to Infinity - additionalTemplateGlobals, -- permissions -+ permissions, -+ auditLogger - } = options; - const workflowRunner = new NunjucksWorkflowRunner({ - actionRegistry, - integrations, - logger, -+ auditLogger, - workingDirectory, - additionalTemplateFilters, - additionalTemplateGlobals, -@@ -2983,7 +3163,8 @@ class TaskWorker { - taskBroker, - runners: { workflowRunner }, - concurrentTasksLimit, -- permissions -+ permissions, -+ auditLogger - }); - } - async recoverTasks() { -@@ -3025,6 +3206,18 @@ class TaskWorker { - } - async runOneTask(task) { - try { -+ await this.auditLogger?.auditLog({ -+ eventName: "ScaffolderTaskExecution", -+ actorId: "scaffolder-backend", -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId: task.taskId, -+ taskParameters: task.spec.parameters, -+ templateRef: task.spec.templateInfo?.entityRef -+ }, -+ message: `Scaffolding task with taskId: ${task.taskId} initiated` -+ }); - if (task.spec.apiVersion !== "scaffolder.backstage.io/v1beta3") { - throw new Error( - `Unsupported Template apiVersion ${task.spec.apiVersion}` -@@ -3087,6 +3280,7 @@ function createDryRunner(options) { - await pluginScaffolderNode.deserializeDirectoryContents(contentsPath, input.directoryContents); - const abortSignal = new AbortController().signal; - const result = await workflowRunner.execute({ -+ taskId: dryRunId, - spec: { - ...input.spec, - steps: [ -@@ -3292,6 +3486,11 @@ async function createRouter(options) { - }); - const concurrentTasksLimit = options.concurrentTasksLimit ?? options.config.getOptionalNumber("scaffolder.concurrentTasksLimit"); - const logger = parentLogger.child({ plugin: "scaffolder" }); -+ const auditLogger = new backstagePluginAuditLogNode.DefaultAuditLogger({ -+ logger, -+ authService: auth, -+ httpAuthService: httpAuth -+ }); - const workingDirectory = await getWorkingDirectory(config, logger); - const integrations = integration.ScmIntegrations.fromConfig(config); - let taskBroker; -@@ -3300,6 +3499,7 @@ async function createRouter(options) { - taskBroker = new StorageTaskBroker( - databaseTaskStore, - logger, -+ auditLogger, - config, - auth, - additionalWorkspaceProviders -@@ -3346,7 +3546,8 @@ async function createRouter(options) { - additionalTemplateFilters, - additionalTemplateGlobals, - concurrentTasksLimit, -- permissions -+ permissions, -+ auditLogger - }); - workers.push(worker); - } -@@ -3375,6 +3576,7 @@ async function createRouter(options) { - actionRegistry, - integrations, - logger, -+ auditLogger, - workingDirectory, - additionalTemplateFilters, - additionalTemplateGlobals, -@@ -3412,297 +3614,821 @@ async function createRouter(options) { - router.get( - "/v2/templates/:namespace/:kind/:name/parameter-schema", - async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- const { token } = await auth.getPluginRequestToken({ -- onBehalfOf: credentials, -- targetPluginId: "catalog" -+ const requestedTemplateRef = `${req.params.kind}:${req.params.namespace}/${req.params.name}`; -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ const credentials = await httpAuth.credentials(req); -+ const { token } = await auth.getPluginRequestToken({ -+ onBehalfOf: credentials, -+ targetPluginId: "catalog" -+ }); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderParameterSchemaFetch", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ templateRef: requestedTemplateRef -+ }, -+ request: req, -+ message: `${actorId} requested the parameter schema for ${requestedTemplateRef}` -+ }); -+ const template = await authorizeTemplate( -+ req.params, -+ token, -+ credentials -+ ); -+ const parameters = [template.spec.parameters ?? []].flat(); -+ const presentation = template.spec.presentation; -+ const templateRef = `${template.kind}:${template.metadata.namespace || "default"}/${template.metadata.name}`; -+ const responseBody = { -+ title: template.metadata.title ?? template.metadata.name, -+ ...presentation ? { presentation } : {}, -+ description: template.metadata.description, -+ "ui:options": template.metadata["ui:options"], -+ steps: parameters.map((schema) => ({ -+ title: schema.title ?? "Please enter the following information", -+ description: schema.description, -+ schema -+ })) -+ }; -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderParameterSchemaFetch", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ templateRef -+ }, -+ request: req, -+ response: { -+ status: 200, -+ body: responseBody -+ }, -+ message: `${actorId} successfully requested the parameter schema for ${templateRef}` -+ }); -+ res.json(responseBody); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderParameterSchemaFetch", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ request: req, -+ metadata: { -+ templateRef: requestedTemplateRef -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `${actorId} failed to request the parameter schema for ${requestedTemplateRef}` -+ }); -+ throw err; -+ } -+ } -+ ).get("/v2/actions", async (req, res) => { -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderInstalledActionsFetch", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ request: req, -+ message: `${actorId} requested the list of installed actions` - }); -- const template = await authorizeTemplate( -- req.params, -- token, -- credentials -- ); -- const parameters = [template.spec.parameters ?? []].flat(); -- const presentation = template.spec.presentation; -- res.json({ -- title: template.metadata.title ?? template.metadata.name, -- ...presentation ? { presentation } : {}, -- description: template.metadata.description, -- "ui:options": template.metadata["ui:options"], -- steps: parameters.map((schema) => ({ -- title: schema.title ?? "Please enter the following information", -- description: schema.description, -- schema -- })) -+ const actionsList = actionRegistry.list().map((action) => { -+ return { -+ id: action.id, -+ description: action.description, -+ examples: action.examples, -+ schema: action.schema -+ }; -+ }); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderInstalledActionsFetch", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ request: req, -+ response: { -+ status: 200, -+ body: actionsList -+ }, -+ message: `${actorId} successfully requested the list of installed actions` - }); -+ res.json(actionsList); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderInstalledActionsFetch", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `${actorId} failed to request for the list of installed actions` -+ }); -+ throw err; - } -- ).get("/v2/actions", async (_req, res) => { -- const actionsList = actionRegistry.list().map((action) => { -- return { -- id: action.id, -- description: action.description, -- examples: action.examples, -- schema: action.schema -- }; -- }); -- res.json(actionsList); - }).post("/v2/tasks", async (req, res) => { - const templateRef = req.body.templateRef; - const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, { - defaultKind: "template" - }); - const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskCreatePermission], -- permissionService: permissions -- }); - const { token } = await auth.getPluginRequestToken({ - onBehalfOf: credentials, - targetPluginId: "catalog" - }); - const userEntityRef = auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0; - const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0; -- let auditLog = `Scaffolding task for ${templateRef}`; -- if (userEntityRef) { -- auditLog += ` created by ${userEntityRef}`; -- } -- logger.info(auditLog); - const values = req.body.values; -- const template = await authorizeTemplate( -- { kind, namespace, name }, -- token, -- credentials -- ); -- for (const parameters of [template.spec.parameters ?? []].flat()) { -- const result2 = jsonschema.validate(values, parameters); -- if (!result2.valid) { -- res.status(400).json({ errors: result2.errors }); -- return; -+ const redactedRequest = lodash.cloneDeep(req); -+ Object.defineProperty(redactedRequest, "ip", { -+ get: () => { -+ return req.ip; - } -+ }); -+ if (req.body.secrets) { -+ const redactedBody = { -+ ...req.body, -+ secrets: Object.keys(req.body.secrets).reduce((acc, key) => { -+ return { -+ ...acc, -+ [key]: "***" -+ }; -+ }, {}) -+ }; -+ redactedRequest.body = redactedBody; - } -- const baseUrl = getEntityBaseUrl(template); -- const taskSpec = { -- apiVersion: template.apiVersion, -- steps: template.spec.steps.map((step, index) => ({ -- ...step, -- id: step.id ?? `step-${index + 1}`, -- name: step.name ?? step.action -- })), -- EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery, -- output: template.spec.output ?? {}, -- parameters: values, -- user: { -- entity: userEntity, -- ref: userEntityRef -- }, -- templateInfo: { -- entityRef: catalogModel.stringifyEntityRef({ kind, name, namespace }), -- baseUrl, -- entity: { -- metadata: template.metadata -+ try { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCreation", -+ stage: "initiation", -+ status: "succeeded", -+ actorId: userEntityRef, -+ request: redactedRequest, -+ metadata: { -+ templateRef -+ }, -+ message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} initiated` -+ }); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskCreatePermission], -+ permissionService: permissions -+ }); -+ const template = await authorizeTemplate( -+ { kind, namespace, name }, -+ token, -+ credentials -+ ); -+ for (const parameters of [template.spec.parameters ?? []].flat()) { -+ const result2 = jsonschema.validate(values, parameters); -+ if (!result2.valid) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCreation", -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ actorId: userEntityRef, -+ request: redactedRequest, -+ metadata: { -+ templateRef -+ }, -+ response: { -+ status: 400, -+ body: { errors: result2.errors } -+ }, -+ errors: result2.errors, -+ message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed` -+ }); -+ return res.status(400).json({ errors: result2.errors }); - } - } -- }; -- const secrets = { -- ...req.body.secrets, -- backstageToken: token, -- __initiatorCredentials: JSON.stringify(credentials) -- }; -- const result = await taskBroker.dispatch({ -- spec: taskSpec, -- createdBy: userEntityRef, -- secrets -- }); -- res.status(201).json({ id: result.taskId }); -- }).get("/v2/tasks", async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskReadPermission], -- permissionService: permissions -- }); -- const [userEntityRef] = [req.query.createdBy].flat(); -- if (typeof userEntityRef !== "string" && typeof userEntityRef !== "undefined") { -- throw new errors.InputError("createdBy query parameter must be a string"); -+ const baseUrl = getEntityBaseUrl(template); -+ const taskSpec = { -+ apiVersion: template.apiVersion, -+ steps: template.spec.steps.map((step, index) => ({ -+ ...step, -+ id: step.id ?? `step-${index + 1}`, -+ name: step.name ?? step.action -+ })), -+ EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery, -+ output: template.spec.output ?? {}, -+ parameters: values, -+ user: { -+ entity: userEntity, -+ ref: userEntityRef -+ }, -+ templateInfo: { -+ entityRef: catalogModel.stringifyEntityRef({ kind, name, namespace }), -+ baseUrl, -+ entity: { -+ metadata: template.metadata -+ } -+ } -+ }; -+ const secrets = { -+ ...req.body.secrets, -+ backstageToken: token, -+ __initiatorCredentials: JSON.stringify(credentials) -+ }; -+ const result = await taskBroker.dispatch({ -+ spec: taskSpec, -+ createdBy: userEntityRef, -+ secrets -+ }); -+ let auditLog = `Scaffolding task for ${templateRef}`; -+ if (userEntityRef) { -+ auditLog += ` created by ${userEntityRef}`; -+ } -+ logger.info(auditLog); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCreation", -+ stage: "completion", -+ status: "succeeded", -+ actorId: userEntityRef, -+ request: redactedRequest, -+ metadata: { -+ taskId: result.taskId, -+ templateRef -+ }, -+ response: { -+ status: 201, -+ body: { id: result.taskId } -+ }, -+ message: `Scaffolding task for ${templateRef} with taskId: ${result.taskId} successfully created by ${userEntityRef}` -+ }); -+ return res.status(201).json({ id: result.taskId }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCreation", -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ actorId: userEntityRef, -+ request: redactedRequest, -+ metadata: { -+ templateRef -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed` -+ }); -+ throw err; - } -- if (!taskBroker.list) { -- throw new Error( -- "TaskBroker does not support listing tasks, please implement the list method on the TaskBroker." -- ); -+ }).get("/v2/tasks", async (req, res) => { -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ const [userEntityRef] = [req.query.createdBy].flat(); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskListFetch", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ request: req, -+ message: `${actorId} requested for the list of scaffolder tasks` -+ }); -+ const credentials = await httpAuth.credentials(req); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskReadPermission], -+ permissionService: permissions -+ }); -+ if (typeof userEntityRef !== "string" && typeof userEntityRef !== "undefined") { -+ throw new errors.InputError("createdBy query parameter must be a string"); -+ } -+ if (!taskBroker.list) { -+ throw new Error( -+ "TaskBroker does not support listing tasks, please implement the list method on the TaskBroker." -+ ); -+ } -+ const tasks = await taskBroker.list({ -+ createdBy: userEntityRef -+ }); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskListFetch", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ request: req, -+ response: { -+ status: 200, -+ body: tasks -+ }, -+ message: `${actorId} successfully requested for the list of scaffolder tasks` -+ }); -+ res.status(200).json(tasks); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskListFetch", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `${actorId} request for the list of scaffolder tasks failed` -+ }); -+ throw err; - } -- const tasks = await taskBroker.list({ -- createdBy: userEntityRef -- }); -- res.status(200).json(tasks); - }).get("/v2/tasks/:taskId", async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskReadPermission], -- permissionService: permissions -- }); - const { taskId } = req.params; -- const task = await taskBroker.get(taskId); -- if (!task) { -- throw new errors.NotFoundError(`Task with id ${taskId} does not exist`); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskFetch", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ message: `${actorId} requested for scaffolder task ${taskId}` -+ }); -+ const credentials = await httpAuth.credentials(req); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskReadPermission], -+ permissionService: permissions -+ }); -+ const task = await taskBroker.get(taskId); -+ if (!task) { -+ throw new errors.NotFoundError(`Task with id ${taskId} does not exist`); -+ } -+ delete task.secrets; -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskFetch", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ request: req, -+ response: { -+ status: 200, -+ body: task -+ }, -+ message: `${actorId} successfully requested for scaffolder tasks ${taskId}` -+ }); -+ res.status(200).json(task); -+ } catch (err) { -+ let status = 500; -+ if (err.name === "NotFoundError") { -+ status = 404; -+ } -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskFetch", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ request: req, -+ response: { -+ status -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `${actorId} request for scaffolder tasks ${taskId} failed` -+ }); -+ throw err; - } -- delete task.secrets; -- res.status(200).json(task); - }).post("/v2/tasks/:taskId/cancel", async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskCancelPermission, alpha$1.taskReadPermission], -- permissionService: permissions -- }); - const { taskId } = req.params; -- await taskBroker.cancel?.(taskId); -- res.status(200).json({ status: "cancelled" }); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCancellation", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ message: `Cancellation request for Scaffolding task with taskId: ${taskId} from ${actorId} received` -+ }); -+ const credentials = await httpAuth.credentials(req); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskCancelPermission], -+ permissionService: permissions -+ }); -+ await taskBroker.cancel?.(taskId); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCancellation", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ response: { -+ status: 200, -+ body: { status: "cancelled" } -+ }, -+ message: `Scaffolding task with taskId: ${taskId} successfully cancelled by ${actorId}` -+ }); -+ res.status(200).json({ status: "cancelled" }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskCancellation", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `${actorId}'s cancel request for task ${taskId} failed` -+ }); -+ throw err; -+ } - }).get("/v2/tasks/:taskId/eventstream", async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskReadPermission], -- permissionService: permissions -- }); - const { taskId } = req.params; -- const after = req.query.after !== void 0 ? Number(req.query.after) : void 0; -- logger.debug(`Event stream observing taskId '${taskId}' opened`); -- res.writeHead(200, { -- Connection: "keep-alive", -- "Cache-Control": "no-cache", -- "Content-Type": "text/event-stream" -- }); -- const subscription = taskBroker.event$({ taskId, after }).subscribe({ -- error: (error) => { -- logger.error( -- `Received error from event stream when observing taskId '${taskId}', ${error}` -- ); -- res.end(); -- }, -- next: ({ events }) => { -- let shouldUnsubscribe = false; -- for (const event of events) { -- res.write( -- `event: ${event.type} -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ const after = req.query.after !== void 0 ? Number(req.query.after) : void 0; -+ logger.debug(`Event stream observing taskId '${taskId}' opened`); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskStream", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ message: `Event stream for scaffolding task with taskId: ${taskId} was opened by ${actorId}` -+ }); -+ const credentials = await httpAuth.credentials(req); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskReadPermission], -+ permissionService: permissions -+ }); -+ res.writeHead(200, { -+ Connection: "keep-alive", -+ "Cache-Control": "no-cache", -+ "Content-Type": "text/event-stream" -+ }); -+ const subscription = taskBroker.event$({ taskId, after }).subscribe({ -+ error: async (error) => { -+ logger.error( -+ `Received error from event stream when observing taskId '${taskId}', ${error}` -+ ); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskStream", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ errors: [ -+ { -+ name: error.name, -+ message: error.message, -+ stack: error.stack, -+ cause: error.cause -+ } -+ ], -+ message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}` -+ }); -+ res.end(); -+ }, -+ next: ({ events }) => { -+ let shouldUnsubscribe = false; -+ for (const event of events) { -+ res.write( -+ `event: ${event.type} - data: ${JSON.stringify(event)} - - ` -- ); -- if (event.type === "completion") { -- shouldUnsubscribe = true; -+ ); -+ if (event.type === "completion") { -+ shouldUnsubscribe = true; -+ } -+ } -+ res.flush?.(); -+ if (shouldUnsubscribe) { -+ subscription.unsubscribe(); -+ res.end(); - } - } -- res.flush?.(); -- if (shouldUnsubscribe) { -- subscription.unsubscribe(); -- res.end(); -- } -- } -- }); -- req.on("close", () => { -- subscription.unsubscribe(); -- logger.debug(`Event stream observing taskId '${taskId}' closed`); -- }); -+ }); -+ req.on("close", async () => { -+ subscription.unsubscribe(); -+ logger.debug(`Event stream observing taskId '${taskId}' closed`); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskStream", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ message: `Event stream observing scaffolding task with taskId: ${taskId} was closed by ${actorId}` -+ }); -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskStream", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}` -+ }); -+ throw err; -+ } - }).get("/v2/tasks/:taskId/events", async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskReadPermission], -- permissionService: permissions -- }); - const { taskId } = req.params; -- const after = Number(req.query.after) || void 0; -- const timeout = setTimeout(() => { -- res.json([]); -- }, 3e4); -- const subscription = taskBroker.event$({ taskId, after }).subscribe({ -- error: (error) => { -- logger.error( -- `Received error from event stream when observing taskId '${taskId}', ${error}` -- ); -- }, -- next: ({ events }) => { -- clearTimeout(timeout); -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ const after = Number(req.query.after) || void 0; -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskEventFetch", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} initiated by ${actorId}` -+ }); -+ const credentials = await httpAuth.credentials(req); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskReadPermission], -+ permissionService: permissions -+ }); -+ const timeout = setTimeout(() => { -+ res.json([]); -+ }, 3e4); -+ const subscription = taskBroker.event$({ taskId, after }).subscribe({ -+ error: async (error) => { -+ logger.error( -+ `Received error from event stream when observing taskId '${taskId}', ${error}` -+ ); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskEventFetch", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ errors: [ -+ { -+ name: error.name, -+ message: error.message, -+ stack: error.stack -+ } -+ ], -+ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed` -+ }); -+ }, -+ next: async ({ events }) => { -+ clearTimeout(timeout); -+ subscription.unsubscribe(); -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskEventFetch", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ response: { -+ status: 200, -+ body: events -+ }, -+ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} by ${actorId} succeeded` -+ }); -+ res.json(events); -+ } -+ }); -+ req.on("close", () => { - subscription.unsubscribe(); -- res.json(events); -- } -- }); -- req.on("close", () => { -- subscription.unsubscribe(); -- clearTimeout(timeout); -- }); -- }).post("/v2/dry-run", async (req, res) => { -- const credentials = await httpAuth.credentials(req); -- await checkPermission({ -- credentials, -- permissions: [alpha$1.taskCreatePermission], -- permissionService: permissions -- }); -- const bodySchema = zod.z.object({ -- template: zod.z.unknown(), -- values: zod.z.record(zod.z.unknown()), -- secrets: zod.z.record(zod.z.string()).optional(), -- directoryContents: zod.z.array( -- zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() }) -- ) -- }); -- const body = await bodySchema.parseAsync(req.body).catch((e) => { -- throw new errors.InputError(`Malformed request: ${e}`); -- }); -- const template = body.template; -- if (!await pluginScaffolderCommon.templateEntityV1beta3Validator.check(template)) { -- throw new errors.InputError("Input template is not a template"); -+ clearTimeout(timeout); -+ }); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskEventFetch", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ taskId -+ }, -+ request: req, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed` -+ }); -+ throw err; - } -- const { token } = await auth.getPluginRequestToken({ -- onBehalfOf: credentials, -- targetPluginId: "catalog" -- }); -- const userEntityRef = auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0; -- const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0; -- for (const parameters of [template.spec.parameters ?? []].flat()) { -- const result2 = jsonschema.validate(body.values, parameters); -- if (!result2.valid) { -- res.status(400).json({ errors: result2.errors }); -- return; -+ }).post("/v2/dry-run", async (req, res) => { -+ const actorId = await auditLogger.getActorId(req); -+ try { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskDryRun", -+ actorId, -+ stage: "initiation", -+ status: "succeeded", -+ metadata: { -+ isDryRun: true -+ }, -+ request: req, -+ message: `Dry Run scaffolder task initiated by ${actorId}` -+ }); -+ const credentials = await httpAuth.credentials(req); -+ await checkPermission({ -+ credentials, -+ permissions: [alpha$1.taskCreatePermission], -+ permissionService: permissions -+ }); -+ const bodySchema = zod.z.object({ -+ template: zod.z.unknown(), -+ values: zod.z.record(zod.z.unknown()), -+ secrets: zod.z.record(zod.z.string()).optional(), -+ directoryContents: zod.z.array( -+ zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() }) -+ ) -+ }); -+ const body = await bodySchema.parseAsync(req.body).catch((e) => { -+ throw new errors.InputError(`Malformed request: ${e}`); -+ }); -+ const template = body.template; -+ if (!await pluginScaffolderCommon.templateEntityV1beta3Validator.check(template)) { -+ throw new errors.InputError("Input template is not a template"); - } -- } -- const steps = template.spec.steps.map((step, index) => ({ -- ...step, -- id: step.id ?? `step-${index + 1}`, -- name: step.name ?? step.action -- })); -- const result = await dryRunner({ -- spec: { -- apiVersion: template.apiVersion, -- steps, -- output: template.spec.output ?? {}, -- parameters: body.values, -- user: { -- entity: userEntity, -- ref: userEntityRef -+ const templateRef = `${template.kind}:${template.metadata.namespace || "default"}/${template.metadata.name}`; -+ const { token } = await auth.getPluginRequestToken({ -+ onBehalfOf: credentials, -+ targetPluginId: "catalog" -+ }); -+ const userEntityRef = auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0; -+ const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0; -+ for (const parameters of [template.spec.parameters ?? []].flat()) { -+ const result2 = jsonschema.validate(body.values, parameters); -+ if (!result2.valid) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskDryRun", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ metadata: { -+ templateRef, -+ parameters: template.spec.parameters, -+ isDryRun: true -+ }, -+ errors: result2.errors, -+ request: req, -+ response: { -+ status: 400, -+ body: { errors: result2.errors } -+ }, -+ message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} failed` -+ }); -+ return res.status(400).json({ errors: result2.errors }); - } -- }, -- directoryContents: (body.directoryContents ?? []).map((file) => ({ -- path: file.path, -- content: Buffer.from(file.base64Content, "base64") -- })), -- secrets: { -- ...body.secrets, -- ...token && { backstageToken: token } -- }, -- credentials -- }); -- res.status(200).json({ -- ...result, -- steps, -- directoryContents: result.directoryContents.map((file) => ({ -- path: file.path, -- executable: file.executable, -- base64Content: file.content.toString("base64") -- })) -- }); -+ } -+ const steps = template.spec.steps.map((step, index) => ({ -+ ...step, -+ id: step.id ?? `step-${index + 1}`, -+ name: step.name ?? step.action -+ })); -+ const result = await dryRunner({ -+ spec: { -+ apiVersion: template.apiVersion, -+ steps, -+ output: template.spec.output ?? {}, -+ parameters: body.values, -+ user: { -+ entity: userEntity, -+ ref: userEntityRef -+ } -+ }, -+ directoryContents: (body.directoryContents ?? []).map((file) => ({ -+ path: file.path, -+ content: Buffer.from(file.base64Content, "base64") -+ })), -+ secrets: { -+ ...body.secrets, -+ ...token && { backstageToken: token } -+ }, -+ credentials -+ }); -+ const dryRunResults = { -+ ...result, -+ steps, -+ directoryContents: result.directoryContents.map((file) => ({ -+ path: file.path, -+ executable: file.executable, -+ base64Content: file.content.toString("base64") -+ })) -+ }; -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskDryRun", -+ actorId, -+ stage: "completion", -+ status: "succeeded", -+ metadata: { -+ templateRef, -+ parameters: template.spec.parameters, -+ isDryRun: true -+ }, -+ request: req, -+ response: { -+ status: 200, -+ body: dryRunResults -+ }, -+ message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} completed successfully` -+ }); -+ return res.status(200).json(dryRunResults); -+ } catch (err) { -+ await auditLogger.auditLog({ -+ eventName: "ScaffolderTaskDryRun", -+ actorId, -+ stage: "completion", -+ status: "failed", -+ level: "error", -+ request: req, -+ metadata: { -+ isDryRun: true -+ }, -+ errors: [ -+ { -+ name: err.name, -+ message: err.message, -+ stack: err.stack -+ } -+ ], -+ message: `Scaffolder Task Dry Run requested by ${actorId} failed` -+ }); -+ throw err; -+ } - }).post("/v2/autocomplete/:provider/:resource", async (req, res) => { - const { token, context } = req.body; - const { provider, resource } = req.params; -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js.map b/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js.map -index 8b048b9..340f733 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js.map -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/cjs/router-O4Kmvgd-.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"router-O4Kmvgd-.cjs.js","sources":["../../src/scaffolder/actions/builtin/catalog/register.examples.ts","../../src/scaffolder/actions/builtin/catalog/register.ts","../../src/scaffolder/actions/builtin/catalog/write.examples.ts","../../src/scaffolder/actions/builtin/catalog/write.ts","../../src/scaffolder/actions/builtin/catalog/fetch.examples.ts","../../src/scaffolder/actions/builtin/catalog/fetch.ts","../../src/scaffolder/actions/builtin/debug/log.examples.ts","../../src/scaffolder/actions/builtin/debug/log.ts","../../src/scaffolder/actions/builtin/debug/wait.examples.ts","../../src/scaffolder/actions/builtin/debug/wait.ts","../../src/scaffolder/actions/builtin/fetch/plain.examples.ts","../../src/scaffolder/actions/builtin/fetch/plain.ts","../../src/scaffolder/actions/builtin/fetch/plainFile.examples.ts","../../src/scaffolder/actions/builtin/fetch/plainFile.ts","../../src/lib/templating/helpers.ts","../../src/lib/templating/SecureTemplater.ts","../../src/lib/templating/filters.ts","../../src/scaffolder/actions/builtin/fetch/template.examples.ts","../../src/scaffolder/actions/builtin/fetch/template.ts","../../src/scaffolder/actions/builtin/filesystem/delete.examples.ts","../../src/scaffolder/actions/builtin/filesystem/delete.ts","../../src/scaffolder/actions/builtin/filesystem/rename.examples.ts","../../src/scaffolder/actions/builtin/filesystem/rename.ts","../../src/scaffolder/actions/builtin/createBuiltinActions.ts","../../src/scaffolder/actions/TemplateActionRegistry.ts","../../src/scaffolder/tasks/taskRecoveryHelper.ts","../../src/scaffolder/tasks/dbUtil.ts","../../src/scaffolder/tasks/DatabaseTaskStore.ts","../../src/scaffolder/tasks/helper.ts","../../src/scaffolder/tasks/DatabaseWorkspaceProvider.ts","../../src/scaffolder/tasks/WorkspaceService.ts","../../src/scaffolder/tasks/StorageTaskBroker.ts","../../src/util/metrics.ts","../../src/service/rules.ts","../../src/scaffolder/tasks/logger.ts","../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts","../../src/scaffolder/tasks/TaskWorker.ts","../../src/scaffolder/dryrun/DecoratedActionsRegistry.ts","../../src/scaffolder/dryrun/createDryRunner.ts","../../src/service/helpers.ts","../../src/util/checkPermissions.ts","../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Register with the catalog',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:register',\n id: 'register-with-catalog',\n name: 'Register with the catalog',\n input: {\n catalogInfoUrl:\n 'http://github.com/backstage/backstage/blob/master/catalog-info.yaml',\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport { stringifyEntityRef, Entity } from '@backstage/catalog-model';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { examples } from './register.examples';\nimport { AuthService } from '@backstage/backend-plugin-api';\n\nconst id = 'catalog:register';\n\n/**\n * Registers entities from a catalog descriptor file in the workspace into the software catalog.\n * @public\n */\nexport function createCatalogRegisterAction(options: {\n catalogClient: CatalogApi;\n integrations: ScmIntegrations;\n auth?: AuthService;\n}) {\n const { catalogClient, integrations, auth } = options;\n\n return createTemplateAction<\n | { catalogInfoUrl: string; optional?: boolean }\n | { repoContentsUrl: string; catalogInfoPath?: string; optional?: boolean }\n >({\n id,\n description:\n 'Registers entities from a catalog descriptor file in the workspace into the software catalog.',\n examples,\n schema: {\n input: {\n oneOf: [\n {\n type: 'object',\n required: ['catalogInfoUrl'],\n properties: {\n catalogInfoUrl: {\n title: 'Catalog Info URL',\n description:\n 'An absolute URL pointing to the catalog info file location',\n type: 'string',\n },\n optional: {\n title: 'Optional',\n description:\n 'Permit the registered location to optionally exist. Default: false',\n type: 'boolean',\n },\n },\n },\n {\n type: 'object',\n required: ['repoContentsUrl'],\n properties: {\n repoContentsUrl: {\n title: 'Repository Contents URL',\n description:\n 'An absolute URL pointing to the root of a repository directory tree',\n type: 'string',\n },\n catalogInfoPath: {\n title: 'Fetch URL',\n description:\n 'A relative path from the repo root pointing to the catalog info file, defaults to /catalog-info.yaml',\n type: 'string',\n },\n optional: {\n title: 'Optional',\n description:\n 'Permit the registered location to optionally exist. Default: false',\n type: 'boolean',\n },\n },\n },\n ],\n },\n output: {\n type: 'object',\n required: ['catalogInfoUrl'],\n properties: {\n entityRef: {\n type: 'string',\n },\n catalogInfoUrl: {\n type: 'string',\n },\n },\n },\n },\n async handler(ctx) {\n const { input } = ctx;\n\n let catalogInfoUrl;\n if ('catalogInfoUrl' in input) {\n catalogInfoUrl = input.catalogInfoUrl;\n } else {\n const { repoContentsUrl, catalogInfoPath = '/catalog-info.yaml' } =\n input;\n const integration = integrations.byUrl(repoContentsUrl);\n if (!integration) {\n throw new InputError(\n `No integration found for host ${repoContentsUrl}`,\n );\n }\n\n catalogInfoUrl = integration.resolveUrl({\n base: repoContentsUrl,\n url: catalogInfoPath,\n });\n }\n\n ctx.logger.info(`Registering ${catalogInfoUrl} in the catalog`);\n\n const { token } = (await auth?.getPluginRequestToken({\n onBehalfOf: await ctx.getInitiatorCredentials(),\n targetPluginId: 'catalog',\n })) ?? { token: ctx.secrets?.backstageToken };\n\n try {\n // 1st try to register the location, this will throw an error if the location already exists (see catch)\n await catalogClient.addLocation(\n {\n type: 'url',\n target: catalogInfoUrl,\n },\n token ? { token } : {},\n );\n } catch (e) {\n if (!input.optional) {\n // if optional is false or unset, it is not allowed to register the same location twice, we rethrow the error\n throw e;\n }\n }\n\n try {\n // 2nd retry the registration as a dry run, this will not throw an error if the location already exists\n const result = await catalogClient.addLocation(\n {\n dryRun: true,\n type: 'url',\n target: catalogInfoUrl,\n },\n token ? { token } : {},\n );\n\n if (result.entities.length) {\n const { entities } = result;\n let entity: Entity | undefined;\n // prioritise 'Component' type as it is the most central kind of entity\n entity = entities.find(\n e =>\n !e.metadata.name.startsWith('generated-') &&\n e.kind === 'Component',\n );\n if (!entity) {\n entity = entities.find(\n e => !e.metadata.name.startsWith('generated-'),\n );\n }\n if (!entity) {\n entity = entities[0];\n }\n\n ctx.output('entityRef', stringifyEntityRef(entity));\n }\n } catch (e) {\n if (!input.optional) {\n throw e;\n }\n }\n\n ctx.output('catalogInfoUrl', catalogInfoUrl);\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Write a catalog yaml file',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:write',\n id: 'create-catalog-info-file',\n name: 'Create catalog file',\n input: {\n entity: {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Component',\n metadata: {\n name: 'test',\n annotations: {},\n },\n spec: {\n type: 'service',\n lifecycle: 'production',\n owner: 'default/owner',\n },\n },\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { z } from 'zod';\nimport { examples } from './write.examples';\n\nconst id = 'catalog:write';\n\n/**\n * Writes a catalog descriptor file containing the provided entity to a path in the workspace.\n * @public\n */\n\nexport function createCatalogWriteAction() {\n return createTemplateAction({\n id,\n description: 'Writes the catalog-info.yaml for your template',\n schema: {\n input: z.object({\n filePath: z\n .string()\n .optional()\n .describe('Defaults to catalog-info.yaml'),\n // TODO: this should reference an zod entity validator if it existed.\n entity: z\n .record(z.any())\n .describe(\n 'You can provide the same values used in the Entity schema.',\n ),\n }),\n },\n examples,\n supportsDryRun: true,\n async handler(ctx) {\n const { filePath, entity } = ctx.input;\n const entityRef = ctx.templateInfo?.entityRef;\n const path = filePath ?? 'catalog-info.yaml';\n ctx.logger.info(`Writing ${path}`);\n\n await fs.writeFile(\n resolveSafeChildPath(ctx.workspacePath, path),\n yaml.stringify({\n ...entity,\n metadata: {\n ...entity.metadata,\n ...(entityRef\n ? {\n annotations: {\n ...entity.metadata.annotations,\n 'backstage.io/source-template': entityRef,\n },\n }\n : undefined),\n },\n }),\n );\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Fetch entity by reference',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:fetch',\n id: 'fetch',\n name: 'Fetch catalog entity',\n input: {\n entityRef: 'component:default/name',\n },\n },\n ],\n }),\n },\n {\n description: 'Fetch multiple entities by reference',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:fetch',\n id: 'fetchMultiple',\n name: 'Fetch catalog entities',\n input: {\n entityRefs: ['component:default/name'],\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CatalogApi } from '@backstage/catalog-client';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { z } from 'zod';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { examples } from './fetch.examples';\nimport { AuthService } from '@backstage/backend-plugin-api';\n\nconst id = 'catalog:fetch';\n\n/**\n * Returns entity or entities from the catalog by entity reference(s).\n *\n * @public\n */\nexport function createFetchCatalogEntityAction(options: {\n catalogClient: CatalogApi;\n auth?: AuthService;\n}) {\n const { catalogClient, auth } = options;\n\n return createTemplateAction({\n id,\n description:\n 'Returns entity or entities from the catalog by entity reference(s)',\n examples,\n supportsDryRun: true,\n schema: {\n input: z.object({\n entityRef: z\n .string({\n description: 'Entity reference of the entity to get',\n })\n .optional(),\n entityRefs: z\n .array(z.string(), {\n description: 'Entity references of the entities to get',\n })\n .optional(),\n optional: z\n .boolean({\n description:\n 'Allow the entity or entities to optionally exist. Default: false',\n })\n .optional(),\n defaultKind: z.string({ description: 'The default kind' }).optional(),\n defaultNamespace: z\n .string({ description: 'The default namespace' })\n .optional(),\n }),\n output: z.object({\n entity: z\n .any({\n description:\n 'Object containing same values used in the Entity schema. Only when used with `entityRef` parameter.',\n })\n .optional(),\n entities: z\n .array(\n z.any({\n description:\n 'Array containing objects with same values used in the Entity schema. Only when used with `entityRefs` parameter.',\n }),\n )\n .optional(),\n }),\n },\n async handler(ctx) {\n const { entityRef, entityRefs, optional, defaultKind, defaultNamespace } =\n ctx.input;\n if (!entityRef && !entityRefs) {\n if (optional) {\n return;\n }\n throw new Error('Missing entity reference or references');\n }\n\n const { token } = (await auth?.getPluginRequestToken({\n onBehalfOf: await ctx.getInitiatorCredentials(),\n targetPluginId: 'catalog',\n })) ?? { token: ctx.secrets?.backstageToken };\n\n if (entityRef) {\n const entity = await catalogClient.getEntityByRef(\n stringifyEntityRef(\n parseEntityRef(entityRef, { defaultKind, defaultNamespace }),\n ),\n {\n token,\n },\n );\n\n if (!entity && !optional) {\n throw new Error(`Entity ${entityRef} not found`);\n }\n ctx.output('entity', entity ?? null);\n }\n\n if (entityRefs) {\n const entities = await catalogClient.getEntitiesByRefs(\n {\n entityRefs: entityRefs.map(ref =>\n stringifyEntityRef(\n parseEntityRef(ref, { defaultKind, defaultNamespace }),\n ),\n ),\n },\n {\n token,\n },\n );\n\n const finalEntities = entities.items.map((e, i) => {\n if (!e && !optional) {\n throw new Error(`Entity ${entityRefs[i]} not found`);\n }\n return e ?? null;\n });\n\n ctx.output('entities', finalEntities);\n }\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Write a debug message',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:log',\n id: 'write-debug-line',\n name: 'Write \"Hello Backstage!\" log line',\n input: {\n message: 'Hello Backstage!',\n },\n },\n ],\n }),\n },\n {\n description: 'List the workspace directory',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:log',\n id: 'write-workspace-directory',\n name: 'List the workspace directory',\n input: {\n listWorkspace: true,\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readdir, stat } from 'fs-extra';\nimport { relative, join } from 'path';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { examples } from './log.examples';\n\nconst id = 'debug:log';\n\n/**\n * Writes a message into the log or lists all files in the workspace\n *\n * @remarks\n *\n * This task is useful for local development and testing of both the scaffolder\n * and scaffolder templates.\n *\n * @public\n */\nexport function createDebugLogAction() {\n return createTemplateAction<{ message?: string; listWorkspace?: boolean }>({\n id,\n description:\n 'Writes a message into the log or lists all files in the workspace.',\n examples,\n schema: {\n input: {\n type: 'object',\n properties: {\n message: {\n title: 'Message to output.',\n type: 'string',\n },\n listWorkspace: {\n title: 'List all files in the workspace, if true.',\n type: 'boolean',\n },\n extra: {\n title: 'Extra info',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info(JSON.stringify(ctx.input, null, 2));\n\n if (ctx.input?.message) {\n ctx.logger.info(ctx.input.message);\n }\n\n if (ctx.input?.listWorkspace) {\n const files = await recursiveReadDir(ctx.workspacePath);\n ctx.logger.info(\n `Workspace:\\n${files\n .map(f => ` - ${relative(ctx.workspacePath, f)}`)\n .join('\\n')}`,\n );\n }\n },\n });\n}\n\nexport async function recursiveReadDir(dir: string): Promise {\n const subdirs = await readdir(dir);\n const files = await Promise.all(\n subdirs.map(async subdir => {\n const res = join(dir, subdir);\n return (await stat(res)).isDirectory() ? recursiveReadDir(res) : [res];\n }),\n );\n return files.reduce((a, f) => a.concat(f), []);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Waiting for 50 milliseconds',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:wait',\n id: 'wait-milliseconds',\n name: 'Waiting for 50 milliseconds',\n input: {\n milliseconds: 50,\n },\n },\n ],\n }),\n },\n {\n description: 'Waiting for 5 seconds',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:wait',\n id: 'wait-5sec',\n name: 'Waiting for 5 seconds',\n input: {\n seconds: 5,\n },\n },\n ],\n }),\n },\n {\n description: 'Waiting for 1 minutes',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:wait',\n id: 'wait-1min',\n name: 'Waiting for 1 minutes',\n input: {\n minutes: 1,\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { HumanDuration } from '@backstage/types';\nimport { Duration } from 'luxon';\nimport { examples } from './wait.examples';\n\nconst id = 'debug:wait';\n\nconst MAX_WAIT_TIME_IN_ISO = 'T00:10:00';\n\n/**\n * Waits for a certain period of time.\n *\n * @remarks\n *\n * This task is useful to give some waiting time for manual intervention.\n * Has to be used in a combination with other actions.\n *\n * @public\n */\nexport function createWaitAction(options?: {\n maxWaitTime?: Duration | HumanDuration;\n}) {\n const toDuration = (\n maxWaitTime: Duration | HumanDuration | undefined,\n ): Duration => {\n if (maxWaitTime) {\n if (maxWaitTime instanceof Duration) {\n return maxWaitTime;\n }\n return Duration.fromObject(maxWaitTime);\n }\n return Duration.fromISOTime(MAX_WAIT_TIME_IN_ISO);\n };\n\n return createTemplateAction({\n id,\n description: 'Waits for a certain period of time.',\n examples,\n schema: {\n input: {\n type: 'object',\n properties: {\n minutes: {\n title: 'Waiting period in minutes.',\n type: 'number',\n },\n seconds: {\n title: 'Waiting period in seconds.',\n type: 'number',\n },\n milliseconds: {\n title: 'Waiting period in milliseconds.',\n type: 'number',\n },\n },\n },\n },\n async handler(ctx) {\n const delayTime = Duration.fromObject(ctx.input);\n const maxWait = toDuration(options?.maxWaitTime);\n\n if (delayTime.minus(maxWait).toMillis() > 0) {\n throw new Error(\n `Waiting duration is longer than the maximum threshold of ${maxWait.toHuman()}`,\n );\n }\n\n await new Promise(resolve => {\n const controller = new AbortController();\n const timeoutHandle = setTimeout(abort, delayTime.toMillis());\n ctx.signal?.addEventListener('abort', abort);\n\n function abort() {\n ctx.signal?.removeEventListener('abort', abort);\n clearTimeout(timeoutHandle!);\n controller.abort();\n resolve('finished');\n }\n });\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Downloads content and places it in the workspace.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:plain',\n id: 'fetch-plain',\n name: 'Fetch plain',\n input: {\n url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets',\n },\n },\n ],\n }),\n },\n {\n description:\n 'Optionally, if you would prefer the data to be downloaded to a subdirectory in the workspace you may specify the ‘targetPath’ input option.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:plain',\n id: 'fetch-plain',\n name: 'Fetch plain',\n input: {\n url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets',\n targetPath: 'fetched-data',\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { examples } from './plain.examples';\n\nimport {\n createTemplateAction,\n fetchContents,\n} from '@backstage/plugin-scaffolder-node';\n\nexport const ACTION_ID = 'fetch:plain';\n\n/**\n * Downloads content and places it in the workspace, or optionally\n * in a subdirectory specified by the 'targetPath' input option.\n * @public\n */\nexport function createFetchPlainAction(options: {\n reader: UrlReader;\n integrations: ScmIntegrations;\n}) {\n const { reader, integrations } = options;\n\n return createTemplateAction<{\n url: string;\n targetPath?: string;\n token?: string;\n }>({\n id: ACTION_ID,\n examples,\n description:\n 'Downloads content and places it in the workspace, or optionally in a subdirectory specified by the `targetPath` input option.',\n schema: {\n input: {\n type: 'object',\n required: ['url'],\n properties: {\n url: {\n title: 'Fetch URL',\n description:\n 'Relative path or absolute URL pointing to the directory tree to fetch',\n type: 'string',\n },\n targetPath: {\n title: 'Target Path',\n description:\n 'Target path within the working directory to download the contents to.',\n type: 'string',\n },\n token: {\n title: 'Token',\n description:\n 'An optional token to use for authentication when reading the resources.',\n type: 'string',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info('Fetching plain content from remote URL');\n\n // Finally move the template result into the task workspace\n const targetPath = ctx.input.targetPath ?? './';\n const outputPath = resolveSafeChildPath(ctx.workspacePath, targetPath);\n\n await fetchContents({\n reader,\n integrations,\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath,\n token: ctx.input.token,\n });\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Downloads a file and places it in the workspace.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:plain:file',\n id: 'fetch-plain-file',\n name: 'Fetch plain file',\n input: {\n url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets/Backstage%20Community%20Sessions.png',\n targetPath: 'target-path',\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { examples } from './plainFile.examples';\nimport {\n createTemplateAction,\n fetchFile,\n} from '@backstage/plugin-scaffolder-node';\n\n/**\n * Downloads content and places it in the workspace, or optionally\n * in a subdirectory specified by the 'targetPath' input option.\n * @public\n */\nexport function createFetchPlainFileAction(options: {\n reader: UrlReader;\n integrations: ScmIntegrations;\n}) {\n const { reader, integrations } = options;\n\n return createTemplateAction<{\n url: string;\n targetPath: string;\n token?: string;\n }>({\n id: 'fetch:plain:file',\n description: 'Downloads single file and places it in the workspace.',\n examples,\n schema: {\n input: {\n type: 'object',\n required: ['url', 'targetPath'],\n properties: {\n url: {\n title: 'Fetch URL',\n description:\n 'Relative path or absolute URL pointing to the single file to fetch.',\n type: 'string',\n },\n targetPath: {\n title: 'Target Path',\n description:\n 'Target path within the working directory to download the file as.',\n type: 'string',\n },\n token: {\n title: 'Token',\n description:\n 'An optional token to use for authentication when reading the resources.',\n type: 'string',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info('Fetching plain content from remote URL');\n\n // Finally move the template result into the task workspace\n const outputPath = resolveSafeChildPath(\n ctx.workspacePath,\n ctx.input.targetPath,\n );\n\n await fetchFile({\n reader,\n integrations,\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath,\n token: ctx.input.token,\n });\n },\n });\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isNoNodeSnapshotOptionProvided(): boolean {\n return (\n process.env.NODE_OPTIONS?.includes('--no-node-snapshot') ||\n process.argv.includes('--no-node-snapshot')\n );\n}\n\n/**\n * Gets the major version of the currently running Node.js process.\n *\n * @remarks\n * This function extracts the major version from `process.versions.node` (a string representing the Node.js version),\n * which includes the major, minor, and patch versions. It splits this string by the `.` character to get an array\n * of these versions, and then parses the first element of this array (the major version) to a number.\n *\n * @returns {number} The major version of the currently running Node.js process.\n */\nexport function getMajorNodeVersion(): number {\n const version = process.versions.node;\n return parseInt(version.split('.')[0], 10);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Isolate } from 'isolated-vm';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport {\n TemplateFilter as _TemplateFilter,\n TemplateGlobal as _TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport fs from 'fs-extra';\nimport { JsonValue } from '@backstage/types';\nimport { getMajorNodeVersion, isNoNodeSnapshotOptionProvided } from './helpers';\n\n// language=JavaScript\nconst mkScript = (nunjucksSource: string) => `\nconst { render, renderCompat } = (() => {\n const module = {};\n const process = { env: {} };\n const require = (pkg) => { if (pkg === 'events') { return function (){}; }};\n\n ${nunjucksSource}\n\n const env = module.exports.configure({\n autoescape: false,\n ...JSON.parse(nunjucksConfigs),\n tags: {\n variableStart: '\\${{',\n variableEnd: '}}',\n },\n });\n\n const compatEnv = module.exports.configure({\n autoescape: false,\n ...JSON.parse(nunjucksConfigs),\n tags: {\n variableStart: '{{',\n variableEnd: '}}',\n },\n });\n compatEnv.addFilter('jsonify', compatEnv.getFilter('dump'));\n\n for (const name of JSON.parse(availableTemplateFilters)) {\n env.addFilter(name, (...args) => JSON.parse(callFilter(name, args)));\n }\n for (const [name, value] of Object.entries(JSON.parse(availableTemplateGlobals))) {\n env.addGlobal(name, value);\n }\n for (const name of JSON.parse(availableTemplateCallbacks)) {\n env.addGlobal(name, (...args) => JSON.parse(callGlobal(name, args)));\n }\n\n let uninstallCompat = undefined;\n\n function render(str, values) {\n try {\n if (uninstallCompat) {\n uninstallCompat();\n uninstallCompat = undefined;\n }\n return env.renderString(str, JSON.parse(values));\n } catch (error) {\n // Make sure errors don't leak anything\n throw new Error(String(error.message));\n }\n }\n\n function renderCompat(str, values) {\n try {\n if (!uninstallCompat) {\n uninstallCompat = module.exports.installJinjaCompat();\n }\n return compatEnv.renderString(str, JSON.parse(values));\n } catch (error) {\n // Make sure errors don't leak anything\n throw new Error(String(error.message));\n }\n }\n\n return { render, renderCompat };\n})();\n`;\n\n/**\n * @public\n * @deprecated Import from `@backstage/plugin-scaffolder-node` instead.\n */\nexport type TemplateFilter = _TemplateFilter;\n\n/**\n * @public\n * @deprecated Import from `@backstage/plugin-scaffolder-node` instead.\n */\nexport type TemplateGlobal = _TemplateGlobal;\n\ninterface SecureTemplaterOptions {\n /* Enables jinja compatibility and the \"jsonify\" filter */\n cookiecutterCompat?: boolean;\n /* Extra user-provided nunjucks filters */\n templateFilters?: Record;\n /* Extra user-provided nunjucks globals */\n templateGlobals?: Record;\n nunjucksConfigs?: { trimBlocks?: boolean; lstripBlocks?: boolean };\n}\n\nexport type SecureTemplateRenderer = (\n template: string,\n values: unknown,\n) => string;\n\nexport class SecureTemplater {\n static async loadRenderer(options: SecureTemplaterOptions = {}) {\n const {\n cookiecutterCompat,\n templateFilters = {},\n templateGlobals = {},\n nunjucksConfigs = {},\n } = options;\n\n const nodeVersion = getMajorNodeVersion();\n if (nodeVersion >= 20 && !isNoNodeSnapshotOptionProvided()) {\n throw new Error(\n `When using Node.js version 20 or newer, the scaffolder backend plugin requires that it be started with the --no-node-snapshot option. \n Please make sure that you have NODE_OPTIONS=--no-node-snapshot in your environment.`,\n );\n }\n\n const isolate = new Isolate({ memoryLimit: 128 });\n const context = await isolate.createContext();\n const contextGlobal = context.global;\n\n const nunjucksSource = await fs.readFile(\n resolvePackagePath(\n '@backstage/plugin-scaffolder-backend',\n 'assets/nunjucks.js.txt',\n ),\n 'utf-8',\n );\n\n const nunjucksScript = await isolate.compileScript(\n mkScript(nunjucksSource),\n );\n\n await contextGlobal.set('nunjucksConfigs', JSON.stringify(nunjucksConfigs));\n\n const availableFilters = Object.keys(templateFilters);\n\n await contextGlobal.set(\n 'availableTemplateFilters',\n JSON.stringify(availableFilters),\n );\n\n const globalCallbacks = [];\n const globalValues: Record = {};\n for (const [name, value] of Object.entries(templateGlobals)) {\n if (typeof value === 'function') {\n globalCallbacks.push(name);\n } else {\n globalValues[name] = value;\n }\n }\n\n await contextGlobal.set(\n 'availableTemplateGlobals',\n JSON.stringify(globalValues),\n );\n await contextGlobal.set(\n 'availableTemplateCallbacks',\n JSON.stringify(globalCallbacks),\n );\n\n await contextGlobal.set(\n 'callFilter',\n (filterName: string, args: JsonValue[]) => {\n if (!Object.hasOwn(templateFilters, filterName)) {\n return '';\n }\n return JSON.stringify(templateFilters[filterName](...args));\n },\n );\n\n await contextGlobal.set(\n 'callGlobal',\n (globalName: string, args: JsonValue[]) => {\n if (!Object.hasOwn(templateGlobals, globalName)) {\n return '';\n }\n const global = templateGlobals[globalName];\n if (typeof global !== 'function') {\n return '';\n }\n return JSON.stringify(global(...args));\n },\n );\n\n await nunjucksScript.run(context);\n\n const render: SecureTemplateRenderer = (template, values) => {\n if (!context) {\n throw new Error('SecureTemplater has not been initialized');\n }\n\n contextGlobal.setSync('templateStr', String(template));\n contextGlobal.setSync('templateValues', JSON.stringify(values));\n\n if (cookiecutterCompat) {\n return context.evalSync(`renderCompat(templateStr, templateValues)`);\n }\n\n return context.evalSync(`render(templateStr, templateValues)`);\n };\n return render;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport type { JsonObject, JsonValue } from '@backstage/types';\nimport {\n parseRepoUrl,\n TemplateFilter,\n} from '@backstage/plugin-scaffolder-node';\nimport get from 'lodash/get';\n\nexport const createDefaultFilters = ({\n integrations,\n}: {\n integrations: ScmIntegrations;\n}): Record => {\n return {\n parseRepoUrl: url => parseRepoUrl(url as string, integrations),\n parseEntityRef: (ref: JsonValue, context?: JsonValue) =>\n parseEntityRef(ref as string, context as JsonObject),\n pick: (obj: JsonValue, key: JsonValue) => get(obj, key as string),\n projectSlug: repoUrl => {\n const { owner, repo } = parseRepoUrl(repoUrl as string, integrations);\n return `${owner}/${repo}`;\n },\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description:\n 'Downloads a skeleton directory that lives alongside the template file and fill it out with values.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:template',\n id: 'fetch-template',\n name: 'Fetch template',\n input: {\n url: './skeleton',\n targetPath: './target',\n values: {\n name: 'test-project',\n count: 1234,\n itemList: ['first', 'second', 'third'],\n showDummyFile: false,\n },\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { extname } from 'path';\nimport { UrlReader } from '@backstage/backend-common';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n createTemplateAction,\n fetchContents,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport globby from 'globby';\nimport fs from 'fs-extra';\nimport { isBinaryFile } from 'isbinaryfile';\nimport { SecureTemplater } from '../../../../lib/templating/SecureTemplater';\nimport { createDefaultFilters } from '../../../../lib/templating/filters';\nimport { examples } from './template.examples';\n\n/**\n * Downloads a skeleton, templates variables into file and directory names and content.\n * Then places the result in the workspace, or optionally in a subdirectory\n * specified by the 'targetPath' input option.\n *\n * @public\n */\nexport function createFetchTemplateAction(options: {\n reader: UrlReader;\n integrations: ScmIntegrations;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n}) {\n const {\n reader,\n integrations,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n } = options;\n\n const defaultTemplateFilters = createDefaultFilters({ integrations });\n\n return createTemplateAction<{\n url: string;\n targetPath?: string;\n values: any;\n templateFileExtension?: string | boolean;\n\n // Cookiecutter compat options\n /**\n * @deprecated This field is deprecated in favor of copyWithoutTemplating.\n */\n copyWithoutRender?: string[];\n copyWithoutTemplating?: string[];\n cookiecutterCompat?: boolean;\n replace?: boolean;\n trimBlocks?: boolean;\n lstripBlocks?: boolean;\n token?: string;\n }>({\n id: 'fetch:template',\n description:\n 'Downloads a skeleton, templates variables into file and directory names and content, and places the result in the workspace, or optionally in a subdirectory specified by the `targetPath` input option.',\n examples,\n schema: {\n input: {\n type: 'object',\n required: ['url'],\n properties: {\n url: {\n title: 'Fetch URL',\n description:\n 'Relative path or absolute URL pointing to the directory tree to fetch',\n type: 'string',\n },\n targetPath: {\n title: 'Target Path',\n description:\n 'Target path within the working directory to download the contents to. Defaults to the working directory root.',\n type: 'string',\n },\n values: {\n title: 'Template Values',\n description: 'Values to pass on to the templating engine',\n type: 'object',\n },\n copyWithoutRender: {\n title: '[Deprecated] Copy Without Render',\n description:\n 'An array of glob patterns. Any files or directories which match are copied without being processed as templates.',\n type: 'array',\n items: {\n type: 'string',\n },\n },\n copyWithoutTemplating: {\n title: 'Copy Without Templating',\n description:\n 'An array of glob patterns. Contents of matched files or directories are copied without being processed, but paths are subject to rendering.',\n type: 'array',\n items: {\n type: 'string',\n },\n },\n cookiecutterCompat: {\n title: 'Cookiecutter compatibility mode',\n description:\n 'Enable features to maximise compatibility with templates built for fetch:cookiecutter',\n type: 'boolean',\n },\n templateFileExtension: {\n title: 'Template File Extension',\n description:\n 'If set, only files with the given extension will be templated. If set to `true`, the default extension `.njk` is used.',\n type: ['string', 'boolean'],\n },\n replace: {\n title: 'Replace files',\n description:\n 'If set, replace files in targetPath instead of skipping existing ones.',\n type: 'boolean',\n },\n token: {\n title: 'Token',\n description:\n 'An optional token to use for authentication when reading the resources.',\n type: 'string',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info('Fetching template content from remote URL');\n\n const workDir = await ctx.createTemporaryDirectory();\n const templateDir = resolveSafeChildPath(workDir, 'template');\n\n const targetPath = ctx.input.targetPath ?? './';\n const outputDir = resolveSafeChildPath(ctx.workspacePath, targetPath);\n if (ctx.input.copyWithoutRender && ctx.input.copyWithoutTemplating) {\n throw new InputError(\n 'Fetch action input copyWithoutRender and copyWithoutTemplating can not be used at the same time',\n );\n }\n\n let copyOnlyPatterns: string[] | undefined;\n let renderFilename: boolean;\n if (ctx.input.copyWithoutRender) {\n ctx.logger.warn(\n '[Deprecated] copyWithoutRender is deprecated Please use copyWithoutTemplating instead.',\n );\n copyOnlyPatterns = ctx.input.copyWithoutRender;\n renderFilename = false;\n } else {\n copyOnlyPatterns = ctx.input.copyWithoutTemplating;\n renderFilename = true;\n }\n\n if (copyOnlyPatterns && !Array.isArray(copyOnlyPatterns)) {\n throw new InputError(\n 'Fetch action input copyWithoutRender/copyWithoutTemplating must be an Array',\n );\n }\n\n if (\n ctx.input.templateFileExtension &&\n (copyOnlyPatterns || ctx.input.cookiecutterCompat)\n ) {\n throw new InputError(\n 'Fetch action input extension incompatible with copyWithoutRender/copyWithoutTemplating and cookiecutterCompat',\n );\n }\n\n let extension: string | false = false;\n if (ctx.input.templateFileExtension) {\n extension =\n ctx.input.templateFileExtension === true\n ? '.njk'\n : ctx.input.templateFileExtension;\n if (!extension.startsWith('.')) {\n extension = `.${extension}`;\n }\n }\n\n await fetchContents({\n reader,\n integrations,\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath: templateDir,\n token: ctx.input.token,\n });\n\n ctx.logger.info('Listing files and directories in template');\n const allEntriesInTemplate = await globby(`**/*`, {\n cwd: templateDir,\n dot: true,\n onlyFiles: false,\n markDirectories: true,\n followSymbolicLinks: false,\n });\n\n const nonTemplatedEntries = new Set(\n await globby(copyOnlyPatterns || [], {\n cwd: templateDir,\n dot: true,\n onlyFiles: false,\n markDirectories: true,\n followSymbolicLinks: false,\n }),\n );\n\n // Cookiecutter prefixes all parameters in templates with\n // `cookiecutter.`. To replicate this, we wrap our parameters\n // in an object with a `cookiecutter` property when compat\n // mode is enabled.\n const { cookiecutterCompat, values } = ctx.input;\n const context = {\n [cookiecutterCompat ? 'cookiecutter' : 'values']: values,\n };\n\n ctx.logger.info(\n `Processing ${allEntriesInTemplate.length} template files/directories with input values`,\n ctx.input.values,\n );\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n cookiecutterCompat: ctx.input.cookiecutterCompat,\n templateFilters: {\n ...defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n nunjucksConfigs: {\n trimBlocks: ctx.input.trimBlocks,\n lstripBlocks: ctx.input.lstripBlocks,\n },\n });\n\n for (const location of allEntriesInTemplate) {\n let renderContents: boolean;\n\n let localOutputPath = location;\n if (extension) {\n renderContents = extname(localOutputPath) === extension;\n if (renderContents) {\n localOutputPath = localOutputPath.slice(0, -extension.length);\n }\n // extension is mutual exclusive with copyWithoutRender/copyWithoutTemplating,\n // therefore the output path is always rendered.\n localOutputPath = renderTemplate(localOutputPath, context);\n } else {\n renderContents = !nonTemplatedEntries.has(location);\n // The logic here is a bit tangled because it depends on two variables.\n // If renderFilename is true, which means copyWithoutTemplating is used,\n // then the path is always rendered.\n // If renderFilename is false, which means copyWithoutRender is used,\n // then matched file/directory won't be processed, same as before.\n if (renderFilename) {\n localOutputPath = renderTemplate(localOutputPath, context);\n } else {\n localOutputPath = renderContents\n ? renderTemplate(localOutputPath, context)\n : localOutputPath;\n }\n }\n\n if (containsSkippedContent(localOutputPath)) {\n continue;\n }\n\n const outputPath = resolveSafeChildPath(outputDir, localOutputPath);\n if (fs.existsSync(outputPath) && !ctx.input.replace) {\n continue;\n }\n\n if (!renderContents && !extension) {\n ctx.logger.info(\n `Copying file/directory ${location} without processing.`,\n );\n }\n\n if (location.endsWith('/')) {\n ctx.logger.info(\n `Writing directory ${location} to template output path.`,\n );\n await fs.ensureDir(outputPath);\n } else {\n const inputFilePath = resolveSafeChildPath(templateDir, location);\n const stats = await fs.promises.lstat(inputFilePath);\n\n if (stats.isSymbolicLink() || (await isBinaryFile(inputFilePath))) {\n ctx.logger.info(\n `Copying file binary or symbolic link at ${location}, to template output path.`,\n );\n await fs.copy(inputFilePath, outputPath);\n } else {\n const statsObj = await fs.stat(inputFilePath);\n ctx.logger.info(\n `Writing file ${location} to template output path with mode ${statsObj.mode}.`,\n );\n const inputFileContents = await fs.readFile(inputFilePath, 'utf-8');\n await fs.outputFile(\n outputPath,\n renderContents\n ? renderTemplate(inputFileContents, context)\n : inputFileContents,\n { mode: statsObj.mode },\n );\n }\n }\n }\n\n ctx.logger.info(`Template result written to ${outputDir}`);\n },\n });\n}\n\nfunction containsSkippedContent(localOutputPath: string): boolean {\n // if the path is empty means that there is a file skipped in the root\n // if the path starts with a separator it means that the root directory has been skipped\n // if the path includes // means that there is a subdirectory skipped\n // All paths returned are considered with / separator because of globby returning the linux separator for all os'.\n return (\n localOutputPath === '' ||\n localOutputPath.startsWith('/') ||\n localOutputPath.includes('//')\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Delete specified files',\n example: yaml.stringify({\n steps: [\n {\n action: 'fs:delete',\n id: 'deleteFiles',\n name: 'Delete files',\n input: {\n files: ['file1.txt', 'file2.txt'],\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { InputError } from '@backstage/errors';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport fs from 'fs-extra';\nimport { examples } from './delete.examples';\n\n/**\n * Creates new action that enables deletion of files and directories in the workspace.\n * @public\n */\nexport const createFilesystemDeleteAction = () => {\n return createTemplateAction<{ files: string[] }>({\n id: 'fs:delete',\n description: 'Deletes files and directories from the workspace',\n examples,\n schema: {\n input: {\n required: ['files'],\n type: 'object',\n properties: {\n files: {\n title: 'Files',\n description: 'A list of files and directories that will be deleted',\n type: 'array',\n items: {\n type: 'string',\n },\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n if (!Array.isArray(ctx.input?.files)) {\n throw new InputError('files must be an Array');\n }\n\n for (const file of ctx.input.files) {\n const filepath = resolveSafeChildPath(ctx.workspacePath, file);\n\n try {\n await fs.remove(filepath);\n ctx.logger.info(`File ${filepath} deleted successfully`);\n } catch (err) {\n ctx.logger.error(`Failed to delete file ${filepath}:`, err);\n throw err;\n }\n }\n },\n });\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Rename specified files ',\n example: yaml.stringify({\n steps: [\n {\n action: 'fs:rename',\n id: 'renameFiles',\n name: 'Rename files',\n input: {\n files: [\n { from: 'file1.txt', to: 'file1Renamed.txt' },\n { from: 'file2.txt', to: 'file2Renamed.txt' },\n { from: 'file3.txt', to: 'file3Renamed.txt', overwrite: true },\n ],\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\nimport fs from 'fs-extra';\nimport { examples } from './rename.examples';\n\n/**\n * Creates a new action that allows renames of files and directories in the workspace.\n * @public\n */\nexport const createFilesystemRenameAction = () => {\n return createTemplateAction<{\n files: Array<{\n from: string;\n to: string;\n overwrite?: boolean;\n }>;\n }>({\n id: 'fs:rename',\n description: 'Renames files and directories within the workspace',\n examples,\n schema: {\n input: {\n required: ['files'],\n type: 'object',\n properties: {\n files: {\n title: 'Files',\n description:\n 'A list of file and directory names that will be renamed',\n type: 'array',\n items: {\n type: 'object',\n required: ['from', 'to'],\n properties: {\n from: {\n type: 'string',\n title: 'The source location of the file to be renamed',\n },\n to: {\n type: 'string',\n title: 'The destination of the new file',\n },\n overwrite: {\n type: 'boolean',\n title:\n 'Overwrite existing file or directory, default is false',\n },\n },\n },\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n if (!Array.isArray(ctx.input?.files)) {\n throw new InputError('files must be an Array');\n }\n\n for (const file of ctx.input.files) {\n if (!file.from || !file.to) {\n throw new InputError('each file must have a from and to property');\n }\n\n const sourceFilepath = resolveSafeChildPath(\n ctx.workspacePath,\n file.from,\n );\n const destFilepath = resolveSafeChildPath(ctx.workspacePath, file.to);\n\n try {\n await fs.move(sourceFilepath, destFilepath, {\n overwrite: file.overwrite ?? false,\n });\n ctx.logger.info(\n `File ${sourceFilepath} renamed to ${destFilepath} successfully`,\n );\n } catch (err) {\n ctx.logger.error(\n `Failed to rename file ${sourceFilepath} to ${destFilepath}:`,\n err,\n );\n throw err;\n }\n }\n },\n });\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport { Config } from '@backstage/config';\nimport {\n DefaultGithubCredentialsProvider,\n GithubCredentialsProvider,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n createCatalogRegisterAction,\n createCatalogWriteAction,\n createFetchCatalogEntityAction,\n} from './catalog';\n\nimport { createDebugLogAction, createWaitAction } from './debug';\nimport {\n createFetchPlainAction,\n createFetchPlainFileAction,\n createFetchTemplateAction,\n} from './fetch';\nimport {\n createFilesystemDeleteAction,\n createFilesystemRenameAction,\n} from './filesystem';\nimport {\n createGithubActionsDispatchAction,\n createGithubAutolinksAction,\n createGithubDeployKeyAction,\n createGithubEnvironmentAction,\n createGithubIssuesLabelAction,\n createGithubRepoCreateAction,\n createGithubRepoPushAction,\n createGithubWebhookAction,\n createPublishGithubAction,\n createPublishGithubPullRequestAction,\n} from '@backstage/plugin-scaffolder-backend-module-github';\n\nimport { createPublishAzureAction } from '@backstage/plugin-scaffolder-backend-module-azure';\n\nimport { createPublishBitbucketAction } from '@backstage/plugin-scaffolder-backend-module-bitbucket';\n\nimport {\n createPublishBitbucketCloudAction,\n createBitbucketPipelinesRunAction,\n} from '@backstage/plugin-scaffolder-backend-module-bitbucket-cloud';\n\nimport {\n createPublishBitbucketServerAction,\n createPublishBitbucketServerPullRequestAction,\n} from '@backstage/plugin-scaffolder-backend-module-bitbucket-server';\n\nimport {\n createPublishGerritAction,\n createPublishGerritReviewAction,\n} from '@backstage/plugin-scaffolder-backend-module-gerrit';\n\nimport {\n createPublishGitlabAction,\n createGitlabRepoPushAction,\n createPublishGitlabMergeRequestAction,\n} from '@backstage/plugin-scaffolder-backend-module-gitlab';\n\nimport { createPublishGiteaAction } from '@backstage/plugin-scaffolder-backend-module-gitea';\nimport { AuthService } from '@backstage/backend-plugin-api';\n\n/**\n * The options passed to {@link createBuiltinActions}\n * @public\n */\nexport interface CreateBuiltInActionsOptions {\n /**\n * The {@link @backstage/backend-common#UrlReader} interface that will be used in the default actions.\n */\n reader: UrlReader;\n /**\n * The {@link @backstage/integrations#ScmIntegrations} that will be used in the default actions.\n */\n integrations: ScmIntegrations;\n /**\n * The {@link @backstage/catalog-client#CatalogApi} that will be used in the default actions.\n */\n catalogClient: CatalogApi;\n /**\n * The {@link @backstage/backend-plugin-api#AuthService} that will be used in the default actions.\n */\n auth?: AuthService;\n /**\n * The {@link @backstage/config#Config} that will be used in the default actions.\n */\n config: Config;\n /**\n * Additional custom filters that will be passed to the nunjucks template engine for use in\n * Template Manifests and also template skeleton files when using `fetch:template`.\n */\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n}\n\n/**\n * A function to generate create a list of default actions that the scaffolder provides.\n * Is called internally in the default setup, but can be used when adding your own actions or overriding the default ones\n *\n * TODO(blam): version 2 of the scaffolder shouldn't ship with the additional modules. We should ship the basics, and let people install\n * modules for the providers they want to use.\n * @public\n * @returns A list of actions that can be used in the scaffolder\n *\n */\nexport const createBuiltinActions = (\n options: CreateBuiltInActionsOptions,\n): TemplateAction[] => {\n const {\n reader,\n integrations,\n catalogClient,\n auth,\n config,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n } = options;\n\n const githubCredentialsProvider: GithubCredentialsProvider =\n DefaultGithubCredentialsProvider.fromIntegrations(integrations);\n\n const actions = [\n createFetchPlainAction({\n reader,\n integrations,\n }),\n createFetchPlainFileAction({\n reader,\n integrations,\n }),\n createFetchTemplateAction({\n integrations,\n reader,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n }),\n createPublishGerritAction({\n integrations,\n config,\n }),\n createPublishGerritReviewAction({\n integrations,\n config,\n }),\n createPublishGiteaAction({\n integrations,\n config,\n }),\n createPublishGithubAction({\n integrations,\n config,\n githubCredentialsProvider,\n }),\n createPublishGithubPullRequestAction({\n integrations,\n githubCredentialsProvider,\n config,\n }),\n createPublishGitlabAction({\n integrations,\n config,\n }),\n createPublishGitlabMergeRequestAction({\n integrations,\n }),\n createGitlabRepoPushAction({\n integrations,\n }),\n createPublishBitbucketAction({\n integrations,\n config,\n }),\n createPublishBitbucketCloudAction({\n integrations,\n config,\n }),\n createPublishBitbucketServerAction({\n integrations,\n config,\n }),\n createPublishBitbucketServerPullRequestAction({\n integrations,\n config,\n }),\n createPublishAzureAction({\n integrations,\n config,\n }),\n createDebugLogAction(),\n createWaitAction(),\n createCatalogRegisterAction({ catalogClient, integrations, auth }),\n createFetchCatalogEntityAction({ catalogClient, auth }),\n createCatalogWriteAction(),\n createFilesystemDeleteAction(),\n createFilesystemRenameAction(),\n createGithubActionsDispatchAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubWebhookAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubIssuesLabelAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubRepoCreateAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubRepoPushAction({\n integrations,\n config,\n githubCredentialsProvider,\n }),\n createGithubEnvironmentAction({\n integrations,\n }),\n createGithubDeployKeyAction({\n integrations,\n }),\n createGithubAutolinksAction({\n integrations,\n githubCredentialsProvider,\n }),\n createBitbucketPipelinesRunAction({\n integrations,\n }),\n ];\n\n return actions as TemplateAction[];\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { TemplateAction } from '@backstage/plugin-scaffolder-node';\n/**\n * Registry of all registered template actions.\n * @public\n */\nexport class TemplateActionRegistry {\n private readonly actions = new Map();\n\n register(action: TemplateAction) {\n if (this.actions.has(action.id)) {\n throw new ConflictError(\n `Template action with ID '${action.id}' has already been registered`,\n );\n }\n\n this.actions.set(action.id, action);\n }\n\n get(actionId: string): TemplateAction {\n const action = this.actions.get(actionId);\n if (!action) {\n throw new NotFoundError(\n `Template action with ID '${actionId}' is not registered.`,\n );\n }\n return action;\n }\n\n list(): TemplateAction[] {\n return [...this.actions.values()];\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SerializedTaskEvent } from '@backstage/plugin-scaffolder-node';\nimport { TaskRecoverStrategy } from '@backstage/plugin-scaffolder-common';\n\nexport const trimEventsTillLastRecovery = (\n events: SerializedTaskEvent[],\n): { events: SerializedTaskEvent[] } => {\n const recoveredEventInd = events\n .slice()\n .reverse()\n .findIndex(event => event.type === 'recovered');\n\n if (recoveredEventInd >= 0) {\n const ind = events.length - recoveredEventInd - 1;\n const { recoverStrategy } = events[ind].body as {\n recoverStrategy: TaskRecoverStrategy;\n };\n if (recoverStrategy === 'startOver') {\n return {\n events: recoveredEventInd === 0 ? [] : events.slice(ind),\n };\n }\n }\n\n return { events };\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Knex } from 'knex';\n\nexport const intervalFromNowTill = (timeoutS: number, knex: Knex) => {\n let heartbeatInterval = knex.raw(`? - interval '${timeoutS} seconds'`, [\n knex.fn.now(),\n ]);\n if (knex.client.config.client.includes('mysql')) {\n heartbeatInterval = knex.raw(\n `date_sub(now(), interval ${timeoutS} second)`,\n );\n } else if (knex.client.config.client.includes('sqlite3')) {\n heartbeatInterval = knex.raw(`datetime('now', ?)`, [\n `-${timeoutS} seconds`,\n ]);\n }\n return heartbeatInterval;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { PluginDatabaseManager } from '@backstage/backend-common';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport {\n TaskStore,\n TaskStoreEmitOptions,\n TaskStoreListEventsOptions,\n TaskStoreCreateTaskOptions,\n TaskStoreCreateTaskResult,\n TaskStoreShutDownTaskOptions,\n TaskStoreRecoverTaskOptions,\n} from './types';\nimport {\n SerializedTaskEvent,\n SerializedTask,\n TaskStatus,\n TaskEventType,\n TaskSecrets,\n} from '@backstage/plugin-scaffolder-node';\nimport { DateTime, Duration } from 'luxon';\nimport { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { trimEventsTillLastRecovery } from './taskRecoveryHelper';\nimport { intervalFromNowTill } from './dbUtil';\nimport {\n restoreWorkspace,\n serializeWorkspace,\n} from '@backstage/plugin-scaffolder-node/alpha';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-scaffolder-backend',\n 'migrations',\n);\n\nexport type RawDbTaskRow = {\n id: string;\n spec: string;\n status: TaskStatus;\n state?: string;\n last_heartbeat_at?: string;\n created_at: string;\n created_by: string | null;\n secrets?: string | null;\n workspace?: Buffer;\n};\n\nexport type RawDbTaskEventRow = {\n id: number;\n task_id: string;\n body: string;\n event_type: TaskEventType;\n created_at: string;\n};\n\n/**\n * DatabaseTaskStore\n *\n * @public\n */\nexport type DatabaseTaskStoreOptions = {\n database: PluginDatabaseManager | Knex;\n};\n\n/**\n * Type guard to help DatabaseTaskStore understand when database is PluginDatabaseManager vs. when database is a Knex instance.\n *\n * * @public\n */\nfunction isPluginDatabaseManager(\n opt: PluginDatabaseManager | Knex,\n): opt is PluginDatabaseManager {\n return (opt as PluginDatabaseManager).getClient !== undefined;\n}\n\nconst parseSqlDateToIsoString = (input: T): T | string => {\n if (typeof input === 'string') {\n const parsed = DateTime.fromSQL(input, { zone: 'UTC' });\n if (!parsed.isValid) {\n throw new Error(\n `Failed to parse database timestamp '${input}', ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n return parsed.toISO()!;\n }\n\n return input;\n};\n\n/**\n * DatabaseTaskStore\n *\n * @public\n */\nexport class DatabaseTaskStore implements TaskStore {\n private readonly db: Knex;\n\n static async create(\n options: DatabaseTaskStoreOptions,\n ): Promise {\n const { database } = options;\n const client = await this.getClient(database);\n\n await this.runMigrations(database, client);\n\n return new DatabaseTaskStore(client);\n }\n\n private isRecoverableTask(spec: TaskSpec): boolean {\n return ['startOver'].includes(\n spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n );\n }\n\n private parseSpec({ spec, id }: { spec: string; id: string }): TaskSpec {\n try {\n return JSON.parse(spec);\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${id}', ${error}`);\n }\n }\n\n private parseTaskSecrets(taskRow: RawDbTaskRow): TaskSecrets | undefined {\n try {\n return taskRow.secrets ? JSON.parse(taskRow.secrets) : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse secrets of task '${taskRow.id}', ${error}`,\n );\n }\n }\n\n private static async getClient(\n database: PluginDatabaseManager | Knex,\n ): Promise {\n if (isPluginDatabaseManager(database)) {\n return database.getClient();\n }\n\n return database;\n }\n\n private static async runMigrations(\n database: PluginDatabaseManager | Knex,\n client: Knex,\n ): Promise {\n if (!isPluginDatabaseManager(database)) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n\n return;\n }\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n }\n\n private constructor(client: Knex) {\n this.db = client;\n }\n\n async list(options: {\n createdBy?: string;\n }): Promise<{ tasks: SerializedTask[] }> {\n const queryBuilder = this.db('tasks');\n\n if (options.createdBy) {\n queryBuilder.where({\n created_by: options.createdBy,\n });\n }\n\n const results = await queryBuilder.orderBy('created_at', 'desc').select();\n\n const tasks = results.map(result => ({\n id: result.id,\n spec: JSON.parse(result.spec),\n status: result.status,\n createdBy: result.created_by ?? undefined,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n }));\n\n return { tasks };\n }\n\n async getTask(taskId: string): Promise {\n const [result] = await this.db('tasks')\n .where({ id: taskId })\n .select();\n if (!result) {\n throw new NotFoundError(`No task with id '${taskId}' found`);\n }\n try {\n const spec = JSON.parse(result.spec);\n const secrets = result.secrets ? JSON.parse(result.secrets) : undefined;\n const state = result.state ? JSON.parse(result.state).state : undefined;\n return {\n id: result.id,\n spec,\n status: result.status,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n createdBy: result.created_by ?? undefined,\n secrets,\n state,\n };\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${taskId}', ${error}`);\n }\n }\n\n async createTask(\n options: TaskStoreCreateTaskOptions,\n ): Promise {\n const taskId = uuid();\n await this.db('tasks').insert({\n id: taskId,\n spec: JSON.stringify(options.spec),\n secrets: options.secrets ? JSON.stringify(options.secrets) : undefined,\n created_by: options.createdBy ?? null,\n status: 'open',\n });\n return { taskId };\n }\n\n async claimTask(): Promise {\n return this.db.transaction(async tx => {\n const [task] = await tx('tasks')\n .where({\n status: 'open',\n })\n .limit(1)\n .select();\n\n if (!task) {\n return undefined;\n }\n\n const spec = this.parseSpec(task);\n\n const updateCount = await tx('tasks')\n .where({ id: task.id, status: 'open' })\n .update({\n status: 'processing',\n last_heartbeat_at: this.db.fn.now(),\n // remove the secrets for non-recoverable tasks when moving to processing state.\n secrets: this.isRecoverableTask(spec) ? task.secrets : null,\n });\n\n if (updateCount < 1) {\n return undefined;\n }\n\n const getState = () => {\n try {\n return task.state ? JSON.parse(task.state).state : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse state of the task '${task.id}', ${error}`,\n );\n }\n };\n\n const secrets = this.parseTaskSecrets(task);\n return {\n id: task.id,\n spec,\n status: 'processing',\n lastHeartbeatAt: task.last_heartbeat_at,\n createdAt: task.created_at,\n createdBy: task.created_by ?? undefined,\n secrets,\n state: getState(),\n };\n });\n }\n\n async heartbeatTask(taskId: string): Promise {\n const updateCount = await this.db('tasks')\n .where({ id: taskId, status: 'processing' })\n .update({\n last_heartbeat_at: this.db.fn.now(),\n });\n if (updateCount === 0) {\n throw new ConflictError(`No running task with taskId ${taskId} found`);\n }\n }\n\n async listStaleTasks(options: { timeoutS: number }): Promise<{\n tasks: { taskId: string; recovery?: TaskRecovery }[];\n }> {\n const { timeoutS } = options;\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n const rawRows = await this.db('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval);\n const tasks = rawRows.map(row => ({\n recovery: (JSON.parse(row.spec) as TaskSpec).EXPERIMENTAL_recovery,\n taskId: row.id,\n }));\n return { tasks };\n }\n\n async completeTask(options: {\n taskId: string;\n status: TaskStatus;\n eventBody: JsonObject;\n }): Promise {\n const { taskId, status, eventBody } = options;\n\n let oldStatus: TaskStatus;\n if (['failed', 'completed', 'cancelled'].includes(status)) {\n oldStatus = 'processing';\n } else {\n throw new Error(\n `Invalid status update of run '${taskId}' to status '${status}'`,\n );\n }\n\n await this.db.transaction(async tx => {\n const [task] = await tx('tasks')\n .where({\n id: taskId,\n })\n .limit(1)\n .select();\n\n const updateTask = async (criteria: {\n id: string;\n status?: TaskStatus;\n }) => {\n const updateCount = await tx('tasks')\n .where(criteria)\n .update({\n status,\n secrets: null,\n });\n\n if (updateCount !== 1) {\n throw new ConflictError(\n `Failed to update status to '${status}' for taskId ${taskId}`,\n );\n }\n\n await tx('task_events').insert({\n task_id: taskId,\n event_type: 'completion',\n body: JSON.stringify(eventBody),\n });\n };\n\n if (status === 'cancelled') {\n await updateTask({\n id: taskId,\n });\n return;\n }\n\n if (task.status === 'cancelled') {\n return;\n }\n\n if (!task) {\n throw new Error(`No task with taskId ${taskId} found`);\n }\n if (task.status !== oldStatus) {\n throw new ConflictError(\n `Refusing to update status of run '${taskId}' to status '${status}' ` +\n `as it is currently '${task.status}', expected '${oldStatus}'`,\n );\n }\n\n await updateTask({\n id: taskId,\n status: oldStatus,\n });\n });\n }\n\n async emitLogEvent(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n await this.db('task_events').insert({\n task_id: taskId,\n event_type: 'log',\n body: serializedBody,\n });\n }\n\n async getTaskState({ taskId }: { taskId: string }): Promise<\n | {\n state: JsonObject;\n }\n | undefined\n > {\n const [result] = await this.db('tasks')\n .where({ id: taskId })\n .select('state');\n return result.state ? JSON.parse(result.state) : undefined;\n }\n\n async saveTaskState(options: {\n taskId: string;\n state?: JsonObject;\n }): Promise {\n if (options.state) {\n const serializedState = JSON.stringify({ state: options.state });\n await this.db('tasks')\n .where({ id: options.taskId })\n .update({\n state: serializedState,\n });\n }\n }\n\n async listEvents(\n options: TaskStoreListEventsOptions,\n ): Promise<{ events: SerializedTaskEvent[] }> {\n const { taskId, after } = options;\n const rawEvents = await this.db('task_events')\n .where({\n task_id: taskId,\n })\n .andWhere(builder => {\n if (typeof after === 'number') {\n builder.where('id', '>', after).orWhere('event_type', 'completion');\n }\n })\n .orderBy('id')\n .select();\n\n const events = rawEvents.map(event => {\n try {\n const body = JSON.parse(event.body) as JsonObject;\n return {\n id: Number(event.id),\n taskId,\n body,\n type: event.event_type,\n createdAt: parseSqlDateToIsoString(event.created_at),\n };\n } catch (error) {\n throw new Error(\n `Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`,\n );\n }\n });\n\n return trimEventsTillLastRecovery(events);\n }\n\n async shutdownTask(options: TaskStoreShutDownTaskOptions): Promise {\n const { taskId } = options;\n const message = `This task was marked as stale as it exceeded its timeout`;\n\n const statusStepEvents = (await this.listEvents({ taskId })).events.filter(\n ({ body }) => body?.stepId,\n );\n\n const completedSteps = statusStepEvents\n .filter(\n ({ body: { status } }) => status === 'failed' || status === 'completed',\n )\n .map(step => step.body.stepId);\n\n const hungProcessingSteps = statusStepEvents\n .filter(({ body: { status } }) => status === 'processing')\n .map(event => event.body.stepId)\n .filter(step => !completedSteps.includes(step));\n\n for (const step of hungProcessingSteps) {\n await this.emitLogEvent({\n taskId,\n body: {\n message,\n stepId: step,\n status: 'failed',\n },\n });\n }\n\n await this.completeTask({\n taskId,\n status: 'failed',\n eventBody: {\n message,\n },\n });\n }\n\n async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n const [result] = await this.db('tasks')\n .where({ id: options.taskId })\n .select('workspace');\n\n await restoreWorkspace({\n path: options.targetPath,\n buffer: result.workspace,\n });\n }\n\n async cleanWorkspace({ taskId }: { taskId: string }): Promise {\n await this.db('tasks').where({ id: taskId }).update({\n workspace: undefined,\n });\n }\n\n async serializeWorkspace(options: {\n path: string;\n taskId: string;\n }): Promise {\n if (options.path) {\n await this.db('tasks')\n .where({ id: options.taskId })\n .update({\n workspace: (await serializeWorkspace(options)).contents,\n });\n }\n }\n\n async cancelTask(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n await this.db('task_events').insert({\n task_id: taskId,\n event_type: 'cancelled',\n body: serializedBody,\n });\n }\n\n async recoverTasks(\n options: TaskStoreRecoverTaskOptions,\n ): Promise<{ ids: string[] }> {\n const taskIdsToRecover: string[] = [];\n const timeoutS = Duration.fromObject(options.timeout).as('seconds');\n\n await this.db.transaction(async tx => {\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n\n const result = await tx('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval)\n .update(\n {\n status: 'open',\n last_heartbeat_at: this.db.fn.now(),\n },\n ['id', 'spec'],\n );\n\n taskIdsToRecover.push(...result.map(i => i.id));\n\n for (const { id, spec } of result) {\n const taskSpec = JSON.parse(spec as string) as TaskSpec;\n await tx('task_events').insert({\n task_id: id,\n event_type: 'recovered',\n body: JSON.stringify({\n recoverStrategy:\n taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n }),\n });\n }\n });\n\n return { ids: taskIdsToRecover };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\nimport { isArray } from 'lodash';\nimport { Schema } from 'jsonschema';\n\n/**\n * Returns true if the input is not `false`, `undefined`, `null`, `\"\"`, `0`, or\n * `[]`. This behavior is based on the behavior of handlebars, see\n * https://handlebarsjs.com/guide/builtin-helpers.html#if\n */\nexport function isTruthy(value: any): boolean {\n return isArray(value) ? value.length > 0 : !!value;\n}\n\nexport function generateExampleOutput(schema: Schema): unknown {\n const { examples } = schema as { examples?: unknown };\n if (examples && Array.isArray(examples)) {\n return examples[0];\n }\n if (schema.type === 'object') {\n return Object.fromEntries(\n Object.entries(schema.properties ?? {}).map(([key, value]) => [\n key,\n generateExampleOutput(value),\n ]),\n );\n } else if (schema.type === 'array') {\n const [firstSchema] = [schema.items]?.flat();\n if (firstSchema) {\n return [generateExampleOutput(firstSchema)];\n }\n return [];\n } else if (schema.type === 'string') {\n return '';\n } else if (schema.type === 'number') {\n return 0;\n } else if (schema.type === 'boolean') {\n return false;\n }\n return '';\n}\n\nexport const readDuration = (\n config: Config | undefined,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config?.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TaskStore } from './types';\n\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\nexport class DatabaseWorkspaceProvider implements WorkspaceProvider {\n static create(storage: TaskStore) {\n return new DatabaseWorkspaceProvider(storage);\n }\n\n private constructor(private readonly storage: TaskStore) {}\n\n public async serializeWorkspace(options: {\n path: string;\n taskId: string;\n }): Promise {\n this.storage.serializeWorkspace?.(options);\n }\n\n public async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n return this.storage.rehydrateWorkspace?.(options);\n }\n\n public async cleanWorkspace(options: { taskId: string }): Promise {\n return this.storage.cleanWorkspace?.(options);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { CurrentClaimedTask } from './StorageTaskBroker';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\nimport { DatabaseWorkspaceProvider } from './DatabaseWorkspaceProvider';\nimport { TaskStore } from './types';\n\nexport interface WorkspaceService {\n serializeWorkspace(options: { path: string }): Promise;\n\n cleanWorkspace(): Promise;\n\n rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise;\n}\n\nexport class DefaultWorkspaceService implements WorkspaceService {\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n additionalWorkspaceProviders?: Record,\n config?: Config,\n ) {\n const workspaceProviderName =\n config?.getOptionalString(\n 'scaffolder.EXPERIMENTAL_workspaceSerializationProvider',\n ) ?? 'database';\n const workspaceProvider =\n additionalWorkspaceProviders?.[workspaceProviderName] ??\n DatabaseWorkspaceProvider.create(storage);\n return new DefaultWorkspaceService(task, workspaceProvider, config);\n }\n\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly workspaceProvider: WorkspaceProvider,\n private readonly config?: Config,\n ) {}\n\n public async serializeWorkspace(options: { path: string }): Promise {\n if (this.isWorkspaceSerializationEnabled()) {\n await this.workspaceProvider.serializeWorkspace({\n path: options.path,\n taskId: this.task.taskId,\n });\n }\n }\n\n public async cleanWorkspace(): Promise {\n if (this.isWorkspaceSerializationEnabled()) {\n await this.workspaceProvider.cleanWorkspace({ taskId: this.task.taskId });\n }\n }\n\n public async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n if (this.isWorkspaceSerializationEnabled()) {\n await this.workspaceProvider.rehydrateWorkspace(options);\n }\n }\n\n private isWorkspaceSerializationEnabled(): boolean {\n return (\n this.config?.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_workspaceSerialization',\n ) ?? false\n );\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Logger } from 'winston';\nimport ObservableImpl from 'zen-observable';\nimport {\n TaskSecrets,\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { readDuration } from './helper';\nimport {\n AuthService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\ntype TaskState = {\n checkpoints: {\n [key: string]:\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n };\n};\n/**\n * TaskManager\n *\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: Logger,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: Logger,\n private readonly workspaceService: WorkspaceService,\n private readonly auth?: AuthService,\n ) {}\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(\n options:\n | {\n key: string;\n status: 'success';\n value: JsonValue;\n }\n | {\n key: string;\n status: 'failed';\n reason: string;\n },\n ): Promise {\n const { key, ...value } = options;\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n\n workspace?: Promise;\n}\n\nfunction defer() {\n let resolve = () => {};\n const promise = new Promise(_resolve => {\n resolve = _resolve;\n });\n return { promise, resolve };\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: Logger,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n ) {}\n\n async list(options?: {\n createdBy?: string;\n }): Promise<{ tasks: SerializedTask[] }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list({ createdBy: options?.createdBy });\n }\n\n private deferredDispatch = defer();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion') {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise {\n const enabled =\n (this.config &&\n this.config.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_recoverTasks',\n )) ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n while (!cancelled) {\n const result = await this.storage.listEvents({ taskId, after });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n try {\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n } catch (error) {\n this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch.promise;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = defer();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Counter,\n CounterConfiguration,\n Gauge,\n GaugeConfiguration,\n Histogram,\n HistogramConfiguration,\n register,\n Summary,\n SummaryConfiguration,\n} from 'prom-client';\n\nexport function createCounterMetric(\n config: CounterConfiguration,\n): Counter {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Counter(config);\n register.registerMetric(metric);\n }\n return metric as Counter;\n}\n\nexport function createGaugeMetric(\n config: GaugeConfiguration,\n): Gauge {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Gauge(config);\n register.registerMetric(metric);\n }\n return metric as Gauge;\n}\n\nexport function createSummaryMetric(\n config: SummaryConfiguration,\n): Summary {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Summary(config);\n register.registerMetric(metric);\n }\n\n return metric as Summary;\n}\n\nexport function createHistogramMetric(\n config: HistogramConfiguration,\n): Histogram {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Histogram(config);\n register.registerMetric(metric);\n }\n\n return metric as Histogram;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeCreatePermissionRule } from '@backstage/plugin-permission-node';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n} from '@backstage/plugin-scaffolder-common/alpha';\n\nimport {\n TemplateEntityStepV1beta3,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\n\nimport { z } from 'zod';\nimport { JsonObject, JsonPrimitive } from '@backstage/types';\nimport { get } from 'lodash';\n\nexport const createTemplatePermissionRule = makeCreatePermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE\n>();\n\nexport const hasTag = createTemplatePermissionRule({\n name: 'HAS_TAG',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n description: `Match parameters or steps with the given tag`,\n paramsSchema: z.object({\n tag: z.string().describe('Name of the tag to match on'),\n }),\n apply: (resource, { tag }) => {\n return resource['backstage:permissions']?.tags?.includes(tag) ?? false;\n },\n toQuery: () => ({}),\n});\n\nexport const createActionPermissionRule = makeCreatePermissionRule<\n {\n action: string;\n input: JsonObject | undefined;\n },\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION\n>();\n\nexport const hasActionId = createActionPermissionRule({\n name: 'HAS_ACTION_ID',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n description: `Match actions with the given actionId`,\n paramsSchema: z.object({\n actionId: z.string().describe('Name of the actionId to match on'),\n }),\n apply: (resource, { actionId }) => {\n return resource.action === actionId;\n },\n toQuery: () => ({}),\n});\n\nexport const hasProperty = buildHasProperty({\n name: 'HAS_PROPERTY',\n valueSchema: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n validateProperty: false,\n});\n\nexport const hasBooleanProperty = buildHasProperty({\n name: 'HAS_BOOLEAN_PROPERTY',\n valueSchema: z.boolean(),\n});\nexport const hasNumberProperty = buildHasProperty({\n name: 'HAS_NUMBER_PROPERTY',\n valueSchema: z.number(),\n});\nexport const hasStringProperty = buildHasProperty({\n name: 'HAS_STRING_PROPERTY',\n valueSchema: z.string(),\n});\n\nfunction buildHasProperty>({\n name,\n valueSchema,\n validateProperty = true,\n}: {\n name: string;\n valueSchema: Schema;\n validateProperty?: boolean;\n}) {\n return createActionPermissionRule({\n name,\n description: `Allow actions with the specified property`,\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n paramsSchema: z.object({\n key: z\n .string()\n .describe(`Property within the action parameters to match on`),\n value: valueSchema\n .optional()\n .describe(`Value of the given property to match on`),\n }) as unknown as z.ZodType<{ key: string; value?: z.infer }>,\n apply: (resource, { key, value }) => {\n const foundValue = get(resource.input, key);\n\n if (validateProperty && !valueSchema.safeParse(foundValue).success) {\n return false;\n }\n if (value !== undefined) {\n if (valueSchema.safeParse(value).success) {\n return value === foundValue;\n }\n return false;\n }\n\n return foundValue !== undefined;\n },\n toQuery: () => ({}),\n });\n}\n\nexport const scaffolderTemplateRules = { hasTag };\nexport const scaffolderActionRules = {\n hasActionId,\n hasBooleanProperty,\n hasNumberProperty,\n hasStringProperty,\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n LoggerService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { Format, TransformableInfo } from 'logform';\nimport Transport, { TransportStreamOptions } from 'winston-transport';\nimport { Logger, format, createLogger, transports } from 'winston';\nimport { LEVEL, MESSAGE, SPLAT } from 'triple-beam';\nimport { TaskContext } from '@backstage/plugin-scaffolder-node';\nimport _ from 'lodash';\n\n/**\n * Escapes a given string to be used inside a RegExp.\n *\n * Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\n */\nconst escapeRegExp = (text: string) => {\n return text.replace(/[.*+?^${}(\\)|[\\]\\\\]/g, '\\\\$&');\n};\n\ninterface WinstonLoggerOptions {\n meta?: JsonObject;\n level: string;\n format: Format;\n transports: Transport[];\n}\n\n// This is a workaround for being able to preserve the log format of the root logger.\n// Will revisit all of this implementation once we can break the router to use only `LoggerService`.\nexport class BackstageLoggerTransport extends Transport {\n constructor(\n private readonly backstageLogger: LoggerService,\n private readonly taskContext: TaskContext,\n private readonly stepId: string,\n opts?: TransportStreamOptions,\n ) {\n super(opts);\n }\n\n log(info: TransformableInfo, callback: VoidFunction) {\n if (typeof info !== 'object' || info === null) {\n callback();\n return;\n }\n\n const message = info[MESSAGE];\n const level = info[LEVEL];\n const splat = info[SPLAT];\n\n switch (level) {\n case 'error':\n this.backstageLogger.error(String(message), ...splat);\n break;\n case 'warn':\n this.backstageLogger.warn(String(message), ...splat);\n break;\n case 'info':\n this.backstageLogger.info(String(message), ...splat);\n break;\n case 'debug':\n this.backstageLogger.debug(String(message), ...splat);\n break;\n default:\n this.backstageLogger.info(String(message), ...splat);\n }\n\n this.taskContext.emitLog(message, { stepId: this.stepId });\n callback();\n }\n}\n\nexport class WinstonLogger implements RootLoggerService {\n #winston: Logger;\n #addRedactions?: (redactions: Iterable) => void;\n\n /**\n * Creates a {@link WinstonLogger} instance.\n */\n static create(options: WinstonLoggerOptions): WinstonLogger {\n const redacter = WinstonLogger.redacter();\n\n let logger = createLogger({\n level: options.level,\n format: format.combine(options.format, redacter.format),\n transports: options.transports ?? new transports.Console(),\n });\n\n if (options.meta) {\n logger = logger.child(options.meta);\n }\n\n return new WinstonLogger(logger, redacter.add);\n }\n\n /**\n * Creates a winston log formatter for redacting secrets.\n */\n static redacter(): {\n format: Format;\n add: (redactions: Iterable) => void;\n } {\n const redactionSet = new Set();\n\n let redactionPattern: RegExp | undefined = undefined;\n\n return {\n format: format((obj: TransformableInfo) => {\n if (!redactionPattern || !obj) {\n return obj;\n }\n\n obj[MESSAGE] = obj[MESSAGE]?.replace?.(redactionPattern, '***');\n\n return obj;\n })(),\n add(newRedactions) {\n let added = 0;\n for (const redactionToTrim of newRedactions) {\n // Trimming the string ensures that we don't accdentally get extra\n // newlines or other whitespace interfering with the redaction; this\n // can happen for example when using string literals in yaml\n const redaction = redactionToTrim.trim();\n // Exclude secrets that are empty or just one character in length. These\n // typically mean that you are running local dev or tests, or using the\n // --lax flag which sets things to just 'x'.\n if (redaction.length <= 1) {\n continue;\n }\n if (!redactionSet.has(redaction)) {\n redactionSet.add(redaction);\n added += 1;\n }\n }\n if (added > 0) {\n const redactions = Array.from(redactionSet)\n .map(r => escapeRegExp(r))\n .join('|');\n redactionPattern = new RegExp(`(${redactions})`, 'g');\n }\n },\n };\n }\n\n /**\n * Creates a pretty printed winston log formatter.\n */\n static colorFormat(): Format {\n const colorizer = format.colorize();\n\n return format.combine(\n format.timestamp(),\n format.colorize({\n colors: {\n timestamp: 'dim',\n prefix: 'blue',\n field: 'cyan',\n debug: 'grey',\n },\n }),\n format.printf((info: TransformableInfo) => {\n const { timestamp, plugin, service } = info;\n const message = info[MESSAGE];\n const level = info[LEVEL];\n const fields = info[SPLAT];\n const prefix = plugin || service;\n const timestampColor = colorizer.colorize('timestamp', timestamp);\n const prefixColor = colorizer.colorize('prefix', prefix);\n\n const extraFields = Object.entries(fields)\n .map(\n ([key, value]) =>\n `${colorizer.colorize('field', `${key}`)}=${value}`,\n )\n .join(' ');\n\n return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;\n }),\n );\n }\n\n private constructor(\n winston: Logger,\n addRedactions?: (redactions: Iterable) => void,\n ) {\n this.#winston = winston;\n this.#addRedactions = addRedactions;\n }\n\n error(message: string, meta?: JsonObject): void {\n this.#winston.error(message, meta);\n }\n\n warn(message: string, meta?: JsonObject): void {\n this.#winston.warn(message, meta);\n }\n\n info(message: string, meta?: JsonObject): void {\n this.#winston.info(message, meta);\n }\n\n debug(message: string, meta?: JsonObject): void {\n this.#winston.debug(message, meta);\n }\n\n child(meta: JsonObject): LoggerService {\n return new WinstonLogger(this.#winston.child(meta));\n }\n\n addRedactions(redactions: Iterable) {\n this.#addRedactions?.(redactions);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\nimport * as winston from 'winston';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport nunjucks from 'nunjucks';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { generateExampleOutput, isTruthy } from './helper';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport { TemplateActionRegistry } from '../actions';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\n\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { createDefaultFilters } from '../../lib/templating/filters';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: winston.Logger;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n};\n\ntype CheckpointState =\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: winston.Logger;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(task.secrets ?? {}));\n\n // This stream logger should be deprecated. We're going to replace it with\n // just using the logger directly, as all those logs get written to step logs\n // using the stepLogStream above.\n // Initially this stream used to be the only way to write to the client logs, but that\n // has changed over time, there's not really a need for this anymore.\n // You can just create a simple wrapper like the below in your action to write to the main logger.\n // This way we also get recactions for free.\n const streamLogger = new PassThrough();\n streamLogger.on('data', async data => {\n const message = data.toString().trim();\n if (message?.length > 1) {\n taskLogger.info(message);\n }\n });\n\n return { taskLogger, streamLogger };\n};\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record;\n\n constructor(private readonly options: NunjucksWorkflowRunnerOptions) {\n this.defaultTemplateFilters = createDefaultFilters({\n integrations: this.options.integrations,\n });\n }\n\n private readonly tracker = scaffoldingTracker();\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n try {\n if (step.if) {\n const ifResult = this.render(step.if, context, renderTemplate);\n if (!isTruthy(ifResult)) {\n await stepTrack.skipFalsy();\n return;\n }\n }\n\n const action: TemplateAction =\n this.options.actionRegistry.get(step.action);\n const { taskLogger, streamLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n });\n\n if (task.isDryRun) {\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n const debugInput =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n debugInput,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n const iterations = (\n step.each\n ? Object.entries(this.render(step.each, context, renderTemplate)).map(\n ([key, value]) => ({\n each: { key, value },\n }),\n )\n : [{}]\n ).map(i => ({\n ...i,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(\n step.input,\n { ...context, secrets: task.secrets ?? {}, ...i },\n renderTemplate,\n )\n : {},\n }));\n for (const iteration of iterations) {\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n\n for (const iteration of iterations) {\n if (iteration.each) {\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? v.toString() : v),\n 0,\n )}`,\n );\n }\n await action.handler({\n input: iteration.input,\n secrets: task.secrets ?? {},\n // TODO(blam): move to LoggerService and away from Winston\n logger: loggerToWinstonLogger(taskLogger),\n logStream: streamLogger,\n workspacePath,\n async checkpoint(\n keySuffix: string,\n fn: () => Promise,\n ) {\n const key = `v1.task.checkpoint.${keySuffix}`;\n try {\n let prevValue: U | undefined;\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as {\n [key: string]: CheckpointState;\n }\n )?.[key];\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as U;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value,\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n });\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed();\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n steps: {},\n user: task.spec.user,\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n for (const step of task.spec.steps) {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n await taskTrack.markSuccessful();\n\n return { output };\n } finally {\n if (workspacePath) {\n await task.cleanWorkspace?.();\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker() {\n const taskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const taskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const stepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const stepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const taskTimer = taskDuration.startTimer({\n template,\n });\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n taskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n taskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n taskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const stepTimer = stepDuration.startTimer({\n template,\n step: step.name,\n });\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n stepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n }\n\n async function markCancelled() {\n stepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n }\n\n async function markFailed() {\n stepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WorkflowRunner } from './types';\nimport {\n TaskContext,\n TaskBroker,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport PQueue from 'p-queue';\nimport { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';\nimport { Logger } from 'winston';\nimport { TemplateActionRegistry } from '../actions';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { assertError, stringifyError } from '@backstage/errors';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\n\n/**\n * TaskWorkerOptions\n *\n * @public\n */\nexport type TaskWorkerOptions = {\n taskBroker: TaskBroker;\n runners: {\n workflowRunner: WorkflowRunner;\n };\n concurrentTasksLimit: number;\n permissions?: PermissionEvaluator;\n logger?: Logger;\n};\n\n/**\n * CreateWorkerOptions\n *\n * @public\n */\nexport type CreateWorkerOptions = {\n taskBroker: TaskBroker;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n workingDirectory: string;\n logger: Logger;\n additionalTemplateFilters?: Record;\n /**\n * The number of tasks that can be executed at the same time by the worker\n * @defaultValue 10\n * @example\n * ```\n * {\n * concurrentTasksLimit: 1,\n * // OR\n * concurrentTasksLimit: Infinity\n * }\n * ```\n */\n concurrentTasksLimit?: number;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * TaskWorker\n *\n * @public\n */\nexport class TaskWorker {\n private taskQueue: PQueue;\n private logger: Logger | undefined;\n private stopWorkers: boolean;\n\n private constructor(private readonly options: TaskWorkerOptions) {\n this.stopWorkers = false;\n this.logger = options.logger;\n this.taskQueue = new PQueue({\n concurrency: options.concurrentTasksLimit,\n });\n }\n\n static async create(options: CreateWorkerOptions): Promise {\n const {\n taskBroker,\n logger,\n actionRegistry,\n integrations,\n workingDirectory,\n additionalTemplateFilters,\n concurrentTasksLimit = 10, // from 1 to Infinity\n additionalTemplateGlobals,\n permissions,\n } = options;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n return new TaskWorker({\n taskBroker: taskBroker,\n runners: { workflowRunner },\n concurrentTasksLimit,\n permissions,\n });\n }\n\n async recoverTasks() {\n try {\n await this.options.taskBroker.recoverTasks?.();\n } catch (err) {\n this.logger?.error(stringifyError(err));\n }\n }\n\n start() {\n (async () => {\n while (!this.stopWorkers) {\n await new Promise(resolve => setTimeout(resolve, 10000));\n await this.recoverTasks();\n }\n })();\n (async () => {\n while (!this.stopWorkers) {\n await this.onReadyToClaimTask();\n if (!this.stopWorkers) {\n const task = await this.options.taskBroker.claim();\n void this.taskQueue.add(() => this.runOneTask(task));\n }\n }\n })();\n }\n\n stop() {\n this.stopWorkers = true;\n }\n\n protected onReadyToClaimTask(): Promise {\n if (this.taskQueue.pending < this.options.concurrentTasksLimit) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n // \"next\" event emits when a task completes\n // https://github.com/sindresorhus/p-queue#next\n this.taskQueue.once('next', () => {\n resolve();\n });\n });\n }\n\n async runOneTask(task: TaskContext) {\n try {\n if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {\n throw new Error(\n `Unsupported Template apiVersion ${task.spec.apiVersion}`,\n );\n }\n\n const { output } = await this.options.runners.workflowRunner.execute(\n task,\n );\n\n await task.complete('completed', { output });\n } catch (error) {\n assertError(error);\n await task.complete('failed', {\n error: { name: error.name, message: error.message },\n });\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\n\n/** @internal */\nexport class DecoratedActionsRegistry extends TemplateActionRegistry {\n constructor(\n private readonly innerRegistry: TemplateActionRegistry,\n extraActions: Array,\n ) {\n super();\n for (const action of extraActions) {\n this.register(action);\n }\n }\n\n get(actionId: string): TemplateAction {\n try {\n return super.get(actionId);\n } catch {\n return this.innerRegistry.get(actionId);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject } from '@backstage/types';\nimport { v4 as uuid } from 'uuid';\nimport { pathToFileURL } from 'url';\nimport { Logger } from 'winston';\nimport {\n createTemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n deserializeDirectoryContents,\n SerializedFile,\n serializeDirectoryContents,\n} from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\nimport { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';\nimport { DecoratedActionsRegistry } from './DecoratedActionsRegistry';\nimport fs from 'fs-extra';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n BackstageCredentials,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport type { UserEntity } from '@backstage/catalog-model';\n\ninterface DryRunInput {\n spec: TaskSpec;\n secrets?: TaskSecrets;\n directoryContents: SerializedFile[];\n credentials: BackstageCredentials;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n}\n\ninterface DryRunResult {\n log: Array<{ body: JsonObject }>;\n directoryContents: SerializedFile[];\n output: JsonObject;\n}\n\n/** @internal */\nexport type TemplateTesterCreateOptions = {\n logger: Logger;\n integrations: ScmIntegrations;\n actionRegistry: TemplateActionRegistry;\n workingDirectory: string;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * Executes a dry-run of the provided template.\n *\n * The provided content will be extracted into a temporary directory\n * which is then use as the base for any relative file fetch paths.\n *\n * @internal\n */\nexport function createDryRunner(options: TemplateTesterCreateOptions) {\n return async function dryRun(input: DryRunInput): Promise {\n let contentPromise;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n ...options,\n actionRegistry: new DecoratedActionsRegistry(options.actionRegistry, [\n createTemplateAction({\n id: 'dry-run:extract',\n supportsDryRun: true,\n async handler(ctx) {\n contentPromise = serializeDirectoryContents(ctx.workspacePath);\n await contentPromise.catch(() => {});\n },\n }),\n ]),\n });\n\n const dryRunId = uuid();\n const log = new Array<{ body: JsonObject }>();\n const contentsPath = resolveSafeChildPath(\n options.workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n\n try {\n await deserializeDirectoryContents(contentsPath, input.directoryContents);\n\n const abortSignal = new AbortController().signal;\n\n const result = await workflowRunner.execute({\n spec: {\n ...input.spec,\n steps: [\n ...input.spec.steps,\n {\n id: dryRunId,\n name: 'dry-run:extract',\n action: 'dry-run:extract',\n },\n ],\n templateInfo: {\n entityRef: 'template:default/dry-run',\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n },\n },\n secrets: input.secrets,\n getInitiatorCredentials: () => Promise.resolve(input.credentials),\n // No need to update this at the end of the run, so just hard-code it\n done: false,\n isDryRun: true,\n getWorkspaceName: async () => `dry-run-${dryRunId}`,\n cancelSignal: abortSignal,\n async emitLog(message: string, logMetadata?: JsonObject) {\n if (logMetadata?.stepId === dryRunId) {\n return;\n }\n log.push({\n body: {\n ...logMetadata,\n message,\n },\n });\n },\n complete: async () => {\n throw new Error('Not implemented');\n },\n });\n\n if (!contentPromise) {\n throw new Error('Content extraction step was skipped');\n }\n const directoryContents = await contentPromise;\n\n return {\n log,\n directoryContents,\n output: result.output,\n };\n } finally {\n await fs.remove(contentsPath);\n }\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n Entity,\n ANNOTATION_LOCATION,\n parseLocationRef,\n ANNOTATION_SOURCE_LOCATION,\n CompoundEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, InputError, NotFoundError } from '@backstage/errors';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport { Logger } from 'winston';\n\nexport async function getWorkingDirectory(\n config: Config,\n logger: Logger,\n): Promise {\n if (!config.has('backend.workingDirectory')) {\n return os.tmpdir();\n }\n\n const workingDirectory = config.getString('backend.workingDirectory');\n try {\n // Check if working directory exists and is writable\n await fs.access(workingDirectory, fs.constants.F_OK | fs.constants.W_OK);\n logger.info(`using working directory: ${workingDirectory}`);\n } catch (err) {\n assertError(err);\n logger.error(\n `working directory ${workingDirectory} ${\n err.code === 'ENOENT' ? 'does not exist' : 'is not writable'\n }`,\n );\n throw err;\n }\n return workingDirectory;\n}\n\n/**\n * Gets the base URL of the entity location that points to the source location\n * of the entity description within a repo. If there is not source location\n * or if it has an invalid type, undefined will be returned instead.\n *\n * For file locations this will return a `file://` URL.\n */\nexport function getEntityBaseUrl(entity: Entity): string | undefined {\n let location = entity.metadata.annotations?.[ANNOTATION_SOURCE_LOCATION];\n if (!location) {\n location = entity.metadata.annotations?.[ANNOTATION_LOCATION];\n }\n if (!location) {\n return undefined;\n }\n\n const { type, target } = parseLocationRef(location);\n if (type === 'url') {\n return target;\n } else if (type === 'file') {\n return `file://${target}`;\n }\n\n // Only url and file location are handled, as we otherwise don't know if\n // what the url is pointing to makes sense to use as a baseUrl\n return undefined;\n}\n\n/**\n * Will use the provided CatalogApi to go find the given template entity with an additional token.\n * Returns the matching template, or throws a NotFoundError if no such template existed.\n */\nexport async function findTemplate(options: {\n entityRef: CompoundEntityRef;\n token?: string;\n catalogApi: CatalogApi;\n}): Promise {\n const { entityRef, token, catalogApi } = options;\n\n if (entityRef.kind.toLocaleLowerCase('en-US') !== 'template') {\n throw new InputError(`Invalid kind, only 'Template' kind is supported`);\n }\n\n const template = await catalogApi.getEntityByRef(entityRef, { token });\n if (!template) {\n throw new NotFoundError(\n `Template ${stringifyEntityRef(entityRef)} not found`,\n );\n }\n\n return template as TemplateEntityV1beta3;\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n BasicPermission,\n} from '@backstage/plugin-permission-common';\n\nexport type checkPermissionOptions = {\n credentials: BackstageCredentials;\n permissions: BasicPermission[];\n permissionService?: PermissionsService;\n};\n\n/**\n * Does a basic check on permissions. Throws 403 error if any permission responds with AuthorizeResult.DENY\n * @public\n */\nexport async function checkPermission(options: checkPermissionOptions) {\n const { permissions, permissionService, credentials } = options;\n if (permissionService) {\n const permissionRequest = permissions.map(permission => ({\n permission,\n }));\n const authorizationResponses = await permissionService.authorize(\n permissionRequest,\n { credentials: credentials },\n );\n\n for (const response of authorizationResponses) {\n if (response.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n HostDiscovery,\n PluginDatabaseManager,\n UrlReader,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n CompoundEntityRef,\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { InputError, NotFoundError, stringifyError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { HumanDuration, JsonObject, JsonValue } from '@backstage/types';\nimport {\n TaskSpec,\n TemplateEntityV1beta3,\n templateEntityV1beta3Validator,\n TemplateParametersV1beta3,\n TemplateEntityStepV1beta3,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n scaffolderActionPermissions,\n scaffolderTemplatePermissions,\n taskCancelPermission,\n taskCreatePermission,\n taskReadPermission,\n templateParameterReadPermission,\n templateStepReadPermission,\n scaffolderTaskPermissions,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { validate } from 'jsonschema';\nimport { Logger } from 'winston';\nimport { z } from 'zod';\nimport {\n TemplateAction,\n TaskBroker,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n createBuiltinActions,\n DatabaseTaskStore,\n TaskWorker,\n TemplateActionRegistry,\n} from '../scaffolder';\nimport { createDryRunner } from '../scaffolder/dryrun';\nimport { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker';\nimport { findTemplate, getEntityBaseUrl, getWorkingDirectory } from './helpers';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport {\n createConditionAuthorizer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { scaffolderActionRules, scaffolderTemplateRules } from './rules';\nimport { Duration } from 'luxon';\nimport {\n AuthService,\n BackstageCredentials,\n DiscoveryService,\n HttpAuthService,\n LifecycleService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport {\n IdentityApi,\n IdentityApiGetIdentityRequest,\n} from '@backstage/plugin-auth-node';\nimport { InternalTaskSecrets } from '../scaffolder/tasks/types';\nimport { checkPermission } from '../util/checkPermissions';\nimport {\n AutocompleteHandler,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\n\n/**\n *\n * @public\n */\nexport type TemplatePermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n TParams\n>;\nfunction isTemplatePermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is TemplatePermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TEMPLATE;\n}\n\n/**\n *\n * @public\n */\nexport type ActionPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION,\n TParams\n>;\nfunction isActionPermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is ActionPermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_ACTION;\n}\n\n/**\n * RouterOptions\n *\n * @public\n */\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n reader: UrlReader;\n lifecycle?: LifecycleService;\n database: PluginDatabaseManager;\n catalogClient: CatalogApi;\n scheduler?: PluginTaskScheduler;\n actions?: TemplateAction[];\n /**\n * @deprecated taskWorkers is deprecated in favor of concurrentTasksLimit option with a single TaskWorker\n * @defaultValue 1\n */\n taskWorkers?: number;\n /**\n * Sets the number of concurrent tasks that can be run at any given time on the TaskWorker\n * @defaultValue 10\n */\n concurrentTasksLimit?: number;\n taskBroker?: TaskBroker;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n additionalWorkspaceProviders?: Record;\n permissions?: PermissionsService;\n permissionRules?: Array<\n TemplatePermissionRuleInput | ActionPermissionRuleInput\n >;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n identity?: IdentityApi;\n discovery?: DiscoveryService;\n\n autocompleteHandlers?: Record;\n}\n\nfunction isSupportedTemplate(entity: TemplateEntityV1beta3) {\n return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';\n}\n\n/*\n * @deprecated This function remains as the DefaultIdentityClient behaves slightly differently to the pre-existing\n * scaffolder behaviour. Specifically if the token fails to parse, the DefaultIdentityClient will raise an error.\n * The scaffolder did not raise an error in this case. As such we chose to allow it to behave as it did previously\n * until someone explicitly passes an IdentityApi. When we have reasonable confidence that most backstage deployments\n * are using the IdentityApi, we can remove this function.\n */\nfunction buildDefaultIdentityClient(options: RouterOptions): IdentityApi {\n return {\n getIdentity: async ({ request }: IdentityApiGetIdentityRequest) => {\n const header = request.headers.authorization;\n const { logger } = options;\n\n if (!header) {\n return undefined;\n }\n\n try {\n const token = header.match(/^Bearer\\s(\\S+\\.\\S+\\.\\S+)$/i)?.[1];\n if (!token) {\n throw new TypeError('Expected Bearer with JWT');\n }\n\n const [_header, rawPayload, _signature] = token.split('.');\n const payload: JsonValue = JSON.parse(\n Buffer.from(rawPayload, 'base64').toString(),\n );\n\n if (\n typeof payload !== 'object' ||\n payload === null ||\n Array.isArray(payload)\n ) {\n throw new TypeError('Malformed JWT payload');\n }\n\n const sub = payload.sub;\n if (typeof sub !== 'string') {\n throw new TypeError('Expected string sub claim');\n }\n\n if (sub === 'backstage-server') {\n return undefined;\n }\n\n // Check that it's a valid ref, otherwise this will throw.\n parseEntityRef(sub);\n\n return {\n identity: {\n userEntityRef: sub,\n ownershipEntityRefs: [],\n type: 'user',\n },\n token,\n };\n } catch (e) {\n logger.error(`Invalid authorization header: ${stringifyError(e)}`);\n return undefined;\n }\n },\n };\n}\n\nconst readDuration = (\n config: Config,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n\n/**\n * A method to create a router for the scaffolder backend plugin.\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = Router();\n // Be generous in upload size to support a wide range of templates in dry-run mode.\n router.use(express.json({ limit: '10MB' }));\n\n const {\n logger: parentLogger,\n config,\n reader,\n database,\n catalogClient,\n actions,\n taskWorkers,\n scheduler,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n additionalWorkspaceProviders,\n permissions,\n permissionRules,\n discovery = HostDiscovery.fromConfig(config),\n identity = buildDefaultIdentityClient(options),\n autocompleteHandlers = {},\n } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...options,\n identity,\n discovery,\n });\n\n const concurrentTasksLimit =\n options.concurrentTasksLimit ??\n options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');\n\n const logger = parentLogger.child({ plugin: 'scaffolder' });\n\n const workingDirectory = await getWorkingDirectory(config, logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n let taskBroker: TaskBroker;\n if (!options.taskBroker) {\n const databaseTaskStore = await DatabaseTaskStore.create({ database });\n taskBroker = new StorageTaskBroker(\n databaseTaskStore,\n logger,\n config,\n auth,\n additionalWorkspaceProviders,\n );\n\n if (scheduler && databaseTaskStore.listStaleTasks) {\n await scheduler.scheduleTask({\n id: 'close_stale_tasks',\n frequency: readDuration(\n config,\n 'scaffolder.taskTimeoutJanitorFrequency',\n {\n minutes: 5,\n },\n ),\n timeout: { minutes: 15 },\n fn: async () => {\n const { tasks } = await databaseTaskStore.listStaleTasks({\n timeoutS: Duration.fromObject(\n readDuration(config, 'scaffolder.taskTimeout', {\n hours: 24,\n }),\n ).as('seconds'),\n });\n\n for (const task of tasks) {\n await databaseTaskStore.shutdownTask(task);\n logger.info(`Successfully closed stale task ${task.taskId}`);\n }\n },\n });\n }\n } else {\n taskBroker = options.taskBroker;\n }\n\n const actionRegistry = new TemplateActionRegistry();\n\n const workers: TaskWorker[] = [];\n if (concurrentTasksLimit !== 0) {\n for (let i = 0; i < (taskWorkers || 1); i++) {\n const worker = await TaskWorker.create({\n taskBroker,\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n concurrentTasksLimit,\n permissions,\n });\n workers.push(worker);\n }\n }\n\n const actionsToRegister = Array.isArray(actions)\n ? actions\n : createBuiltinActions({\n integrations,\n catalogClient,\n reader,\n config,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n });\n\n actionsToRegister.forEach(action => actionRegistry.register(action));\n\n const launchWorkers = () => workers.forEach(worker => worker.start());\n\n const shutdownWorkers = () => {\n workers.forEach(worker => worker.stop());\n };\n\n if (options.lifecycle) {\n options.lifecycle.addStartupHook(launchWorkers);\n options.lifecycle.addShutdownHook(shutdownWorkers);\n } else {\n launchWorkers();\n }\n\n const dryRunner = createDryRunner({\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n const templateRules: TemplatePermissionRuleInput[] = Object.values(\n scaffolderTemplateRules,\n );\n const actionRules: ActionPermissionRuleInput[] = Object.values(\n scaffolderActionRules,\n );\n\n if (permissionRules) {\n templateRules.push(\n ...permissionRules.filter(isTemplatePermissionRuleInput),\n );\n actionRules.push(...permissionRules.filter(isActionPermissionRuleInput));\n }\n\n const isAuthorized = createConditionAuthorizer(Object.values(templateRules));\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resources: [\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n permissions: scaffolderTemplatePermissions,\n rules: templateRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n permissions: scaffolderActionPermissions,\n rules: actionRules,\n },\n ],\n permissions: scaffolderTaskPermissions,\n });\n\n router.use(permissionIntegrationRouter);\n\n router\n .get(\n '/v2/templates/:namespace/:kind/:name/parameter-schema',\n async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const template = await authorizeTemplate(\n req.params,\n token,\n credentials,\n );\n\n const parameters = [template.spec.parameters ?? []].flat();\n\n const presentation = template.spec.presentation;\n\n res.json({\n title: template.metadata.title ?? template.metadata.name,\n ...(presentation ? { presentation } : {}),\n description: template.metadata.description,\n 'ui:options': template.metadata['ui:options'],\n steps: parameters.map(schema => ({\n title: schema.title ?? 'Please enter the following information',\n description: schema.description,\n schema,\n })),\n });\n },\n )\n .get('/v2/actions', async (_req, res) => {\n const actionsList = actionRegistry.list().map(action => {\n return {\n id: action.id,\n description: action.description,\n examples: action.examples,\n schema: action.schema,\n };\n });\n res.json(actionsList);\n })\n .post('/v2/tasks', async (req, res) => {\n const templateRef: string = req.body.templateRef;\n const { kind, namespace, name } = parseEntityRef(templateRef, {\n defaultKind: 'template',\n });\n\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n\n let auditLog = `Scaffolding task for ${templateRef}`;\n if (userEntityRef) {\n auditLog += ` created by ${userEntityRef}`;\n }\n logger.info(auditLog);\n\n const values = req.body.values;\n\n const template = await authorizeTemplate(\n { kind, namespace, name },\n token,\n credentials,\n );\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(values, parameters);\n\n if (!result.valid) {\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const baseUrl = getEntityBaseUrl(template);\n\n const taskSpec: TaskSpec = {\n apiVersion: template.apiVersion,\n steps: template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n })),\n EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery,\n output: template.spec.output ?? {},\n parameters: values,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n templateInfo: {\n entityRef: stringifyEntityRef({ kind, name, namespace }),\n baseUrl,\n entity: {\n metadata: template.metadata,\n },\n },\n };\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: token,\n __initiatorCredentials: JSON.stringify(credentials),\n };\n\n const result = await taskBroker.dispatch({\n spec: taskSpec,\n createdBy: userEntityRef,\n secrets,\n });\n\n res.status(201).json({ id: result.taskId });\n })\n .get('/v2/tasks', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const [userEntityRef] = [req.query.createdBy].flat();\n if (\n typeof userEntityRef !== 'string' &&\n typeof userEntityRef !== 'undefined'\n ) {\n throw new InputError('createdBy query parameter must be a string');\n }\n\n if (!taskBroker.list) {\n throw new Error(\n 'TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.',\n );\n }\n\n const tasks = await taskBroker.list({\n createdBy: userEntityRef,\n });\n\n res.status(200).json(tasks);\n })\n .get('/v2/tasks/:taskId', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n const task = await taskBroker.get(taskId);\n if (!task) {\n throw new NotFoundError(`Task with id ${taskId} does not exist`);\n }\n // Do not disclose secrets\n delete task.secrets;\n res.status(200).json(task);\n })\n .post('/v2/tasks/:taskId/cancel', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n // Requires both read and cancel permissions\n await checkPermission({\n credentials,\n permissions: [taskCancelPermission, taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n await taskBroker.cancel?.(taskId);\n res.status(200).json({ status: 'cancelled' });\n })\n .get('/v2/tasks/:taskId/eventstream', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n const after =\n req.query.after !== undefined ? Number(req.query.after) : undefined;\n\n logger.debug(`Event stream observing taskId '${taskId}' opened`);\n\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // After client opens connection send all events as string\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n res.end();\n },\n next: ({ events }) => {\n let shouldUnsubscribe = false;\n for (const event of events) {\n res.write(\n `event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n );\n if (event.type === 'completion') {\n shouldUnsubscribe = true;\n }\n }\n // res.flush() is only available with the compression middleware\n res.flush?.();\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n res.end();\n }\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n logger.debug(`Event stream observing taskId '${taskId}' closed`);\n });\n })\n .get('/v2/tasks/:taskId/events', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const { taskId } = req.params;\n const after = Number(req.query.after) || undefined;\n\n // cancel the request after 30 seconds. this aligns with the recommendations of RFC 6202.\n const timeout = setTimeout(() => {\n res.json([]);\n }, 30_000);\n\n // Get all known events after an id (always includes the completion event) and return the first callback\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n },\n next: ({ events }) => {\n clearTimeout(timeout);\n subscription.unsubscribe();\n res.json(events);\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n clearTimeout(timeout);\n });\n })\n .post('/v2/dry-run', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const bodySchema = z.object({\n template: z.unknown(),\n values: z.record(z.unknown()),\n secrets: z.record(z.string()).optional(),\n directoryContents: z.array(\n z.object({ path: z.string(), base64Content: z.string() }),\n ),\n });\n const body = await bodySchema.parseAsync(req.body).catch(e => {\n throw new InputError(`Malformed request: ${e}`);\n });\n\n const template = body.template as TemplateEntityV1beta3;\n if (!(await templateEntityV1beta3Validator.check(template))) {\n throw new InputError('Input template is not a template');\n }\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(body.values, parameters);\n if (!result.valid) {\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const steps = template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n }));\n\n const result = await dryRunner({\n spec: {\n apiVersion: template.apiVersion,\n steps,\n output: template.spec.output ?? {},\n parameters: body.values as JsonObject,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n },\n directoryContents: (body.directoryContents ?? []).map(file => ({\n path: file.path,\n content: Buffer.from(file.base64Content, 'base64'),\n })),\n secrets: {\n ...body.secrets,\n ...(token && { backstageToken: token }),\n },\n credentials,\n });\n\n res.status(200).json({\n ...result,\n steps,\n directoryContents: result.directoryContents.map(file => ({\n path: file.path,\n executable: file.executable,\n base64Content: file.content.toString('base64'),\n })),\n });\n })\n .post('/v2/autocomplete/:provider/:resource', async (req, res) => {\n const { token, context } = req.body;\n const { provider, resource } = req.params;\n\n if (!token) throw new InputError('Missing token query parameter');\n\n if (!autocompleteHandlers[provider]) {\n throw new InputError(`Unsupported provider: ${provider}`);\n }\n\n const { results } = await autocompleteHandlers[provider]({\n resource,\n token,\n context,\n });\n\n res.status(200).json({ results });\n });\n\n const app = express();\n app.set('logger', logger);\n app.use('/', router);\n\n async function authorizeTemplate(\n entityRef: CompoundEntityRef,\n token: string | undefined,\n credentials: BackstageCredentials,\n ) {\n const template = await findTemplate({\n catalogApi: catalogClient,\n entityRef,\n token,\n });\n\n if (!isSupportedTemplate(template)) {\n throw new InputError(\n `Unsupported apiVersion field in schema entity, ${\n (template as Entity).apiVersion\n }`,\n );\n }\n\n if (!permissions) {\n return template;\n }\n\n const [parameterDecision, stepDecision] =\n await permissions.authorizeConditional(\n [\n { permission: templateParameterReadPermission },\n { permission: templateStepReadPermission },\n ],\n { credentials },\n );\n\n // Authorize parameters\n if (Array.isArray(template.spec.parameters)) {\n template.spec.parameters = template.spec.parameters.filter(step =>\n isAuthorized(parameterDecision, step),\n );\n } else if (\n template.spec.parameters &&\n !isAuthorized(parameterDecision, template.spec.parameters)\n ) {\n template.spec.parameters = undefined;\n }\n\n // Authorize steps\n template.spec.steps = template.spec.steps.filter(step =>\n isAuthorized(stepDecision, step),\n );\n\n return template;\n }\n\n return app;\n}\n"],"names":["examples","yaml","id","createTemplateAction","InputError","stringifyEntityRef","z","fs","resolveSafeChildPath","parseEntityRef","relative","readdir","join","stat","Duration","fetchContents","fetchFile","Isolate","resolvePackagePath","parseRepoUrl","get","globby","extname","isBinaryFile","DefaultGithubCredentialsProvider","createPublishGerritAction","createPublishGerritReviewAction","createPublishGiteaAction","createPublishGithubAction","createPublishGithubPullRequestAction","createPublishGitlabAction","createPublishGitlabMergeRequestAction","createGitlabRepoPushAction","createPublishBitbucketAction","createPublishBitbucketCloudAction","createPublishBitbucketServerAction","createPublishBitbucketServerPullRequestAction","createPublishAzureAction","createGithubActionsDispatchAction","createGithubWebhookAction","createGithubIssuesLabelAction","createGithubRepoCreateAction","createGithubRepoPushAction","createGithubEnvironmentAction","createGithubDeployKeyAction","createGithubAutolinksAction","createBitbucketPipelinesRunAction","ConflictError","NotFoundError","DateTime","uuid","restoreWorkspace","serializeWorkspace","isArray","readDuration","config","readDurationFromConfig","ObservableImpl","register","Counter","Histogram","makeCreatePermissionRule","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","RESOURCE_TYPE_SCAFFOLDER_ACTION","Transport","MESSAGE","LEVEL","SPLAT","createLogger","format","transports","winston","PassThrough","createConditionAuthorizer","nunjucks","templated","validateJsonSchema","errors","NotAllowedError","loggerToWinstonLogger","stringifyError","path","actionExecutePermission","AuthorizeResult","PQueue","assertError","serializeDirectoryContents","deserializeDirectoryContents","pathToFileURL","os","ANNOTATION_SOURCE_LOCATION","ANNOTATION_LOCATION","parseLocationRef","Router","express","HostDiscovery","createLegacyAuthAdapters","ScmIntegrations","createPermissionIntegrationRouter","scaffolderTemplatePermissions","scaffolderActionPermissions","scaffolderTaskPermissions","taskCreatePermission","result","validate","taskReadPermission","taskCancelPermission","templateEntityV1beta3Validator","templateParameterReadPermission","templateStepReadPermission"],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"router-O4Kmvgd-.cjs.js","sources":["../../src/scaffolder/actions/builtin/catalog/register.examples.ts","../../src/scaffolder/actions/builtin/catalog/register.ts","../../src/scaffolder/actions/builtin/catalog/write.examples.ts","../../src/scaffolder/actions/builtin/catalog/write.ts","../../src/scaffolder/actions/builtin/catalog/fetch.examples.ts","../../src/scaffolder/actions/builtin/catalog/fetch.ts","../../src/scaffolder/actions/builtin/debug/log.examples.ts","../../src/scaffolder/actions/builtin/debug/log.ts","../../src/scaffolder/actions/builtin/debug/wait.examples.ts","../../src/scaffolder/actions/builtin/debug/wait.ts","../../src/scaffolder/actions/builtin/fetch/plain.examples.ts","../../src/scaffolder/actions/builtin/fetch/plain.ts","../../src/scaffolder/actions/builtin/fetch/plainFile.examples.ts","../../src/scaffolder/actions/builtin/fetch/plainFile.ts","../../src/lib/templating/helpers.ts","../../src/lib/templating/SecureTemplater.ts","../../src/lib/templating/filters.ts","../../src/scaffolder/actions/builtin/fetch/template.examples.ts","../../src/scaffolder/actions/builtin/fetch/template.ts","../../src/scaffolder/actions/builtin/filesystem/delete.examples.ts","../../src/scaffolder/actions/builtin/filesystem/delete.ts","../../src/scaffolder/actions/builtin/filesystem/rename.examples.ts","../../src/scaffolder/actions/builtin/filesystem/rename.ts","../../src/scaffolder/actions/builtin/createBuiltinActions.ts","../../src/scaffolder/actions/TemplateActionRegistry.ts","../../src/scaffolder/tasks/taskRecoveryHelper.ts","../../src/scaffolder/tasks/dbUtil.ts","../../src/scaffolder/tasks/DatabaseTaskStore.ts","../../src/scaffolder/tasks/helper.ts","../../src/scaffolder/tasks/DatabaseWorkspaceProvider.ts","../../src/scaffolder/tasks/WorkspaceService.ts","../../src/scaffolder/tasks/StorageTaskBroker.ts","../../src/util/metrics.ts","../../src/service/rules.ts","../../src/scaffolder/tasks/logger.ts","../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts","../../src/scaffolder/tasks/TaskWorker.ts","../../src/scaffolder/dryrun/DecoratedActionsRegistry.ts","../../src/scaffolder/dryrun/createDryRunner.ts","../../src/service/helpers.ts","../../src/util/checkPermissions.ts","../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Register with the catalog',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:register',\n id: 'register-with-catalog',\n name: 'Register with the catalog',\n input: {\n catalogInfoUrl:\n 'http://github.com/backstage/backstage/blob/master/catalog-info.yaml',\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport { stringifyEntityRef, Entity } from '@backstage/catalog-model';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { examples } from './register.examples';\nimport { AuthService } from '@backstage/backend-plugin-api';\n\nconst id = 'catalog:register';\n\n/**\n * Registers entities from a catalog descriptor file in the workspace into the software catalog.\n * @public\n */\nexport function createCatalogRegisterAction(options: {\n catalogClient: CatalogApi;\n integrations: ScmIntegrations;\n auth?: AuthService;\n}) {\n const { catalogClient, integrations, auth } = options;\n\n return createTemplateAction<\n | { catalogInfoUrl: string; optional?: boolean }\n | { repoContentsUrl: string; catalogInfoPath?: string; optional?: boolean }\n >({\n id,\n description:\n 'Registers entities from a catalog descriptor file in the workspace into the software catalog.',\n examples,\n schema: {\n input: {\n oneOf: [\n {\n type: 'object',\n required: ['catalogInfoUrl'],\n properties: {\n catalogInfoUrl: {\n title: 'Catalog Info URL',\n description:\n 'An absolute URL pointing to the catalog info file location',\n type: 'string',\n },\n optional: {\n title: 'Optional',\n description:\n 'Permit the registered location to optionally exist. Default: false',\n type: 'boolean',\n },\n },\n },\n {\n type: 'object',\n required: ['repoContentsUrl'],\n properties: {\n repoContentsUrl: {\n title: 'Repository Contents URL',\n description:\n 'An absolute URL pointing to the root of a repository directory tree',\n type: 'string',\n },\n catalogInfoPath: {\n title: 'Fetch URL',\n description:\n 'A relative path from the repo root pointing to the catalog info file, defaults to /catalog-info.yaml',\n type: 'string',\n },\n optional: {\n title: 'Optional',\n description:\n 'Permit the registered location to optionally exist. Default: false',\n type: 'boolean',\n },\n },\n },\n ],\n },\n output: {\n type: 'object',\n required: ['catalogInfoUrl'],\n properties: {\n entityRef: {\n type: 'string',\n },\n catalogInfoUrl: {\n type: 'string',\n },\n },\n },\n },\n async handler(ctx) {\n const { input } = ctx;\n\n let catalogInfoUrl;\n if ('catalogInfoUrl' in input) {\n catalogInfoUrl = input.catalogInfoUrl;\n } else {\n const { repoContentsUrl, catalogInfoPath = '/catalog-info.yaml' } =\n input;\n const integration = integrations.byUrl(repoContentsUrl);\n if (!integration) {\n throw new InputError(\n `No integration found for host ${repoContentsUrl}`,\n );\n }\n\n catalogInfoUrl = integration.resolveUrl({\n base: repoContentsUrl,\n url: catalogInfoPath,\n });\n }\n\n ctx.logger.info(`Registering ${catalogInfoUrl} in the catalog`);\n\n const { token } = (await auth?.getPluginRequestToken({\n onBehalfOf: await ctx.getInitiatorCredentials(),\n targetPluginId: 'catalog',\n })) ?? { token: ctx.secrets?.backstageToken };\n\n try {\n // 1st try to register the location, this will throw an error if the location already exists (see catch)\n await catalogClient.addLocation(\n {\n type: 'url',\n target: catalogInfoUrl,\n },\n token ? { token } : {},\n );\n } catch (e) {\n if (!input.optional) {\n // if optional is false or unset, it is not allowed to register the same location twice, we rethrow the error\n throw e;\n }\n }\n\n try {\n // 2nd retry the registration as a dry run, this will not throw an error if the location already exists\n const result = await catalogClient.addLocation(\n {\n dryRun: true,\n type: 'url',\n target: catalogInfoUrl,\n },\n token ? { token } : {},\n );\n\n if (result.entities.length) {\n const { entities } = result;\n let entity: Entity | undefined;\n // prioritise 'Component' type as it is the most central kind of entity\n entity = entities.find(\n e =>\n !e.metadata.name.startsWith('generated-') &&\n e.kind === 'Component',\n );\n if (!entity) {\n entity = entities.find(\n e => !e.metadata.name.startsWith('generated-'),\n );\n }\n if (!entity) {\n entity = entities[0];\n }\n\n ctx.output('entityRef', stringifyEntityRef(entity));\n }\n } catch (e) {\n if (!input.optional) {\n throw e;\n }\n }\n\n ctx.output('catalogInfoUrl', catalogInfoUrl);\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Write a catalog yaml file',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:write',\n id: 'create-catalog-info-file',\n name: 'Create catalog file',\n input: {\n entity: {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Component',\n metadata: {\n name: 'test',\n annotations: {},\n },\n spec: {\n type: 'service',\n lifecycle: 'production',\n owner: 'default/owner',\n },\n },\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { z } from 'zod';\nimport { examples } from './write.examples';\n\nconst id = 'catalog:write';\n\n/**\n * Writes a catalog descriptor file containing the provided entity to a path in the workspace.\n * @public\n */\n\nexport function createCatalogWriteAction() {\n return createTemplateAction({\n id,\n description: 'Writes the catalog-info.yaml for your template',\n schema: {\n input: z.object({\n filePath: z\n .string()\n .optional()\n .describe('Defaults to catalog-info.yaml'),\n // TODO: this should reference an zod entity validator if it existed.\n entity: z\n .record(z.any())\n .describe(\n 'You can provide the same values used in the Entity schema.',\n ),\n }),\n },\n examples,\n supportsDryRun: true,\n async handler(ctx) {\n const { filePath, entity } = ctx.input;\n const entityRef = ctx.templateInfo?.entityRef;\n const path = filePath ?? 'catalog-info.yaml';\n ctx.logger.info(`Writing ${path}`);\n\n await fs.writeFile(\n resolveSafeChildPath(ctx.workspacePath, path),\n yaml.stringify({\n ...entity,\n metadata: {\n ...entity.metadata,\n ...(entityRef\n ? {\n annotations: {\n ...entity.metadata.annotations,\n 'backstage.io/source-template': entityRef,\n },\n }\n : undefined),\n },\n }),\n );\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Fetch entity by reference',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:fetch',\n id: 'fetch',\n name: 'Fetch catalog entity',\n input: {\n entityRef: 'component:default/name',\n },\n },\n ],\n }),\n },\n {\n description: 'Fetch multiple entities by reference',\n example: yaml.stringify({\n steps: [\n {\n action: 'catalog:fetch',\n id: 'fetchMultiple',\n name: 'Fetch catalog entities',\n input: {\n entityRefs: ['component:default/name'],\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CatalogApi } from '@backstage/catalog-client';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { z } from 'zod';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { examples } from './fetch.examples';\nimport { AuthService } from '@backstage/backend-plugin-api';\n\nconst id = 'catalog:fetch';\n\n/**\n * Returns entity or entities from the catalog by entity reference(s).\n *\n * @public\n */\nexport function createFetchCatalogEntityAction(options: {\n catalogClient: CatalogApi;\n auth?: AuthService;\n}) {\n const { catalogClient, auth } = options;\n\n return createTemplateAction({\n id,\n description:\n 'Returns entity or entities from the catalog by entity reference(s)',\n examples,\n supportsDryRun: true,\n schema: {\n input: z.object({\n entityRef: z\n .string({\n description: 'Entity reference of the entity to get',\n })\n .optional(),\n entityRefs: z\n .array(z.string(), {\n description: 'Entity references of the entities to get',\n })\n .optional(),\n optional: z\n .boolean({\n description:\n 'Allow the entity or entities to optionally exist. Default: false',\n })\n .optional(),\n defaultKind: z.string({ description: 'The default kind' }).optional(),\n defaultNamespace: z\n .string({ description: 'The default namespace' })\n .optional(),\n }),\n output: z.object({\n entity: z\n .any({\n description:\n 'Object containing same values used in the Entity schema. Only when used with `entityRef` parameter.',\n })\n .optional(),\n entities: z\n .array(\n z.any({\n description:\n 'Array containing objects with same values used in the Entity schema. Only when used with `entityRefs` parameter.',\n }),\n )\n .optional(),\n }),\n },\n async handler(ctx) {\n const { entityRef, entityRefs, optional, defaultKind, defaultNamespace } =\n ctx.input;\n if (!entityRef && !entityRefs) {\n if (optional) {\n return;\n }\n throw new Error('Missing entity reference or references');\n }\n\n const { token } = (await auth?.getPluginRequestToken({\n onBehalfOf: await ctx.getInitiatorCredentials(),\n targetPluginId: 'catalog',\n })) ?? { token: ctx.secrets?.backstageToken };\n\n if (entityRef) {\n const entity = await catalogClient.getEntityByRef(\n stringifyEntityRef(\n parseEntityRef(entityRef, { defaultKind, defaultNamespace }),\n ),\n {\n token,\n },\n );\n\n if (!entity && !optional) {\n throw new Error(`Entity ${entityRef} not found`);\n }\n ctx.output('entity', entity ?? null);\n }\n\n if (entityRefs) {\n const entities = await catalogClient.getEntitiesByRefs(\n {\n entityRefs: entityRefs.map(ref =>\n stringifyEntityRef(\n parseEntityRef(ref, { defaultKind, defaultNamespace }),\n ),\n ),\n },\n {\n token,\n },\n );\n\n const finalEntities = entities.items.map((e, i) => {\n if (!e && !optional) {\n throw new Error(`Entity ${entityRefs[i]} not found`);\n }\n return e ?? null;\n });\n\n ctx.output('entities', finalEntities);\n }\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Write a debug message',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:log',\n id: 'write-debug-line',\n name: 'Write \"Hello Backstage!\" log line',\n input: {\n message: 'Hello Backstage!',\n },\n },\n ],\n }),\n },\n {\n description: 'List the workspace directory',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:log',\n id: 'write-workspace-directory',\n name: 'List the workspace directory',\n input: {\n listWorkspace: true,\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readdir, stat } from 'fs-extra';\nimport { relative, join } from 'path';\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { examples } from './log.examples';\n\nconst id = 'debug:log';\n\n/**\n * Writes a message into the log or lists all files in the workspace\n *\n * @remarks\n *\n * This task is useful for local development and testing of both the scaffolder\n * and scaffolder templates.\n *\n * @public\n */\nexport function createDebugLogAction() {\n return createTemplateAction<{ message?: string; listWorkspace?: boolean }>({\n id,\n description:\n 'Writes a message into the log or lists all files in the workspace.',\n examples,\n schema: {\n input: {\n type: 'object',\n properties: {\n message: {\n title: 'Message to output.',\n type: 'string',\n },\n listWorkspace: {\n title: 'List all files in the workspace, if true.',\n type: 'boolean',\n },\n extra: {\n title: 'Extra info',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info(JSON.stringify(ctx.input, null, 2));\n\n if (ctx.input?.message) {\n ctx.logger.info(ctx.input.message);\n }\n\n if (ctx.input?.listWorkspace) {\n const files = await recursiveReadDir(ctx.workspacePath);\n ctx.logger.info(\n `Workspace:\\n${files\n .map(f => ` - ${relative(ctx.workspacePath, f)}`)\n .join('\\n')}`,\n );\n }\n },\n });\n}\n\nexport async function recursiveReadDir(dir: string): Promise {\n const subdirs = await readdir(dir);\n const files = await Promise.all(\n subdirs.map(async subdir => {\n const res = join(dir, subdir);\n return (await stat(res)).isDirectory() ? recursiveReadDir(res) : [res];\n }),\n );\n return files.reduce((a, f) => a.concat(f), []);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Waiting for 50 milliseconds',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:wait',\n id: 'wait-milliseconds',\n name: 'Waiting for 50 milliseconds',\n input: {\n milliseconds: 50,\n },\n },\n ],\n }),\n },\n {\n description: 'Waiting for 5 seconds',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:wait',\n id: 'wait-5sec',\n name: 'Waiting for 5 seconds',\n input: {\n seconds: 5,\n },\n },\n ],\n }),\n },\n {\n description: 'Waiting for 1 minutes',\n example: yaml.stringify({\n steps: [\n {\n action: 'debug:wait',\n id: 'wait-1min',\n name: 'Waiting for 1 minutes',\n input: {\n minutes: 1,\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { HumanDuration } from '@backstage/types';\nimport { Duration } from 'luxon';\nimport { examples } from './wait.examples';\n\nconst id = 'debug:wait';\n\nconst MAX_WAIT_TIME_IN_ISO = 'T00:10:00';\n\n/**\n * Waits for a certain period of time.\n *\n * @remarks\n *\n * This task is useful to give some waiting time for manual intervention.\n * Has to be used in a combination with other actions.\n *\n * @public\n */\nexport function createWaitAction(options?: {\n maxWaitTime?: Duration | HumanDuration;\n}) {\n const toDuration = (\n maxWaitTime: Duration | HumanDuration | undefined,\n ): Duration => {\n if (maxWaitTime) {\n if (maxWaitTime instanceof Duration) {\n return maxWaitTime;\n }\n return Duration.fromObject(maxWaitTime);\n }\n return Duration.fromISOTime(MAX_WAIT_TIME_IN_ISO);\n };\n\n return createTemplateAction({\n id,\n description: 'Waits for a certain period of time.',\n examples,\n schema: {\n input: {\n type: 'object',\n properties: {\n minutes: {\n title: 'Waiting period in minutes.',\n type: 'number',\n },\n seconds: {\n title: 'Waiting period in seconds.',\n type: 'number',\n },\n milliseconds: {\n title: 'Waiting period in milliseconds.',\n type: 'number',\n },\n },\n },\n },\n async handler(ctx) {\n const delayTime = Duration.fromObject(ctx.input);\n const maxWait = toDuration(options?.maxWaitTime);\n\n if (delayTime.minus(maxWait).toMillis() > 0) {\n throw new Error(\n `Waiting duration is longer than the maximum threshold of ${maxWait.toHuman()}`,\n );\n }\n\n await new Promise(resolve => {\n const controller = new AbortController();\n const timeoutHandle = setTimeout(abort, delayTime.toMillis());\n ctx.signal?.addEventListener('abort', abort);\n\n function abort() {\n ctx.signal?.removeEventListener('abort', abort);\n clearTimeout(timeoutHandle!);\n controller.abort();\n resolve('finished');\n }\n });\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Downloads content and places it in the workspace.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:plain',\n id: 'fetch-plain',\n name: 'Fetch plain',\n input: {\n url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets',\n },\n },\n ],\n }),\n },\n {\n description:\n 'Optionally, if you would prefer the data to be downloaded to a subdirectory in the workspace you may specify the ‘targetPath’ input option.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:plain',\n id: 'fetch-plain',\n name: 'Fetch plain',\n input: {\n url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets',\n targetPath: 'fetched-data',\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { examples } from './plain.examples';\n\nimport {\n createTemplateAction,\n fetchContents,\n} from '@backstage/plugin-scaffolder-node';\n\nexport const ACTION_ID = 'fetch:plain';\n\n/**\n * Downloads content and places it in the workspace, or optionally\n * in a subdirectory specified by the 'targetPath' input option.\n * @public\n */\nexport function createFetchPlainAction(options: {\n reader: UrlReader;\n integrations: ScmIntegrations;\n}) {\n const { reader, integrations } = options;\n\n return createTemplateAction<{\n url: string;\n targetPath?: string;\n token?: string;\n }>({\n id: ACTION_ID,\n examples,\n description:\n 'Downloads content and places it in the workspace, or optionally in a subdirectory specified by the `targetPath` input option.',\n schema: {\n input: {\n type: 'object',\n required: ['url'],\n properties: {\n url: {\n title: 'Fetch URL',\n description:\n 'Relative path or absolute URL pointing to the directory tree to fetch',\n type: 'string',\n },\n targetPath: {\n title: 'Target Path',\n description:\n 'Target path within the working directory to download the contents to.',\n type: 'string',\n },\n token: {\n title: 'Token',\n description:\n 'An optional token to use for authentication when reading the resources.',\n type: 'string',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info('Fetching plain content from remote URL');\n\n // Finally move the template result into the task workspace\n const targetPath = ctx.input.targetPath ?? './';\n const outputPath = resolveSafeChildPath(ctx.workspacePath, targetPath);\n\n await fetchContents({\n reader,\n integrations,\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath,\n token: ctx.input.token,\n });\n },\n });\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Downloads a file and places it in the workspace.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:plain:file',\n id: 'fetch-plain-file',\n name: 'Fetch plain file',\n input: {\n url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets/Backstage%20Community%20Sessions.png',\n targetPath: 'target-path',\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { examples } from './plainFile.examples';\nimport {\n createTemplateAction,\n fetchFile,\n} from '@backstage/plugin-scaffolder-node';\n\n/**\n * Downloads content and places it in the workspace, or optionally\n * in a subdirectory specified by the 'targetPath' input option.\n * @public\n */\nexport function createFetchPlainFileAction(options: {\n reader: UrlReader;\n integrations: ScmIntegrations;\n}) {\n const { reader, integrations } = options;\n\n return createTemplateAction<{\n url: string;\n targetPath: string;\n token?: string;\n }>({\n id: 'fetch:plain:file',\n description: 'Downloads single file and places it in the workspace.',\n examples,\n schema: {\n input: {\n type: 'object',\n required: ['url', 'targetPath'],\n properties: {\n url: {\n title: 'Fetch URL',\n description:\n 'Relative path or absolute URL pointing to the single file to fetch.',\n type: 'string',\n },\n targetPath: {\n title: 'Target Path',\n description:\n 'Target path within the working directory to download the file as.',\n type: 'string',\n },\n token: {\n title: 'Token',\n description:\n 'An optional token to use for authentication when reading the resources.',\n type: 'string',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info('Fetching plain content from remote URL');\n\n // Finally move the template result into the task workspace\n const outputPath = resolveSafeChildPath(\n ctx.workspacePath,\n ctx.input.targetPath,\n );\n\n await fetchFile({\n reader,\n integrations,\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath,\n token: ctx.input.token,\n });\n },\n });\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isNoNodeSnapshotOptionProvided(): boolean {\n return (\n process.env.NODE_OPTIONS?.includes('--no-node-snapshot') ||\n process.argv.includes('--no-node-snapshot')\n );\n}\n\n/**\n * Gets the major version of the currently running Node.js process.\n *\n * @remarks\n * This function extracts the major version from `process.versions.node` (a string representing the Node.js version),\n * which includes the major, minor, and patch versions. It splits this string by the `.` character to get an array\n * of these versions, and then parses the first element of this array (the major version) to a number.\n *\n * @returns {number} The major version of the currently running Node.js process.\n */\nexport function getMajorNodeVersion(): number {\n const version = process.versions.node;\n return parseInt(version.split('.')[0], 10);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Isolate } from 'isolated-vm';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport {\n TemplateFilter as _TemplateFilter,\n TemplateGlobal as _TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport fs from 'fs-extra';\nimport { JsonValue } from '@backstage/types';\nimport { getMajorNodeVersion, isNoNodeSnapshotOptionProvided } from './helpers';\n\n// language=JavaScript\nconst mkScript = (nunjucksSource: string) => `\nconst { render, renderCompat } = (() => {\n const module = {};\n const process = { env: {} };\n const require = (pkg) => { if (pkg === 'events') { return function (){}; }};\n\n ${nunjucksSource}\n\n const env = module.exports.configure({\n autoescape: false,\n ...JSON.parse(nunjucksConfigs),\n tags: {\n variableStart: '\\${{',\n variableEnd: '}}',\n },\n });\n\n const compatEnv = module.exports.configure({\n autoescape: false,\n ...JSON.parse(nunjucksConfigs),\n tags: {\n variableStart: '{{',\n variableEnd: '}}',\n },\n });\n compatEnv.addFilter('jsonify', compatEnv.getFilter('dump'));\n\n for (const name of JSON.parse(availableTemplateFilters)) {\n env.addFilter(name, (...args) => JSON.parse(callFilter(name, args)));\n }\n for (const [name, value] of Object.entries(JSON.parse(availableTemplateGlobals))) {\n env.addGlobal(name, value);\n }\n for (const name of JSON.parse(availableTemplateCallbacks)) {\n env.addGlobal(name, (...args) => JSON.parse(callGlobal(name, args)));\n }\n\n let uninstallCompat = undefined;\n\n function render(str, values) {\n try {\n if (uninstallCompat) {\n uninstallCompat();\n uninstallCompat = undefined;\n }\n return env.renderString(str, JSON.parse(values));\n } catch (error) {\n // Make sure errors don't leak anything\n throw new Error(String(error.message));\n }\n }\n\n function renderCompat(str, values) {\n try {\n if (!uninstallCompat) {\n uninstallCompat = module.exports.installJinjaCompat();\n }\n return compatEnv.renderString(str, JSON.parse(values));\n } catch (error) {\n // Make sure errors don't leak anything\n throw new Error(String(error.message));\n }\n }\n\n return { render, renderCompat };\n})();\n`;\n\n/**\n * @public\n * @deprecated Import from `@backstage/plugin-scaffolder-node` instead.\n */\nexport type TemplateFilter = _TemplateFilter;\n\n/**\n * @public\n * @deprecated Import from `@backstage/plugin-scaffolder-node` instead.\n */\nexport type TemplateGlobal = _TemplateGlobal;\n\ninterface SecureTemplaterOptions {\n /* Enables jinja compatibility and the \"jsonify\" filter */\n cookiecutterCompat?: boolean;\n /* Extra user-provided nunjucks filters */\n templateFilters?: Record;\n /* Extra user-provided nunjucks globals */\n templateGlobals?: Record;\n nunjucksConfigs?: { trimBlocks?: boolean; lstripBlocks?: boolean };\n}\n\nexport type SecureTemplateRenderer = (\n template: string,\n values: unknown,\n) => string;\n\nexport class SecureTemplater {\n static async loadRenderer(options: SecureTemplaterOptions = {}) {\n const {\n cookiecutterCompat,\n templateFilters = {},\n templateGlobals = {},\n nunjucksConfigs = {},\n } = options;\n\n const nodeVersion = getMajorNodeVersion();\n if (nodeVersion >= 20 && !isNoNodeSnapshotOptionProvided()) {\n throw new Error(\n `When using Node.js version 20 or newer, the scaffolder backend plugin requires that it be started with the --no-node-snapshot option. \n Please make sure that you have NODE_OPTIONS=--no-node-snapshot in your environment.`,\n );\n }\n\n const isolate = new Isolate({ memoryLimit: 128 });\n const context = await isolate.createContext();\n const contextGlobal = context.global;\n\n const nunjucksSource = await fs.readFile(\n resolvePackagePath(\n '@backstage/plugin-scaffolder-backend',\n 'assets/nunjucks.js.txt',\n ),\n 'utf-8',\n );\n\n const nunjucksScript = await isolate.compileScript(\n mkScript(nunjucksSource),\n );\n\n await contextGlobal.set('nunjucksConfigs', JSON.stringify(nunjucksConfigs));\n\n const availableFilters = Object.keys(templateFilters);\n\n await contextGlobal.set(\n 'availableTemplateFilters',\n JSON.stringify(availableFilters),\n );\n\n const globalCallbacks = [];\n const globalValues: Record = {};\n for (const [name, value] of Object.entries(templateGlobals)) {\n if (typeof value === 'function') {\n globalCallbacks.push(name);\n } else {\n globalValues[name] = value;\n }\n }\n\n await contextGlobal.set(\n 'availableTemplateGlobals',\n JSON.stringify(globalValues),\n );\n await contextGlobal.set(\n 'availableTemplateCallbacks',\n JSON.stringify(globalCallbacks),\n );\n\n await contextGlobal.set(\n 'callFilter',\n (filterName: string, args: JsonValue[]) => {\n if (!Object.hasOwn(templateFilters, filterName)) {\n return '';\n }\n return JSON.stringify(templateFilters[filterName](...args));\n },\n );\n\n await contextGlobal.set(\n 'callGlobal',\n (globalName: string, args: JsonValue[]) => {\n if (!Object.hasOwn(templateGlobals, globalName)) {\n return '';\n }\n const global = templateGlobals[globalName];\n if (typeof global !== 'function') {\n return '';\n }\n return JSON.stringify(global(...args));\n },\n );\n\n await nunjucksScript.run(context);\n\n const render: SecureTemplateRenderer = (template, values) => {\n if (!context) {\n throw new Error('SecureTemplater has not been initialized');\n }\n\n contextGlobal.setSync('templateStr', String(template));\n contextGlobal.setSync('templateValues', JSON.stringify(values));\n\n if (cookiecutterCompat) {\n return context.evalSync(`renderCompat(templateStr, templateValues)`);\n }\n\n return context.evalSync(`render(templateStr, templateValues)`);\n };\n return render;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport type { JsonObject, JsonValue } from '@backstage/types';\nimport {\n parseRepoUrl,\n TemplateFilter,\n} from '@backstage/plugin-scaffolder-node';\nimport get from 'lodash/get';\n\nexport const createDefaultFilters = ({\n integrations,\n}: {\n integrations: ScmIntegrations;\n}): Record => {\n return {\n parseRepoUrl: url => parseRepoUrl(url as string, integrations),\n parseEntityRef: (ref: JsonValue, context?: JsonValue) =>\n parseEntityRef(ref as string, context as JsonObject),\n pick: (obj: JsonValue, key: JsonValue) => get(obj, key as string),\n projectSlug: repoUrl => {\n const { owner, repo } = parseRepoUrl(repoUrl as string, integrations);\n return `${owner}/${repo}`;\n },\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description:\n 'Downloads a skeleton directory that lives alongside the template file and fill it out with values.',\n example: yaml.stringify({\n steps: [\n {\n action: 'fetch:template',\n id: 'fetch-template',\n name: 'Fetch template',\n input: {\n url: './skeleton',\n targetPath: './target',\n values: {\n name: 'test-project',\n count: 1234,\n itemList: ['first', 'second', 'third'],\n showDummyFile: false,\n },\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { extname } from 'path';\nimport { UrlReader } from '@backstage/backend-common';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n createTemplateAction,\n fetchContents,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport globby from 'globby';\nimport fs from 'fs-extra';\nimport { isBinaryFile } from 'isbinaryfile';\nimport { SecureTemplater } from '../../../../lib/templating/SecureTemplater';\nimport { createDefaultFilters } from '../../../../lib/templating/filters';\nimport { examples } from './template.examples';\n\n/**\n * Downloads a skeleton, templates variables into file and directory names and content.\n * Then places the result in the workspace, or optionally in a subdirectory\n * specified by the 'targetPath' input option.\n *\n * @public\n */\nexport function createFetchTemplateAction(options: {\n reader: UrlReader;\n integrations: ScmIntegrations;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n}) {\n const {\n reader,\n integrations,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n } = options;\n\n const defaultTemplateFilters = createDefaultFilters({ integrations });\n\n return createTemplateAction<{\n url: string;\n targetPath?: string;\n values: any;\n templateFileExtension?: string | boolean;\n\n // Cookiecutter compat options\n /**\n * @deprecated This field is deprecated in favor of copyWithoutTemplating.\n */\n copyWithoutRender?: string[];\n copyWithoutTemplating?: string[];\n cookiecutterCompat?: boolean;\n replace?: boolean;\n trimBlocks?: boolean;\n lstripBlocks?: boolean;\n token?: string;\n }>({\n id: 'fetch:template',\n description:\n 'Downloads a skeleton, templates variables into file and directory names and content, and places the result in the workspace, or optionally in a subdirectory specified by the `targetPath` input option.',\n examples,\n schema: {\n input: {\n type: 'object',\n required: ['url'],\n properties: {\n url: {\n title: 'Fetch URL',\n description:\n 'Relative path or absolute URL pointing to the directory tree to fetch',\n type: 'string',\n },\n targetPath: {\n title: 'Target Path',\n description:\n 'Target path within the working directory to download the contents to. Defaults to the working directory root.',\n type: 'string',\n },\n values: {\n title: 'Template Values',\n description: 'Values to pass on to the templating engine',\n type: 'object',\n },\n copyWithoutRender: {\n title: '[Deprecated] Copy Without Render',\n description:\n 'An array of glob patterns. Any files or directories which match are copied without being processed as templates.',\n type: 'array',\n items: {\n type: 'string',\n },\n },\n copyWithoutTemplating: {\n title: 'Copy Without Templating',\n description:\n 'An array of glob patterns. Contents of matched files or directories are copied without being processed, but paths are subject to rendering.',\n type: 'array',\n items: {\n type: 'string',\n },\n },\n cookiecutterCompat: {\n title: 'Cookiecutter compatibility mode',\n description:\n 'Enable features to maximise compatibility with templates built for fetch:cookiecutter',\n type: 'boolean',\n },\n templateFileExtension: {\n title: 'Template File Extension',\n description:\n 'If set, only files with the given extension will be templated. If set to `true`, the default extension `.njk` is used.',\n type: ['string', 'boolean'],\n },\n replace: {\n title: 'Replace files',\n description:\n 'If set, replace files in targetPath instead of skipping existing ones.',\n type: 'boolean',\n },\n token: {\n title: 'Token',\n description:\n 'An optional token to use for authentication when reading the resources.',\n type: 'string',\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n ctx.logger.info('Fetching template content from remote URL');\n\n const workDir = await ctx.createTemporaryDirectory();\n const templateDir = resolveSafeChildPath(workDir, 'template');\n\n const targetPath = ctx.input.targetPath ?? './';\n const outputDir = resolveSafeChildPath(ctx.workspacePath, targetPath);\n if (ctx.input.copyWithoutRender && ctx.input.copyWithoutTemplating) {\n throw new InputError(\n 'Fetch action input copyWithoutRender and copyWithoutTemplating can not be used at the same time',\n );\n }\n\n let copyOnlyPatterns: string[] | undefined;\n let renderFilename: boolean;\n if (ctx.input.copyWithoutRender) {\n ctx.logger.warn(\n '[Deprecated] copyWithoutRender is deprecated Please use copyWithoutTemplating instead.',\n );\n copyOnlyPatterns = ctx.input.copyWithoutRender;\n renderFilename = false;\n } else {\n copyOnlyPatterns = ctx.input.copyWithoutTemplating;\n renderFilename = true;\n }\n\n if (copyOnlyPatterns && !Array.isArray(copyOnlyPatterns)) {\n throw new InputError(\n 'Fetch action input copyWithoutRender/copyWithoutTemplating must be an Array',\n );\n }\n\n if (\n ctx.input.templateFileExtension &&\n (copyOnlyPatterns || ctx.input.cookiecutterCompat)\n ) {\n throw new InputError(\n 'Fetch action input extension incompatible with copyWithoutRender/copyWithoutTemplating and cookiecutterCompat',\n );\n }\n\n let extension: string | false = false;\n if (ctx.input.templateFileExtension) {\n extension =\n ctx.input.templateFileExtension === true\n ? '.njk'\n : ctx.input.templateFileExtension;\n if (!extension.startsWith('.')) {\n extension = `.${extension}`;\n }\n }\n\n await fetchContents({\n reader,\n integrations,\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath: templateDir,\n token: ctx.input.token,\n });\n\n ctx.logger.info('Listing files and directories in template');\n const allEntriesInTemplate = await globby(`**/*`, {\n cwd: templateDir,\n dot: true,\n onlyFiles: false,\n markDirectories: true,\n followSymbolicLinks: false,\n });\n\n const nonTemplatedEntries = new Set(\n await globby(copyOnlyPatterns || [], {\n cwd: templateDir,\n dot: true,\n onlyFiles: false,\n markDirectories: true,\n followSymbolicLinks: false,\n }),\n );\n\n // Cookiecutter prefixes all parameters in templates with\n // `cookiecutter.`. To replicate this, we wrap our parameters\n // in an object with a `cookiecutter` property when compat\n // mode is enabled.\n const { cookiecutterCompat, values } = ctx.input;\n const context = {\n [cookiecutterCompat ? 'cookiecutter' : 'values']: values,\n };\n\n ctx.logger.info(\n `Processing ${allEntriesInTemplate.length} template files/directories with input values`,\n ctx.input.values,\n );\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n cookiecutterCompat: ctx.input.cookiecutterCompat,\n templateFilters: {\n ...defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n nunjucksConfigs: {\n trimBlocks: ctx.input.trimBlocks,\n lstripBlocks: ctx.input.lstripBlocks,\n },\n });\n\n for (const location of allEntriesInTemplate) {\n let renderContents: boolean;\n\n let localOutputPath = location;\n if (extension) {\n renderContents = extname(localOutputPath) === extension;\n if (renderContents) {\n localOutputPath = localOutputPath.slice(0, -extension.length);\n }\n // extension is mutual exclusive with copyWithoutRender/copyWithoutTemplating,\n // therefore the output path is always rendered.\n localOutputPath = renderTemplate(localOutputPath, context);\n } else {\n renderContents = !nonTemplatedEntries.has(location);\n // The logic here is a bit tangled because it depends on two variables.\n // If renderFilename is true, which means copyWithoutTemplating is used,\n // then the path is always rendered.\n // If renderFilename is false, which means copyWithoutRender is used,\n // then matched file/directory won't be processed, same as before.\n if (renderFilename) {\n localOutputPath = renderTemplate(localOutputPath, context);\n } else {\n localOutputPath = renderContents\n ? renderTemplate(localOutputPath, context)\n : localOutputPath;\n }\n }\n\n if (containsSkippedContent(localOutputPath)) {\n continue;\n }\n\n const outputPath = resolveSafeChildPath(outputDir, localOutputPath);\n if (fs.existsSync(outputPath) && !ctx.input.replace) {\n continue;\n }\n\n if (!renderContents && !extension) {\n ctx.logger.info(\n `Copying file/directory ${location} without processing.`,\n );\n }\n\n if (location.endsWith('/')) {\n ctx.logger.info(\n `Writing directory ${location} to template output path.`,\n );\n await fs.ensureDir(outputPath);\n } else {\n const inputFilePath = resolveSafeChildPath(templateDir, location);\n const stats = await fs.promises.lstat(inputFilePath);\n\n if (stats.isSymbolicLink() || (await isBinaryFile(inputFilePath))) {\n ctx.logger.info(\n `Copying file binary or symbolic link at ${location}, to template output path.`,\n );\n await fs.copy(inputFilePath, outputPath);\n } else {\n const statsObj = await fs.stat(inputFilePath);\n ctx.logger.info(\n `Writing file ${location} to template output path with mode ${statsObj.mode}.`,\n );\n const inputFileContents = await fs.readFile(inputFilePath, 'utf-8');\n await fs.outputFile(\n outputPath,\n renderContents\n ? renderTemplate(inputFileContents, context)\n : inputFileContents,\n { mode: statsObj.mode },\n );\n }\n }\n }\n\n ctx.logger.info(`Template result written to ${outputDir}`);\n },\n });\n}\n\nfunction containsSkippedContent(localOutputPath: string): boolean {\n // if the path is empty means that there is a file skipped in the root\n // if the path starts with a separator it means that the root directory has been skipped\n // if the path includes // means that there is a subdirectory skipped\n // All paths returned are considered with / separator because of globby returning the linux separator for all os'.\n return (\n localOutputPath === '' ||\n localOutputPath.startsWith('/') ||\n localOutputPath.includes('//')\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Delete specified files',\n example: yaml.stringify({\n steps: [\n {\n action: 'fs:delete',\n id: 'deleteFiles',\n name: 'Delete files',\n input: {\n files: ['file1.txt', 'file2.txt'],\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { InputError } from '@backstage/errors';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport fs from 'fs-extra';\nimport { examples } from './delete.examples';\n\n/**\n * Creates new action that enables deletion of files and directories in the workspace.\n * @public\n */\nexport const createFilesystemDeleteAction = () => {\n return createTemplateAction<{ files: string[] }>({\n id: 'fs:delete',\n description: 'Deletes files and directories from the workspace',\n examples,\n schema: {\n input: {\n required: ['files'],\n type: 'object',\n properties: {\n files: {\n title: 'Files',\n description: 'A list of files and directories that will be deleted',\n type: 'array',\n items: {\n type: 'string',\n },\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n if (!Array.isArray(ctx.input?.files)) {\n throw new InputError('files must be an Array');\n }\n\n for (const file of ctx.input.files) {\n const filepath = resolveSafeChildPath(ctx.workspacePath, file);\n\n try {\n await fs.remove(filepath);\n ctx.logger.info(`File ${filepath} deleted successfully`);\n } catch (err) {\n ctx.logger.error(`Failed to delete file ${filepath}:`, err);\n throw err;\n }\n }\n },\n });\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateExample } from '@backstage/plugin-scaffolder-node';\nimport * as yaml from 'yaml';\n\nexport const examples: TemplateExample[] = [\n {\n description: 'Rename specified files ',\n example: yaml.stringify({\n steps: [\n {\n action: 'fs:rename',\n id: 'renameFiles',\n name: 'Rename files',\n input: {\n files: [\n { from: 'file1.txt', to: 'file1Renamed.txt' },\n { from: 'file2.txt', to: 'file2Renamed.txt' },\n { from: 'file3.txt', to: 'file3Renamed.txt', overwrite: true },\n ],\n },\n },\n ],\n }),\n },\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\nimport fs from 'fs-extra';\nimport { examples } from './rename.examples';\n\n/**\n * Creates a new action that allows renames of files and directories in the workspace.\n * @public\n */\nexport const createFilesystemRenameAction = () => {\n return createTemplateAction<{\n files: Array<{\n from: string;\n to: string;\n overwrite?: boolean;\n }>;\n }>({\n id: 'fs:rename',\n description: 'Renames files and directories within the workspace',\n examples,\n schema: {\n input: {\n required: ['files'],\n type: 'object',\n properties: {\n files: {\n title: 'Files',\n description:\n 'A list of file and directory names that will be renamed',\n type: 'array',\n items: {\n type: 'object',\n required: ['from', 'to'],\n properties: {\n from: {\n type: 'string',\n title: 'The source location of the file to be renamed',\n },\n to: {\n type: 'string',\n title: 'The destination of the new file',\n },\n overwrite: {\n type: 'boolean',\n title:\n 'Overwrite existing file or directory, default is false',\n },\n },\n },\n },\n },\n },\n },\n supportsDryRun: true,\n async handler(ctx) {\n if (!Array.isArray(ctx.input?.files)) {\n throw new InputError('files must be an Array');\n }\n\n for (const file of ctx.input.files) {\n if (!file.from || !file.to) {\n throw new InputError('each file must have a from and to property');\n }\n\n const sourceFilepath = resolveSafeChildPath(\n ctx.workspacePath,\n file.from,\n );\n const destFilepath = resolveSafeChildPath(ctx.workspacePath, file.to);\n\n try {\n await fs.move(sourceFilepath, destFilepath, {\n overwrite: file.overwrite ?? false,\n });\n ctx.logger.info(\n `File ${sourceFilepath} renamed to ${destFilepath} successfully`,\n );\n } catch (err) {\n ctx.logger.error(\n `Failed to rename file ${sourceFilepath} to ${destFilepath}:`,\n err,\n );\n throw err;\n }\n }\n },\n });\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { UrlReader } from '@backstage/backend-common';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport { Config } from '@backstage/config';\nimport {\n DefaultGithubCredentialsProvider,\n GithubCredentialsProvider,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n createCatalogRegisterAction,\n createCatalogWriteAction,\n createFetchCatalogEntityAction,\n} from './catalog';\n\nimport { createDebugLogAction, createWaitAction } from './debug';\nimport {\n createFetchPlainAction,\n createFetchPlainFileAction,\n createFetchTemplateAction,\n} from './fetch';\nimport {\n createFilesystemDeleteAction,\n createFilesystemRenameAction,\n} from './filesystem';\nimport {\n createGithubActionsDispatchAction,\n createGithubAutolinksAction,\n createGithubDeployKeyAction,\n createGithubEnvironmentAction,\n createGithubIssuesLabelAction,\n createGithubRepoCreateAction,\n createGithubRepoPushAction,\n createGithubWebhookAction,\n createPublishGithubAction,\n createPublishGithubPullRequestAction,\n} from '@backstage/plugin-scaffolder-backend-module-github';\n\nimport { createPublishAzureAction } from '@backstage/plugin-scaffolder-backend-module-azure';\n\nimport { createPublishBitbucketAction } from '@backstage/plugin-scaffolder-backend-module-bitbucket';\n\nimport {\n createPublishBitbucketCloudAction,\n createBitbucketPipelinesRunAction,\n} from '@backstage/plugin-scaffolder-backend-module-bitbucket-cloud';\n\nimport {\n createPublishBitbucketServerAction,\n createPublishBitbucketServerPullRequestAction,\n} from '@backstage/plugin-scaffolder-backend-module-bitbucket-server';\n\nimport {\n createPublishGerritAction,\n createPublishGerritReviewAction,\n} from '@backstage/plugin-scaffolder-backend-module-gerrit';\n\nimport {\n createPublishGitlabAction,\n createGitlabRepoPushAction,\n createPublishGitlabMergeRequestAction,\n} from '@backstage/plugin-scaffolder-backend-module-gitlab';\n\nimport { createPublishGiteaAction } from '@backstage/plugin-scaffolder-backend-module-gitea';\nimport { AuthService } from '@backstage/backend-plugin-api';\n\n/**\n * The options passed to {@link createBuiltinActions}\n * @public\n */\nexport interface CreateBuiltInActionsOptions {\n /**\n * The {@link @backstage/backend-common#UrlReader} interface that will be used in the default actions.\n */\n reader: UrlReader;\n /**\n * The {@link @backstage/integrations#ScmIntegrations} that will be used in the default actions.\n */\n integrations: ScmIntegrations;\n /**\n * The {@link @backstage/catalog-client#CatalogApi} that will be used in the default actions.\n */\n catalogClient: CatalogApi;\n /**\n * The {@link @backstage/backend-plugin-api#AuthService} that will be used in the default actions.\n */\n auth?: AuthService;\n /**\n * The {@link @backstage/config#Config} that will be used in the default actions.\n */\n config: Config;\n /**\n * Additional custom filters that will be passed to the nunjucks template engine for use in\n * Template Manifests and also template skeleton files when using `fetch:template`.\n */\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n}\n\n/**\n * A function to generate create a list of default actions that the scaffolder provides.\n * Is called internally in the default setup, but can be used when adding your own actions or overriding the default ones\n *\n * TODO(blam): version 2 of the scaffolder shouldn't ship with the additional modules. We should ship the basics, and let people install\n * modules for the providers they want to use.\n * @public\n * @returns A list of actions that can be used in the scaffolder\n *\n */\nexport const createBuiltinActions = (\n options: CreateBuiltInActionsOptions,\n): TemplateAction[] => {\n const {\n reader,\n integrations,\n catalogClient,\n auth,\n config,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n } = options;\n\n const githubCredentialsProvider: GithubCredentialsProvider =\n DefaultGithubCredentialsProvider.fromIntegrations(integrations);\n\n const actions = [\n createFetchPlainAction({\n reader,\n integrations,\n }),\n createFetchPlainFileAction({\n reader,\n integrations,\n }),\n createFetchTemplateAction({\n integrations,\n reader,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n }),\n createPublishGerritAction({\n integrations,\n config,\n }),\n createPublishGerritReviewAction({\n integrations,\n config,\n }),\n createPublishGiteaAction({\n integrations,\n config,\n }),\n createPublishGithubAction({\n integrations,\n config,\n githubCredentialsProvider,\n }),\n createPublishGithubPullRequestAction({\n integrations,\n githubCredentialsProvider,\n config,\n }),\n createPublishGitlabAction({\n integrations,\n config,\n }),\n createPublishGitlabMergeRequestAction({\n integrations,\n }),\n createGitlabRepoPushAction({\n integrations,\n }),\n createPublishBitbucketAction({\n integrations,\n config,\n }),\n createPublishBitbucketCloudAction({\n integrations,\n config,\n }),\n createPublishBitbucketServerAction({\n integrations,\n config,\n }),\n createPublishBitbucketServerPullRequestAction({\n integrations,\n config,\n }),\n createPublishAzureAction({\n integrations,\n config,\n }),\n createDebugLogAction(),\n createWaitAction(),\n createCatalogRegisterAction({ catalogClient, integrations, auth }),\n createFetchCatalogEntityAction({ catalogClient, auth }),\n createCatalogWriteAction(),\n createFilesystemDeleteAction(),\n createFilesystemRenameAction(),\n createGithubActionsDispatchAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubWebhookAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubIssuesLabelAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubRepoCreateAction({\n integrations,\n githubCredentialsProvider,\n }),\n createGithubRepoPushAction({\n integrations,\n config,\n githubCredentialsProvider,\n }),\n createGithubEnvironmentAction({\n integrations,\n }),\n createGithubDeployKeyAction({\n integrations,\n }),\n createGithubAutolinksAction({\n integrations,\n githubCredentialsProvider,\n }),\n createBitbucketPipelinesRunAction({\n integrations,\n }),\n ];\n\n return actions as TemplateAction[];\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { TemplateAction } from '@backstage/plugin-scaffolder-node';\n/**\n * Registry of all registered template actions.\n * @public\n */\nexport class TemplateActionRegistry {\n private readonly actions = new Map();\n\n register(action: TemplateAction) {\n if (this.actions.has(action.id)) {\n throw new ConflictError(\n `Template action with ID '${action.id}' has already been registered`,\n );\n }\n\n this.actions.set(action.id, action);\n }\n\n get(actionId: string): TemplateAction {\n const action = this.actions.get(actionId);\n if (!action) {\n throw new NotFoundError(\n `Template action with ID '${actionId}' is not registered.`,\n );\n }\n return action;\n }\n\n list(): TemplateAction[] {\n return [...this.actions.values()];\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SerializedTaskEvent } from '@backstage/plugin-scaffolder-node';\nimport { TaskRecoverStrategy } from '@backstage/plugin-scaffolder-common';\n\nexport const trimEventsTillLastRecovery = (\n events: SerializedTaskEvent[],\n): { events: SerializedTaskEvent[] } => {\n const recoveredEventInd = events\n .slice()\n .reverse()\n .findIndex(event => event.type === 'recovered');\n\n if (recoveredEventInd >= 0) {\n const ind = events.length - recoveredEventInd - 1;\n const { recoverStrategy } = events[ind].body as {\n recoverStrategy: TaskRecoverStrategy;\n };\n if (recoverStrategy === 'startOver') {\n return {\n events: recoveredEventInd === 0 ? [] : events.slice(ind),\n };\n }\n }\n\n return { events };\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Knex } from 'knex';\n\nexport const intervalFromNowTill = (timeoutS: number, knex: Knex) => {\n let heartbeatInterval = knex.raw(`? - interval '${timeoutS} seconds'`, [\n knex.fn.now(),\n ]);\n if (knex.client.config.client.includes('mysql')) {\n heartbeatInterval = knex.raw(\n `date_sub(now(), interval ${timeoutS} second)`,\n );\n } else if (knex.client.config.client.includes('sqlite3')) {\n heartbeatInterval = knex.raw(`datetime('now', ?)`, [\n `-${timeoutS} seconds`,\n ]);\n }\n return heartbeatInterval;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { PluginDatabaseManager } from '@backstage/backend-common';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport {\n TaskStore,\n TaskStoreEmitOptions,\n TaskStoreListEventsOptions,\n TaskStoreCreateTaskOptions,\n TaskStoreCreateTaskResult,\n TaskStoreShutDownTaskOptions,\n TaskStoreRecoverTaskOptions,\n} from './types';\nimport {\n SerializedTaskEvent,\n SerializedTask,\n TaskStatus,\n TaskEventType,\n TaskSecrets,\n} from '@backstage/plugin-scaffolder-node';\nimport { DateTime, Duration } from 'luxon';\nimport { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { trimEventsTillLastRecovery } from './taskRecoveryHelper';\nimport { intervalFromNowTill } from './dbUtil';\nimport {\n restoreWorkspace,\n serializeWorkspace,\n} from '@backstage/plugin-scaffolder-node/alpha';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-scaffolder-backend',\n 'migrations',\n);\n\nexport type RawDbTaskRow = {\n id: string;\n spec: string;\n status: TaskStatus;\n state?: string;\n last_heartbeat_at?: string;\n created_at: string;\n created_by: string | null;\n secrets?: string | null;\n workspace?: Buffer;\n};\n\nexport type RawDbTaskEventRow = {\n id: number;\n task_id: string;\n body: string;\n event_type: TaskEventType;\n created_at: string;\n};\n\n/**\n * DatabaseTaskStore\n *\n * @public\n */\nexport type DatabaseTaskStoreOptions = {\n database: PluginDatabaseManager | Knex;\n};\n\n/**\n * Type guard to help DatabaseTaskStore understand when database is PluginDatabaseManager vs. when database is a Knex instance.\n *\n * * @public\n */\nfunction isPluginDatabaseManager(\n opt: PluginDatabaseManager | Knex,\n): opt is PluginDatabaseManager {\n return (opt as PluginDatabaseManager).getClient !== undefined;\n}\n\nconst parseSqlDateToIsoString = (input: T): T | string => {\n if (typeof input === 'string') {\n const parsed = DateTime.fromSQL(input, { zone: 'UTC' });\n if (!parsed.isValid) {\n throw new Error(\n `Failed to parse database timestamp '${input}', ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n return parsed.toISO()!;\n }\n\n return input;\n};\n\n/**\n * DatabaseTaskStore\n *\n * @public\n */\nexport class DatabaseTaskStore implements TaskStore {\n private readonly db: Knex;\n\n static async create(\n options: DatabaseTaskStoreOptions,\n ): Promise {\n const { database } = options;\n const client = await this.getClient(database);\n\n await this.runMigrations(database, client);\n\n return new DatabaseTaskStore(client);\n }\n\n private isRecoverableTask(spec: TaskSpec): boolean {\n return ['startOver'].includes(\n spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n );\n }\n\n private parseSpec({ spec, id }: { spec: string; id: string }): TaskSpec {\n try {\n return JSON.parse(spec);\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${id}', ${error}`);\n }\n }\n\n private parseTaskSecrets(taskRow: RawDbTaskRow): TaskSecrets | undefined {\n try {\n return taskRow.secrets ? JSON.parse(taskRow.secrets) : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse secrets of task '${taskRow.id}', ${error}`,\n );\n }\n }\n\n private static async getClient(\n database: PluginDatabaseManager | Knex,\n ): Promise {\n if (isPluginDatabaseManager(database)) {\n return database.getClient();\n }\n\n return database;\n }\n\n private static async runMigrations(\n database: PluginDatabaseManager | Knex,\n client: Knex,\n ): Promise {\n if (!isPluginDatabaseManager(database)) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n\n return;\n }\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n }\n\n private constructor(client: Knex) {\n this.db = client;\n }\n\n async list(options: {\n createdBy?: string;\n }): Promise<{ tasks: SerializedTask[] }> {\n const queryBuilder = this.db('tasks');\n\n if (options.createdBy) {\n queryBuilder.where({\n created_by: options.createdBy,\n });\n }\n\n const results = await queryBuilder.orderBy('created_at', 'desc').select();\n\n const tasks = results.map(result => ({\n id: result.id,\n spec: JSON.parse(result.spec),\n status: result.status,\n createdBy: result.created_by ?? undefined,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n }));\n\n return { tasks };\n }\n\n async getTask(taskId: string): Promise {\n const [result] = await this.db('tasks')\n .where({ id: taskId })\n .select();\n if (!result) {\n throw new NotFoundError(`No task with id '${taskId}' found`);\n }\n try {\n const spec = JSON.parse(result.spec);\n const secrets = result.secrets ? JSON.parse(result.secrets) : undefined;\n const state = result.state ? JSON.parse(result.state).state : undefined;\n return {\n id: result.id,\n spec,\n status: result.status,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n createdBy: result.created_by ?? undefined,\n secrets,\n state,\n };\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${taskId}', ${error}`);\n }\n }\n\n async createTask(\n options: TaskStoreCreateTaskOptions,\n ): Promise {\n const taskId = uuid();\n await this.db('tasks').insert({\n id: taskId,\n spec: JSON.stringify(options.spec),\n secrets: options.secrets ? JSON.stringify(options.secrets) : undefined,\n created_by: options.createdBy ?? null,\n status: 'open',\n });\n return { taskId };\n }\n\n async claimTask(): Promise {\n return this.db.transaction(async tx => {\n const [task] = await tx('tasks')\n .where({\n status: 'open',\n })\n .limit(1)\n .select();\n\n if (!task) {\n return undefined;\n }\n\n const spec = this.parseSpec(task);\n\n const updateCount = await tx('tasks')\n .where({ id: task.id, status: 'open' })\n .update({\n status: 'processing',\n last_heartbeat_at: this.db.fn.now(),\n // remove the secrets for non-recoverable tasks when moving to processing state.\n secrets: this.isRecoverableTask(spec) ? task.secrets : null,\n });\n\n if (updateCount < 1) {\n return undefined;\n }\n\n const getState = () => {\n try {\n return task.state ? JSON.parse(task.state).state : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse state of the task '${task.id}', ${error}`,\n );\n }\n };\n\n const secrets = this.parseTaskSecrets(task);\n return {\n id: task.id,\n spec,\n status: 'processing',\n lastHeartbeatAt: task.last_heartbeat_at,\n createdAt: task.created_at,\n createdBy: task.created_by ?? undefined,\n secrets,\n state: getState(),\n };\n });\n }\n\n async heartbeatTask(taskId: string): Promise {\n const updateCount = await this.db('tasks')\n .where({ id: taskId, status: 'processing' })\n .update({\n last_heartbeat_at: this.db.fn.now(),\n });\n if (updateCount === 0) {\n throw new ConflictError(`No running task with taskId ${taskId} found`);\n }\n }\n\n async listStaleTasks(options: { timeoutS: number }): Promise<{\n tasks: { taskId: string; recovery?: TaskRecovery }[];\n }> {\n const { timeoutS } = options;\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n const rawRows = await this.db('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval);\n const tasks = rawRows.map(row => ({\n recovery: (JSON.parse(row.spec) as TaskSpec).EXPERIMENTAL_recovery,\n taskId: row.id,\n }));\n return { tasks };\n }\n\n async completeTask(options: {\n taskId: string;\n status: TaskStatus;\n eventBody: JsonObject;\n }): Promise {\n const { taskId, status, eventBody } = options;\n\n let oldStatus: TaskStatus;\n if (['failed', 'completed', 'cancelled'].includes(status)) {\n oldStatus = 'processing';\n } else {\n throw new Error(\n `Invalid status update of run '${taskId}' to status '${status}'`,\n );\n }\n\n await this.db.transaction(async tx => {\n const [task] = await tx('tasks')\n .where({\n id: taskId,\n })\n .limit(1)\n .select();\n\n const updateTask = async (criteria: {\n id: string;\n status?: TaskStatus;\n }) => {\n const updateCount = await tx('tasks')\n .where(criteria)\n .update({\n status,\n secrets: null,\n });\n\n if (updateCount !== 1) {\n throw new ConflictError(\n `Failed to update status to '${status}' for taskId ${taskId}`,\n );\n }\n\n await tx('task_events').insert({\n task_id: taskId,\n event_type: 'completion',\n body: JSON.stringify(eventBody),\n });\n };\n\n if (status === 'cancelled') {\n await updateTask({\n id: taskId,\n });\n return;\n }\n\n if (task.status === 'cancelled') {\n return;\n }\n\n if (!task) {\n throw new Error(`No task with taskId ${taskId} found`);\n }\n if (task.status !== oldStatus) {\n throw new ConflictError(\n `Refusing to update status of run '${taskId}' to status '${status}' ` +\n `as it is currently '${task.status}', expected '${oldStatus}'`,\n );\n }\n\n await updateTask({\n id: taskId,\n status: oldStatus,\n });\n });\n }\n\n async emitLogEvent(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n await this.db('task_events').insert({\n task_id: taskId,\n event_type: 'log',\n body: serializedBody,\n });\n }\n\n async getTaskState({ taskId }: { taskId: string }): Promise<\n | {\n state: JsonObject;\n }\n | undefined\n > {\n const [result] = await this.db('tasks')\n .where({ id: taskId })\n .select('state');\n return result.state ? JSON.parse(result.state) : undefined;\n }\n\n async saveTaskState(options: {\n taskId: string;\n state?: JsonObject;\n }): Promise {\n if (options.state) {\n const serializedState = JSON.stringify({ state: options.state });\n await this.db('tasks')\n .where({ id: options.taskId })\n .update({\n state: serializedState,\n });\n }\n }\n\n async listEvents(\n options: TaskStoreListEventsOptions,\n ): Promise<{ events: SerializedTaskEvent[] }> {\n const { taskId, after } = options;\n const rawEvents = await this.db('task_events')\n .where({\n task_id: taskId,\n })\n .andWhere(builder => {\n if (typeof after === 'number') {\n builder.where('id', '>', after).orWhere('event_type', 'completion');\n }\n })\n .orderBy('id')\n .select();\n\n const events = rawEvents.map(event => {\n try {\n const body = JSON.parse(event.body) as JsonObject;\n return {\n id: Number(event.id),\n taskId,\n body,\n type: event.event_type,\n createdAt: parseSqlDateToIsoString(event.created_at),\n };\n } catch (error) {\n throw new Error(\n `Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`,\n );\n }\n });\n\n return trimEventsTillLastRecovery(events);\n }\n\n async shutdownTask(options: TaskStoreShutDownTaskOptions): Promise {\n const { taskId } = options;\n const message = `This task was marked as stale as it exceeded its timeout`;\n\n const statusStepEvents = (await this.listEvents({ taskId })).events.filter(\n ({ body }) => body?.stepId,\n );\n\n const completedSteps = statusStepEvents\n .filter(\n ({ body: { status } }) => status === 'failed' || status === 'completed',\n )\n .map(step => step.body.stepId);\n\n const hungProcessingSteps = statusStepEvents\n .filter(({ body: { status } }) => status === 'processing')\n .map(event => event.body.stepId)\n .filter(step => !completedSteps.includes(step));\n\n for (const step of hungProcessingSteps) {\n await this.emitLogEvent({\n taskId,\n body: {\n message,\n stepId: step,\n status: 'failed',\n },\n });\n }\n\n await this.completeTask({\n taskId,\n status: 'failed',\n eventBody: {\n message,\n },\n });\n }\n\n async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n const [result] = await this.db('tasks')\n .where({ id: options.taskId })\n .select('workspace');\n\n await restoreWorkspace({\n path: options.targetPath,\n buffer: result.workspace,\n });\n }\n\n async cleanWorkspace({ taskId }: { taskId: string }): Promise {\n await this.db('tasks').where({ id: taskId }).update({\n workspace: undefined,\n });\n }\n\n async serializeWorkspace(options: {\n path: string;\n taskId: string;\n }): Promise {\n if (options.path) {\n await this.db('tasks')\n .where({ id: options.taskId })\n .update({\n workspace: (await serializeWorkspace(options)).contents,\n });\n }\n }\n\n async cancelTask(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n await this.db('task_events').insert({\n task_id: taskId,\n event_type: 'cancelled',\n body: serializedBody,\n });\n }\n\n async recoverTasks(\n options: TaskStoreRecoverTaskOptions,\n ): Promise<{ ids: string[] }> {\n const taskIdsToRecover: string[] = [];\n const timeoutS = Duration.fromObject(options.timeout).as('seconds');\n\n await this.db.transaction(async tx => {\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n\n const result = await tx('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval)\n .update(\n {\n status: 'open',\n last_heartbeat_at: this.db.fn.now(),\n },\n ['id', 'spec'],\n );\n\n taskIdsToRecover.push(...result.map(i => i.id));\n\n for (const { id, spec } of result) {\n const taskSpec = JSON.parse(spec as string) as TaskSpec;\n await tx('task_events').insert({\n task_id: id,\n event_type: 'recovered',\n body: JSON.stringify({\n recoverStrategy:\n taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n }),\n });\n }\n });\n\n return { ids: taskIdsToRecover };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\nimport { isArray } from 'lodash';\nimport { Schema } from 'jsonschema';\n\n/**\n * Returns true if the input is not `false`, `undefined`, `null`, `\"\"`, `0`, or\n * `[]`. This behavior is based on the behavior of handlebars, see\n * https://handlebarsjs.com/guide/builtin-helpers.html#if\n */\nexport function isTruthy(value: any): boolean {\n return isArray(value) ? value.length > 0 : !!value;\n}\n\nexport function generateExampleOutput(schema: Schema): unknown {\n const { examples } = schema as { examples?: unknown };\n if (examples && Array.isArray(examples)) {\n return examples[0];\n }\n if (schema.type === 'object') {\n return Object.fromEntries(\n Object.entries(schema.properties ?? {}).map(([key, value]) => [\n key,\n generateExampleOutput(value),\n ]),\n );\n } else if (schema.type === 'array') {\n const [firstSchema] = [schema.items]?.flat();\n if (firstSchema) {\n return [generateExampleOutput(firstSchema)];\n }\n return [];\n } else if (schema.type === 'string') {\n return '';\n } else if (schema.type === 'number') {\n return 0;\n } else if (schema.type === 'boolean') {\n return false;\n }\n return '';\n}\n\nexport const readDuration = (\n config: Config | undefined,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config?.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TaskStore } from './types';\n\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\nexport class DatabaseWorkspaceProvider implements WorkspaceProvider {\n static create(storage: TaskStore) {\n return new DatabaseWorkspaceProvider(storage);\n }\n\n private constructor(private readonly storage: TaskStore) {}\n\n public async serializeWorkspace(options: {\n path: string;\n taskId: string;\n }): Promise {\n this.storage.serializeWorkspace?.(options);\n }\n\n public async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n return this.storage.rehydrateWorkspace?.(options);\n }\n\n public async cleanWorkspace(options: { taskId: string }): Promise {\n return this.storage.cleanWorkspace?.(options);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { CurrentClaimedTask } from './StorageTaskBroker';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\nimport { DatabaseWorkspaceProvider } from './DatabaseWorkspaceProvider';\nimport { TaskStore } from './types';\n\nexport interface WorkspaceService {\n serializeWorkspace(options: { path: string }): Promise;\n\n cleanWorkspace(): Promise;\n\n rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise;\n}\n\nexport class DefaultWorkspaceService implements WorkspaceService {\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n additionalWorkspaceProviders?: Record,\n config?: Config,\n ) {\n const workspaceProviderName =\n config?.getOptionalString(\n 'scaffolder.EXPERIMENTAL_workspaceSerializationProvider',\n ) ?? 'database';\n const workspaceProvider =\n additionalWorkspaceProviders?.[workspaceProviderName] ??\n DatabaseWorkspaceProvider.create(storage);\n return new DefaultWorkspaceService(task, workspaceProvider, config);\n }\n\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly workspaceProvider: WorkspaceProvider,\n private readonly config?: Config,\n ) {}\n\n public async serializeWorkspace(options: { path: string }): Promise {\n if (this.isWorkspaceSerializationEnabled()) {\n await this.workspaceProvider.serializeWorkspace({\n path: options.path,\n taskId: this.task.taskId,\n });\n }\n }\n\n public async cleanWorkspace(): Promise {\n if (this.isWorkspaceSerializationEnabled()) {\n await this.workspaceProvider.cleanWorkspace({ taskId: this.task.taskId });\n }\n }\n\n public async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n if (this.isWorkspaceSerializationEnabled()) {\n await this.workspaceProvider.rehydrateWorkspace(options);\n }\n }\n\n private isWorkspaceSerializationEnabled(): boolean {\n return (\n this.config?.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_workspaceSerialization',\n ) ?? false\n );\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Logger } from 'winston';\nimport ObservableImpl from 'zen-observable';\nimport {\n TaskSecrets,\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { readDuration } from './helper';\nimport {\n AuthService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\ntype TaskState = {\n checkpoints: {\n [key: string]:\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n };\n};\n/**\n * TaskManager\n *\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: Logger,\n auditLogger: AuditLogger,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auditLogger,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: Logger,\n private readonly workspaceService: WorkspaceService,\n private readonly auditLogger: AuditLogger,\n private readonly auth?: AuthService,\n ) {}\n\n get taskId() {\n return this.task.taskId;\n }\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(\n options:\n | {\n key: string;\n status: 'success';\n value: JsonValue;\n }\n | {\n key: string;\n status: 'failed';\n reason: string;\n },\n ): Promise {\n const { key, ...value } = options;\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n const commonAuditFields = {\n eventName: 'ScaffolderTaskExecution',\n actorId: 'scaffolder-backend',\n stage: 'completion',\n metadata: {\n taskId: this.task.taskId,\n taskParameters: this.task.spec.parameters,\n },\n };\n if (result === 'failed') {\n await this.auditLogger?.auditLog({\n ...commonAuditFields,\n status: 'failed',\n level: 'error',\n errors: [metadata?.error],\n message: `Scaffolding task with taskId: ${this.task.taskId} failed`,\n });\n } else {\n await this.auditLogger?.auditLog({\n ...commonAuditFields,\n status: 'succeeded',\n metadata: {\n ...commonAuditFields.metadata,\n ...metadata,\n },\n message: `Scaffolding task with taskId: ${this.task.taskId} completed successfully`,\n });\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n\n workspace?: Promise;\n}\n\nfunction defer() {\n let resolve = () => {};\n const promise = new Promise(_resolve => {\n resolve = _resolve;\n });\n return { promise, resolve };\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: Logger,\n private readonly auditLogger: AuditLogger,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n ) {}\n\n async list(options?: {\n createdBy?: string;\n }): Promise<{ tasks: SerializedTask[] }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list({ createdBy: options?.createdBy });\n }\n\n private deferredDispatch = defer();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion') {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise {\n const enabled =\n this.config?.getOptionalBoolean('scaffolder.EXPERIMENTAL_recoverTasks') ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auditLogger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n while (!cancelled) {\n const result = await this.storage.listEvents({ taskId, after });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n try {\n this.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderStaleTaskCancellation',\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId: task.taskId,\n },\n message: `Attempting to cancel Stale scaffolding task ${task.taskId} because the task worker lost connection to the task broker`,\n });\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n this.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderStaleTaskCancellation',\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId: task.taskId,\n },\n message: `Stale scaffolding task ${task.taskId} successfully cancelled`,\n });\n } catch (error) {\n this.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderStaleTaskCancellation',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId: task.taskId,\n },\n errors: [\n {\n name: error.name,\n message: error.message,\n stack: error.stack,\n },\n ],\n message: `Failed to cancel stale scaffolding task ${task.taskId}`,\n });\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch.promise;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = defer();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Counter,\n CounterConfiguration,\n Gauge,\n GaugeConfiguration,\n Histogram,\n HistogramConfiguration,\n register,\n Summary,\n SummaryConfiguration,\n} from 'prom-client';\n\nexport function createCounterMetric(\n config: CounterConfiguration,\n): Counter {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Counter(config);\n register.registerMetric(metric);\n }\n return metric as Counter;\n}\n\nexport function createGaugeMetric(\n config: GaugeConfiguration,\n): Gauge {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Gauge(config);\n register.registerMetric(metric);\n }\n return metric as Gauge;\n}\n\nexport function createSummaryMetric(\n config: SummaryConfiguration,\n): Summary {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Summary(config);\n register.registerMetric(metric);\n }\n\n return metric as Summary;\n}\n\nexport function createHistogramMetric(\n config: HistogramConfiguration,\n): Histogram {\n let metric = register.getSingleMetric(config.name);\n if (!metric) {\n metric = new Histogram(config);\n register.registerMetric(metric);\n }\n\n return metric as Histogram;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeCreatePermissionRule } from '@backstage/plugin-permission-node';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n} from '@backstage/plugin-scaffolder-common/alpha';\n\nimport {\n TemplateEntityStepV1beta3,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\n\nimport { z } from 'zod';\nimport { JsonObject, JsonPrimitive } from '@backstage/types';\nimport { get } from 'lodash';\n\nexport const createTemplatePermissionRule = makeCreatePermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE\n>();\n\nexport const hasTag = createTemplatePermissionRule({\n name: 'HAS_TAG',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n description: `Match parameters or steps with the given tag`,\n paramsSchema: z.object({\n tag: z.string().describe('Name of the tag to match on'),\n }),\n apply: (resource, { tag }) => {\n return resource['backstage:permissions']?.tags?.includes(tag) ?? false;\n },\n toQuery: () => ({}),\n});\n\nexport const createActionPermissionRule = makeCreatePermissionRule<\n {\n action: string;\n input: JsonObject | undefined;\n },\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION\n>();\n\nexport const hasActionId = createActionPermissionRule({\n name: 'HAS_ACTION_ID',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n description: `Match actions with the given actionId`,\n paramsSchema: z.object({\n actionId: z.string().describe('Name of the actionId to match on'),\n }),\n apply: (resource, { actionId }) => {\n return resource.action === actionId;\n },\n toQuery: () => ({}),\n});\n\nexport const hasProperty = buildHasProperty({\n name: 'HAS_PROPERTY',\n valueSchema: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n validateProperty: false,\n});\n\nexport const hasBooleanProperty = buildHasProperty({\n name: 'HAS_BOOLEAN_PROPERTY',\n valueSchema: z.boolean(),\n});\nexport const hasNumberProperty = buildHasProperty({\n name: 'HAS_NUMBER_PROPERTY',\n valueSchema: z.number(),\n});\nexport const hasStringProperty = buildHasProperty({\n name: 'HAS_STRING_PROPERTY',\n valueSchema: z.string(),\n});\n\nfunction buildHasProperty>({\n name,\n valueSchema,\n validateProperty = true,\n}: {\n name: string;\n valueSchema: Schema;\n validateProperty?: boolean;\n}) {\n return createActionPermissionRule({\n name,\n description: `Allow actions with the specified property`,\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n paramsSchema: z.object({\n key: z\n .string()\n .describe(`Property within the action parameters to match on`),\n value: valueSchema\n .optional()\n .describe(`Value of the given property to match on`),\n }) as unknown as z.ZodType<{ key: string; value?: z.infer }>,\n apply: (resource, { key, value }) => {\n const foundValue = get(resource.input, key);\n\n if (validateProperty && !valueSchema.safeParse(foundValue).success) {\n return false;\n }\n if (value !== undefined) {\n if (valueSchema.safeParse(value).success) {\n return value === foundValue;\n }\n return false;\n }\n\n return foundValue !== undefined;\n },\n toQuery: () => ({}),\n });\n}\n\nexport const scaffolderTemplateRules = { hasTag };\nexport const scaffolderActionRules = {\n hasActionId,\n hasBooleanProperty,\n hasNumberProperty,\n hasStringProperty,\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n LoggerService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { Format, TransformableInfo } from 'logform';\nimport Transport, { TransportStreamOptions } from 'winston-transport';\nimport { Logger, format, createLogger, transports } from 'winston';\nimport { LEVEL, MESSAGE, SPLAT } from 'triple-beam';\nimport { TaskContext } from '@backstage/plugin-scaffolder-node';\nimport _ from 'lodash';\n\n/**\n * Escapes a given string to be used inside a RegExp.\n *\n * Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\n */\nconst escapeRegExp = (text: string) => {\n return text.replace(/[.*+?^${}(\\)|[\\]\\\\]/g, '\\\\$&');\n};\n\ninterface WinstonLoggerOptions {\n meta?: JsonObject;\n level: string;\n format: Format;\n transports: Transport[];\n}\n\n// This is a workaround for being able to preserve the log format of the root logger.\n// Will revisit all of this implementation once we can break the router to use only `LoggerService`.\nexport class BackstageLoggerTransport extends Transport {\n constructor(\n private readonly backstageLogger: LoggerService,\n private readonly taskContext: TaskContext,\n private readonly stepId: string,\n opts?: TransportStreamOptions,\n ) {\n super(opts);\n }\n\n log(info: TransformableInfo, callback: VoidFunction) {\n if (typeof info !== 'object' || info === null) {\n callback();\n return;\n }\n\n const message = info[MESSAGE];\n const level = info[LEVEL];\n const splat = info[SPLAT];\n\n switch (level) {\n case 'error':\n this.backstageLogger.error(String(message), ...splat);\n break;\n case 'warn':\n this.backstageLogger.warn(String(message), ...splat);\n break;\n case 'info':\n this.backstageLogger.info(String(message), ...splat);\n break;\n case 'debug':\n this.backstageLogger.debug(String(message), ...splat);\n break;\n default:\n this.backstageLogger.info(String(message), ...splat);\n }\n\n this.taskContext.emitLog(message, { stepId: this.stepId });\n callback();\n }\n}\n\nexport class WinstonLogger implements RootLoggerService {\n #winston: Logger;\n #addRedactions?: (redactions: Iterable) => void;\n\n /**\n * Creates a {@link WinstonLogger} instance.\n */\n static create(options: WinstonLoggerOptions): WinstonLogger {\n const redacter = WinstonLogger.redacter();\n\n let logger = createLogger({\n level: options.level,\n format: format.combine(options.format, redacter.format),\n transports: options.transports ?? new transports.Console(),\n });\n\n if (options.meta) {\n logger = logger.child(options.meta);\n }\n\n return new WinstonLogger(logger, redacter.add);\n }\n\n /**\n * Creates a winston log formatter for redacting secrets.\n */\n static redacter(): {\n format: Format;\n add: (redactions: Iterable) => void;\n } {\n const redactionSet = new Set();\n\n let redactionPattern: RegExp | undefined = undefined;\n\n return {\n format: format((obj: TransformableInfo) => {\n if (!redactionPattern || !obj) {\n return obj;\n }\n\n obj[MESSAGE] = obj[MESSAGE]?.replace?.(redactionPattern, '***');\n\n return obj;\n })(),\n add(newRedactions) {\n let added = 0;\n for (const redactionToTrim of newRedactions) {\n // Trimming the string ensures that we don't accdentally get extra\n // newlines or other whitespace interfering with the redaction; this\n // can happen for example when using string literals in yaml\n const redaction = redactionToTrim.trim();\n // Exclude secrets that are empty or just one character in length. These\n // typically mean that you are running local dev or tests, or using the\n // --lax flag which sets things to just 'x'.\n if (redaction.length <= 1) {\n continue;\n }\n if (!redactionSet.has(redaction)) {\n redactionSet.add(redaction);\n added += 1;\n }\n }\n if (added > 0) {\n const redactions = Array.from(redactionSet)\n .map(r => escapeRegExp(r))\n .join('|');\n redactionPattern = new RegExp(`(${redactions})`, 'g');\n }\n },\n };\n }\n\n /**\n * Creates a pretty printed winston log formatter.\n */\n static colorFormat(): Format {\n const colorizer = format.colorize();\n\n return format.combine(\n format.timestamp(),\n format.colorize({\n colors: {\n timestamp: 'dim',\n prefix: 'blue',\n field: 'cyan',\n debug: 'grey',\n },\n }),\n format.printf((info: TransformableInfo) => {\n const { timestamp, plugin, service } = info;\n const message = info[MESSAGE];\n const level = info[LEVEL];\n const fields = info[SPLAT];\n const prefix = plugin || service;\n const timestampColor = colorizer.colorize('timestamp', timestamp);\n const prefixColor = colorizer.colorize('prefix', prefix);\n\n const extraFields = Object.entries(fields)\n .map(\n ([key, value]) =>\n `${colorizer.colorize('field', `${key}`)}=${value}`,\n )\n .join(' ');\n\n return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;\n }),\n );\n }\n\n private constructor(\n winston: Logger,\n addRedactions?: (redactions: Iterable) => void,\n ) {\n this.#winston = winston;\n this.#addRedactions = addRedactions;\n }\n\n error(message: string, meta?: JsonObject): void {\n this.#winston.error(message, meta);\n }\n\n warn(message: string, meta?: JsonObject): void {\n this.#winston.warn(message, meta);\n }\n\n info(message: string, meta?: JsonObject): void {\n this.#winston.info(message, meta);\n }\n\n debug(message: string, meta?: JsonObject): void {\n this.#winston.debug(message, meta);\n }\n\n child(meta: JsonObject): LoggerService {\n return new WinstonLogger(this.#winston.child(meta));\n }\n\n addRedactions(redactions: Iterable) {\n this.#addRedactions?.(redactions);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\nimport * as winston from 'winston';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport nunjucks from 'nunjucks';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { generateExampleOutput, isTruthy } from './helper';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport { TemplateActionRegistry } from '../actions';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\n\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { createDefaultFilters } from '../../lib/templating/filters';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: winston.Logger;\n auditLogger: AuditLogger;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n};\n\ntype CheckpointState =\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: winston.Logger;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(task.secrets ?? {}));\n\n // This stream logger should be deprecated. We're going to replace it with\n // just using the logger directly, as all those logs get written to step logs\n // using the stepLogStream above.\n // Initially this stream used to be the only way to write to the client logs, but that\n // has changed over time, there's not really a need for this anymore.\n // You can just create a simple wrapper like the below in your action to write to the main logger.\n // This way we also get redactions for free.\n const streamLogger = new PassThrough();\n streamLogger.on('data', async data => {\n const message = data.toString().trim();\n if (message?.length > 1) {\n taskLogger.info(message);\n }\n });\n\n return { taskLogger, streamLogger };\n};\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record;\n private readonly tracker;\n\n constructor(private readonly options: NunjucksWorkflowRunnerOptions) {\n this.defaultTemplateFilters = createDefaultFilters({\n integrations: this.options.integrations,\n });\n this.tracker = scaffoldingTracker(this.options.auditLogger);\n }\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n try {\n const action: TemplateAction =\n this.options.actionRegistry.get(step.action);\n const { taskLogger, streamLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n });\n\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n const stepInputs =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n const commonStepAuditMetadata = {\n templateRef: task.spec.templateInfo?.entityRef || '',\n taskId: task.taskId,\n stepId: step.id,\n stepName: step.name,\n stepAction: step.action,\n stepInputs: stepInputs,\n stepConditional: step.if,\n stepEach: step.each,\n isDryRun: task.isDryRun || false,\n };\n if (step.if) {\n const ifResult = this.render(step.if, context, renderTemplate);\n if (!isTruthy(ifResult)) {\n await stepTrack.skipFalsy();\n await this.options.auditLogger.auditLog({\n eventName: 'ScaffolderTaskStepSkip',\n actorId: 'scaffolder-backend',\n stage: 'completion',\n status: 'succeeded',\n metadata: commonStepAuditMetadata,\n message: `Skipped step ${step.name} (id: ${step.id}) of task ${task.taskId}`,\n });\n return;\n }\n }\n\n await this.options.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepExecution',\n stage: 'initiation',\n status: 'succeeded',\n metadata: commonStepAuditMetadata,\n message: `Started ${step.name} (id: ${step.id}) of task ${task.taskId} triggering the ${step.action} action`,\n });\n\n if (task.isDryRun) {\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n stepInputs,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n const iterations = (\n step.each\n ? Object.entries(this.render(step.each, context, renderTemplate)).map(\n ([key, value]) => ({\n each: { key, value },\n }),\n )\n : [{}]\n ).map(i => ({\n ...i,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(\n step.input,\n { ...context, secrets: task.secrets ?? {}, ...i },\n renderTemplate,\n )\n : {},\n }));\n for (const iteration of iterations) {\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n let iterationCount: number = 0;\n for (const iteration of iterations) {\n if (iteration.each) {\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? v.toString() : v),\n 0,\n )}`,\n );\n\n await this.options.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepIteration',\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n ...commonStepAuditMetadata,\n stepInputs: undefined,\n stepAction: `${step.action}[${iteration.each.key}]`,\n stepIterationInputs: iteration.input,\n stepIterationCount: ++iterationCount,\n stepIterationValue: iteration.each.value,\n totalIterations: iterations.length,\n },\n message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} started`,\n });\n }\n\n await action.handler({\n input: iteration.input,\n secrets: task.secrets ?? {},\n // TODO(blam): move to LoggerService and away from Winston\n logger: loggerToWinstonLogger(taskLogger),\n logStream: streamLogger,\n workspacePath,\n async checkpoint(\n keySuffix: string,\n fn: () => Promise,\n ) {\n const key = `v1.task.checkpoint.${keySuffix}`;\n try {\n let prevValue: U | undefined;\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as {\n [key: string]: CheckpointState;\n }\n )?.[key];\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as U;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value,\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n });\n if (iteration.each) {\n await this.options.auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepIteration',\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n ...commonStepAuditMetadata,\n stepInputs: undefined,\n stepAction: `${step.action}[${iteration.each.key}]`,\n stepIterationCount: iterationCount,\n stepIterationValue: iteration.each.value,\n stepIterationInputs: iteration.input,\n totalIterations: iterations.length,\n },\n message: `Iteration ${iterationCount}/${iterations.length} of action ${step.action} of step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded`,\n });\n }\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed(err);\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n steps: {},\n user: task.spec.user,\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n for (const step of task.spec.steps) {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n await taskTrack.markSuccessful();\n\n return { output };\n } finally {\n if (workspacePath) {\n await task.cleanWorkspace?.();\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker(auditLogger: AuditLogger) {\n const taskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const taskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const stepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const stepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const taskTimer = taskDuration.startTimer({\n template,\n });\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n taskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n taskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n taskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const stepTimer = stepDuration.startTimer({\n template,\n step: step.name,\n });\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n stepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n await auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepExecution',\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n templateRef: template,\n taskId: task.taskId,\n stepId: step.id,\n stepName: step.name,\n stepAction: step.action,\n isDryRun: task.isDryRun || false,\n },\n message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} succeeded`,\n });\n }\n\n async function markCancelled() {\n stepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n }\n\n async function markFailed(err: Error) {\n stepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n await auditLogger.auditLog({\n actorId: 'scaffolder-backend',\n eventName: 'ScaffolderTaskStepExecution',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n templateRef: template,\n taskId: task.taskId,\n stepId: step.id,\n stepName: step.name,\n stepAction: step.action,\n isDryRun: task.isDryRun || false,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Step ${step.name} (id: ${step.id}) of task ${task.taskId} failed`,\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WorkflowRunner } from './types';\nimport {\n TaskContext,\n TaskBroker,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport PQueue from 'p-queue';\nimport { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';\nimport { Logger } from 'winston';\nimport { TemplateActionRegistry } from '../actions';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { assertError, stringifyError } from '@backstage/errors';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\n/**\n * TaskWorkerOptions\n *\n * @public\n */\nexport type TaskWorkerOptions = {\n taskBroker: TaskBroker;\n runners: {\n workflowRunner: WorkflowRunner;\n };\n concurrentTasksLimit: number;\n permissions?: PermissionEvaluator;\n logger?: Logger;\n auditLogger?: AuditLogger;\n};\n\n/**\n * CreateWorkerOptions\n *\n * @public\n */\nexport type CreateWorkerOptions = {\n taskBroker: TaskBroker;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n workingDirectory: string;\n logger: Logger;\n auditLogger: AuditLogger;\n additionalTemplateFilters?: Record;\n /**\n * The number of tasks that can be executed at the same time by the worker\n * @defaultValue 10\n * @example\n * ```\n * {\n * concurrentTasksLimit: 1,\n * // OR\n * concurrentTasksLimit: Infinity\n * }\n * ```\n */\n concurrentTasksLimit?: number;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * TaskWorker\n *\n * @public\n */\nexport class TaskWorker {\n private taskQueue: PQueue;\n private logger: Logger | undefined;\n private stopWorkers: boolean;\n private auditLogger: AuditLogger | undefined;\n\n private constructor(private readonly options: TaskWorkerOptions) {\n this.stopWorkers = false;\n this.logger = options.logger;\n this.auditLogger = options.auditLogger;\n this.taskQueue = new PQueue({\n concurrency: options.concurrentTasksLimit,\n });\n }\n\n static async create(options: CreateWorkerOptions): Promise {\n const {\n taskBroker,\n logger,\n actionRegistry,\n integrations,\n workingDirectory,\n additionalTemplateFilters,\n concurrentTasksLimit = 10, // from 1 to Infinity\n additionalTemplateGlobals,\n permissions,\n auditLogger,\n } = options;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n actionRegistry,\n integrations,\n logger,\n auditLogger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n return new TaskWorker({\n taskBroker: taskBroker,\n runners: { workflowRunner },\n concurrentTasksLimit,\n permissions,\n auditLogger,\n });\n }\n\n async recoverTasks() {\n try {\n await this.options.taskBroker.recoverTasks?.();\n } catch (err) {\n this.logger?.error(stringifyError(err));\n }\n }\n\n start() {\n (async () => {\n while (!this.stopWorkers) {\n await new Promise(resolve => setTimeout(resolve, 10000));\n await this.recoverTasks();\n }\n })();\n (async () => {\n while (!this.stopWorkers) {\n await this.onReadyToClaimTask();\n if (!this.stopWorkers) {\n const task = await this.options.taskBroker.claim();\n void this.taskQueue.add(() => this.runOneTask(task));\n }\n }\n })();\n }\n\n stop() {\n this.stopWorkers = true;\n }\n\n protected onReadyToClaimTask(): Promise {\n if (this.taskQueue.pending < this.options.concurrentTasksLimit) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n // \"next\" event emits when a task completes\n // https://github.com/sindresorhus/p-queue#next\n this.taskQueue.once('next', () => {\n resolve();\n });\n });\n }\n\n async runOneTask(task: TaskContext) {\n try {\n await this.auditLogger?.auditLog({\n eventName: 'ScaffolderTaskExecution',\n actorId: 'scaffolder-backend',\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId: task.taskId,\n taskParameters: task.spec.parameters,\n templateRef: task.spec.templateInfo?.entityRef,\n },\n message: `Scaffolding task with taskId: ${task.taskId} initiated`,\n });\n if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {\n throw new Error(\n `Unsupported Template apiVersion ${task.spec.apiVersion}`,\n );\n }\n const { output } = await this.options.runners.workflowRunner.execute(\n task,\n );\n await task.complete('completed', { output });\n } catch (error) {\n assertError(error);\n await task.complete('failed', {\n error: { name: error.name, message: error.message },\n });\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\n\n/** @internal */\nexport class DecoratedActionsRegistry extends TemplateActionRegistry {\n constructor(\n private readonly innerRegistry: TemplateActionRegistry,\n extraActions: Array,\n ) {\n super();\n for (const action of extraActions) {\n this.register(action);\n }\n }\n\n get(actionId: string): TemplateAction {\n try {\n return super.get(actionId);\n } catch {\n return this.innerRegistry.get(actionId);\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ScmIntegrations } from '@backstage/integration';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject } from '@backstage/types';\nimport { v4 as uuid } from 'uuid';\nimport { pathToFileURL } from 'url';\nimport { Logger } from 'winston';\nimport {\n createTemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n deserializeDirectoryContents,\n SerializedFile,\n serializeDirectoryContents,\n} from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\nimport { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';\nimport { DecoratedActionsRegistry } from './DecoratedActionsRegistry';\nimport fs from 'fs-extra';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n BackstageCredentials,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport type { UserEntity } from '@backstage/catalog-model';\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\ninterface DryRunInput {\n spec: TaskSpec;\n secrets?: TaskSecrets;\n directoryContents: SerializedFile[];\n credentials: BackstageCredentials;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n}\n\ninterface DryRunResult {\n log: Array<{ body: JsonObject }>;\n directoryContents: SerializedFile[];\n output: JsonObject;\n}\n\n/** @internal */\nexport type TemplateTesterCreateOptions = {\n logger: Logger;\n auditLogger: AuditLogger;\n integrations: ScmIntegrations;\n actionRegistry: TemplateActionRegistry;\n workingDirectory: string;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * Executes a dry-run of the provided template.\n *\n * The provided content will be extracted into a temporary directory\n * which is then use as the base for any relative file fetch paths.\n *\n * @internal\n */\nexport function createDryRunner(options: TemplateTesterCreateOptions) {\n return async function dryRun(input: DryRunInput): Promise {\n let contentPromise;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n ...options,\n actionRegistry: new DecoratedActionsRegistry(options.actionRegistry, [\n createTemplateAction({\n id: 'dry-run:extract',\n supportsDryRun: true,\n async handler(ctx) {\n contentPromise = serializeDirectoryContents(ctx.workspacePath);\n await contentPromise.catch(() => {});\n },\n }),\n ]),\n });\n\n const dryRunId = uuid();\n const log = new Array<{ body: JsonObject }>();\n const contentsPath = resolveSafeChildPath(\n options.workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n\n try {\n await deserializeDirectoryContents(contentsPath, input.directoryContents);\n\n const abortSignal = new AbortController().signal;\n\n const result = await workflowRunner.execute({\n taskId: dryRunId,\n spec: {\n ...input.spec,\n steps: [\n ...input.spec.steps,\n {\n id: dryRunId,\n name: 'dry-run:extract',\n action: 'dry-run:extract',\n },\n ],\n templateInfo: {\n entityRef: 'template:default/dry-run',\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n },\n },\n secrets: input.secrets,\n getInitiatorCredentials: () => Promise.resolve(input.credentials),\n // No need to update this at the end of the run, so just hard-code it\n done: false,\n isDryRun: true,\n getWorkspaceName: async () => `dry-run-${dryRunId}`,\n cancelSignal: abortSignal,\n async emitLog(message: string, logMetadata?: JsonObject) {\n if (logMetadata?.stepId === dryRunId) {\n return;\n }\n log.push({\n body: {\n ...logMetadata,\n message,\n },\n });\n },\n complete: async () => {\n throw new Error('Not implemented');\n },\n });\n\n if (!contentPromise) {\n throw new Error('Content extraction step was skipped');\n }\n const directoryContents = await contentPromise;\n\n return {\n log,\n directoryContents,\n output: result.output,\n };\n } finally {\n await fs.remove(contentsPath);\n }\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n Entity,\n ANNOTATION_LOCATION,\n parseLocationRef,\n ANNOTATION_SOURCE_LOCATION,\n CompoundEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, InputError, NotFoundError } from '@backstage/errors';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport { Logger } from 'winston';\n\nexport async function getWorkingDirectory(\n config: Config,\n logger: Logger,\n): Promise {\n if (!config.has('backend.workingDirectory')) {\n return os.tmpdir();\n }\n\n const workingDirectory = config.getString('backend.workingDirectory');\n try {\n // Check if working directory exists and is writable\n await fs.access(workingDirectory, fs.constants.F_OK | fs.constants.W_OK);\n logger.info(`using working directory: ${workingDirectory}`);\n } catch (err) {\n assertError(err);\n logger.error(\n `working directory ${workingDirectory} ${\n err.code === 'ENOENT' ? 'does not exist' : 'is not writable'\n }`,\n );\n throw err;\n }\n return workingDirectory;\n}\n\n/**\n * Gets the base URL of the entity location that points to the source location\n * of the entity description within a repo. If there is not source location\n * or if it has an invalid type, undefined will be returned instead.\n *\n * For file locations this will return a `file://` URL.\n */\nexport function getEntityBaseUrl(entity: Entity): string | undefined {\n let location = entity.metadata.annotations?.[ANNOTATION_SOURCE_LOCATION];\n if (!location) {\n location = entity.metadata.annotations?.[ANNOTATION_LOCATION];\n }\n if (!location) {\n return undefined;\n }\n\n const { type, target } = parseLocationRef(location);\n if (type === 'url') {\n return target;\n } else if (type === 'file') {\n return `file://${target}`;\n }\n\n // Only url and file location are handled, as we otherwise don't know if\n // what the url is pointing to makes sense to use as a baseUrl\n return undefined;\n}\n\n/**\n * Will use the provided CatalogApi to go find the given template entity with an additional token.\n * Returns the matching template, or throws a NotFoundError if no such template existed.\n */\nexport async function findTemplate(options: {\n entityRef: CompoundEntityRef;\n token?: string;\n catalogApi: CatalogApi;\n}): Promise {\n const { entityRef, token, catalogApi } = options;\n\n if (entityRef.kind.toLocaleLowerCase('en-US') !== 'template') {\n throw new InputError(`Invalid kind, only 'Template' kind is supported`);\n }\n\n const template = await catalogApi.getEntityByRef(entityRef, { token });\n if (!template) {\n throw new NotFoundError(\n `Template ${stringifyEntityRef(entityRef)} not found`,\n );\n }\n\n return template as TemplateEntityV1beta3;\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n BasicPermission,\n} from '@backstage/plugin-permission-common';\n\nexport type checkPermissionOptions = {\n credentials: BackstageCredentials;\n permissions: BasicPermission[];\n permissionService?: PermissionsService;\n};\n\n/**\n * Does a basic check on permissions. Throws 403 error if any permission responds with AuthorizeResult.DENY\n * @public\n */\nexport async function checkPermission(options: checkPermissionOptions) {\n const { permissions, permissionService, credentials } = options;\n if (permissionService) {\n const permissionRequest = permissions.map(permission => ({\n permission,\n }));\n const authorizationResponses = await permissionService.authorize(\n permissionRequest,\n { credentials: credentials },\n );\n\n for (const response of authorizationResponses) {\n if (response.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n HostDiscovery,\n PluginDatabaseManager,\n UrlReader,\n createLegacyAuthAdapters,\n} from '@backstage/backend-common';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n CompoundEntityRef,\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { InputError, NotFoundError, stringifyError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { HumanDuration, JsonObject, JsonValue } from '@backstage/types';\nimport {\n TaskSpec,\n TemplateEntityV1beta3,\n templateEntityV1beta3Validator,\n TemplateParametersV1beta3,\n TemplateEntityStepV1beta3,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n scaffolderActionPermissions,\n scaffolderTemplatePermissions,\n taskCancelPermission,\n taskCreatePermission,\n taskReadPermission,\n templateParameterReadPermission,\n templateStepReadPermission,\n scaffolderTaskPermissions,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { validate } from 'jsonschema';\nimport { Logger } from 'winston';\nimport { z } from 'zod';\nimport {\n TemplateAction,\n TaskBroker,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n createBuiltinActions,\n DatabaseTaskStore,\n TaskWorker,\n TemplateActionRegistry,\n} from '../scaffolder';\nimport { createDryRunner } from '../scaffolder/dryrun';\nimport { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker';\nimport { findTemplate, getEntityBaseUrl, getWorkingDirectory } from './helpers';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport {\n createConditionAuthorizer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { scaffolderActionRules, scaffolderTemplateRules } from './rules';\nimport { Duration } from 'luxon';\nimport {\n AuthService,\n BackstageCredentials,\n DiscoveryService,\n HttpAuthService,\n LifecycleService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport {\n IdentityApi,\n IdentityApiGetIdentityRequest,\n} from '@backstage/plugin-auth-node';\nimport { InternalTaskSecrets } from '../scaffolder/tasks/types';\nimport { checkPermission } from '../util/checkPermissions';\nimport {\n AutocompleteHandler,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { cloneDeep } from 'lodash';\n\nimport { DefaultAuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\n\n/**\n *\n * @public\n */\nexport type TemplatePermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n TParams\n>;\nfunction isTemplatePermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is TemplatePermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TEMPLATE;\n}\n\n/**\n *\n * @public\n */\nexport type ActionPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION,\n TParams\n>;\nfunction isActionPermissionRuleInput(\n permissionRule: TemplatePermissionRuleInput | ActionPermissionRuleInput,\n): permissionRule is ActionPermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_ACTION;\n}\n\n/**\n * RouterOptions\n *\n * @public\n */\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n reader: UrlReader;\n lifecycle?: LifecycleService;\n database: PluginDatabaseManager;\n catalogClient: CatalogApi;\n scheduler?: PluginTaskScheduler;\n actions?: TemplateAction[];\n /**\n * @deprecated taskWorkers is deprecated in favor of concurrentTasksLimit option with a single TaskWorker\n * @defaultValue 1\n */\n taskWorkers?: number;\n /**\n * Sets the number of concurrent tasks that can be run at any given time on the TaskWorker\n * @defaultValue 10\n */\n concurrentTasksLimit?: number;\n taskBroker?: TaskBroker;\n additionalTemplateFilters?: Record;\n additionalTemplateGlobals?: Record;\n additionalWorkspaceProviders?: Record;\n permissions?: PermissionsService;\n permissionRules?: Array<\n TemplatePermissionRuleInput | ActionPermissionRuleInput\n >;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n identity?: IdentityApi;\n discovery?: DiscoveryService;\n\n autocompleteHandlers?: Record;\n}\n\nfunction isSupportedTemplate(entity: TemplateEntityV1beta3) {\n return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';\n}\n\n/*\n * @deprecated This function remains as the DefaultIdentityClient behaves slightly differently to the pre-existing\n * scaffolder behaviour. Specifically if the token fails to parse, the DefaultIdentityClient will raise an error.\n * The scaffolder did not raise an error in this case. As such we chose to allow it to behave as it did previously\n * until someone explicitly passes an IdentityApi. When we have reasonable confidence that most backstage deployments\n * are using the IdentityApi, we can remove this function.\n */\nfunction buildDefaultIdentityClient(options: RouterOptions): IdentityApi {\n return {\n getIdentity: async ({ request }: IdentityApiGetIdentityRequest) => {\n const header = request.headers.authorization;\n const { logger } = options;\n\n if (!header) {\n return undefined;\n }\n\n try {\n const token = header.match(/^Bearer\\s(\\S+\\.\\S+\\.\\S+)$/i)?.[1];\n if (!token) {\n throw new TypeError('Expected Bearer with JWT');\n }\n\n const [_header, rawPayload, _signature] = token.split('.');\n const payload: JsonValue = JSON.parse(\n Buffer.from(rawPayload, 'base64').toString(),\n );\n\n if (\n typeof payload !== 'object' ||\n payload === null ||\n Array.isArray(payload)\n ) {\n throw new TypeError('Malformed JWT payload');\n }\n\n const sub = payload.sub;\n if (typeof sub !== 'string') {\n throw new TypeError('Expected string sub claim');\n }\n\n if (sub === 'backstage-server') {\n return undefined;\n }\n\n // Check that it's a valid ref, otherwise this will throw.\n parseEntityRef(sub);\n\n return {\n identity: {\n userEntityRef: sub,\n ownershipEntityRefs: [],\n type: 'user',\n },\n token,\n };\n } catch (e) {\n logger.error(`Invalid authorization header: ${stringifyError(e)}`);\n return undefined;\n }\n },\n };\n}\n\nconst readDuration = (\n config: Config,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n\n/**\n * A method to create a router for the scaffolder backend plugin.\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise {\n const router = Router();\n // Be generous in upload size to support a wide range of templates in dry-run mode.\n router.use(express.json({ limit: '10MB' }));\n\n const {\n logger: parentLogger,\n config,\n reader,\n database,\n catalogClient,\n actions,\n taskWorkers,\n scheduler,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n additionalWorkspaceProviders,\n permissions,\n permissionRules,\n discovery = HostDiscovery.fromConfig(config),\n identity = buildDefaultIdentityClient(options),\n autocompleteHandlers = {},\n } = options;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...options,\n identity,\n discovery,\n });\n\n const concurrentTasksLimit =\n options.concurrentTasksLimit ??\n options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');\n\n const logger = parentLogger.child({ plugin: 'scaffolder' });\n const auditLogger = new DefaultAuditLogger({\n logger,\n authService: auth,\n httpAuthService: httpAuth,\n });\n\n const workingDirectory = await getWorkingDirectory(config, logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n let taskBroker: TaskBroker;\n if (!options.taskBroker) {\n const databaseTaskStore = await DatabaseTaskStore.create({ database });\n taskBroker = new StorageTaskBroker(\n databaseTaskStore,\n logger,\n auditLogger,\n config,\n auth,\n additionalWorkspaceProviders,\n );\n\n if (scheduler && databaseTaskStore.listStaleTasks) {\n await scheduler.scheduleTask({\n id: 'close_stale_tasks',\n frequency: readDuration(\n config,\n 'scaffolder.taskTimeoutJanitorFrequency',\n {\n minutes: 5,\n },\n ),\n timeout: { minutes: 15 },\n fn: async () => {\n const { tasks } = await databaseTaskStore.listStaleTasks({\n timeoutS: Duration.fromObject(\n readDuration(config, 'scaffolder.taskTimeout', {\n hours: 24,\n }),\n ).as('seconds'),\n });\n\n for (const task of tasks) {\n await databaseTaskStore.shutdownTask(task);\n logger.info(`Successfully closed stale task ${task.taskId}`);\n }\n },\n });\n }\n } else {\n taskBroker = options.taskBroker;\n }\n\n const actionRegistry = new TemplateActionRegistry();\n\n const workers: TaskWorker[] = [];\n if (concurrentTasksLimit !== 0) {\n for (let i = 0; i < (taskWorkers || 1); i++) {\n const worker = await TaskWorker.create({\n taskBroker,\n actionRegistry,\n integrations,\n logger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n concurrentTasksLimit,\n permissions,\n auditLogger,\n });\n workers.push(worker);\n }\n }\n\n const actionsToRegister = Array.isArray(actions)\n ? actions\n : createBuiltinActions({\n integrations,\n catalogClient,\n reader,\n config,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n });\n\n actionsToRegister.forEach(action => actionRegistry.register(action));\n\n const launchWorkers = () => workers.forEach(worker => worker.start());\n\n const shutdownWorkers = () => {\n workers.forEach(worker => worker.stop());\n };\n\n if (options.lifecycle) {\n options.lifecycle.addStartupHook(launchWorkers);\n options.lifecycle.addShutdownHook(shutdownWorkers);\n } else {\n launchWorkers();\n }\n\n const dryRunner = createDryRunner({\n actionRegistry,\n integrations,\n logger,\n auditLogger,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n });\n\n const templateRules: TemplatePermissionRuleInput[] = Object.values(\n scaffolderTemplateRules,\n );\n const actionRules: ActionPermissionRuleInput[] = Object.values(\n scaffolderActionRules,\n );\n\n if (permissionRules) {\n templateRules.push(\n ...permissionRules.filter(isTemplatePermissionRuleInput),\n );\n actionRules.push(...permissionRules.filter(isActionPermissionRuleInput));\n }\n\n const isAuthorized = createConditionAuthorizer(Object.values(templateRules));\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resources: [\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n permissions: scaffolderTemplatePermissions,\n rules: templateRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n permissions: scaffolderActionPermissions,\n rules: actionRules,\n },\n ],\n permissions: scaffolderTaskPermissions,\n });\n\n router.use(permissionIntegrationRouter);\n\n router\n .get(\n '/v2/templates/:namespace/:kind/:name/parameter-schema',\n async (req, res) => {\n const requestedTemplateRef = `${req.params.kind}:${req.params.namespace}/${req.params.name}`;\n const actorId = await auditLogger.getActorId(req);\n try {\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n await auditLogger.auditLog({\n eventName: 'ScaffolderParameterSchemaFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n templateRef: requestedTemplateRef,\n },\n request: req,\n message: `${actorId} requested the parameter schema for ${requestedTemplateRef}`,\n });\n const template = await authorizeTemplate(\n req.params,\n token,\n credentials,\n );\n\n const parameters = [template.spec.parameters ?? []].flat();\n\n const presentation = template.spec.presentation;\n const templateRef = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n const responseBody = {\n title: template.metadata.title ?? template.metadata.name,\n ...(presentation ? { presentation } : {}),\n description: template.metadata.description,\n 'ui:options': template.metadata['ui:options'],\n steps: parameters.map(schema => ({\n title: schema.title ?? 'Please enter the following information',\n description: schema.description,\n schema,\n })),\n };\n await auditLogger.auditLog({\n eventName: 'ScaffolderParameterSchemaFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n templateRef: templateRef,\n },\n request: req,\n response: {\n status: 200,\n body: responseBody,\n },\n message: `${actorId} successfully requested the parameter schema for ${templateRef}`,\n });\n\n res.json(responseBody);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderParameterSchemaFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n metadata: {\n templateRef: requestedTemplateRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} failed to request the parameter schema for ${requestedTemplateRef}`,\n });\n throw err;\n }\n },\n )\n .get('/v2/actions', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderInstalledActionsFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n request: req,\n message: `${actorId} requested the list of installed actions`,\n });\n const actionsList = actionRegistry.list().map(action => {\n return {\n id: action.id,\n description: action.description,\n examples: action.examples,\n schema: action.schema,\n };\n });\n await auditLogger.auditLog({\n eventName: 'ScaffolderInstalledActionsFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n request: req,\n response: {\n status: 200,\n body: actionsList,\n },\n message: `${actorId} successfully requested the list of installed actions`,\n });\n res.json(actionsList);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderInstalledActionsFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} failed to request for the list of installed actions`,\n });\n throw err;\n }\n })\n .post('/v2/tasks', async (req, res) => {\n const templateRef: string = req.body.templateRef;\n const { kind, namespace, name } = parseEntityRef(templateRef, {\n defaultKind: 'template',\n });\n const credentials = await httpAuth.credentials(req);\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n const values = req.body.values;\n const redactedRequest = cloneDeep(req);\n\n // Workaround ensure that redactedRequest.ip accesses the original req.ip with the correct context, preventing 'Illegal invocation' errors\n Object.defineProperty(redactedRequest, 'ip', {\n get: () => {\n return req.ip;\n },\n });\n if (req.body.secrets) {\n const redactedBody = {\n ...req.body,\n secrets: Object.keys(req.body.secrets).reduce((acc, key) => {\n return {\n ...acc,\n [key]: '***',\n };\n }, {} as TaskSecrets),\n };\n redactedRequest.body = redactedBody;\n }\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'initiation',\n status: 'succeeded',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n templateRef: templateRef,\n },\n message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} initiated`,\n });\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n const template = await authorizeTemplate(\n { kind, namespace, name },\n token,\n credentials,\n );\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(values, parameters);\n if (!result.valid) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n templateRef: templateRef,\n },\n response: {\n status: 400,\n body: { errors: result.errors },\n },\n errors: result.errors,\n message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed`,\n });\n return res.status(400).json({ errors: result.errors });\n }\n }\n\n const baseUrl = getEntityBaseUrl(template);\n\n const taskSpec: TaskSpec = {\n apiVersion: template.apiVersion,\n steps: template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n })),\n EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery,\n output: template.spec.output ?? {},\n parameters: values,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n templateInfo: {\n entityRef: stringifyEntityRef({ kind, name, namespace }),\n baseUrl,\n entity: {\n metadata: template.metadata,\n },\n },\n };\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: token,\n __initiatorCredentials: JSON.stringify(credentials),\n };\n\n const result = await taskBroker.dispatch({\n spec: taskSpec,\n createdBy: userEntityRef,\n secrets,\n });\n\n let auditLog = `Scaffolding task for ${templateRef}`;\n if (userEntityRef) {\n auditLog += ` created by ${userEntityRef}`;\n }\n\n logger.info(auditLog);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'completion',\n status: 'succeeded',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n taskId: result.taskId,\n templateRef: templateRef,\n },\n response: {\n status: 201,\n body: { id: result.taskId },\n },\n message: `Scaffolding task for ${templateRef} with taskId: ${result.taskId} successfully created by ${userEntityRef}`,\n });\n return res.status(201).json({ id: result.taskId });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCreation',\n stage: 'completion',\n status: 'failed',\n level: 'error',\n actorId: userEntityRef,\n request: redactedRequest,\n metadata: {\n templateRef: templateRef,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Scaffolding task for ${templateRef} creation attempt by ${userEntityRef} failed`,\n });\n throw err;\n }\n })\n .get('/v2/tasks', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n\n try {\n const [userEntityRef] = [req.query.createdBy].flat();\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskListFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n request: req,\n message: `${actorId} requested for the list of scaffolder tasks`,\n });\n const credentials = await httpAuth.credentials(req);\n\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n if (\n typeof userEntityRef !== 'string' &&\n typeof userEntityRef !== 'undefined'\n ) {\n throw new InputError('createdBy query parameter must be a string');\n }\n\n if (!taskBroker.list) {\n throw new Error(\n 'TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.',\n );\n }\n\n const tasks = await taskBroker.list({\n createdBy: userEntityRef,\n });\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskListFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n request: req,\n response: {\n status: 200,\n body: tasks,\n },\n message: `${actorId} successfully requested for the list of scaffolder tasks`,\n });\n res.status(200).json(tasks);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskListFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} request for the list of scaffolder tasks failed`,\n });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId: taskId,\n },\n request: req,\n message: `${actorId} requested for scaffolder task ${taskId}`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const task = await taskBroker.get(taskId);\n if (!task) {\n throw new NotFoundError(`Task with id ${taskId} does not exist`);\n }\n // Do not disclose secrets\n delete task.secrets;\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n request: req,\n response: {\n status: 200,\n body: task,\n },\n message: `${actorId} successfully requested for scaffolder tasks ${taskId}`,\n });\n res.status(200).json(task);\n } catch (err) {\n let status = 500;\n if (err.name === 'NotFoundError') {\n status = 404;\n }\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n response: {\n status: status,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId} request for scaffolder tasks ${taskId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/cancel', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCancellation',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Cancellation request for Scaffolding task with taskId: ${taskId} from ${actorId} received`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCancelPermission],\n permissionService: permissions,\n });\n await taskBroker.cancel?.(taskId);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCancellation',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n response: {\n status: 200,\n body: { status: 'cancelled' },\n },\n message: `Scaffolding task with taskId: ${taskId} successfully cancelled by ${actorId}`,\n });\n res.status(200).json({ status: 'cancelled' });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskCancellation',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `${actorId}'s cancel request for task ${taskId} failed`,\n });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/eventstream', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n const after =\n req.query.after !== undefined ? Number(req.query.after) : undefined;\n\n logger.debug(`Event stream observing taskId '${taskId}' opened`);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Event stream for scaffolding task with taskId: ${taskId} was opened by ${actorId}`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // After client opens connection send all events as string\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: error.name,\n message: error.message,\n stack: error.stack,\n cause: error.cause,\n },\n ],\n message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}`,\n });\n res.end();\n },\n next: ({ events }) => {\n let shouldUnsubscribe = false;\n for (const event of events) {\n res.write(\n `event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n );\n if (event.type === 'completion') {\n shouldUnsubscribe = true;\n }\n }\n // res.flush() is only available with the compression middleware\n res.flush?.();\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n res.end();\n }\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', async () => {\n subscription.unsubscribe();\n logger.debug(`Event stream observing taskId '${taskId}' closed`);\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Event stream observing scaffolding task with taskId: ${taskId} was closed by ${actorId}`,\n });\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskStream',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Received error from event stream observing scaffolding task with taskId: ${taskId} requested by ${actorId}`,\n });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/events', async (req, res) => {\n const { taskId } = req.params;\n const actorId = await auditLogger.getActorId(req);\n try {\n const after = Number(req.query.after) || undefined;\n\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} initiated by ${actorId}`,\n });\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n // cancel the request after 30 seconds. this aligns with the recommendations of RFC 6202.\n const timeout = setTimeout(() => {\n res.json([]);\n }, 30_000);\n\n // Get all known events after an id (always includes the completion event) and return the first callback\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: error.name,\n message: error.message,\n stack: error.stack,\n },\n ],\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed`,\n });\n },\n next: async ({ events }) => {\n clearTimeout(timeout);\n subscription.unsubscribe();\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n taskId,\n },\n request: req,\n response: {\n status: 200,\n body: events,\n },\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} by ${actorId} succeeded`,\n });\n res.json(events);\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n clearTimeout(timeout);\n });\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskEventFetch',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n taskId,\n },\n request: req,\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Task events fetch attempt for scaffolding task with taskId: ${taskId} requested by ${actorId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/dry-run', async (req, res) => {\n const actorId = await auditLogger.getActorId(req);\n try {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'initiation',\n status: 'succeeded',\n metadata: {\n isDryRun: true,\n },\n request: req,\n message: `Dry Run scaffolder task initiated by ${actorId}`,\n });\n const credentials = await httpAuth.credentials(req);\n\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n const bodySchema = z.object({\n template: z.unknown(),\n values: z.record(z.unknown()),\n secrets: z.record(z.string()).optional(),\n directoryContents: z.array(\n z.object({ path: z.string(), base64Content: z.string() }),\n ),\n });\n const body = await bodySchema.parseAsync(req.body).catch(e => {\n throw new InputError(`Malformed request: ${e}`);\n });\n\n const template = body.template as TemplateEntityV1beta3;\n if (!(await templateEntityV1beta3Validator.check(template))) {\n throw new InputError('Input template is not a template');\n }\n const templateRef: string = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n const userEntity = userEntityRef\n ? await catalogClient.getEntityByRef(userEntityRef, { token })\n : undefined;\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(body.values, parameters);\n if (!result.valid) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n metadata: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n isDryRun: true,\n },\n errors: result.errors,\n request: req,\n response: {\n status: 400,\n body: { errors: result.errors },\n },\n message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} failed`,\n });\n return res.status(400).json({ errors: result.errors });\n }\n }\n\n const steps = template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n }));\n\n const result = await dryRunner({\n spec: {\n apiVersion: template.apiVersion,\n steps,\n output: template.spec.output ?? {},\n parameters: body.values as JsonObject,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n },\n directoryContents: (body.directoryContents ?? []).map(file => ({\n path: file.path,\n content: Buffer.from(file.base64Content, 'base64'),\n })),\n secrets: {\n ...body.secrets,\n ...(token && { backstageToken: token }),\n },\n credentials,\n });\n\n const dryRunResults = {\n ...result,\n steps,\n directoryContents: result.directoryContents.map(file => ({\n path: file.path,\n executable: file.executable,\n base64Content: file.content.toString('base64'),\n })),\n };\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'completion',\n status: 'succeeded',\n metadata: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n isDryRun: true,\n },\n request: req,\n response: {\n status: 200,\n body: dryRunResults,\n },\n message: `Dry Run scaffolder task for ${templateRef} initiated by ${actorId} completed successfully`,\n });\n return res.status(200).json(dryRunResults);\n } catch (err) {\n await auditLogger.auditLog({\n eventName: 'ScaffolderTaskDryRun',\n actorId,\n stage: 'completion',\n status: 'failed',\n level: 'error',\n request: req,\n metadata: {\n isDryRun: true,\n },\n errors: [\n {\n name: err.name,\n message: err.message,\n stack: err.stack,\n },\n ],\n message: `Scaffolder Task Dry Run requested by ${actorId} failed`,\n });\n throw err;\n }\n })\n .post('/v2/autocomplete/:provider/:resource', async (req, res) => {\n const { token, context } = req.body;\n const { provider, resource } = req.params;\n\n if (!token) throw new InputError('Missing token query parameter');\n\n if (!autocompleteHandlers[provider]) {\n throw new InputError(`Unsupported provider: ${provider}`);\n }\n\n const { results } = await autocompleteHandlers[provider]({\n resource,\n token,\n context,\n });\n\n res.status(200).json({ results });\n });\n\n const app = express();\n app.set('logger', logger);\n app.use('/', router);\n\n async function authorizeTemplate(\n entityRef: CompoundEntityRef,\n token: string | undefined,\n credentials: BackstageCredentials,\n ) {\n const template = await findTemplate({\n catalogApi: catalogClient,\n entityRef,\n token,\n });\n\n if (!isSupportedTemplate(template)) {\n throw new InputError(\n `Unsupported apiVersion field in schema entity, ${\n (template as Entity).apiVersion\n }`,\n );\n }\n\n if (!permissions) {\n return template;\n }\n\n const [parameterDecision, stepDecision] =\n await permissions.authorizeConditional(\n [\n { permission: templateParameterReadPermission },\n { permission: templateStepReadPermission },\n ],\n { credentials },\n );\n\n // Authorize parameters\n if (Array.isArray(template.spec.parameters)) {\n template.spec.parameters = template.spec.parameters.filter(step =>\n isAuthorized(parameterDecision, step),\n );\n } else if (\n template.spec.parameters &&\n !isAuthorized(parameterDecision, template.spec.parameters)\n ) {\n template.spec.parameters = undefined;\n }\n\n // Authorize steps\n template.spec.steps = template.spec.steps.filter(step =>\n isAuthorized(stepDecision, step),\n );\n\n return template;\n }\n\n return app;\n}\n"],"names":["examples","yaml","id","createTemplateAction","InputError","stringifyEntityRef","z","fs","resolveSafeChildPath","parseEntityRef","relative","readdir","join","stat","Duration","fetchContents","fetchFile","Isolate","resolvePackagePath","parseRepoUrl","get","globby","extname","isBinaryFile","DefaultGithubCredentialsProvider","createPublishGerritAction","createPublishGerritReviewAction","createPublishGiteaAction","createPublishGithubAction","createPublishGithubPullRequestAction","createPublishGitlabAction","createPublishGitlabMergeRequestAction","createGitlabRepoPushAction","createPublishBitbucketAction","createPublishBitbucketCloudAction","createPublishBitbucketServerAction","createPublishBitbucketServerPullRequestAction","createPublishAzureAction","createGithubActionsDispatchAction","createGithubWebhookAction","createGithubIssuesLabelAction","createGithubRepoCreateAction","createGithubRepoPushAction","createGithubEnvironmentAction","createGithubDeployKeyAction","createGithubAutolinksAction","createBitbucketPipelinesRunAction","ConflictError","NotFoundError","DateTime","uuid","restoreWorkspace","serializeWorkspace","isArray","readDuration","config","readDurationFromConfig","ObservableImpl","register","Counter","Histogram","makeCreatePermissionRule","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","RESOURCE_TYPE_SCAFFOLDER_ACTION","Transport","MESSAGE","LEVEL","SPLAT","createLogger","format","transports","winston","PassThrough","createConditionAuthorizer","nunjucks","templated","validateJsonSchema","errors","NotAllowedError","loggerToWinstonLogger","stringifyError","path","actionExecutePermission","AuthorizeResult","PQueue","assertError","serializeDirectoryContents","deserializeDirectoryContents","pathToFileURL","os","ANNOTATION_SOURCE_LOCATION","ANNOTATION_LOCATION","parseLocationRef","Router","express","HostDiscovery","createLegacyAuthAdapters","DefaultAuditLogger","ScmIntegrations","createPermissionIntegrationRouter","scaffolderTemplatePermissions","scaffolderActionPermissions","scaffolderTaskPermissions","cloneDeep","taskCreatePermission","result","validate","taskReadPermission","taskCancelPermission","templateEntityV1beta3Validator","templateParameterReadPermission","templateStepReadPermission"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBO,MAAMA,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,2BAAA;AAAA,IACb,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,kBAAA;AAAA,UACR,EAAI,EAAA,uBAAA;AAAA,UACJ,IAAM,EAAA,2BAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,cACE,EAAA,qEAAA;AAAA,WACJ;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;ACZA,MAAMC,IAAK,GAAA,kBAAA,CAAA;AAMJ,SAAS,4BAA4B,OAIzC,EAAA;AACD,EAAA,MAAM,EAAE,aAAA,EAAe,YAAc,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AAE9C,EAAA,OAAOC,yCAGL,CAAA;AAAA,QACAD,IAAA;AAAA,IACA,WACE,EAAA,+FAAA;AAAA,cACFF,UAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL;AAAA,YACE,IAAM,EAAA,QAAA;AAAA,YACN,QAAA,EAAU,CAAC,gBAAgB,CAAA;AAAA,YAC3B,UAAY,EAAA;AAAA,cACV,cAAgB,EAAA;AAAA,gBACd,KAAO,EAAA,kBAAA;AAAA,gBACP,WACE,EAAA,4DAAA;AAAA,gBACF,IAAM,EAAA,QAAA;AAAA,eACR;AAAA,cACA,QAAU,EAAA;AAAA,gBACR,KAAO,EAAA,UAAA;AAAA,gBACP,WACE,EAAA,oEAAA;AAAA,gBACF,IAAM,EAAA,SAAA;AAAA,eACR;AAAA,aACF;AAAA,WACF;AAAA,UACA;AAAA,YACE,IAAM,EAAA,QAAA;AAAA,YACN,QAAA,EAAU,CAAC,iBAAiB,CAAA;AAAA,YAC5B,UAAY,EAAA;AAAA,cACV,eAAiB,EAAA;AAAA,gBACf,KAAO,EAAA,yBAAA;AAAA,gBACP,WACE,EAAA,qEAAA;AAAA,gBACF,IAAM,EAAA,QAAA;AAAA,eACR;AAAA,cACA,eAAiB,EAAA;AAAA,gBACf,KAAO,EAAA,WAAA;AAAA,gBACP,WACE,EAAA,sGAAA;AAAA,gBACF,IAAM,EAAA,QAAA;AAAA,eACR;AAAA,cACA,QAAU,EAAA;AAAA,gBACR,KAAO,EAAA,UAAA;AAAA,gBACP,WACE,EAAA,oEAAA;AAAA,gBACF,IAAM,EAAA,SAAA;AAAA,eACR;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,MACA,MAAQ,EAAA;AAAA,QACN,IAAM,EAAA,QAAA;AAAA,QACN,QAAA,EAAU,CAAC,gBAAgB,CAAA;AAAA,QAC3B,UAAY,EAAA;AAAA,UACV,SAAW,EAAA;AAAA,YACT,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,cAAgB,EAAA;AAAA,YACd,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAM,MAAA,EAAE,OAAU,GAAA,GAAA,CAAA;AAElB,MAAI,IAAA,cAAA,CAAA;AACJ,MAAA,IAAI,oBAAoB,KAAO,EAAA;AAC7B,QAAA,cAAA,GAAiB,KAAM,CAAA,cAAA,CAAA;AAAA,OAClB,MAAA;AACL,QAAA,MAAM,EAAE,eAAA,EAAiB,eAAkB,GAAA,oBAAA,EACzC,GAAA,KAAA,CAAA;AACF,QAAM,MAAA,WAAA,GAAc,YAAa,CAAA,KAAA,CAAM,eAAe,CAAA,CAAA;AACtD,QAAA,IAAI,CAAC,WAAa,EAAA;AAChB,UAAA,MAAM,IAAII,iBAAA;AAAA,YACR,iCAAiC,eAAe,CAAA,CAAA;AAAA,WAClD,CAAA;AAAA,SACF;AAEA,QAAA,cAAA,GAAiB,YAAY,UAAW,CAAA;AAAA,UACtC,IAAM,EAAA,eAAA;AAAA,UACN,GAAK,EAAA,eAAA;AAAA,SACN,CAAA,CAAA;AAAA,OACH;AAEA,MAAA,GAAA,CAAI,MAAO,CAAA,IAAA,CAAK,CAAe,YAAA,EAAA,cAAc,CAAiB,eAAA,CAAA,CAAA,CAAA;AAE9D,MAAA,MAAM,EAAE,KAAA,EAAW,GAAA,MAAM,MAAM,qBAAsB,CAAA;AAAA,QACnD,UAAA,EAAY,MAAM,GAAA,CAAI,uBAAwB,EAAA;AAAA,QAC9C,cAAgB,EAAA,SAAA;AAAA,OACjB,CAAM,IAAA,EAAE,KAAO,EAAA,GAAA,CAAI,SAAS,cAAe,EAAA,CAAA;AAE5C,MAAI,IAAA;AAEF,QAAA,MAAM,aAAc,CAAA,WAAA;AAAA,UAClB;AAAA,YACE,IAAM,EAAA,KAAA;AAAA,YACN,MAAQ,EAAA,cAAA;AAAA,WACV;AAAA,UACA,KAAQ,GAAA,EAAE,KAAM,EAAA,GAAI,EAAC;AAAA,SACvB,CAAA;AAAA,eACO,CAAG,EAAA;AACV,QAAI,IAAA,CAAC,MAAM,QAAU,EAAA;AAEnB,UAAM,MAAA,CAAA,CAAA;AAAA,SACR;AAAA,OACF;AAEA,MAAI,IAAA;AAEF,QAAM,MAAA,MAAA,GAAS,MAAM,aAAc,CAAA,WAAA;AAAA,UACjC;AAAA,YACE,MAAQ,EAAA,IAAA;AAAA,YACR,IAAM,EAAA,KAAA;AAAA,YACN,MAAQ,EAAA,cAAA;AAAA,WACV;AAAA,UACA,KAAQ,GAAA,EAAE,KAAM,EAAA,GAAI,EAAC;AAAA,SACvB,CAAA;AAEA,QAAI,IAAA,MAAA,CAAO,SAAS,MAAQ,EAAA;AAC1B,UAAM,MAAA,EAAE,UAAa,GAAA,MAAA,CAAA;AACrB,UAAI,IAAA,MAAA,CAAA;AAEJ,UAAA,MAAA,GAAS,QAAS,CAAA,IAAA;AAAA,YAChB,CAAA,CAAA,KACE,CAAC,CAAE,CAAA,QAAA,CAAS,KAAK,UAAW,CAAA,YAAY,CACxC,IAAA,CAAA,CAAE,IAAS,KAAA,WAAA;AAAA,WACf,CAAA;AACA,UAAA,IAAI,CAAC,MAAQ,EAAA;AACX,YAAA,MAAA,GAAS,QAAS,CAAA,IAAA;AAAA,cAChB,OAAK,CAAC,CAAA,CAAE,QAAS,CAAA,IAAA,CAAK,WAAW,YAAY,CAAA;AAAA,aAC/C,CAAA;AAAA,WACF;AACA,UAAA,IAAI,CAAC,MAAQ,EAAA;AACX,YAAA,MAAA,GAAS,SAAS,CAAC,CAAA,CAAA;AAAA,WACrB;AAEA,UAAA,GAAA,CAAI,MAAO,CAAA,WAAA,EAAaC,+BAAmB,CAAA,MAAM,CAAC,CAAA,CAAA;AAAA,SACpD;AAAA,eACO,CAAG,EAAA;AACV,QAAI,IAAA,CAAC,MAAM,QAAU,EAAA;AACnB,UAAM,MAAA,CAAA,CAAA;AAAA,SACR;AAAA,OACF;AAEA,MAAI,GAAA,CAAA,MAAA,CAAO,kBAAkB,cAAc,CAAA,CAAA;AAAA,KAC7C;AAAA,GACD,CAAA,CAAA;AACH;;AC3KO,MAAML,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,2BAAA;AAAA,IACb,OAAA,EAASC,gBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,eAAA;AAAA,UACR,EAAI,EAAA,0BAAA;AAAA,UACJ,IAAM,EAAA,qBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,MAAQ,EAAA;AAAA,cACN,UAAY,EAAA,uBAAA;AAAA,cACZ,IAAM,EAAA,WAAA;AAAA,cACN,QAAU,EAAA;AAAA,gBACR,IAAM,EAAA,MAAA;AAAA,gBACN,aAAa,EAAC;AAAA,eAChB;AAAA,cACA,IAAM,EAAA;AAAA,gBACJ,IAAM,EAAA,SAAA;AAAA,gBACN,SAAW,EAAA,YAAA;AAAA,gBACX,KAAO,EAAA,eAAA;AAAA,eACT;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;ACxBA,MAAMC,IAAK,GAAA,eAAA,CAAA;AAOJ,SAAS,wBAA2B,GAAA;AACzC,EAAA,OAAOC,yCAAqB,CAAA;AAAA,QAC1BD,IAAA;AAAA,IACA,WAAa,EAAA,gDAAA;AAAA,IACb,MAAQ,EAAA;AAAA,MACN,KAAA,EAAOI,MAAE,MAAO,CAAA;AAAA,QACd,UAAUA,KACP,CAAA,MAAA,GACA,QAAS,EAAA,CACT,SAAS,+BAA+B,CAAA;AAAA;AAAA,QAE3C,QAAQA,KACL,CAAA,MAAA,CAAOA,KAAE,CAAA,GAAA,EAAK,CACd,CAAA,QAAA;AAAA,UACC,4DAAA;AAAA,SACF;AAAA,OACH,CAAA;AAAA,KACH;AAAA,cACAN,UAAA;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAA,MAAM,EAAE,QAAA,EAAU,MAAO,EAAA,GAAI,GAAI,CAAA,KAAA,CAAA;AACjC,MAAM,MAAA,SAAA,GAAY,IAAI,YAAc,EAAA,SAAA,CAAA;AACpC,MAAA,MAAM,OAAO,QAAY,IAAA,mBAAA,CAAA;AACzB,MAAA,GAAA,CAAI,MAAO,CAAA,IAAA,CAAK,CAAW,QAAA,EAAA,IAAI,CAAE,CAAA,CAAA,CAAA;AAEjC,MAAA,MAAMO,mBAAG,CAAA,SAAA;AAAA,QACPC,qCAAA,CAAqB,GAAI,CAAA,aAAA,EAAe,IAAI,CAAA;AAAA,QAC5CP,gBAAK,SAAU,CAAA;AAAA,UACb,GAAG,MAAA;AAAA,UACH,QAAU,EAAA;AAAA,YACR,GAAG,MAAO,CAAA,QAAA;AAAA,YACV,GAAI,SACA,GAAA;AAAA,cACE,WAAa,EAAA;AAAA,gBACX,GAAG,OAAO,QAAS,CAAA,WAAA;AAAA,gBACnB,8BAAgC,EAAA,SAAA;AAAA,eAClC;AAAA,aAEF,GAAA,KAAA,CAAA;AAAA,WACN;AAAA,SACD,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH;;ACxDO,MAAMD,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,2BAAA;AAAA,IACb,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,eAAA;AAAA,UACR,EAAI,EAAA,OAAA;AAAA,UACJ,IAAM,EAAA,sBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,SAAW,EAAA,wBAAA;AAAA,WACb;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AAAA,EACA;AAAA,IACE,WAAa,EAAA,sCAAA;AAAA,IACb,OAAA,EAASA,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,eAAA;AAAA,UACR,EAAI,EAAA,eAAA;AAAA,UACJ,IAAM,EAAA,wBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,UAAA,EAAY,CAAC,wBAAwB,CAAA;AAAA,WACvC;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;AC3BA,MAAMC,IAAK,GAAA,eAAA,CAAA;AAOJ,SAAS,+BAA+B,OAG5C,EAAA;AACD,EAAM,MAAA,EAAE,aAAe,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AAEhC,EAAA,OAAOC,yCAAqB,CAAA;AAAA,QAC1BD,IAAA;AAAA,IACA,WACE,EAAA,oEAAA;AAAA,cACFF,UAAA;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAQ,EAAA;AAAA,MACN,KAAA,EAAOM,MAAE,MAAO,CAAA;AAAA,QACd,SAAA,EAAWA,MACR,MAAO,CAAA;AAAA,UACN,WAAa,EAAA,uCAAA;AAAA,SACd,EACA,QAAS,EAAA;AAAA,QACZ,UAAY,EAAAA,KAAA,CACT,KAAM,CAAAA,KAAA,CAAE,QAAU,EAAA;AAAA,UACjB,WAAa,EAAA,0CAAA;AAAA,SACd,EACA,QAAS,EAAA;AAAA,QACZ,QAAA,EAAUA,MACP,OAAQ,CAAA;AAAA,UACP,WACE,EAAA,kEAAA;AAAA,SACH,EACA,QAAS,EAAA;AAAA,QACZ,WAAA,EAAaA,MAAE,MAAO,CAAA,EAAE,aAAa,kBAAmB,EAAC,EAAE,QAAS,EAAA;AAAA,QACpE,gBAAA,EAAkBA,MACf,MAAO,CAAA,EAAE,aAAa,uBAAwB,EAAC,EAC/C,QAAS,EAAA;AAAA,OACb,CAAA;AAAA,MACD,MAAA,EAAQA,MAAE,MAAO,CAAA;AAAA,QACf,MAAA,EAAQA,MACL,GAAI,CAAA;AAAA,UACH,WACE,EAAA,qGAAA;AAAA,SACH,EACA,QAAS,EAAA;AAAA,QACZ,UAAUA,KACP,CAAA,KAAA;AAAA,UACCA,MAAE,GAAI,CAAA;AAAA,YACJ,WACE,EAAA,kHAAA;AAAA,WACH,CAAA;AAAA,UAEF,QAAS,EAAA;AAAA,OACb,CAAA;AAAA,KACH;AAAA,IACA,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAA,MAAM,EAAE,SAAW,EAAA,UAAA,EAAY,UAAU,WAAa,EAAA,gBAAA,KACpD,GAAI,CAAA,KAAA,CAAA;AACN,MAAI,IAAA,CAAC,SAAa,IAAA,CAAC,UAAY,EAAA;AAC7B,QAAA,IAAI,QAAU,EAAA;AACZ,UAAA,OAAA;AAAA,SACF;AACA,QAAM,MAAA,IAAI,MAAM,wCAAwC,CAAA,CAAA;AAAA,OAC1D;AAEA,MAAA,MAAM,EAAE,KAAA,EAAW,GAAA,MAAM,MAAM,qBAAsB,CAAA;AAAA,QACnD,UAAA,EAAY,MAAM,GAAA,CAAI,uBAAwB,EAAA;AAAA,QAC9C,cAAgB,EAAA,SAAA;AAAA,OACjB,CAAM,IAAA,EAAE,KAAO,EAAA,GAAA,CAAI,SAAS,cAAe,EAAA,CAAA;AAE5C,MAAA,IAAI,SAAW,EAAA;AACb,QAAM,MAAA,MAAA,GAAS,MAAM,aAAc,CAAA,cAAA;AAAA,UACjCD,+BAAA;AAAA,YACEI,2BAAe,CAAA,SAAA,EAAW,EAAE,WAAA,EAAa,kBAAkB,CAAA;AAAA,WAC7D;AAAA,UACA;AAAA,YACE,KAAA;AAAA,WACF;AAAA,SACF,CAAA;AAEA,QAAI,IAAA,CAAC,MAAU,IAAA,CAAC,QAAU,EAAA;AACxB,UAAA,MAAM,IAAI,KAAA,CAAM,CAAU,OAAA,EAAA,SAAS,CAAY,UAAA,CAAA,CAAA,CAAA;AAAA,SACjD;AACA,QAAI,GAAA,CAAA,MAAA,CAAO,QAAU,EAAA,MAAA,IAAU,IAAI,CAAA,CAAA;AAAA,OACrC;AAEA,MAAA,IAAI,UAAY,EAAA;AACd,QAAM,MAAA,QAAA,GAAW,MAAM,aAAc,CAAA,iBAAA;AAAA,UACnC;AAAA,YACE,YAAY,UAAW,CAAA,GAAA;AAAA,cAAI,CACzB,GAAA,KAAAJ,+BAAA;AAAA,gBACEI,2BAAe,CAAA,GAAA,EAAK,EAAE,WAAA,EAAa,kBAAkB,CAAA;AAAA,eACvD;AAAA,aACF;AAAA,WACF;AAAA,UACA;AAAA,YACE,KAAA;AAAA,WACF;AAAA,SACF,CAAA;AAEA,QAAA,MAAM,gBAAgB,QAAS,CAAA,KAAA,CAAM,GAAI,CAAA,CAAC,GAAG,CAAM,KAAA;AACjD,UAAI,IAAA,CAAC,CAAK,IAAA,CAAC,QAAU,EAAA;AACnB,YAAA,MAAM,IAAI,KAAM,CAAA,CAAA,OAAA,EAAU,UAAW,CAAA,CAAC,CAAC,CAAY,UAAA,CAAA,CAAA,CAAA;AAAA,WACrD;AACA,UAAA,OAAO,CAAK,IAAA,IAAA,CAAA;AAAA,SACb,CAAA,CAAA;AAED,QAAI,GAAA,CAAA,MAAA,CAAO,YAAY,aAAa,CAAA,CAAA;AAAA,OACtC;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH;;ACvHO,MAAMT,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,uBAAA;AAAA,IACb,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,WAAA;AAAA,UACR,EAAI,EAAA,kBAAA;AAAA,UACJ,IAAM,EAAA,mCAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,OAAS,EAAA,kBAAA;AAAA,WACX;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AAAA,EACA;AAAA,IACE,WAAa,EAAA,8BAAA;AAAA,IACb,OAAA,EAASA,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,WAAA;AAAA,UACR,EAAI,EAAA,2BAAA;AAAA,UACJ,IAAM,EAAA,8BAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,aAAe,EAAA,IAAA;AAAA,WACjB;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;AC7BA,MAAMC,IAAK,GAAA,WAAA,CAAA;AAYJ,SAAS,oBAAuB,GAAA;AACrC,EAAA,OAAOC,yCAAoE,CAAA;AAAA,QACzED,IAAA;AAAA,IACA,WACE,EAAA,oEAAA;AAAA,cACFF,UAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,IAAM,EAAA,QAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,OAAS,EAAA;AAAA,YACP,KAAO,EAAA,oBAAA;AAAA,YACP,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,aAAe,EAAA;AAAA,YACb,KAAO,EAAA,2CAAA;AAAA,YACP,IAAM,EAAA,SAAA;AAAA,WACR;AAAA,UACA,KAAO,EAAA;AAAA,YACL,KAAO,EAAA,YAAA;AAAA,WACT;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAI,GAAA,CAAA,MAAA,CAAO,KAAK,IAAK,CAAA,SAAA,CAAU,IAAI,KAAO,EAAA,IAAA,EAAM,CAAC,CAAC,CAAA,CAAA;AAElD,MAAI,IAAA,GAAA,CAAI,OAAO,OAAS,EAAA;AACtB,QAAA,GAAA,CAAI,MAAO,CAAA,IAAA,CAAK,GAAI,CAAA,KAAA,CAAM,OAAO,CAAA,CAAA;AAAA,OACnC;AAEA,MAAI,IAAA,GAAA,CAAI,OAAO,aAAe,EAAA;AAC5B,QAAA,MAAM,KAAQ,GAAA,MAAM,gBAAiB,CAAA,GAAA,CAAI,aAAa,CAAA,CAAA;AACtD,QAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,UACT,CAAA;AAAA,EAAe,KACZ,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,IAAA,EAAOU,aAAS,CAAA,GAAA,CAAI,aAAe,EAAA,CAAC,CAAC,CAAA,CAAE,CAChD,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,SACf,CAAA;AAAA,OACF;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH,CAAA;AAEA,eAAsB,iBAAiB,GAAgC,EAAA;AACrE,EAAM,MAAA,OAAA,GAAU,MAAMC,UAAA,CAAQ,GAAG,CAAA,CAAA;AACjC,EAAM,MAAA,KAAA,GAAQ,MAAM,OAAQ,CAAA,GAAA;AAAA,IAC1B,OAAA,CAAQ,GAAI,CAAA,OAAM,MAAU,KAAA;AAC1B,MAAM,MAAA,GAAA,GAAMC,SAAK,CAAA,GAAA,EAAK,MAAM,CAAA,CAAA;AAC5B,MAAQ,OAAA,CAAA,MAAMC,OAAK,CAAA,GAAG,CAAG,EAAA,WAAA,KAAgB,gBAAiB,CAAA,GAAG,CAAI,GAAA,CAAC,GAAG,CAAA,CAAA;AAAA,KACtE,CAAA;AAAA,GACH,CAAA;AACA,EAAO,OAAA,KAAA,CAAM,MAAO,CAAA,CAAC,CAAG,EAAA,CAAA,KAAM,EAAE,MAAO,CAAA,CAAC,CAAG,EAAA,EAAE,CAAA,CAAA;AAC/C;;ACnEO,MAAMb,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,6BAAA;AAAA,IACb,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,YAAA;AAAA,UACR,EAAI,EAAA,mBAAA;AAAA,UACJ,IAAM,EAAA,6BAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,YAAc,EAAA,EAAA;AAAA,WAChB;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AAAA,EACA;AAAA,IACE,WAAa,EAAA,uBAAA;AAAA,IACb,OAAA,EAASA,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,YAAA;AAAA,UACR,EAAI,EAAA,WAAA;AAAA,UACJ,IAAM,EAAA,uBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,OAAS,EAAA,CAAA;AAAA,WACX;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AAAA,EACA;AAAA,IACE,WAAa,EAAA,uBAAA;AAAA,IACb,OAAA,EAASA,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,YAAA;AAAA,UACR,EAAI,EAAA,WAAA;AAAA,UACJ,IAAM,EAAA,uBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,OAAS,EAAA,CAAA;AAAA,WACX;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;AC5CA,MAAM,EAAK,GAAA,YAAA,CAAA;AAEX,MAAM,oBAAuB,GAAA,WAAA,CAAA;AAYtB,SAAS,iBAAiB,OAE9B,EAAA;AACD,EAAM,MAAA,UAAA,GAAa,CACjB,WACa,KAAA;AACb,IAAA,IAAI,WAAa,EAAA;AACf,MAAA,IAAI,uBAAuBa,cAAU,EAAA;AACnC,QAAO,OAAA,WAAA,CAAA;AAAA,OACT;AACA,MAAO,OAAAA,cAAA,CAAS,WAAW,WAAW,CAAA,CAAA;AAAA,KACxC;AACA,IAAO,OAAAA,cAAA,CAAS,YAAY,oBAAoB,CAAA,CAAA;AAAA,GAClD,CAAA;AAEA,EAAA,OAAOX,yCAAoC,CAAA;AAAA,IACzC,EAAA;AAAA,IACA,WAAa,EAAA,qCAAA;AAAA,cACbH,UAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,IAAM,EAAA,QAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,OAAS,EAAA;AAAA,YACP,KAAO,EAAA,4BAAA;AAAA,YACP,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,OAAS,EAAA;AAAA,YACP,KAAO,EAAA,4BAAA;AAAA,YACP,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,YAAc,EAAA;AAAA,YACZ,KAAO,EAAA,iCAAA;AAAA,YACP,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAA,MAAM,SAAY,GAAAc,cAAA,CAAS,UAAW,CAAA,GAAA,CAAI,KAAK,CAAA,CAAA;AAC/C,MAAM,MAAA,OAAA,GAAU,UAAW,CAAA,OAAA,EAAS,WAAW,CAAA,CAAA;AAE/C,MAAA,IAAI,UAAU,KAAM,CAAA,OAAO,CAAE,CAAA,QAAA,KAAa,CAAG,EAAA;AAC3C,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,yDAAA,EAA4D,OAAQ,CAAA,OAAA,EAAS,CAAA,CAAA;AAAA,SAC/E,CAAA;AAAA,OACF;AAEA,MAAM,MAAA,IAAI,QAAQ,CAAW,OAAA,KAAA;AAC3B,QAAM,MAAA,UAAA,GAAa,IAAI,eAAgB,EAAA,CAAA;AACvC,QAAA,MAAM,aAAgB,GAAA,UAAA,CAAW,KAAO,EAAA,SAAA,CAAU,UAAU,CAAA,CAAA;AAC5D,QAAI,GAAA,CAAA,MAAA,EAAQ,gBAAiB,CAAA,OAAA,EAAS,KAAK,CAAA,CAAA;AAE3C,QAAA,SAAS,KAAQ,GAAA;AACf,UAAI,GAAA,CAAA,MAAA,EAAQ,mBAAoB,CAAA,OAAA,EAAS,KAAK,CAAA,CAAA;AAC9C,UAAA,YAAA,CAAa,aAAc,CAAA,CAAA;AAC3B,UAAA,UAAA,CAAW,KAAM,EAAA,CAAA;AACjB,UAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,SACpB;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AACH;;AC9EO,MAAMd,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,mDAAA;AAAA,IACb,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,aAAA;AAAA,UACR,EAAI,EAAA,aAAA;AAAA,UACJ,IAAM,EAAA,aAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,GAAK,EAAA,sFAAA;AAAA,WACP;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AAAA,EACA;AAAA,IACE,WACE,EAAA,uJAAA;AAAA,IACF,OAAA,EAASA,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,aAAA;AAAA,UACR,EAAI,EAAA,aAAA;AAAA,UACJ,IAAM,EAAA,aAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,GAAK,EAAA,sFAAA;AAAA,YACL,UAAY,EAAA,cAAA;AAAA,WACd;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;AC1BO,MAAM,SAAY,GAAA,aAAA,CAAA;AAOlB,SAAS,uBAAuB,OAGpC,EAAA;AACD,EAAM,MAAA,EAAE,MAAQ,EAAA,YAAA,EAAiB,GAAA,OAAA,CAAA;AAEjC,EAAA,OAAOE,yCAIJ,CAAA;AAAA,IACD,EAAI,EAAA,SAAA;AAAA,cACJH,UAAA;AAAA,IACA,WACE,EAAA,+HAAA;AAAA,IACF,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,IAAM,EAAA,QAAA;AAAA,QACN,QAAA,EAAU,CAAC,KAAK,CAAA;AAAA,QAChB,UAAY,EAAA;AAAA,UACV,GAAK,EAAA;AAAA,YACH,KAAO,EAAA,WAAA;AAAA,YACP,WACE,EAAA,uEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,UAAY,EAAA;AAAA,YACV,KAAO,EAAA,aAAA;AAAA,YACP,WACE,EAAA,uEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,KAAO,EAAA;AAAA,YACL,KAAO,EAAA,OAAA;AAAA,YACP,WACE,EAAA,yEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAI,GAAA,CAAA,MAAA,CAAO,KAAK,wCAAwC,CAAA,CAAA;AAGxD,MAAM,MAAA,UAAA,GAAa,GAAI,CAAA,KAAA,CAAM,UAAc,IAAA,IAAA,CAAA;AAC3C,MAAA,MAAM,UAAa,GAAAQ,qCAAA,CAAqB,GAAI,CAAA,aAAA,EAAe,UAAU,CAAA,CAAA;AAErE,MAAA,MAAMO,kCAAc,CAAA;AAAA,QAClB,MAAA;AAAA,QACA,YAAA;AAAA,QACA,OAAA,EAAS,IAAI,YAAc,EAAA,OAAA;AAAA,QAC3B,QAAA,EAAU,IAAI,KAAM,CAAA,GAAA;AAAA,QACpB,UAAA;AAAA,QACA,KAAA,EAAO,IAAI,KAAM,CAAA,KAAA;AAAA,OAClB,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AACH;;ACzEO,MAAMf,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,kDAAA;AAAA,IACb,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,kBAAA;AAAA,UACR,EAAI,EAAA,kBAAA;AAAA,UACJ,IAAM,EAAA,kBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,GAAK,EAAA,2HAAA;AAAA,YACL,UAAY,EAAA,aAAA;AAAA,WACd;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;ACNO,SAAS,2BAA2B,OAGxC,EAAA;AACD,EAAM,MAAA,EAAE,MAAQ,EAAA,YAAA,EAAiB,GAAA,OAAA,CAAA;AAEjC,EAAA,OAAOE,yCAIJ,CAAA;AAAA,IACD,EAAI,EAAA,kBAAA;AAAA,IACJ,WAAa,EAAA,uDAAA;AAAA,cACbH,UAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,IAAM,EAAA,QAAA;AAAA,QACN,QAAA,EAAU,CAAC,KAAA,EAAO,YAAY,CAAA;AAAA,QAC9B,UAAY,EAAA;AAAA,UACV,GAAK,EAAA;AAAA,YACH,KAAO,EAAA,WAAA;AAAA,YACP,WACE,EAAA,qEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,UAAY,EAAA;AAAA,YACV,KAAO,EAAA,aAAA;AAAA,YACP,WACE,EAAA,mEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,KAAO,EAAA;AAAA,YACL,KAAO,EAAA,OAAA;AAAA,YACP,WACE,EAAA,yEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAI,GAAA,CAAA,MAAA,CAAO,KAAK,wCAAwC,CAAA,CAAA;AAGxD,MAAA,MAAM,UAAa,GAAAQ,qCAAA;AAAA,QACjB,GAAI,CAAA,aAAA;AAAA,QACJ,IAAI,KAAM,CAAA,UAAA;AAAA,OACZ,CAAA;AAEA,MAAA,MAAMQ,8BAAU,CAAA;AAAA,QACd,MAAA;AAAA,QACA,YAAA;AAAA,QACA,OAAA,EAAS,IAAI,YAAc,EAAA,OAAA;AAAA,QAC3B,QAAA,EAAU,IAAI,KAAM,CAAA,GAAA;AAAA,QACpB,UAAA;AAAA,QACA,KAAA,EAAO,IAAI,KAAM,CAAA,KAAA;AAAA,OAClB,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AACH;;AC1EO,SAAS,8BAA0C,GAAA;AACxD,EACE,OAAA,OAAA,CAAQ,IAAI,YAAc,EAAA,QAAA,CAAS,oBAAoB,CACvD,IAAA,OAAA,CAAQ,IAAK,CAAA,QAAA,CAAS,oBAAoB,CAAA,CAAA;AAE9C,CAAA;AAYO,SAAS,mBAA8B,GAAA;AAC5C,EAAM,MAAA,OAAA,GAAU,QAAQ,QAAS,CAAA,IAAA,CAAA;AACjC,EAAA,OAAO,SAAS,OAAQ,CAAA,KAAA,CAAM,GAAG,CAAE,CAAA,CAAC,GAAG,EAAE,CAAA,CAAA;AAC3C;;ACTA,MAAM,QAAA,GAAW,CAAC,cAA2B,KAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EAMzC,cAAc,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,CAAA;AAyFX,MAAM,eAAgB,CAAA;AAAA,EAC3B,aAAa,YAAA,CAAa,OAAkC,GAAA,EAAI,EAAA;AAC9D,IAAM,MAAA;AAAA,MACJ,kBAAA;AAAA,MACA,kBAAkB,EAAC;AAAA,MACnB,kBAAkB,EAAC;AAAA,MACnB,kBAAkB,EAAC;AAAA,KACjB,GAAA,OAAA,CAAA;AAEJ,IAAA,MAAM,cAAc,mBAAoB,EAAA,CAAA;AACxC,IAAA,IAAI,WAAe,IAAA,EAAA,IAAM,CAAC,8BAAA,EAAkC,EAAA;AAC1D,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA;AAAA,2FAAA,CAAA;AAAA,OAEF,CAAA;AAAA,KACF;AAEA,IAAA,MAAM,UAAU,IAAIC,kBAAA,CAAQ,EAAE,WAAA,EAAa,KAAK,CAAA,CAAA;AAChD,IAAM,MAAA,OAAA,GAAU,MAAM,OAAA,CAAQ,aAAc,EAAA,CAAA;AAC5C,IAAA,MAAM,gBAAgB,OAAQ,CAAA,MAAA,CAAA;AAE9B,IAAM,MAAA,cAAA,GAAiB,MAAMV,mBAAG,CAAA,QAAA;AAAA,MAC9BW,mCAAA;AAAA,QACE,sCAAA;AAAA,QACA,wBAAA;AAAA,OACF;AAAA,MACA,OAAA;AAAA,KACF,CAAA;AAEA,IAAM,MAAA,cAAA,GAAiB,MAAM,OAAQ,CAAA,aAAA;AAAA,MACnC,SAAS,cAAc,CAAA;AAAA,KACzB,CAAA;AAEA,IAAA,MAAM,cAAc,GAAI,CAAA,iBAAA,EAAmB,IAAK,CAAA,SAAA,CAAU,eAAe,CAAC,CAAA,CAAA;AAE1E,IAAM,MAAA,gBAAA,GAAmB,MAAO,CAAA,IAAA,CAAK,eAAe,CAAA,CAAA;AAEpD,IAAA,MAAM,aAAc,CAAA,GAAA;AAAA,MAClB,0BAAA;AAAA,MACA,IAAA,CAAK,UAAU,gBAAgB,CAAA;AAAA,KACjC,CAAA;AAEA,IAAA,MAAM,kBAAkB,EAAC,CAAA;AACzB,IAAA,MAAM,eAAwC,EAAC,CAAA;AAC/C,IAAA,KAAA,MAAW,CAAC,IAAM,EAAA,KAAK,KAAK,MAAO,CAAA,OAAA,CAAQ,eAAe,CAAG,EAAA;AAC3D,MAAI,IAAA,OAAO,UAAU,UAAY,EAAA;AAC/B,QAAA,eAAA,CAAgB,KAAK,IAAI,CAAA,CAAA;AAAA,OACpB,MAAA;AACL,QAAA,YAAA,CAAa,IAAI,CAAI,GAAA,KAAA,CAAA;AAAA,OACvB;AAAA,KACF;AAEA,IAAA,MAAM,aAAc,CAAA,GAAA;AAAA,MAClB,0BAAA;AAAA,MACA,IAAA,CAAK,UAAU,YAAY,CAAA;AAAA,KAC7B,CAAA;AACA,IAAA,MAAM,aAAc,CAAA,GAAA;AAAA,MAClB,4BAAA;AAAA,MACA,IAAA,CAAK,UAAU,eAAe,CAAA;AAAA,KAChC,CAAA;AAEA,IAAA,MAAM,aAAc,CAAA,GAAA;AAAA,MAClB,YAAA;AAAA,MACA,CAAC,YAAoB,IAAsB,KAAA;AACzC,QAAA,IAAI,CAAC,MAAA,CAAO,MAAO,CAAA,eAAA,EAAiB,UAAU,CAAG,EAAA;AAC/C,UAAO,OAAA,EAAA,CAAA;AAAA,SACT;AACA,QAAA,OAAO,KAAK,SAAU,CAAA,eAAA,CAAgB,UAAU,CAAE,CAAA,GAAG,IAAI,CAAC,CAAA,CAAA;AAAA,OAC5D;AAAA,KACF,CAAA;AAEA,IAAA,MAAM,aAAc,CAAA,GAAA;AAAA,MAClB,YAAA;AAAA,MACA,CAAC,YAAoB,IAAsB,KAAA;AACzC,QAAA,IAAI,CAAC,MAAA,CAAO,MAAO,CAAA,eAAA,EAAiB,UAAU,CAAG,EAAA;AAC/C,UAAO,OAAA,EAAA,CAAA;AAAA,SACT;AACA,QAAM,MAAA,MAAA,GAAS,gBAAgB,UAAU,CAAA,CAAA;AACzC,QAAI,IAAA,OAAO,WAAW,UAAY,EAAA;AAChC,UAAO,OAAA,EAAA,CAAA;AAAA,SACT;AACA,QAAA,OAAO,IAAK,CAAA,SAAA,CAAU,MAAO,CAAA,GAAG,IAAI,CAAC,CAAA,CAAA;AAAA,OACvC;AAAA,KACF,CAAA;AAEA,IAAM,MAAA,cAAA,CAAe,IAAI,OAAO,CAAA,CAAA;AAEhC,IAAM,MAAA,MAAA,GAAiC,CAAC,QAAA,EAAU,MAAW,KAAA;AAC3D,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAM,MAAA,IAAI,MAAM,0CAA0C,CAAA,CAAA;AAAA,OAC5D;AAEA,MAAA,aAAA,CAAc,OAAQ,CAAA,aAAA,EAAe,MAAO,CAAA,QAAQ,CAAC,CAAA,CAAA;AACrD,MAAA,aAAA,CAAc,OAAQ,CAAA,gBAAA,EAAkB,IAAK,CAAA,SAAA,CAAU,MAAM,CAAC,CAAA,CAAA;AAE9D,MAAA,IAAI,kBAAoB,EAAA;AACtB,QAAO,OAAA,OAAA,CAAQ,SAAS,CAA2C,yCAAA,CAAA,CAAA,CAAA;AAAA,OACrE;AAEA,MAAO,OAAA,OAAA,CAAQ,SAAS,CAAqC,mCAAA,CAAA,CAAA,CAAA;AAAA,KAC/D,CAAA;AACA,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AACF;;ACzMO,MAAM,uBAAuB,CAAC;AAAA,EACnC,YAAA;AACF,CAEsC,KAAA;AACpC,EAAO,OAAA;AAAA,IACL,YAAc,EAAA,CAAA,GAAA,KAAOC,iCAAa,CAAA,GAAA,EAAe,YAAY,CAAA;AAAA,IAC7D,gBAAgB,CAAC,GAAA,EAAgB,OAC/B,KAAAV,2BAAA,CAAe,KAAe,OAAqB,CAAA;AAAA,IACrD,MAAM,CAAC,GAAA,EAAgB,GAAmB,KAAAW,oBAAA,CAAI,KAAK,GAAa,CAAA;AAAA,IAChE,aAAa,CAAW,OAAA,KAAA;AACtB,MAAA,MAAM,EAAE,KAAO,EAAA,IAAA,EAAS,GAAAD,iCAAA,CAAa,SAAmB,YAAY,CAAA,CAAA;AACpE,MAAO,OAAA,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAA;AAAA,KACzB;AAAA,GACF,CAAA;AACF,CAAA;;ACpBO,MAAMnB,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WACE,EAAA,oGAAA;AAAA,IACF,OAAA,EAASC,wBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,gBAAA;AAAA,UACR,EAAI,EAAA,gBAAA;AAAA,UACJ,IAAM,EAAA,gBAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,GAAK,EAAA,YAAA;AAAA,YACL,UAAY,EAAA,UAAA;AAAA,YACZ,MAAQ,EAAA;AAAA,cACN,IAAM,EAAA,cAAA;AAAA,cACN,KAAO,EAAA,IAAA;AAAA,cACP,QAAU,EAAA,CAAC,OAAS,EAAA,QAAA,EAAU,OAAO,CAAA;AAAA,cACrC,aAAe,EAAA,KAAA;AAAA,aACjB;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;ACFO,SAAS,0BAA0B,OAKvC,EAAA;AACD,EAAM,MAAA;AAAA,IACJ,MAAA;AAAA,IACA,YAAA;AAAA,IACA,yBAAA;AAAA,IACA,yBAAA;AAAA,GACE,GAAA,OAAA,CAAA;AAEJ,EAAA,MAAM,sBAAyB,GAAA,oBAAA,CAAqB,EAAE,YAAA,EAAc,CAAA,CAAA;AAEpE,EAAA,OAAOE,yCAiBJ,CAAA;AAAA,IACD,EAAI,EAAA,gBAAA;AAAA,IACJ,WACE,EAAA,0MAAA;AAAA,cACFH,UAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,IAAM,EAAA,QAAA;AAAA,QACN,QAAA,EAAU,CAAC,KAAK,CAAA;AAAA,QAChB,UAAY,EAAA;AAAA,UACV,GAAK,EAAA;AAAA,YACH,KAAO,EAAA,WAAA;AAAA,YACP,WACE,EAAA,uEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,UAAY,EAAA;AAAA,YACV,KAAO,EAAA,aAAA;AAAA,YACP,WACE,EAAA,+GAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,MAAQ,EAAA;AAAA,YACN,KAAO,EAAA,iBAAA;AAAA,YACP,WAAa,EAAA,4CAAA;AAAA,YACb,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,UACA,iBAAmB,EAAA;AAAA,YACjB,KAAO,EAAA,kCAAA;AAAA,YACP,WACE,EAAA,kHAAA;AAAA,YACF,IAAM,EAAA,OAAA;AAAA,YACN,KAAO,EAAA;AAAA,cACL,IAAM,EAAA,QAAA;AAAA,aACR;AAAA,WACF;AAAA,UACA,qBAAuB,EAAA;AAAA,YACrB,KAAO,EAAA,yBAAA;AAAA,YACP,WACE,EAAA,6IAAA;AAAA,YACF,IAAM,EAAA,OAAA;AAAA,YACN,KAAO,EAAA;AAAA,cACL,IAAM,EAAA,QAAA;AAAA,aACR;AAAA,WACF;AAAA,UACA,kBAAoB,EAAA;AAAA,YAClB,KAAO,EAAA,iCAAA;AAAA,YACP,WACE,EAAA,uFAAA;AAAA,YACF,IAAM,EAAA,SAAA;AAAA,WACR;AAAA,UACA,qBAAuB,EAAA;AAAA,YACrB,KAAO,EAAA,yBAAA;AAAA,YACP,WACE,EAAA,wHAAA;AAAA,YACF,IAAA,EAAM,CAAC,QAAA,EAAU,SAAS,CAAA;AAAA,WAC5B;AAAA,UACA,OAAS,EAAA;AAAA,YACP,KAAO,EAAA,eAAA;AAAA,YACP,WACE,EAAA,wEAAA;AAAA,YACF,IAAM,EAAA,SAAA;AAAA,WACR;AAAA,UACA,KAAO,EAAA;AAAA,YACL,KAAO,EAAA,OAAA;AAAA,YACP,WACE,EAAA,yEAAA;AAAA,YACF,IAAM,EAAA,QAAA;AAAA,WACR;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAI,GAAA,CAAA,MAAA,CAAO,KAAK,2CAA2C,CAAA,CAAA;AAE3D,MAAM,MAAA,OAAA,GAAU,MAAM,GAAA,CAAI,wBAAyB,EAAA,CAAA;AACnD,MAAM,MAAA,WAAA,GAAcQ,qCAAqB,CAAA,OAAA,EAAS,UAAU,CAAA,CAAA;AAE5D,MAAM,MAAA,UAAA,GAAa,GAAI,CAAA,KAAA,CAAM,UAAc,IAAA,IAAA,CAAA;AAC3C,MAAA,MAAM,SAAY,GAAAA,qCAAA,CAAqB,GAAI,CAAA,aAAA,EAAe,UAAU,CAAA,CAAA;AACpE,MAAA,IAAI,GAAI,CAAA,KAAA,CAAM,iBAAqB,IAAA,GAAA,CAAI,MAAM,qBAAuB,EAAA;AAClE,QAAA,MAAM,IAAIJ,iBAAA;AAAA,UACR,iGAAA;AAAA,SACF,CAAA;AAAA,OACF;AAEA,MAAI,IAAA,gBAAA,CAAA;AACJ,MAAI,IAAA,cAAA,CAAA;AACJ,MAAI,IAAA,GAAA,CAAI,MAAM,iBAAmB,EAAA;AAC/B,QAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,UACT,wFAAA;AAAA,SACF,CAAA;AACA,QAAA,gBAAA,GAAmB,IAAI,KAAM,CAAA,iBAAA,CAAA;AAC7B,QAAiB,cAAA,GAAA,KAAA,CAAA;AAAA,OACZ,MAAA;AACL,QAAA,gBAAA,GAAmB,IAAI,KAAM,CAAA,qBAAA,CAAA;AAC7B,QAAiB,cAAA,GAAA,IAAA,CAAA;AAAA,OACnB;AAEA,MAAA,IAAI,gBAAoB,IAAA,CAAC,KAAM,CAAA,OAAA,CAAQ,gBAAgB,CAAG,EAAA;AACxD,QAAA,MAAM,IAAIA,iBAAA;AAAA,UACR,6EAAA;AAAA,SACF,CAAA;AAAA,OACF;AAEA,MAAA,IACE,IAAI,KAAM,CAAA,qBAAA,KACT,gBAAoB,IAAA,GAAA,CAAI,MAAM,kBAC/B,CAAA,EAAA;AACA,QAAA,MAAM,IAAIA,iBAAA;AAAA,UACR,+GAAA;AAAA,SACF,CAAA;AAAA,OACF;AAEA,MAAA,IAAI,SAA4B,GAAA,KAAA,CAAA;AAChC,MAAI,IAAA,GAAA,CAAI,MAAM,qBAAuB,EAAA;AACnC,QAAA,SAAA,GACE,IAAI,KAAM,CAAA,qBAAA,KAA0B,IAChC,GAAA,MAAA,GACA,IAAI,KAAM,CAAA,qBAAA,CAAA;AAChB,QAAA,IAAI,CAAC,SAAA,CAAU,UAAW,CAAA,GAAG,CAAG,EAAA;AAC9B,UAAA,SAAA,GAAY,IAAI,SAAS,CAAA,CAAA,CAAA;AAAA,SAC3B;AAAA,OACF;AAEA,MAAA,MAAMW,kCAAc,CAAA;AAAA,QAClB,MAAA;AAAA,QACA,YAAA;AAAA,QACA,OAAA,EAAS,IAAI,YAAc,EAAA,OAAA;AAAA,QAC3B,QAAA,EAAU,IAAI,KAAM,CAAA,GAAA;AAAA,QACpB,UAAY,EAAA,WAAA;AAAA,QACZ,KAAA,EAAO,IAAI,KAAM,CAAA,KAAA;AAAA,OAClB,CAAA,CAAA;AAED,MAAI,GAAA,CAAA,MAAA,CAAO,KAAK,2CAA2C,CAAA,CAAA;AAC3D,MAAM,MAAA,oBAAA,GAAuB,MAAMM,uBAAA,CAAO,CAAQ,IAAA,CAAA,EAAA;AAAA,QAChD,GAAK,EAAA,WAAA;AAAA,QACL,GAAK,EAAA,IAAA;AAAA,QACL,SAAW,EAAA,KAAA;AAAA,QACX,eAAiB,EAAA,IAAA;AAAA,QACjB,mBAAqB,EAAA,KAAA;AAAA,OACtB,CAAA,CAAA;AAED,MAAA,MAAM,sBAAsB,IAAI,GAAA;AAAA,QAC9B,MAAMA,uBAAA,CAAO,gBAAoB,IAAA,EAAI,EAAA;AAAA,UACnC,GAAK,EAAA,WAAA;AAAA,UACL,GAAK,EAAA,IAAA;AAAA,UACL,SAAW,EAAA,KAAA;AAAA,UACX,eAAiB,EAAA,IAAA;AAAA,UACjB,mBAAqB,EAAA,KAAA;AAAA,SACtB,CAAA;AAAA,OACH,CAAA;AAMA,MAAA,MAAM,EAAE,kBAAA,EAAoB,MAAO,EAAA,GAAI,GAAI,CAAA,KAAA,CAAA;AAC3C,MAAA,MAAM,OAAU,GAAA;AAAA,QACd,CAAC,kBAAA,GAAqB,cAAiB,GAAA,QAAQ,GAAG,MAAA;AAAA,OACpD,CAAA;AAEA,MAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,QACT,CAAA,WAAA,EAAc,qBAAqB,MAAM,CAAA,6CAAA,CAAA;AAAA,QACzC,IAAI,KAAM,CAAA,MAAA;AAAA,OACZ,CAAA;AAEA,MAAM,MAAA,cAAA,GAAiB,MAAM,eAAA,CAAgB,YAAa,CAAA;AAAA,QACxD,kBAAA,EAAoB,IAAI,KAAM,CAAA,kBAAA;AAAA,QAC9B,eAAiB,EAAA;AAAA,UACf,GAAG,sBAAA;AAAA,UACH,GAAG,yBAAA;AAAA,SACL;AAAA,QACA,eAAiB,EAAA,yBAAA;AAAA,QACjB,eAAiB,EAAA;AAAA,UACf,UAAA,EAAY,IAAI,KAAM,CAAA,UAAA;AAAA,UACtB,YAAA,EAAc,IAAI,KAAM,CAAA,YAAA;AAAA,SAC1B;AAAA,OACD,CAAA,CAAA;AAED,MAAA,KAAA,MAAW,YAAY,oBAAsB,EAAA;AAC3C,QAAI,IAAA,cAAA,CAAA;AAEJ,QAAA,IAAI,eAAkB,GAAA,QAAA,CAAA;AACtB,QAAA,IAAI,SAAW,EAAA;AACb,UAAiB,cAAA,GAAAC,YAAA,CAAQ,eAAe,CAAM,KAAA,SAAA,CAAA;AAC9C,UAAA,IAAI,cAAgB,EAAA;AAClB,YAAA,eAAA,GAAkB,eAAgB,CAAA,KAAA,CAAM,CAAG,EAAA,CAAC,UAAU,MAAM,CAAA,CAAA;AAAA,WAC9D;AAGA,UAAkB,eAAA,GAAA,cAAA,CAAe,iBAAiB,OAAO,CAAA,CAAA;AAAA,SACpD,MAAA;AACL,UAAiB,cAAA,GAAA,CAAC,mBAAoB,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAMlD,UAAA,IAAI,cAAgB,EAAA;AAClB,YAAkB,eAAA,GAAA,cAAA,CAAe,iBAAiB,OAAO,CAAA,CAAA;AAAA,WACpD,MAAA;AACL,YAAA,eAAA,GAAkB,cACd,GAAA,cAAA,CAAe,eAAiB,EAAA,OAAO,CACvC,GAAA,eAAA,CAAA;AAAA,WACN;AAAA,SACF;AAEA,QAAI,IAAA,sBAAA,CAAuB,eAAe,CAAG,EAAA;AAC3C,UAAA,SAAA;AAAA,SACF;AAEA,QAAM,MAAA,UAAA,GAAad,qCAAqB,CAAA,SAAA,EAAW,eAAe,CAAA,CAAA;AAClE,QAAA,IAAID,oBAAG,UAAW,CAAA,UAAU,KAAK,CAAC,GAAA,CAAI,MAAM,OAAS,EAAA;AACnD,UAAA,SAAA;AAAA,SACF;AAEA,QAAI,IAAA,CAAC,cAAkB,IAAA,CAAC,SAAW,EAAA;AACjC,UAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,YACT,0BAA0B,QAAQ,CAAA,oBAAA,CAAA;AAAA,WACpC,CAAA;AAAA,SACF;AAEA,QAAI,IAAA,QAAA,CAAS,QAAS,CAAA,GAAG,CAAG,EAAA;AAC1B,UAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,YACT,qBAAqB,QAAQ,CAAA,yBAAA,CAAA;AAAA,WAC/B,CAAA;AACA,UAAM,MAAAA,mBAAA,CAAG,UAAU,UAAU,CAAA,CAAA;AAAA,SACxB,MAAA;AACL,UAAM,MAAA,aAAA,GAAgBC,qCAAqB,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAChE,UAAA,MAAM,KAAQ,GAAA,MAAMD,mBAAG,CAAA,QAAA,CAAS,MAAM,aAAa,CAAA,CAAA;AAEnD,UAAA,IAAI,MAAM,cAAe,EAAA,IAAM,MAAMgB,yBAAA,CAAa,aAAa,CAAI,EAAA;AACjE,YAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,cACT,2CAA2C,QAAQ,CAAA,0BAAA,CAAA;AAAA,aACrD,CAAA;AACA,YAAM,MAAAhB,mBAAA,CAAG,IAAK,CAAA,aAAA,EAAe,UAAU,CAAA,CAAA;AAAA,WAClC,MAAA;AACL,YAAA,MAAM,QAAW,GAAA,MAAMA,mBAAG,CAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AAC5C,YAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,cACT,CAAgB,aAAA,EAAA,QAAQ,CAAsC,mCAAA,EAAA,QAAA,CAAS,IAAI,CAAA,CAAA,CAAA;AAAA,aAC7E,CAAA;AACA,YAAA,MAAM,iBAAoB,GAAA,MAAMA,mBAAG,CAAA,QAAA,CAAS,eAAe,OAAO,CAAA,CAAA;AAClE,YAAA,MAAMA,mBAAG,CAAA,UAAA;AAAA,cACP,UAAA;AAAA,cACA,cACI,GAAA,cAAA,CAAe,iBAAmB,EAAA,OAAO,CACzC,GAAA,iBAAA;AAAA,cACJ,EAAE,IAAM,EAAA,QAAA,CAAS,IAAK,EAAA;AAAA,aACxB,CAAA;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAEA,MAAA,GAAA,CAAI,MAAO,CAAA,IAAA,CAAK,CAA8B,2BAAA,EAAA,SAAS,CAAE,CAAA,CAAA,CAAA;AAAA,KAC3D;AAAA,GACD,CAAA,CAAA;AACH,CAAA;AAEA,SAAS,uBAAuB,eAAkC,EAAA;AAKhE,EACE,OAAA,eAAA,KAAoB,MACpB,eAAgB,CAAA,UAAA,CAAW,GAAG,CAC9B,IAAA,eAAA,CAAgB,SAAS,IAAI,CAAA,CAAA;AAEjC;;ACpUO,MAAMP,UAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,wBAAA;AAAA,IACb,OAAA,EAASC,gBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,WAAA;AAAA,UACR,EAAI,EAAA,aAAA;AAAA,UACJ,IAAM,EAAA,cAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,KAAA,EAAO,CAAC,WAAA,EAAa,WAAW,CAAA;AAAA,WAClC;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;ACTO,MAAM,+BAA+B,MAAM;AAChD,EAAA,OAAOE,yCAA0C,CAAA;AAAA,IAC/C,EAAI,EAAA,WAAA;AAAA,IACJ,WAAa,EAAA,kDAAA;AAAA,cACbH,UAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,QAAA,EAAU,CAAC,OAAO,CAAA;AAAA,QAClB,IAAM,EAAA,QAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,KAAO,EAAA;AAAA,YACL,KAAO,EAAA,OAAA;AAAA,YACP,WAAa,EAAA,sDAAA;AAAA,YACb,IAAM,EAAA,OAAA;AAAA,YACN,KAAO,EAAA;AAAA,cACL,IAAM,EAAA,QAAA;AAAA,aACR;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAA,IAAI,CAAC,KAAM,CAAA,OAAA,CAAQ,GAAI,CAAA,KAAA,EAAO,KAAK,CAAG,EAAA;AACpC,QAAM,MAAA,IAAII,kBAAW,wBAAwB,CAAA,CAAA;AAAA,OAC/C;AAEA,MAAW,KAAA,MAAA,IAAA,IAAQ,GAAI,CAAA,KAAA,CAAM,KAAO,EAAA;AAClC,QAAA,MAAM,QAAW,GAAAI,qCAAA,CAAqB,GAAI,CAAA,aAAA,EAAe,IAAI,CAAA,CAAA;AAE7D,QAAI,IAAA;AACF,UAAM,MAAAD,mBAAA,CAAG,OAAO,QAAQ,CAAA,CAAA;AACxB,UAAA,GAAA,CAAI,MAAO,CAAA,IAAA,CAAK,CAAQ,KAAA,EAAA,QAAQ,CAAuB,qBAAA,CAAA,CAAA,CAAA;AAAA,iBAChD,GAAK,EAAA;AACZ,UAAA,GAAA,CAAI,MAAO,CAAA,KAAA,CAAM,CAAyB,sBAAA,EAAA,QAAQ,KAAK,GAAG,CAAA,CAAA;AAC1D,UAAM,MAAA,GAAA,CAAA;AAAA,SACR;AAAA,OACF;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH;;AC/CO,MAAM,QAA8B,GAAA;AAAA,EACzC;AAAA,IACE,WAAa,EAAA,yBAAA;AAAA,IACb,OAAA,EAASN,gBAAK,SAAU,CAAA;AAAA,MACtB,KAAO,EAAA;AAAA,QACL;AAAA,UACE,MAAQ,EAAA,WAAA;AAAA,UACR,EAAI,EAAA,aAAA;AAAA,UACJ,IAAM,EAAA,cAAA;AAAA,UACN,KAAO,EAAA;AAAA,YACL,KAAO,EAAA;AAAA,cACL,EAAE,IAAA,EAAM,WAAa,EAAA,EAAA,EAAI,kBAAmB,EAAA;AAAA,cAC5C,EAAE,IAAA,EAAM,WAAa,EAAA,EAAA,EAAI,kBAAmB,EAAA;AAAA,cAC5C,EAAE,IAAM,EAAA,WAAA,EAAa,EAAI,EAAA,kBAAA,EAAoB,WAAW,IAAK,EAAA;AAAA,aAC/D;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AACF,CAAA;;ACbO,MAAM,+BAA+B,MAAM;AAChD,EAAA,OAAOE,yCAMJ,CAAA;AAAA,IACD,EAAI,EAAA,WAAA;AAAA,IACJ,WAAa,EAAA,oDAAA;AAAA,IACb,QAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA;AAAA,QACL,QAAA,EAAU,CAAC,OAAO,CAAA;AAAA,QAClB,IAAM,EAAA,QAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,KAAO,EAAA;AAAA,YACL,KAAO,EAAA,OAAA;AAAA,YACP,WACE,EAAA,yDAAA;AAAA,YACF,IAAM,EAAA,OAAA;AAAA,YACN,KAAO,EAAA;AAAA,cACL,IAAM,EAAA,QAAA;AAAA,cACN,QAAA,EAAU,CAAC,MAAA,EAAQ,IAAI,CAAA;AAAA,cACvB,UAAY,EAAA;AAAA,gBACV,IAAM,EAAA;AAAA,kBACJ,IAAM,EAAA,QAAA;AAAA,kBACN,KAAO,EAAA,+CAAA;AAAA,iBACT;AAAA,gBACA,EAAI,EAAA;AAAA,kBACF,IAAM,EAAA,QAAA;AAAA,kBACN,KAAO,EAAA,iCAAA;AAAA,iBACT;AAAA,gBACA,SAAW,EAAA;AAAA,kBACT,IAAM,EAAA,SAAA;AAAA,kBACN,KACE,EAAA,wDAAA;AAAA,iBACJ;AAAA,eACF;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAA,IAAI,CAAC,KAAM,CAAA,OAAA,CAAQ,GAAI,CAAA,KAAA,EAAO,KAAK,CAAG,EAAA;AACpC,QAAM,MAAA,IAAIC,kBAAW,wBAAwB,CAAA,CAAA;AAAA,OAC/C;AAEA,MAAW,KAAA,MAAA,IAAA,IAAQ,GAAI,CAAA,KAAA,CAAM,KAAO,EAAA;AAClC,QAAA,IAAI,CAAC,IAAA,CAAK,IAAQ,IAAA,CAAC,KAAK,EAAI,EAAA;AAC1B,UAAM,MAAA,IAAIA,kBAAW,4CAA4C,CAAA,CAAA;AAAA,SACnE;AAEA,QAAA,MAAM,cAAiB,GAAAI,qCAAA;AAAA,UACrB,GAAI,CAAA,aAAA;AAAA,UACJ,IAAK,CAAA,IAAA;AAAA,SACP,CAAA;AACA,QAAA,MAAM,YAAe,GAAAA,qCAAA,CAAqB,GAAI,CAAA,aAAA,EAAe,KAAK,EAAE,CAAA,CAAA;AAEpE,QAAI,IAAA;AACF,UAAM,MAAAD,mBAAA,CAAG,IAAK,CAAA,cAAA,EAAgB,YAAc,EAAA;AAAA,YAC1C,SAAA,EAAW,KAAK,SAAa,IAAA,KAAA;AAAA,WAC9B,CAAA,CAAA;AACD,UAAA,GAAA,CAAI,MAAO,CAAA,IAAA;AAAA,YACT,CAAA,KAAA,EAAQ,cAAc,CAAA,YAAA,EAAe,YAAY,CAAA,aAAA,CAAA;AAAA,WACnD,CAAA;AAAA,iBACO,GAAK,EAAA;AACZ,UAAA,GAAA,CAAI,MAAO,CAAA,KAAA;AAAA,YACT,CAAA,sBAAA,EAAyB,cAAc,CAAA,IAAA,EAAO,YAAY,CAAA,CAAA,CAAA;AAAA,YAC1D,GAAA;AAAA,WACF,CAAA;AACA,UAAM,MAAA,GAAA,CAAA;AAAA,SACR;AAAA,OACF;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH;;ACyBa,MAAA,oBAAA,GAAuB,CAClC,OACqB,KAAA;AACrB,EAAM,MAAA;AAAA,IACJ,MAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAA;AAAA,IACA,yBAAA;AAAA,IACA,yBAAA;AAAA,GACE,GAAA,OAAA,CAAA;AAEJ,EAAM,MAAA,yBAAA,GACJiB,4CAAiC,CAAA,gBAAA,CAAiB,YAAY,CAAA,CAAA;AAEhE,EAAA,MAAM,OAAU,GAAA;AAAA,IACd,sBAAuB,CAAA;AAAA,MACrB,MAAA;AAAA,MACA,YAAA;AAAA,KACD,CAAA;AAAA,IACD,0BAA2B,CAAA;AAAA,MACzB,MAAA;AAAA,MACA,YAAA;AAAA,KACD,CAAA;AAAA,IACD,yBAA0B,CAAA;AAAA,MACxB,YAAA;AAAA,MACA,MAAA;AAAA,MACA,yBAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,gCAA0B,CAAA;AAAA,MACxB,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,sCAAgC,CAAA;AAAA,MAC9B,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,2DAAyB,CAAA;AAAA,MACvB,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,gCAA0B,CAAA;AAAA,MACxB,YAAA;AAAA,MACA,MAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,2CAAqC,CAAA;AAAA,MACnC,YAAA;AAAA,MACA,yBAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,gCAA0B,CAAA;AAAA,MACxB,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,4CAAsC,CAAA;AAAA,MACpC,YAAA;AAAA,KACD,CAAA;AAAA,IACDC,iCAA2B,CAAA;AAAA,MACzB,YAAA;AAAA,KACD,CAAA;AAAA,IACDC,sCAA6B,CAAA;AAAA,MAC3B,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,gDAAkC,CAAA;AAAA,MAChC,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,kDAAmC,CAAA;AAAA,MACjC,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,6DAA8C,CAAA;AAAA,MAC5C,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACDC,8BAAyB,CAAA;AAAA,MACvB,YAAA;AAAA,MACA,MAAA;AAAA,KACD,CAAA;AAAA,IACD,oBAAqB,EAAA;AAAA,IACrB,gBAAiB,EAAA;AAAA,IACjB,2BAA4B,CAAA,EAAE,aAAe,EAAA,YAAA,EAAc,MAAM,CAAA;AAAA,IACjE,8BAA+B,CAAA,EAAE,aAAe,EAAA,IAAA,EAAM,CAAA;AAAA,IACtD,wBAAyB,EAAA;AAAA,IACzB,4BAA6B,EAAA;AAAA,IAC7B,4BAA6B,EAAA;AAAA,IAC7BC,wCAAkC,CAAA;AAAA,MAChC,YAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,gCAA0B,CAAA;AAAA,MACxB,YAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,oCAA8B,CAAA;AAAA,MAC5B,YAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,mCAA6B,CAAA;AAAA,MAC3B,YAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,iCAA2B,CAAA;AAAA,MACzB,YAAA;AAAA,MACA,MAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,oCAA8B,CAAA;AAAA,MAC5B,YAAA;AAAA,KACD,CAAA;AAAA,IACDC,kCAA4B,CAAA;AAAA,MAC1B,YAAA;AAAA,KACD,CAAA;AAAA,IACDC,kCAA4B,CAAA;AAAA,MAC1B,YAAA;AAAA,MACA,yBAAA;AAAA,KACD,CAAA;AAAA,IACDC,gDAAkC,CAAA;AAAA,MAChC,YAAA;AAAA,KACD,CAAA;AAAA,GACH,CAAA;AAEA,EAAO,OAAA,OAAA,CAAA;AACT;;AC1OO,MAAM,sBAAuB,CAAA;AAAA,EACjB,OAAA,uBAAc,GAA4B,EAAA,CAAA;AAAA,EAE3D,SAAS,MAAwB,EAAA;AAC/B,IAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,GAAI,CAAA,MAAA,CAAO,EAAE,CAAG,EAAA;AAC/B,MAAA,MAAM,IAAIC,oBAAA;AAAA,QACR,CAAA,yBAAA,EAA4B,OAAO,EAAE,CAAA,6BAAA,CAAA;AAAA,OACvC,CAAA;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,OAAQ,CAAA,GAAA,CAAI,MAAO,CAAA,EAAA,EAAI,MAAM,CAAA,CAAA;AAAA,GACpC;AAAA,EAEA,IAAI,QAAkC,EAAA;AACpC,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,OAAQ,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AACxC,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAA,MAAM,IAAIC,oBAAA;AAAA,QACR,4BAA4B,QAAQ,CAAA,oBAAA,CAAA;AAAA,OACtC,CAAA;AAAA,KACF;AACA,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AAAA,EAEA,IAAyB,GAAA;AACvB,IAAA,OAAO,CAAC,GAAG,IAAK,CAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA;AAAA,GAClC;AACF;;AC7Ba,MAAA,0BAAA,GAA6B,CACxC,MACsC,KAAA;AACtC,EAAM,MAAA,iBAAA,GAAoB,MACvB,CAAA,KAAA,EACA,CAAA,OAAA,GACA,SAAU,CAAA,CAAA,KAAA,KAAS,KAAM,CAAA,IAAA,KAAS,WAAW,CAAA,CAAA;AAEhD,EAAA,IAAI,qBAAqB,CAAG,EAAA;AAC1B,IAAM,MAAA,GAAA,GAAM,MAAO,CAAA,MAAA,GAAS,iBAAoB,GAAA,CAAA,CAAA;AAChD,IAAA,MAAM,EAAE,eAAA,EAAoB,GAAA,MAAA,CAAO,GAAG,CAAE,CAAA,IAAA,CAAA;AAGxC,IAAA,IAAI,oBAAoB,WAAa,EAAA;AACnC,MAAO,OAAA;AAAA,QACL,QAAQ,iBAAsB,KAAA,CAAA,GAAI,EAAK,GAAA,MAAA,CAAO,MAAM,GAAG,CAAA;AAAA,OACzD,CAAA;AAAA,KACF;AAAA,GACF;AAEA,EAAA,OAAO,EAAE,MAAO,EAAA,CAAA;AAClB,CAAA;;ACvBa,MAAA,mBAAA,GAAsB,CAAC,QAAA,EAAkB,IAAe,KAAA;AACnE,EAAA,IAAI,iBAAoB,GAAA,IAAA,CAAK,GAAI,CAAA,CAAA,cAAA,EAAiB,QAAQ,CAAa,SAAA,CAAA,EAAA;AAAA,IACrE,IAAA,CAAK,GAAG,GAAI,EAAA;AAAA,GACb,CAAA,CAAA;AACD,EAAA,IAAI,KAAK,MAAO,CAAA,MAAA,CAAO,MAAO,CAAA,QAAA,CAAS,OAAO,CAAG,EAAA;AAC/C,IAAA,iBAAA,GAAoB,IAAK,CAAA,GAAA;AAAA,MACvB,4BAA4B,QAAQ,CAAA,QAAA,CAAA;AAAA,KACtC,CAAA;AAAA,aACS,IAAK,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,QAAA,CAAS,SAAS,CAAG,EAAA;AACxD,IAAoB,iBAAA,GAAA,IAAA,CAAK,IAAI,CAAsB,kBAAA,CAAA,EAAA;AAAA,MACjD,IAAI,QAAQ,CAAA,QAAA,CAAA;AAAA,KACb,CAAA,CAAA;AAAA,GACH;AACA,EAAO,OAAA,iBAAA,CAAA;AACT,CAAA;;ACgBA,MAAM,aAAgB,GAAA9B,mCAAA;AAAA,EACpB,sCAAA;AAAA,EACA,YAAA;AACF,CAAA,CAAA;AAoCA,SAAS,wBACP,GAC8B,EAAA;AAC9B,EAAA,OAAQ,IAA8B,SAAc,KAAA,KAAA,CAAA,CAAA;AACtD,CAAA;AAEA,MAAM,uBAAA,GAA0B,CAAI,KAAyB,KAAA;AAC3D,EAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC7B,IAAA,MAAM,SAAS+B,cAAS,CAAA,OAAA,CAAQ,OAAO,EAAE,IAAA,EAAM,OAAO,CAAA,CAAA;AACtD,IAAI,IAAA,CAAC,OAAO,OAAS,EAAA;AACnB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,uCAAuC,KAAK,CAAA,GAAA,EAAM,OAAO,aAAa,CAAA,EAAA,EAAK,OAAO,kBAAkB,CAAA,CAAA;AAAA,OACtG,CAAA;AAAA,KACF;AACA,IAAA,OAAO,OAAO,KAAM,EAAA,CAAA;AAAA,GACtB;AAEA,EAAO,OAAA,KAAA,CAAA;AACT,CAAA,CAAA;AAOO,MAAM,iBAAuC,CAAA;AAAA,EACjC,EAAA,CAAA;AAAA,EAEjB,aAAa,OACX,OAC4B,EAAA;AAC5B,IAAM,MAAA,EAAE,UAAa,GAAA,OAAA,CAAA;AACrB,IAAA,MAAM,MAAS,GAAA,MAAM,IAAK,CAAA,SAAA,CAAU,QAAQ,CAAA,CAAA;AAE5C,IAAM,MAAA,IAAA,CAAK,aAAc,CAAA,QAAA,EAAU,MAAM,CAAA,CAAA;AAEzC,IAAO,OAAA,IAAI,kBAAkB,MAAM,CAAA,CAAA;AAAA,GACrC;AAAA,EAEQ,kBAAkB,IAAyB,EAAA;AACjD,IAAO,OAAA,CAAC,WAAW,CAAE,CAAA,QAAA;AAAA,MACnB,IAAA,CAAK,uBAAuB,qBAAyB,IAAA,MAAA;AAAA,KACvD,CAAA;AAAA,GACF;AAAA,EAEQ,SAAU,CAAA,EAAE,IAAM,EAAA,EAAA,EAA8C,EAAA;AACtE,IAAI,IAAA;AACF,MAAO,OAAA,IAAA,CAAK,MAAM,IAAI,CAAA,CAAA;AAAA,aACf,KAAO,EAAA;AACd,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,8BAAA,EAAiC,EAAE,CAAA,GAAA,EAAM,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,KAClE;AAAA,GACF;AAAA,EAEQ,iBAAiB,OAAgD,EAAA;AACvE,IAAI,IAAA;AACF,MAAA,OAAO,QAAQ,OAAU,GAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,OAAO,CAAI,GAAA,KAAA,CAAA,CAAA;AAAA,aAChD,KAAO,EAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAoC,iCAAA,EAAA,OAAA,CAAQ,EAAE,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA;AAAA,OAC3D,CAAA;AAAA,KACF;AAAA,GACF;AAAA,EAEA,aAAqB,UACnB,QACe,EAAA;AACf,IAAI,IAAA,uBAAA,CAAwB,QAAQ,CAAG,EAAA;AACrC,MAAA,OAAO,SAAS,SAAU,EAAA,CAAA;AAAA,KAC5B;AAEA,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AAAA,EAEA,aAAqB,aACnB,CAAA,QAAA,EACA,MACe,EAAA;AACf,IAAI,IAAA,CAAC,uBAAwB,CAAA,QAAQ,CAAG,EAAA;AACtC,MAAM,MAAA,MAAA,CAAO,QAAQ,MAAO,CAAA;AAAA,QAC1B,SAAW,EAAA,aAAA;AAAA,OACZ,CAAA,CAAA;AAED,MAAA,OAAA;AAAA,KACF;AAEA,IAAI,IAAA,CAAC,QAAS,CAAA,UAAA,EAAY,IAAM,EAAA;AAC9B,MAAM,MAAA,MAAA,CAAO,QAAQ,MAAO,CAAA;AAAA,QAC1B,SAAW,EAAA,aAAA;AAAA,OACZ,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AAAA,EAEQ,YAAY,MAAc,EAAA;AAChC,IAAA,IAAA,CAAK,EAAK,GAAA,MAAA,CAAA;AAAA,GACZ;AAAA,EAEA,MAAM,KAAK,OAE8B,EAAA;AACvC,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,EAAA,CAAiB,OAAO,CAAA,CAAA;AAElD,IAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,MAAA,YAAA,CAAa,KAAM,CAAA;AAAA,QACjB,YAAY,OAAQ,CAAA,SAAA;AAAA,OACrB,CAAA,CAAA;AAAA,KACH;AAEA,IAAA,MAAM,UAAU,MAAM,YAAA,CAAa,QAAQ,YAAc,EAAA,MAAM,EAAE,MAAO,EAAA,CAAA;AAExE,IAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,GAAA,CAAI,CAAW,MAAA,MAAA;AAAA,MACnC,IAAI,MAAO,CAAA,EAAA;AAAA,MACX,IAAM,EAAA,IAAA,CAAK,KAAM,CAAA,MAAA,CAAO,IAAI,CAAA;AAAA,MAC5B,QAAQ,MAAO,CAAA,MAAA;AAAA,MACf,SAAA,EAAW,OAAO,UAAc,IAAA,KAAA,CAAA;AAAA,MAChC,eAAA,EAAiB,uBAAwB,CAAA,MAAA,CAAO,iBAAiB,CAAA;AAAA,MACjE,SAAA,EAAW,uBAAwB,CAAA,MAAA,CAAO,UAAU,CAAA;AAAA,KACpD,CAAA,CAAA,CAAA;AAEF,IAAA,OAAO,EAAE,KAAM,EAAA,CAAA;AAAA,GACjB;AAAA,EAEA,MAAM,QAAQ,MAAyC,EAAA;AACrD,IAAA,MAAM,CAAC,MAAM,CAAI,GAAA,MAAM,KAAK,EAAiB,CAAA,OAAO,CACjD,CAAA,KAAA,CAAM,EAAE,EAAA,EAAI,MAAO,EAAC,EACpB,MAAO,EAAA,CAAA;AACV,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAA,MAAM,IAAID,oBAAA,CAAc,CAAoB,iBAAA,EAAA,MAAM,CAAS,OAAA,CAAA,CAAA,CAAA;AAAA,KAC7D;AACA,IAAI,IAAA;AACF,MAAA,MAAM,IAAO,GAAA,IAAA,CAAK,KAAM,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AACnC,MAAA,MAAM,UAAU,MAAO,CAAA,OAAA,GAAU,KAAK,KAAM,CAAA,MAAA,CAAO,OAAO,CAAI,GAAA,KAAA,CAAA,CAAA;AAC9D,MAAM,MAAA,KAAA,GAAQ,OAAO,KAAQ,GAAA,IAAA,CAAK,MAAM,MAAO,CAAA,KAAK,EAAE,KAAQ,GAAA,KAAA,CAAA,CAAA;AAC9D,MAAO,OAAA;AAAA,QACL,IAAI,MAAO,CAAA,EAAA;AAAA,QACX,IAAA;AAAA,QACA,QAAQ,MAAO,CAAA,MAAA;AAAA,QACf,eAAA,EAAiB,uBAAwB,CAAA,MAAA,CAAO,iBAAiB,CAAA;AAAA,QACjE,SAAA,EAAW,uBAAwB,CAAA,MAAA,CAAO,UAAU,CAAA;AAAA,QACpD,SAAA,EAAW,OAAO,UAAc,IAAA,KAAA,CAAA;AAAA,QAChC,OAAA;AAAA,QACA,KAAA;AAAA,OACF,CAAA;AAAA,aACO,KAAO,EAAA;AACd,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,8BAAA,EAAiC,MAAM,CAAA,GAAA,EAAM,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,KACtE;AAAA,GACF;AAAA,EAEA,MAAM,WACJ,OACoC,EAAA;AACpC,IAAA,MAAM,SAASE,OAAK,EAAA,CAAA;AACpB,IAAA,MAAM,IAAK,CAAA,EAAA,CAAiB,OAAO,CAAA,CAAE,MAAO,CAAA;AAAA,MAC1C,EAAI,EAAA,MAAA;AAAA,MACJ,IAAM,EAAA,IAAA,CAAK,SAAU,CAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACjC,SAAS,OAAQ,CAAA,OAAA,GAAU,KAAK,SAAU,CAAA,OAAA,CAAQ,OAAO,CAAI,GAAA,KAAA,CAAA;AAAA,MAC7D,UAAA,EAAY,QAAQ,SAAa,IAAA,IAAA;AAAA,MACjC,MAAQ,EAAA,MAAA;AAAA,KACT,CAAA,CAAA;AACD,IAAA,OAAO,EAAE,MAAO,EAAA,CAAA;AAAA,GAClB;AAAA,EAEA,MAAM,SAAiD,GAAA;AACrD,IAAA,OAAO,IAAK,CAAA,EAAA,CAAG,WAAY,CAAA,OAAM,EAAM,KAAA;AACrC,MAAA,MAAM,CAAC,IAAI,CAAA,GAAI,MAAM,EAAiB,CAAA,OAAO,EAC1C,KAAM,CAAA;AAAA,QACL,MAAQ,EAAA,MAAA;AAAA,OACT,CAAA,CACA,KAAM,CAAA,CAAC,EACP,MAAO,EAAA,CAAA;AAEV,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAO,OAAA,KAAA,CAAA,CAAA;AAAA,OACT;AAEA,MAAM,MAAA,IAAA,GAAO,IAAK,CAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAEhC,MAAA,MAAM,WAAc,GAAA,MAAM,EAAiB,CAAA,OAAO,EAC/C,KAAM,CAAA,EAAE,EAAI,EAAA,IAAA,CAAK,EAAI,EAAA,MAAA,EAAQ,MAAO,EAAC,EACrC,MAAO,CAAA;AAAA,QACN,MAAQ,EAAA,YAAA;AAAA,QACR,iBAAmB,EAAA,IAAA,CAAK,EAAG,CAAA,EAAA,CAAG,GAAI,EAAA;AAAA;AAAA,QAElC,SAAS,IAAK,CAAA,iBAAA,CAAkB,IAAI,CAAA,GAAI,KAAK,OAAU,GAAA,IAAA;AAAA,OACxD,CAAA,CAAA;AAEH,MAAA,IAAI,cAAc,CAAG,EAAA;AACnB,QAAO,OAAA,KAAA,CAAA,CAAA;AAAA,OACT;AAEA,MAAA,MAAM,WAAW,MAAM;AACrB,QAAI,IAAA;AACF,UAAA,OAAO,KAAK,KAAQ,GAAA,IAAA,CAAK,MAAM,IAAK,CAAA,KAAK,EAAE,KAAQ,GAAA,KAAA,CAAA,CAAA;AAAA,iBAC5C,KAAO,EAAA;AACd,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAsC,mCAAA,EAAA,IAAA,CAAK,EAAE,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA;AAAA,WAC1D,CAAA;AAAA,SACF;AAAA,OACF,CAAA;AAEA,MAAM,MAAA,OAAA,GAAU,IAAK,CAAA,gBAAA,CAAiB,IAAI,CAAA,CAAA;AAC1C,MAAO,OAAA;AAAA,QACL,IAAI,IAAK,CAAA,EAAA;AAAA,QACT,IAAA;AAAA,QACA,MAAQ,EAAA,YAAA;AAAA,QACR,iBAAiB,IAAK,CAAA,iBAAA;AAAA,QACtB,WAAW,IAAK,CAAA,UAAA;AAAA,QAChB,SAAA,EAAW,KAAK,UAAc,IAAA,KAAA,CAAA;AAAA,QAC9B,OAAA;AAAA,QACA,OAAO,QAAS,EAAA;AAAA,OAClB,CAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,cAAc,MAA+B,EAAA;AACjD,IAAA,MAAM,WAAc,GAAA,MAAM,IAAK,CAAA,EAAA,CAAiB,OAAO,CACpD,CAAA,KAAA,CAAM,EAAE,EAAA,EAAI,MAAQ,EAAA,MAAA,EAAQ,YAAa,EAAC,EAC1C,MAAO,CAAA;AAAA,MACN,iBAAmB,EAAA,IAAA,CAAK,EAAG,CAAA,EAAA,CAAG,GAAI,EAAA;AAAA,KACnC,CAAA,CAAA;AACH,IAAA,IAAI,gBAAgB,CAAG,EAAA;AACrB,MAAA,MAAM,IAAIH,oBAAA,CAAc,CAA+B,4BAAA,EAAA,MAAM,CAAQ,MAAA,CAAA,CAAA,CAAA;AAAA,KACvE;AAAA,GACF;AAAA,EAEA,MAAM,eAAe,OAElB,EAAA;AACD,IAAM,MAAA,EAAE,UAAa,GAAA,OAAA,CAAA;AACrB,IAAA,MAAM,iBAAoB,GAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAC/D,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,EAAA,CAAiB,OAAO,CAAA,CAChD,KAAM,CAAA,QAAA,EAAU,YAAY,CAAA,CAC5B,QAAS,CAAA,mBAAA,EAAqB,MAAM,iBAAiB,CAAA,CAAA;AACxD,IAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,GAAA,CAAI,CAAQ,GAAA,MAAA;AAAA,MAChC,QAAW,EAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAI,IAAI,CAAe,CAAA,qBAAA;AAAA,MAC7C,QAAQ,GAAI,CAAA,EAAA;AAAA,KACZ,CAAA,CAAA,CAAA;AACF,IAAA,OAAO,EAAE,KAAM,EAAA,CAAA;AAAA,GACjB;AAAA,EAEA,MAAM,aAAa,OAID,EAAA;AAChB,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAQ,EAAA,SAAA,EAAc,GAAA,OAAA,CAAA;AAEtC,IAAI,IAAA,SAAA,CAAA;AACJ,IAAA,IAAI,CAAC,QAAU,EAAA,WAAA,EAAa,WAAW,CAAE,CAAA,QAAA,CAAS,MAAM,CAAG,EAAA;AACzD,MAAY,SAAA,GAAA,YAAA,CAAA;AAAA,KACP,MAAA;AACL,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,8BAAA,EAAiC,MAAM,CAAA,aAAA,EAAgB,MAAM,CAAA,CAAA,CAAA;AAAA,OAC/D,CAAA;AAAA,KACF;AAEA,IAAA,MAAM,IAAK,CAAA,EAAA,CAAG,WAAY,CAAA,OAAM,EAAM,KAAA;AACpC,MAAA,MAAM,CAAC,IAAI,CAAA,GAAI,MAAM,EAAiB,CAAA,OAAO,EAC1C,KAAM,CAAA;AAAA,QACL,EAAI,EAAA,MAAA;AAAA,OACL,CAAA,CACA,KAAM,CAAA,CAAC,EACP,MAAO,EAAA,CAAA;AAEV,MAAM,MAAA,UAAA,GAAa,OAAO,QAGpB,KAAA;AACJ,QAAM,MAAA,WAAA,GAAc,MAAM,EAAiB,CAAA,OAAO,EAC/C,KAAM,CAAA,QAAQ,EACd,MAAO,CAAA;AAAA,UACN,MAAA;AAAA,UACA,OAAS,EAAA,IAAA;AAAA,SACV,CAAA,CAAA;AAEH,QAAA,IAAI,gBAAgB,CAAG,EAAA;AACrB,UAAA,MAAM,IAAIA,oBAAA;AAAA,YACR,CAAA,4BAAA,EAA+B,MAAM,CAAA,aAAA,EAAgB,MAAM,CAAA,CAAA;AAAA,WAC7D,CAAA;AAAA,SACF;AAEA,QAAM,MAAA,EAAA,CAAsB,aAAa,CAAA,CAAE,MAAO,CAAA;AAAA,UAChD,OAAS,EAAA,MAAA;AAAA,UACT,UAAY,EAAA,YAAA;AAAA,UACZ,IAAA,EAAM,IAAK,CAAA,SAAA,CAAU,SAAS,CAAA;AAAA,SAC/B,CAAA,CAAA;AAAA,OACH,CAAA;AAEA,MAAA,IAAI,WAAW,WAAa,EAAA;AAC1B,QAAA,MAAM,UAAW,CAAA;AAAA,UACf,EAAI,EAAA,MAAA;AAAA,SACL,CAAA,CAAA;AACD,QAAA,OAAA;AAAA,OACF;AAEA,MAAI,IAAA,IAAA,CAAK,WAAW,WAAa,EAAA;AAC/B,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,MAAM,IAAI,KAAA,CAAM,CAAuB,oBAAA,EAAA,MAAM,CAAQ,MAAA,CAAA,CAAA,CAAA;AAAA,OACvD;AACA,MAAI,IAAA,IAAA,CAAK,WAAW,SAAW,EAAA;AAC7B,QAAA,MAAM,IAAIA,oBAAA;AAAA,UACR,CAAA,kCAAA,EAAqC,MAAM,CAAgB,aAAA,EAAA,MAAM,yBACxC,IAAK,CAAA,MAAM,gBAAgB,SAAS,CAAA,CAAA,CAAA;AAAA,SAC/D,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,UAAW,CAAA;AAAA,QACf,EAAI,EAAA,MAAA;AAAA,QACJ,MAAQ,EAAA,SAAA;AAAA,OACT,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,aACJ,OACe,EAAA;AACf,IAAM,MAAA,EAAE,MAAQ,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AACzB,IAAM,MAAA,cAAA,GAAiB,IAAK,CAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAC1C,IAAA,MAAM,IAAK,CAAA,EAAA,CAAsB,aAAa,CAAA,CAAE,MAAO,CAAA;AAAA,MACrD,OAAS,EAAA,MAAA;AAAA,MACT,UAAY,EAAA,KAAA;AAAA,MACZ,IAAM,EAAA,cAAA;AAAA,KACP,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,YAAA,CAAa,EAAE,MAAA,EAKnB,EAAA;AACA,IAAA,MAAM,CAAC,MAAM,CAAI,GAAA,MAAM,KAAK,EAAiB,CAAA,OAAO,CACjD,CAAA,KAAA,CAAM,EAAE,EAAI,EAAA,MAAA,EAAQ,CAAA,CACpB,OAAO,OAAO,CAAA,CAAA;AACjB,IAAA,OAAO,OAAO,KAAQ,GAAA,IAAA,CAAK,KAAM,CAAA,MAAA,CAAO,KAAK,CAAI,GAAA,KAAA,CAAA,CAAA;AAAA,GACnD;AAAA,EAEA,MAAM,cAAc,OAGF,EAAA;AAChB,IAAA,IAAI,QAAQ,KAAO,EAAA;AACjB,MAAA,MAAM,kBAAkB,IAAK,CAAA,SAAA,CAAU,EAAE,KAAO,EAAA,OAAA,CAAQ,OAAO,CAAA,CAAA;AAC/D,MAAM,MAAA,IAAA,CAAK,EAAiB,CAAA,OAAO,CAChC,CAAA,KAAA,CAAM,EAAE,EAAA,EAAI,OAAQ,CAAA,MAAA,EAAQ,CAAA,CAC5B,MAAO,CAAA;AAAA,QACN,KAAO,EAAA,eAAA;AAAA,OACR,CAAA,CAAA;AAAA,KACL;AAAA,GACF;AAAA,EAEA,MAAM,WACJ,OAC4C,EAAA;AAC5C,IAAM,MAAA,EAAE,MAAQ,EAAA,KAAA,EAAU,GAAA,OAAA,CAAA;AAC1B,IAAA,MAAM,YAAY,MAAM,IAAA,CAAK,EAAsB,CAAA,aAAa,EAC7D,KAAM,CAAA;AAAA,MACL,OAAS,EAAA,MAAA;AAAA,KACV,CACA,CAAA,QAAA,CAAS,CAAW,OAAA,KAAA;AACnB,MAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC7B,QAAA,OAAA,CAAQ,MAAM,IAAM,EAAA,GAAA,EAAK,KAAK,CAAE,CAAA,OAAA,CAAQ,cAAc,YAAY,CAAA,CAAA;AAAA,OACpE;AAAA,KACD,CAAA,CACA,OAAQ,CAAA,IAAI,EACZ,MAAO,EAAA,CAAA;AAEV,IAAM,MAAA,MAAA,GAAS,SAAU,CAAA,GAAA,CAAI,CAAS,KAAA,KAAA;AACpC,MAAI,IAAA;AACF,QAAA,MAAM,IAAO,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,IAAI,CAAA,CAAA;AAClC,QAAO,OAAA;AAAA,UACL,EAAA,EAAI,MAAO,CAAA,KAAA,CAAM,EAAE,CAAA;AAAA,UACnB,MAAA;AAAA,UACA,IAAA;AAAA,UACA,MAAM,KAAM,CAAA,UAAA;AAAA,UACZ,SAAA,EAAW,uBAAwB,CAAA,KAAA,CAAM,UAAU,CAAA;AAAA,SACrD,CAAA;AAAA,eACO,KAAO,EAAA;AACd,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,gDAAgD,MAAM,CAAA,IAAA,EAAO,KAAM,CAAA,EAAE,KAAK,KAAK,CAAA,CAAA;AAAA,SACjF,CAAA;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAED,IAAA,OAAO,2BAA2B,MAAM,CAAA,CAAA;AAAA,GAC1C;AAAA,EAEA,MAAM,aAAa,OAAsD,EAAA;AACvE,IAAM,MAAA,EAAE,QAAW,GAAA,OAAA,CAAA;AACnB,IAAA,MAAM,OAAU,GAAA,CAAA,wDAAA,CAAA,CAAA;AAEhB,IAAM,MAAA,gBAAA,GAAA,CAAoB,MAAM,IAAK,CAAA,UAAA,CAAW,EAAE,MAAO,EAAC,GAAG,MAAO,CAAA,MAAA;AAAA,MAClE,CAAC,EAAE,IAAK,EAAA,KAAM,IAAM,EAAA,MAAA;AAAA,KACtB,CAAA;AAEA,IAAA,MAAM,iBAAiB,gBACpB,CAAA,MAAA;AAAA,MACC,CAAC,EAAE,IAAM,EAAA,EAAE,QAAS,EAAA,KAAM,MAAW,KAAA,QAAA,IAAY,MAAW,KAAA,WAAA;AAAA,KAE7D,CAAA,GAAA,CAAI,CAAQ,IAAA,KAAA,IAAA,CAAK,KAAK,MAAM,CAAA,CAAA;AAE/B,IAAM,MAAA,mBAAA,GAAsB,gBACzB,CAAA,MAAA,CAAO,CAAC,EAAE,MAAM,EAAE,MAAA,EAAS,EAAA,KAAM,MAAW,KAAA,YAAY,EACxD,GAAI,CAAA,CAAA,KAAA,KAAS,KAAM,CAAA,IAAA,CAAK,MAAM,CAAA,CAC9B,MAAO,CAAA,CAAA,IAAA,KAAQ,CAAC,cAAA,CAAe,QAAS,CAAA,IAAI,CAAC,CAAA,CAAA;AAEhD,IAAA,KAAA,MAAW,QAAQ,mBAAqB,EAAA;AACtC,MAAA,MAAM,KAAK,YAAa,CAAA;AAAA,QACtB,MAAA;AAAA,QACA,IAAM,EAAA;AAAA,UACJ,OAAA;AAAA,UACA,MAAQ,EAAA,IAAA;AAAA,UACR,MAAQ,EAAA,QAAA;AAAA,SACV;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAEA,IAAA,MAAM,KAAK,YAAa,CAAA;AAAA,MACtB,MAAA;AAAA,MACA,MAAQ,EAAA,QAAA;AAAA,MACR,SAAW,EAAA;AAAA,QACT,OAAA;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,mBAAmB,OAGP,EAAA;AAChB,IAAA,MAAM,CAAC,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,GAAiB,OAAO,CAAA,CACjD,KAAM,CAAA,EAAE,IAAI,OAAQ,CAAA,MAAA,EAAQ,CAAA,CAC5B,OAAO,WAAW,CAAA,CAAA;AAErB,IAAA,MAAMI,sBAAiB,CAAA;AAAA,MACrB,MAAM,OAAQ,CAAA,UAAA;AAAA,MACd,QAAQ,MAAO,CAAA,SAAA;AAAA,KAChB,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,cAAA,CAAe,EAAE,MAAA,EAA6C,EAAA;AAClE,IAAM,MAAA,IAAA,CAAK,EAAiB,CAAA,OAAO,CAAE,CAAA,KAAA,CAAM,EAAE,EAAI,EAAA,MAAA,EAAQ,CAAA,CAAE,MAAO,CAAA;AAAA,MAChE,SAAW,EAAA,KAAA,CAAA;AAAA,KACZ,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,mBAAmB,OAGP,EAAA;AAChB,IAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,MAAM,MAAA,IAAA,CAAK,EAAiB,CAAA,OAAO,CAChC,CAAA,KAAA,CAAM,EAAE,EAAA,EAAI,OAAQ,CAAA,MAAA,EAAQ,CAAA,CAC5B,MAAO,CAAA;AAAA,QACN,SAAY,EAAA,CAAA,MAAMC,wBAAmB,CAAA,OAAO,CAAG,EAAA,QAAA;AAAA,OAChD,CAAA,CAAA;AAAA,KACL;AAAA,GACF;AAAA,EAEA,MAAM,WACJ,OACe,EAAA;AACf,IAAM,MAAA,EAAE,MAAQ,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AACzB,IAAM,MAAA,cAAA,GAAiB,IAAK,CAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAC1C,IAAA,MAAM,IAAK,CAAA,EAAA,CAAsB,aAAa,CAAA,CAAE,MAAO,CAAA;AAAA,MACrD,OAAS,EAAA,MAAA;AAAA,MACT,UAAY,EAAA,WAAA;AAAA,MACZ,IAAM,EAAA,cAAA;AAAA,KACP,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,aACJ,OAC4B,EAAA;AAC5B,IAAA,MAAM,mBAA6B,EAAC,CAAA;AACpC,IAAA,MAAM,WAAWtC,cAAS,CAAA,UAAA,CAAW,QAAQ,OAAO,CAAA,CAAE,GAAG,SAAS,CAAA,CAAA;AAElE,IAAA,MAAM,IAAK,CAAA,EAAA,CAAG,WAAY,CAAA,OAAM,EAAM,KAAA;AACpC,MAAA,MAAM,iBAAoB,GAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAE/D,MAAA,MAAM,MAAS,GAAA,MAAM,EAAiB,CAAA,OAAO,CAC1C,CAAA,KAAA,CAAM,QAAU,EAAA,YAAY,CAC5B,CAAA,QAAA,CAAS,mBAAqB,EAAA,IAAA,EAAM,iBAAiB,CACrD,CAAA,MAAA;AAAA,QACC;AAAA,UACE,MAAQ,EAAA,MAAA;AAAA,UACR,iBAAmB,EAAA,IAAA,CAAK,EAAG,CAAA,EAAA,CAAG,GAAI,EAAA;AAAA,SACpC;AAAA,QACA,CAAC,MAAM,MAAM,CAAA;AAAA,OACf,CAAA;AAEF,MAAA,gBAAA,CAAiB,KAAK,GAAG,MAAA,CAAO,IAAI,CAAK,CAAA,KAAA,CAAA,CAAE,EAAE,CAAC,CAAA,CAAA;AAE9C,MAAA,KAAA,MAAW,EAAE,EAAA,EAAI,IAAK,EAAA,IAAK,MAAQ,EAAA;AACjC,QAAM,MAAA,QAAA,GAAW,IAAK,CAAA,KAAA,CAAM,IAAc,CAAA,CAAA;AAC1C,QAAM,MAAA,EAAA,CAAsB,aAAa,CAAA,CAAE,MAAO,CAAA;AAAA,UAChD,OAAS,EAAA,EAAA;AAAA,UACT,UAAY,EAAA,WAAA;AAAA,UACZ,IAAA,EAAM,KAAK,SAAU,CAAA;AAAA,YACnB,eAAA,EACE,QAAS,CAAA,qBAAA,EAAuB,qBAAyB,IAAA,MAAA;AAAA,WAC5D,CAAA;AAAA,SACF,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAED,IAAO,OAAA,EAAE,KAAK,gBAAiB,EAAA,CAAA;AAAA,GACjC;AACF;;ACzjBO,SAAS,SAAS,KAAqB,EAAA;AAC5C,EAAA,OAAOuC,eAAQ,KAAK,CAAA,GAAI,MAAM,MAAS,GAAA,CAAA,GAAI,CAAC,CAAC,KAAA,CAAA;AAC/C,CAAA;AAEO,SAAS,sBAAsB,MAAyB,EAAA;AAC7D,EAAM,MAAA,EAAE,UAAa,GAAA,MAAA,CAAA;AACrB,EAAA,IAAI,QAAY,IAAA,KAAA,CAAM,OAAQ,CAAA,QAAQ,CAAG,EAAA;AACvC,IAAA,OAAO,SAAS,CAAC,CAAA,CAAA;AAAA,GACnB;AACA,EAAI,IAAA,MAAA,CAAO,SAAS,QAAU,EAAA;AAC5B,IAAA,OAAO,MAAO,CAAA,WAAA;AAAA,MACZ,MAAO,CAAA,OAAA,CAAQ,MAAO,CAAA,UAAA,IAAc,EAAE,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,GAAK,EAAA,KAAK,CAAM,KAAA;AAAA,QAC5D,GAAA;AAAA,QACA,sBAAsB,KAAK,CAAA;AAAA,OAC5B,CAAA;AAAA,KACH,CAAA;AAAA,GACF,MAAA,IAAW,MAAO,CAAA,IAAA,KAAS,OAAS,EAAA;AAClC,IAAA,MAAM,CAAC,WAAW,CAAA,GAAI,CAAC,MAAO,CAAA,KAAK,GAAG,IAAK,EAAA,CAAA;AAC3C,IAAA,IAAI,WAAa,EAAA;AACf,MAAO,OAAA,CAAC,qBAAsB,CAAA,WAAW,CAAC,CAAA,CAAA;AAAA,KAC5C;AACA,IAAA,OAAO,EAAC,CAAA;AAAA,GACV,MAAA,IAAW,MAAO,CAAA,IAAA,KAAS,QAAU,EAAA;AACnC,IAAO,OAAA,WAAA,CAAA;AAAA,GACT,MAAA,IAAW,MAAO,CAAA,IAAA,KAAS,QAAU,EAAA;AACnC,IAAO,OAAA,CAAA,CAAA;AAAA,GACT,MAAA,IAAW,MAAO,CAAA,IAAA,KAAS,SAAW,EAAA;AACpC,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AACA,EAAO,OAAA,WAAA,CAAA;AACT,CAAA;AAEO,MAAMC,cAAe,GAAA,CAC1BC,QACA,EAAA,GAAA,EACA,YACG,KAAA;AACH,EAAI,IAAAA,QAAA,EAAQ,GAAI,CAAA,GAAG,CAAG,EAAA;AACpB,IAAA,OAAOC,6BAAuB,CAAAD,QAAA,EAAQ,EAAE,GAAA,EAAK,CAAA,CAAA;AAAA,GAC/C;AACA,EAAO,OAAA,YAAA,CAAA;AACT,CAAA;;AChDO,MAAM,yBAAuD,CAAA;AAAA,EAK1D,YAA6B,OAAoB,EAAA;AAApB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AAAA,GAAqB;AAAA,EAJ1D,OAAO,OAAO,OAAoB,EAAA;AAChC,IAAO,OAAA,IAAI,0BAA0B,OAAO,CAAA,CAAA;AAAA,GAC9C;AAAA,EAIA,MAAa,mBAAmB,OAGd,EAAA;AAChB,IAAK,IAAA,CAAA,OAAA,CAAQ,qBAAqB,OAAO,CAAA,CAAA;AAAA,GAC3C;AAAA,EAEA,MAAa,mBAAmB,OAGd,EAAA;AAChB,IAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,kBAAA,GAAqB,OAAO,CAAA,CAAA;AAAA,GAClD;AAAA,EAEA,MAAa,eAAe,OAA4C,EAAA;AACtE,IAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,cAAA,GAAiB,OAAO,CAAA,CAAA;AAAA,GAC9C;AACF;;ACXO,MAAM,uBAAoD,CAAA;AAAA,EAiBvD,WAAA,CACW,IACA,EAAA,iBAAA,EACA,MACjB,EAAA;AAHiB,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,iBAAA,GAAA,iBAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAChB;AAAA,EApBH,OAAO,MAAA,CACL,IACA,EAAA,OAAA,EACA,8BACA,MACA,EAAA;AACA,IAAA,MAAM,wBACJ,MAAQ,EAAA,iBAAA;AAAA,MACN,wDAAA;AAAA,KACG,IAAA,UAAA,CAAA;AACP,IAAA,MAAM,oBACJ,4BAA+B,GAAA,qBAAqB,CACpD,IAAA,yBAAA,CAA0B,OAAO,OAAO,CAAA,CAAA;AAC1C,IAAA,OAAO,IAAI,uBAAA,CAAwB,IAAM,EAAA,iBAAA,EAAmB,MAAM,CAAA,CAAA;AAAA,GACpE;AAAA,EAQA,MAAa,mBAAmB,OAA0C,EAAA;AACxE,IAAI,IAAA,IAAA,CAAK,iCAAmC,EAAA;AAC1C,MAAM,MAAA,IAAA,CAAK,kBAAkB,kBAAmB,CAAA;AAAA,QAC9C,MAAM,OAAQ,CAAA,IAAA;AAAA,QACd,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,OACnB,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AAAA,EAEA,MAAa,cAAgC,GAAA;AAC3C,IAAI,IAAA,IAAA,CAAK,iCAAmC,EAAA;AAC1C,MAAM,MAAA,IAAA,CAAK,kBAAkB,cAAe,CAAA,EAAE,QAAQ,IAAK,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,KAC1E;AAAA,GACF;AAAA,EAEA,MAAa,mBAAmB,OAGd,EAAA;AAChB,IAAI,IAAA,IAAA,CAAK,iCAAmC,EAAA;AAC1C,MAAM,MAAA,IAAA,CAAK,iBAAkB,CAAA,kBAAA,CAAmB,OAAO,CAAA,CAAA;AAAA,KACzD;AAAA,GACF;AAAA,EAEQ,+BAA2C,GAAA;AACjD,IAAA,OACE,KAAK,MAAQ,EAAA,kBAAA;AAAA,MACX,gDAAA;AAAA,KACG,IAAA,KAAA,CAAA;AAAA,GAET;AACF;;AC5BO,MAAM,WAAmC,CAAA;AAAA;AAAA,EAoCtC,YACW,IACA,EAAA,OAAA,EACA,QACA,MACA,EAAA,gBAAA,EACA,aACA,IACjB,EAAA;AAPiB,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AAAA,GAChB;AAAA,EA3CK,MAAS,GAAA,KAAA,CAAA;AAAA,EAET,kBAAA,CAAA;AAAA,EAER,OAAO,OACL,IACA,EAAA,OAAA,EACA,aACA,MACA,EAAA,WAAA,EACA,IACA,EAAA,MAAA,EACA,4BACA,EAAA;AACA,IAAA,MAAM,mBAAmB,uBAAwB,CAAA,MAAA;AAAA,MAC/C,IAAA;AAAA,MACA,OAAA;AAAA,MACA,4BAAA;AAAA,MACA,MAAA;AAAA,KACF,CAAA;AAEA,IAAA,MAAM,QAAQ,IAAI,WAAA;AAAA,MAChB,IAAA;AAAA,MACA,OAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,gBAAA;AAAA,MACA,WAAA;AAAA,MACA,IAAA;AAAA,KACF,CAAA;AACA,IAAA,KAAA,CAAM,YAAa,EAAA,CAAA;AACnB,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAAA,EAaA,IAAI,MAAS,GAAA;AACX,IAAA,OAAO,KAAK,IAAK,CAAA,MAAA,CAAA;AAAA,GACnB;AAAA,EAEA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,KAAK,IAAK,CAAA,IAAA,CAAA;AAAA,GACnB;AAAA,EAEA,IAAI,YAAe,GAAA;AACjB,IAAA,OAAO,IAAK,CAAA,MAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,OAAU,GAAA;AACZ,IAAA,OAAO,KAAK,IAAK,CAAA,OAAA,CAAA;AAAA,GACnB;AAAA,EAEA,IAAI,SAAY,GAAA;AACd,IAAA,OAAO,KAAK,IAAK,CAAA,SAAA,CAAA;AAAA,GACnB;AAAA,EAEA,MAAM,gBAAmB,GAAA;AACvB,IAAA,OAAO,KAAK,IAAK,CAAA,MAAA,CAAA;AAAA,GACnB;AAAA,EAEA,MAAM,mBAAoB,OAGR,EAAA;AAChB,IAAM,MAAA,IAAA,CAAK,gBAAiB,CAAA,kBAAA,CAAmB,OAAO,CAAA,CAAA;AAAA,GACxD;AAAA,EAEA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,IAAK,CAAA,MAAA,CAAA;AAAA,GACd;AAAA,EAEA,MAAM,OAAQ,CAAA,OAAA,EAAiB,WAAyC,EAAA;AACtE,IAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,MAC9B,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,IAAM,EAAA,EAAE,OAAS,EAAA,GAAG,WAAY,EAAA;AAAA,KACjC,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,YAKJ,GAAA;AACA,IAAO,OAAA,IAAA,CAAK,QAAQ,YAAe,GAAA,EAAE,QAAQ,IAAK,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,GACjE;AAAA,EAEA,MAAM,iBACJ,OAWe,EAAA;AACf,IAAA,MAAM,EAAE,GAAA,EAAK,GAAG,KAAA,EAAU,GAAA,OAAA,CAAA;AAC1B,IAAI,IAAA,IAAA,CAAK,KAAK,KAAO,EAAA;AACnB,MAAC,IAAK,CAAA,IAAA,CAAK,KAAoB,CAAA,WAAA,CAAY,GAAG,CAAI,GAAA,KAAA,CAAA;AAAA,KAC7C,MAAA;AACL,MAAK,IAAA,CAAA,IAAA,CAAK,QAAQ,EAAE,WAAA,EAAa,EAAE,CAAC,GAAG,GAAG,KAAA,EAAQ,EAAA,CAAA;AAAA,KACpD;AACA,IAAM,MAAA,IAAA,CAAK,QAAQ,aAAgB,GAAA;AAAA,MACjC,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,KAAA,EAAO,KAAK,IAAK,CAAA,KAAA;AAAA,KAClB,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,mBAAoB,OAA0C,EAAA;AAClE,IAAM,MAAA,IAAA,CAAK,gBAAiB,CAAA,kBAAA,CAAmB,OAAO,CAAA,CAAA;AAAA,GACxD;AAAA,EAEA,MAAM,cAAiC,GAAA;AACrC,IAAM,MAAA,IAAA,CAAK,iBAAiB,cAAe,EAAA,CAAA;AAAA,GAC7C;AAAA,EAEA,MAAM,QACJ,CAAA,MAAA,EACA,QACe,EAAA;AACf,IAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,MAC9B,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,MAAA,EAAQ,MAAW,KAAA,QAAA,GAAW,QAAW,GAAA,WAAA;AAAA,MACzC,SAAW,EAAA;AAAA,QACT,OAAA,EAAS,8BAA8B,MAAM,CAAA,CAAA;AAAA,QAC7C,GAAG,QAAA;AAAA,OACL;AAAA,KACD,CAAA,CAAA;AACD,IAAA,IAAA,CAAK,MAAS,GAAA,IAAA,CAAA;AACd,IAAA,IAAI,KAAK,kBAAoB,EAAA;AAC3B,MAAA,YAAA,CAAa,KAAK,kBAAkB,CAAA,CAAA;AAAA,KACtC;AACA,IAAA,MAAM,iBAAoB,GAAA;AAAA,MACxB,SAAW,EAAA,yBAAA;AAAA,MACX,OAAS,EAAA,oBAAA;AAAA,MACT,KAAO,EAAA,YAAA;AAAA,MACP,QAAU,EAAA;AAAA,QACR,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,QAClB,cAAA,EAAgB,IAAK,CAAA,IAAA,CAAK,IAAK,CAAA,UAAA;AAAA,OACjC;AAAA,KACF,CAAA;AACA,IAAA,IAAI,WAAW,QAAU,EAAA;AACvB,MAAM,MAAA,IAAA,CAAK,aAAa,QAAS,CAAA;AAAA,QAC/B,GAAG,iBAAA;AAAA,QACH,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,MAAA,EAAQ,CAAC,QAAA,EAAU,KAAK,CAAA;AAAA,QACxB,OAAS,EAAA,CAAA,8BAAA,EAAiC,IAAK,CAAA,IAAA,CAAK,MAAM,CAAA,OAAA,CAAA;AAAA,OAC3D,CAAA,CAAA;AAAA,KACI,MAAA;AACL,MAAM,MAAA,IAAA,CAAK,aAAa,QAAS,CAAA;AAAA,QAC/B,GAAG,iBAAA;AAAA,QACH,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,GAAG,iBAAkB,CAAA,QAAA;AAAA,UACrB,GAAG,QAAA;AAAA,SACL;AAAA,QACA,OAAS,EAAA,CAAA,8BAAA,EAAiC,IAAK,CAAA,IAAA,CAAK,MAAM,CAAA,uBAAA,CAAA;AAAA,OAC3D,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AAAA,EAEQ,YAAe,GAAA;AACrB,IAAK,IAAA,CAAA,kBAAA,GAAqB,WAAW,YAAY;AAC/C,MAAI,IAAA;AACF,QAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,aAAc,CAAA,IAAA,CAAK,KAAK,MAAM,CAAA,CAAA;AACjD,QAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,eACX,KAAO,EAAA;AACd,QAAA,IAAA,CAAK,MAAS,GAAA,IAAA,CAAA;AAEd,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,UACV,CAAA,mBAAA,EAAsB,IAAK,CAAA,IAAA,CAAK,MAAM,CAAA,OAAA,CAAA;AAAA,UACtC,KAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,OACC,GAAI,CAAA,CAAA;AAAA,GACT;AAAA,EAEA,MAAM,uBAAyD,GAAA;AAC7D,IAAM,MAAA,OAAA,GAAU,KAAK,IAAK,CAAA,OAAA,CAAA;AAE1B,IAAI,IAAA,OAAA,IAAW,QAAQ,sBAAwB,EAAA;AAC7C,MAAO,OAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,sBAAsB,CAAA,CAAA;AAAA,KAClD;AACA,IAAI,IAAA,CAAC,KAAK,IAAM,EAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,oIAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAO,OAAA,IAAA,CAAK,KAAK,kBAAmB,EAAA,CAAA;AAAA,GACtC;AACF,CAAA;AAgCA,SAAS,KAAQ,GAAA;AACf,EAAA,IAAI,UAAU,MAAM;AAAA,GAAC,CAAA;AACrB,EAAM,MAAA,OAAA,GAAU,IAAI,OAAA,CAAc,CAAY,QAAA,KAAA;AAC5C,IAAU,OAAA,GAAA,QAAA,CAAA;AAAA,GACX,CAAA,CAAA;AACD,EAAO,OAAA,EAAE,SAAS,OAAQ,EAAA,CAAA;AAC5B,CAAA;AAEO,MAAM,iBAAwC,CAAA;AAAA,EACnD,YACmB,OACA,EAAA,MAAA,EACA,WACA,EAAA,MAAA,EACA,MACA,4BAIjB,EAAA;AATiB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,4BAAA,GAAA,4BAAA,CAAA;AAAA,GAIhB;AAAA,EAEH,MAAM,KAAK,OAE8B,EAAA;AACvC,IAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA;AACtB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,yGAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAO,OAAA,MAAM,KAAK,OAAQ,CAAA,IAAA,CAAK,EAAE,SAAW,EAAA,OAAA,EAAS,WAAW,CAAA,CAAA;AAAA,GAClE;AAAA,EAEQ,mBAAmB,KAAM,EAAA,CAAA;AAAA,EAEjC,MAAc,mBACZ,CAAA,MAAA,EACA,eACA,EAAA;AACA,IAAA,IAAI,iBAAoB,GAAA,KAAA,CAAA;AACxB,IAAM,MAAA,YAAA,GAAe,KAAK,MAAO,CAAA,EAAE,QAAQ,KAAO,EAAA,KAAA,CAAA,EAAW,CAAA,CAAE,SAAU,CAAA;AAAA,MACvE,OAAO,CAAK,CAAA,KAAA;AACV,QAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AAAA,OAC3B;AAAA,MACA,IAAM,EAAA,CAAC,EAAE,MAAA,EAAa,KAAA;AACpB,QAAA,KAAA,MAAW,SAAS,MAAQ,EAAA;AAC1B,UAAI,IAAA,KAAA,CAAM,SAAS,WAAa,EAAA;AAC9B,YAAA,eAAA,CAAgB,KAAM,EAAA,CAAA;AACtB,YAAoB,iBAAA,GAAA,IAAA,CAAA;AAAA,WACtB;AAEA,UAAI,IAAA,KAAA,CAAM,SAAS,YAAc,EAAA;AAC/B,YAAoB,iBAAA,GAAA,IAAA,CAAA;AAAA,WACtB;AAAA,SACF;AACA,QAAA,IAAI,iBAAmB,EAAA;AACrB,UAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AAAA,SAC3B;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAa,YAA8B,GAAA;AACzC,IAAA,MAAM,OACJ,GAAA,IAAA,CAAK,MAAQ,EAAA,kBAAA,CAAmB,sCAAsC,CACtE,IAAA,KAAA,CAAA;AAEF,IAAA,IAAI,OAAS,EAAA;AACX,MAAM,MAAA,cAAA,GAAiB,EAAE,OAAA,EAAS,EAAG,EAAA,CAAA;AACrC,MAAA,MAAM,OAAU,GAAAD,cAAA;AAAA,QACd,IAAK,CAAA,MAAA;AAAA,QACL,6CAAA;AAAA,QACA,cAAA;AAAA,OACF,CAAA;AACA,MAAA,MAAM,EAAE,GAAK,EAAA,gBAAA,KAAsB,MAAM,IAAA,CAAK,QAAQ,YAAe,GAAA;AAAA,QACnE,OAAA;AAAA,OACD,CAAA,IAAM,EAAE,GAAA,EAAK,EAAG,EAAA,CAAA;AACjB,MAAI,IAAA,gBAAA,CAAiB,SAAS,CAAG,EAAA;AAC/B,QAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AAAA,OACtB;AAAA,KACF;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAA8B,GAAA;AAClC,IAAS,WAAA;AACP,MAAA,MAAM,WAAc,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAU,EAAA,CAAA;AACjD,MAAA,IAAI,WAAa,EAAA;AACf,QAAM,MAAA,eAAA,GAAkB,IAAI,eAAgB,EAAA,CAAA;AAC5C,QAAA,MAAM,IAAK,CAAA,mBAAA,CAAoB,WAAY,CAAA,EAAA,EAAI,eAAe,CAAA,CAAA;AAC9D,QAAA,OAAO,WAAY,CAAA,MAAA;AAAA,UACjB;AAAA,YACE,QAAQ,WAAY,CAAA,EAAA;AAAA,YACpB,MAAM,WAAY,CAAA,IAAA;AAAA,YAClB,SAAS,WAAY,CAAA,OAAA;AAAA,YACrB,WAAW,WAAY,CAAA,SAAA;AAAA,YACvB,OAAO,WAAY,CAAA,KAAA;AAAA,WACrB;AAAA,UACA,IAAK,CAAA,OAAA;AAAA,UACL,eAAgB,CAAA,MAAA;AAAA,UAChB,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA,WAAA;AAAA,UACL,IAAK,CAAA,IAAA;AAAA,UACL,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA,4BAAA;AAAA,SACP,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,KAAK,eAAgB,EAAA,CAAA;AAAA,KAC7B;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,OAC6B,EAAA;AAC7B,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,WAAW,OAAO,CAAA,CAAA;AACrD,IAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AACpB,IAAO,OAAA;AAAA,MACL,QAAQ,OAAQ,CAAA,MAAA;AAAA,KAClB,CAAA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,MAAyC,EAAA;AACjD,IAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AAAA,GACpC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAG2C,EAAA;AAChD,IAAO,OAAA,IAAIG,gCAAe,CAAY,QAAA,KAAA;AACpC,MAAM,MAAA,EAAE,QAAW,GAAA,OAAA,CAAA;AAEnB,MAAA,IAAI,QAAQ,OAAQ,CAAA,KAAA,CAAA;AACpB,MAAA,IAAI,SAAY,GAAA,KAAA,CAAA;AAEhB,MAAA,CAAC,YAAY;AACX,QAAA,OAAO,CAAC,SAAW,EAAA;AACjB,UAAM,MAAA,MAAA,GAAS,MAAM,IAAK,CAAA,OAAA,CAAQ,WAAW,EAAE,MAAA,EAAQ,OAAO,CAAA,CAAA;AAC9D,UAAM,MAAA,EAAE,QAAW,GAAA,MAAA,CAAA;AACnB,UAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,YAAA,KAAA,GAAQ,MAAO,CAAA,MAAA,CAAO,MAAS,GAAA,CAAC,CAAE,CAAA,EAAA,CAAA;AAClC,YAAA,QAAA,CAAS,KAAK,MAAM,CAAA,CAAA;AAAA,WACtB;AAEA,UAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAI,CAAC,CAAA,CAAA;AAAA,SACxD;AAAA,OACC,GAAA,CAAA;AAEH,MAAA,OAAO,MAAM;AACX,QAAY,SAAA,GAAA,IAAA,CAAA;AAAA,OACd,CAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,OAA8C,EAAA;AAC9D,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAK,CAAA,OAAA,CAAQ,eAAe,OAAO,CAAA,CAAA;AAC3D,IAAA,MAAM,OAAQ,CAAA,GAAA;AAAA,MACZ,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AACtB,QAAI,IAAA;AACF,UAAA,IAAA,CAAK,YAAY,QAAS,CAAA;AAAA,YACxB,OAAS,EAAA,oBAAA;AAAA,YACT,SAAW,EAAA,iCAAA;AAAA,YACX,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,WAAA;AAAA,YACR,QAAU,EAAA;AAAA,cACR,QAAQ,IAAK,CAAA,MAAA;AAAA,aACf;AAAA,YACA,OAAA,EAAS,CAA+C,4CAAA,EAAA,IAAA,CAAK,MAAM,CAAA,2DAAA,CAAA;AAAA,WACpE,CAAA,CAAA;AACD,UAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,YAC9B,QAAQ,IAAK,CAAA,MAAA;AAAA,YACb,MAAQ,EAAA,QAAA;AAAA,YACR,SAAW,EAAA;AAAA,cACT,OACE,EAAA,mFAAA;AAAA,aACJ;AAAA,WACD,CAAA,CAAA;AACD,UAAA,IAAA,CAAK,YAAY,QAAS,CAAA;AAAA,YACxB,OAAS,EAAA,oBAAA;AAAA,YACT,SAAW,EAAA,iCAAA;AAAA,YACX,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,WAAA;AAAA,YACR,QAAU,EAAA;AAAA,cACR,QAAQ,IAAK,CAAA,MAAA;AAAA,aACf;AAAA,YACA,OAAA,EAAS,CAA0B,uBAAA,EAAA,IAAA,CAAK,MAAM,CAAA,uBAAA,CAAA;AAAA,WAC/C,CAAA,CAAA;AAAA,iBACM,KAAO,EAAA;AACd,UAAA,IAAA,CAAK,YAAY,QAAS,CAAA;AAAA,YACxB,OAAS,EAAA,oBAAA;AAAA,YACT,SAAW,EAAA,iCAAA;AAAA,YACX,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,QAAA;AAAA,YACR,KAAO,EAAA,OAAA;AAAA,YACP,QAAU,EAAA;AAAA,cACR,QAAQ,IAAK,CAAA,MAAA;AAAA,aACf;AAAA,YACA,MAAQ,EAAA;AAAA,cACN;AAAA,gBACE,MAAM,KAAM,CAAA,IAAA;AAAA,gBACZ,SAAS,KAAM,CAAA,OAAA;AAAA,gBACf,OAAO,KAAM,CAAA,KAAA;AAAA,eACf;AAAA,aACF;AAAA,YACA,OAAA,EAAS,CAA2C,wCAAA,EAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,WAChE,CAAA,CAAA;AAAA,SACH;AAAA,OACD,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AAAA,EAEQ,eAAkB,GAAA;AACxB,IAAA,OAAO,KAAK,gBAAiB,CAAA,OAAA,CAAA;AAAA,GAC/B;AAAA,EAEQ,cAAiB,GAAA;AACvB,IAAA,IAAA,CAAK,iBAAiB,OAAQ,EAAA,CAAA;AAC9B,IAAA,IAAA,CAAK,mBAAmB,KAAM,EAAA,CAAA;AAAA,GAChC;AAAA,EAEA,MAAM,OAAO,MAAgB,EAAA;AAC3B,IAAM,MAAA,EAAE,QAAW,GAAA,MAAM,KAAK,OAAQ,CAAA,UAAA,CAAW,EAAE,MAAA,EAAQ,CAAA,CAAA;AAC3D,IAAM,MAAA,aAAA,GACJ,MAAO,CAAA,MAAA,GAAS,CACZ,GAAA,MAAA,CACG,OAAO,CAAC,EAAE,IAAK,EAAA,KAAM,IAAM,EAAA,MAAM,EACjC,MAAO,CAAA,CAAC,IAAM,EAAA,IAAA,KAAU,IAAK,CAAA,EAAA,GAAK,IAAK,CAAA,EAAA,GAAK,IAAO,GAAA,IAAK,CAAE,CAAA,IAAA,CAC1D,MACH,GAAA,CAAA,CAAA;AAEN,IAAM,MAAA,IAAA,CAAK,QAAQ,UAAa,GAAA;AAAA,MAC9B,MAAA;AAAA,MACA,IAAM,EAAA;AAAA,QACJ,OAAA,EAAS,QAAQ,aAAa,CAAA,oBAAA,CAAA;AAAA,QAC9B,MAAQ,EAAA,aAAA;AAAA,QACR,MAAQ,EAAA,WAAA;AAAA,OACV;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF;;ACzgBO,SAAS,oBACd,MACY,EAAA;AACZ,EAAA,IAAI,MAAS,GAAAC,mBAAA,CAAS,eAAgB,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AACjD,EAAA,IAAI,CAAC,MAAQ,EAAA;AACX,IAAS,MAAA,GAAA,IAAIC,mBAAW,MAAM,CAAA,CAAA;AAC9B,IAAAD,mBAAA,CAAS,eAAe,MAAM,CAAA,CAAA;AAAA,GAChC;AACA,EAAO,OAAA,MAAA,CAAA;AACT,CAAA;AAyBO,SAAS,sBACd,MACc,EAAA;AACd,EAAA,IAAI,MAAS,GAAAA,mBAAA,CAAS,eAAgB,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AACjD,EAAA,IAAI,CAAC,MAAQ,EAAA;AACX,IAAS,MAAA,GAAA,IAAIE,qBAAa,MAAM,CAAA,CAAA;AAChC,IAAAF,mBAAA,CAAS,eAAe,MAAM,CAAA,CAAA;AAAA,GAChC;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;ACzCO,MAAM,+BAA+BG,6CAI1C,EAAA,CAAA;AAEK,MAAM,SAAS,4BAA6B,CAAA;AAAA,EACjD,IAAM,EAAA,SAAA;AAAA,EACN,YAAc,EAAAC,yCAAA;AAAA,EACd,WAAa,EAAA,CAAA,4CAAA,CAAA;AAAA,EACb,YAAA,EAAcxD,MAAE,MAAO,CAAA;AAAA,IACrB,GAAK,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,SAAS,6BAA6B,CAAA;AAAA,GACvD,CAAA;AAAA,EACD,KAAO,EAAA,CAAC,QAAU,EAAA,EAAE,KAAU,KAAA;AAC5B,IAAA,OAAO,SAAS,uBAAuB,CAAA,EAAG,IAAM,EAAA,QAAA,CAAS,GAAG,CAAK,IAAA,KAAA,CAAA;AAAA,GACnE;AAAA,EACA,OAAA,EAAS,OAAO,EAAC,CAAA;AACnB,CAAC,CAAA,CAAA;AAEM,MAAM,6BAA6BuD,6CAOxC,EAAA,CAAA;AAEK,MAAM,cAAc,0BAA2B,CAAA;AAAA,EACpD,IAAM,EAAA,eAAA;AAAA,EACN,YAAc,EAAAE,uCAAA;AAAA,EACd,WAAa,EAAA,CAAA,qCAAA,CAAA;AAAA,EACb,YAAA,EAAczD,MAAE,MAAO,CAAA;AAAA,IACrB,QAAU,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,SAAS,kCAAkC,CAAA;AAAA,GACjE,CAAA;AAAA,EACD,KAAO,EAAA,CAAC,QAAU,EAAA,EAAE,UAAe,KAAA;AACjC,IAAA,OAAO,SAAS,MAAW,KAAA,QAAA,CAAA;AAAA,GAC7B;AAAA,EACA,OAAA,EAAS,OAAO,EAAC,CAAA;AACnB,CAAC,CAAA,CAAA;AAE0B,gBAAiB,CAAA;AAAA,EAC1C,IAAM,EAAA,cAAA;AAAA,EACN,aAAaA,KAAE,CAAA,KAAA,CAAM,CAACA,KAAA,CAAE,QAAU,EAAAA,KAAA,CAAE,MAAO,EAAA,EAAGA,MAAE,OAAQ,EAAA,EAAGA,KAAE,CAAA,IAAA,EAAM,CAAC,CAAA;AAAA,EACpE,gBAAkB,EAAA,KAAA;AACpB,CAAC,EAAA;AAEM,MAAM,qBAAqB,gBAAiB,CAAA;AAAA,EACjD,IAAM,EAAA,sBAAA;AAAA,EACN,WAAA,EAAaA,MAAE,OAAQ,EAAA;AACzB,CAAC,CAAA,CAAA;AACM,MAAM,oBAAoB,gBAAiB,CAAA;AAAA,EAChD,IAAM,EAAA,qBAAA;AAAA,EACN,WAAA,EAAaA,MAAE,MAAO,EAAA;AACxB,CAAC,CAAA,CAAA;AACM,MAAM,oBAAoB,gBAAiB,CAAA;AAAA,EAChD,IAAM,EAAA,qBAAA;AAAA,EACN,WAAA,EAAaA,MAAE,MAAO,EAAA;AACxB,CAAC,CAAA,CAAA;AAED,SAAS,gBAA0D,CAAA;AAAA,EACjE,IAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAmB,GAAA,IAAA;AACrB,CAIG,EAAA;AACD,EAAA,OAAO,0BAA2B,CAAA;AAAA,IAChC,IAAA;AAAA,IACA,WAAa,EAAA,CAAA,yCAAA,CAAA;AAAA,IACb,YAAc,EAAAyD,uCAAA;AAAA,IACd,YAAA,EAAczD,MAAE,MAAO,CAAA;AAAA,MACrB,GAAK,EAAAA,KAAA,CACF,MAAO,EAAA,CACP,SAAS,CAAmD,iDAAA,CAAA,CAAA;AAAA,MAC/D,KAAO,EAAA,WAAA,CACJ,QAAS,EAAA,CACT,SAAS,CAAyC,uCAAA,CAAA,CAAA;AAAA,KACtD,CAAA;AAAA,IACD,OAAO,CAAC,QAAA,EAAU,EAAE,GAAA,EAAK,OAAY,KAAA;AACnC,MAAA,MAAM,UAAa,GAAAc,UAAA,CAAI,QAAS,CAAA,KAAA,EAAO,GAAG,CAAA,CAAA;AAE1C,MAAA,IAAI,oBAAoB,CAAC,WAAA,CAAY,SAAU,CAAA,UAAU,EAAE,OAAS,EAAA;AAClE,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AACA,MAAA,IAAI,UAAU,KAAW,CAAA,EAAA;AACvB,QAAA,IAAI,WAAY,CAAA,SAAA,CAAU,KAAK,CAAA,CAAE,OAAS,EAAA;AACxC,UAAA,OAAO,KAAU,KAAA,UAAA,CAAA;AAAA,SACnB;AACA,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AAEA,MAAA,OAAO,UAAe,KAAA,KAAA,CAAA,CAAA;AAAA,KACxB;AAAA,IACA,OAAA,EAAS,OAAO,EAAC,CAAA;AAAA,GAClB,CAAA,CAAA;AACH,CAAA;AAEa,MAAA,uBAAA,GAA0B,EAAE,MAAO,GAAA;AACzC,MAAM,qBAAwB,GAAA;AAAA,EACnC,WAAA;AAAA,EACA,kBAAA;AAAA,EACA,iBAAA;AAAA,EACA,iBAAA;AACF;;ACzGA,MAAM,YAAA,GAAe,CAAC,IAAiB,KAAA;AACrC,EAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,sBAAA,EAAwB,MAAM,CAAA,CAAA;AACpD,CAAA,CAAA;AAWO,MAAM,iCAAiC4C,0BAAU,CAAA;AAAA,EACtD,WACmB,CAAA,eAAA,EACA,WACA,EAAA,MAAA,EACjB,IACA,EAAA;AACA,IAAA,KAAA,CAAM,IAAI,CAAA,CAAA;AALO,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AAAA,GAInB;AAAA,EAEA,GAAA,CAAI,MAAyB,QAAwB,EAAA;AACnD,IAAA,IAAI,OAAO,IAAA,KAAS,QAAY,IAAA,IAAA,KAAS,IAAM,EAAA;AAC7C,MAAS,QAAA,EAAA,CAAA;AACT,MAAA,OAAA;AAAA,KACF;AAEA,IAAM,MAAA,OAAA,GAAU,KAAKC,kBAAO,CAAA,CAAA;AAC5B,IAAM,MAAA,KAAA,GAAQ,KAAKC,gBAAK,CAAA,CAAA;AACxB,IAAM,MAAA,KAAA,GAAQ,KAAKC,gBAAK,CAAA,CAAA;AAExB,IAAA,QAAQ,KAAO;AAAA,MACb,KAAK,OAAA;AACH,QAAA,IAAA,CAAK,gBAAgB,KAAM,CAAA,MAAA,CAAO,OAAO,CAAA,EAAG,GAAG,KAAK,CAAA,CAAA;AACpD,QAAA,MAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,IAAA,CAAK,gBAAgB,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,EAAG,GAAG,KAAK,CAAA,CAAA;AACnD,QAAA,MAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,IAAA,CAAK,gBAAgB,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,EAAG,GAAG,KAAK,CAAA,CAAA;AACnD,QAAA,MAAA;AAAA,MACF,KAAK,OAAA;AACH,QAAA,IAAA,CAAK,gBAAgB,KAAM,CAAA,MAAA,CAAO,OAAO,CAAA,EAAG,GAAG,KAAK,CAAA,CAAA;AACpD,QAAA,MAAA;AAAA,MACF;AACE,QAAA,IAAA,CAAK,gBAAgB,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,EAAG,GAAG,KAAK,CAAA,CAAA;AAAA,KACvD;AAEA,IAAA,IAAA,CAAK,YAAY,OAAQ,CAAA,OAAA,EAAS,EAAE,MAAQ,EAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AACzD,IAAS,QAAA,EAAA,CAAA;AAAA,GACX;AACF,CAAA;AAEO,MAAM,aAA2C,CAAA;AAAA,EACtD,QAAA,CAAA;AAAA,EACA,cAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAO,OAA8C,EAAA;AAC1D,IAAM,MAAA,QAAA,GAAW,cAAc,QAAS,EAAA,CAAA;AAExC,IAAA,IAAI,SAASC,oBAAa,CAAA;AAAA,MACxB,OAAO,OAAQ,CAAA,KAAA;AAAA,MACf,QAAQC,cAAO,CAAA,OAAA,CAAQ,OAAQ,CAAA,MAAA,EAAQ,SAAS,MAAM,CAAA;AAAA,MACtD,UAAY,EAAA,OAAA,CAAQ,UAAc,IAAA,IAAIC,mBAAW,OAAQ,EAAA;AAAA,KAC1D,CAAA,CAAA;AAED,IAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,MAAS,MAAA,GAAA,MAAA,CAAO,KAAM,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAAA,KACpC;AAEA,IAAA,OAAO,IAAI,aAAA,CAAc,MAAQ,EAAA,QAAA,CAAS,GAAG,CAAA,CAAA;AAAA,GAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,QAGL,GAAA;AACA,IAAM,MAAA,YAAA,uBAAmB,GAAY,EAAA,CAAA;AAErC,IAAA,IAAI,gBAAuC,GAAA,KAAA,CAAA,CAAA;AAE3C,IAAO,OAAA;AAAA,MACL,MAAA,EAAQD,cAAO,CAAA,CAAC,GAA2B,KAAA;AACzC,QAAI,IAAA,CAAC,gBAAoB,IAAA,CAAC,GAAK,EAAA;AAC7B,UAAO,OAAA,GAAA,CAAA;AAAA,SACT;AAEA,QAAA,GAAA,CAAIJ,kBAAO,CAAI,GAAA,GAAA,CAAIA,kBAAO,CAAG,EAAA,OAAA,GAAU,kBAAkB,KAAK,CAAA,CAAA;AAE9D,QAAO,OAAA,GAAA,CAAA;AAAA,OACR,CAAE,EAAA;AAAA,MACH,IAAI,aAAe,EAAA;AACjB,QAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,QAAA,KAAA,MAAW,mBAAmB,aAAe,EAAA;AAI3C,UAAM,MAAA,SAAA,GAAY,gBAAgB,IAAK,EAAA,CAAA;AAIvC,UAAI,IAAA,SAAA,CAAU,UAAU,CAAG,EAAA;AACzB,YAAA,SAAA;AAAA,WACF;AACA,UAAA,IAAI,CAAC,YAAA,CAAa,GAAI,CAAA,SAAS,CAAG,EAAA;AAChC,YAAA,YAAA,CAAa,IAAI,SAAS,CAAA,CAAA;AAC1B,YAAS,KAAA,IAAA,CAAA,CAAA;AAAA,WACX;AAAA,SACF;AACA,QAAA,IAAI,QAAQ,CAAG,EAAA;AACb,UAAA,MAAM,UAAa,GAAA,KAAA,CAAM,IAAK,CAAA,YAAY,CACvC,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,YAAA,CAAa,CAAC,CAAC,CACxB,CAAA,IAAA,CAAK,GAAG,CAAA,CAAA;AACX,UAAA,gBAAA,GAAmB,IAAI,MAAA,CAAO,CAAI,CAAA,EAAA,UAAU,KAAK,GAAG,CAAA,CAAA;AAAA,SACtD;AAAA,OACF;AAAA,KACF,CAAA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WAAsB,GAAA;AAC3B,IAAM,MAAA,SAAA,GAAYI,eAAO,QAAS,EAAA,CAAA;AAElC,IAAA,OAAOA,cAAO,CAAA,OAAA;AAAA,MACZA,eAAO,SAAU,EAAA;AAAA,MACjBA,eAAO,QAAS,CAAA;AAAA,QACd,MAAQ,EAAA;AAAA,UACN,SAAW,EAAA,KAAA;AAAA,UACX,MAAQ,EAAA,MAAA;AAAA,UACR,KAAO,EAAA,MAAA;AAAA,UACP,KAAO,EAAA,MAAA;AAAA,SACT;AAAA,OACD,CAAA;AAAA,MACDA,cAAA,CAAO,MAAO,CAAA,CAAC,IAA4B,KAAA;AACzC,QAAA,MAAM,EAAE,SAAA,EAAW,MAAQ,EAAA,OAAA,EAAY,GAAA,IAAA,CAAA;AACvC,QAAM,MAAA,OAAA,GAAU,KAAKJ,kBAAO,CAAA,CAAA;AAC5B,QAAM,MAAA,KAAA,GAAQ,KAAKC,gBAAK,CAAA,CAAA;AACxB,QAAM,MAAA,MAAA,GAAS,KAAKC,gBAAK,CAAA,CAAA;AACzB,QAAA,MAAM,SAAS,MAAU,IAAA,OAAA,CAAA;AACzB,QAAA,MAAM,cAAiB,GAAA,SAAA,CAAU,QAAS,CAAA,WAAA,EAAa,SAAS,CAAA,CAAA;AAChE,QAAA,MAAM,WAAc,GAAA,SAAA,CAAU,QAAS,CAAA,QAAA,EAAU,MAAM,CAAA,CAAA;AAEvD,QAAA,MAAM,WAAc,GAAA,MAAA,CAAO,OAAQ,CAAA,MAAM,CACtC,CAAA,GAAA;AAAA,UACC,CAAC,CAAC,GAAK,EAAA,KAAK,MACV,CAAG,EAAA,SAAA,CAAU,QAAS,CAAA,OAAA,EAAS,CAAG,EAAA,GAAG,CAAE,CAAA,CAAC,IAAI,KAAK,CAAA,CAAA;AAAA,SACrD,CACC,KAAK,GAAG,CAAA,CAAA;AAEX,QAAO,OAAA,CAAA,EAAG,cAAc,CAAI,CAAA,EAAA,WAAW,IAAI,KAAK,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,CAAA;AAAA,OAC3E,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AAAA,EAEQ,WAAA,CACN,SACA,aACA,EAAA;AACA,IAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAA;AAChB,IAAA,IAAA,CAAK,cAAiB,GAAA,aAAA,CAAA;AAAA,GACxB;AAAA,EAEA,KAAA,CAAM,SAAiB,IAAyB,EAAA;AAC9C,IAAK,IAAA,CAAA,QAAA,CAAS,KAAM,CAAA,OAAA,EAAS,IAAI,CAAA,CAAA;AAAA,GACnC;AAAA,EAEA,IAAA,CAAK,SAAiB,IAAyB,EAAA;AAC7C,IAAK,IAAA,CAAA,QAAA,CAAS,IAAK,CAAA,OAAA,EAAS,IAAI,CAAA,CAAA;AAAA,GAClC;AAAA,EAEA,IAAA,CAAK,SAAiB,IAAyB,EAAA;AAC7C,IAAK,IAAA,CAAA,QAAA,CAAS,IAAK,CAAA,OAAA,EAAS,IAAI,CAAA,CAAA;AAAA,GAClC;AAAA,EAEA,KAAA,CAAM,SAAiB,IAAyB,EAAA;AAC9C,IAAK,IAAA,CAAA,QAAA,CAAS,KAAM,CAAA,OAAA,EAAS,IAAI,CAAA,CAAA;AAAA,GACnC;AAAA,EAEA,MAAM,IAAiC,EAAA;AACrC,IAAA,OAAO,IAAI,aAAc,CAAA,IAAA,CAAK,QAAS,CAAA,KAAA,CAAM,IAAI,CAAC,CAAA,CAAA;AAAA,GACpD;AAAA,EAEA,cAAc,UAA8B,EAAA;AAC1C,IAAA,IAAA,CAAK,iBAAiB,UAAU,CAAA,CAAA;AAAA,GAClC;AACF;;ACnIA,MAAM,eAAA,GAAkB,CAAC,QAAoD,KAAA;AAC3E,EAAA,OAAO,SAAS,UAAe,KAAA,iCAAA,CAAA;AACjC,CAAA,CAAA;AAEA,MAAM,mBAAmB,CAAC;AAAA,EACxB,IAAA;AAAA,EACA,IAAA;AAAA,EACA,UAAA;AACF,CAIM,KAAA;AACJ,EAAM,MAAA,UAAA,GAAa,cAAc,MAAO,CAAA;AAAA,IACtC,KAAA,EAAO,OAAQ,CAAA,GAAA,CAAI,SAAa,IAAA,MAAA;AAAA,IAChC,MAAA,EAAQI,mBAAQ,MAAO,CAAA,OAAA;AAAA,MACrBA,kBAAA,CAAQ,OAAO,QAAS,EAAA;AAAA,MACxBA,kBAAA,CAAQ,OAAO,MAAO,EAAA;AAAA,KACxB;AAAA,IACA,UAAA,EAAY,CAAC,IAAI,wBAAA,CAAyB,YAAY,IAAM,EAAA,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,GACrE,CAAA,CAAA;AAED,EAAA,UAAA,CAAW,cAAc,MAAO,CAAA,MAAA,CAAO,KAAK,OAAW,IAAA,EAAE,CAAC,CAAA,CAAA;AAS1D,EAAM,MAAA,YAAA,GAAe,IAAIC,kBAAY,EAAA,CAAA;AACrC,EAAa,YAAA,CAAA,EAAA,CAAG,MAAQ,EAAA,OAAM,IAAQ,KAAA;AACpC,IAAA,MAAM,OAAU,GAAA,IAAA,CAAK,QAAS,EAAA,CAAE,IAAK,EAAA,CAAA;AACrC,IAAI,IAAA,OAAA,EAAS,SAAS,CAAG,EAAA;AACvB,MAAA,UAAA,CAAW,KAAK,OAAO,CAAA,CAAA;AAAA,KACzB;AAAA,GACD,CAAA,CAAA;AAED,EAAO,OAAA,EAAE,YAAY,YAAa,EAAA,CAAA;AACpC,CAAA,CAAA;AAEA,MAAM,kBAAqB,GAAAC,8CAAA;AAAA,EACzB,MAAA,CAAO,OAAO,qBAAqB,CAAA;AACrC,CAAA,CAAA;AAEO,MAAM,sBAAiD,CAAA;AAAA,EAI5D,YAA6B,OAAwC,EAAA;AAAxC,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,yBAAyB,oBAAqB,CAAA;AAAA,MACjD,YAAA,EAAc,KAAK,OAAQ,CAAA,YAAA;AAAA,KAC5B,CAAA,CAAA;AACD,IAAA,IAAA,CAAK,OAAU,GAAA,kBAAA,CAAmB,IAAK,CAAA,OAAA,CAAQ,WAAW,CAAA,CAAA;AAAA,GAC5D;AAAA,EARiB,sBAAA,CAAA;AAAA,EACA,OAAA,CAAA;AAAA,EAST,uBAAuB,KAAe,EAAA;AAC5C,IAAM,MAAA,EAAE,MAAQ,EAAA,KAAA,EAAU,GAAAC,yBAAA,CAAA;AAW1B,IAAA,MAAM,SAAS,MAAO,CAAA,KAAA;AAAA,MACpB,KAAA;AAAA,MACA,EAAC;AAAA,MACD;AAAA,QACE,UAAY,EAAA,KAAA;AAAA,QACZ,IAAM,EAAA;AAAA,UACJ,aAAe,EAAA,KAAA;AAAA,UACf,WAAa,EAAA,IAAA;AAAA,SACf;AAAA,OACF;AAAA,KACF,CAAA;AAEA,IAAA,OACE,MAAO,CAAA,QAAA,CAAS,MAAW,KAAA,CAAA,IAC3B,EAAE,MAAA,CAAO,QAAS,CAAA,CAAC,CAAG,EAAA,QAAA,GAAW,CAAC,CAAA,YAAa,KAAM,CAAA,YAAA,CAAA,CAAA;AAAA,GAEzD;AAAA,EAEQ,MAAA,CACN,KACA,EAAA,OAAA,EACA,cACG,EAAA;AACH,IAAO,OAAA,IAAA,CAAK,MAAM,IAAK,CAAA,SAAA,CAAU,KAAK,CAAG,EAAA,CAAC,MAAM,KAAU,KAAA;AACxD,MAAI,IAAA;AACF,QAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC7B,UAAI,IAAA;AACF,YAAI,IAAA,IAAA,CAAK,sBAAuB,CAAA,KAAK,CAAG,EAAA;AAEtC,cAAA,MAAM,gBAAgB,KAAM,CAAA,OAAA;AAAA,gBAC1B,aAAA;AAAA,gBACA,sBAAA;AAAA,eACF,CAAA;AAGA,cAAMC,MAAAA,UAAAA,GAAY,cAAe,CAAA,aAAA,EAAe,OAAO,CAAA,CAAA;AAGvD,cAAA,IAAIA,eAAc,EAAI,EAAA;AACpB,gBAAO,OAAA,KAAA,CAAA,CAAA;AAAA,eACT;AAGA,cAAO,OAAA,IAAA,CAAK,MAAMA,UAAS,CAAA,CAAA;AAAA,aAC7B;AAAA,mBACO,EAAI,EAAA;AACX,YAAA,IAAA,CAAK,QAAQ,MAAO,CAAA,KAAA;AAAA,cAClB,CAAoC,iCAAA,EAAA,KAAK,CAAe,YAAA,EAAA,EAAA,CAAG,OAAO,CAAA,CAAA;AAAA,aACpE,CAAA;AAAA,WACF;AAGA,UAAM,MAAA,SAAA,GAAY,cAAe,CAAA,KAAA,EAAO,OAAO,CAAA,CAAA;AAE/C,UAAA,IAAI,cAAc,EAAI,EAAA;AACpB,YAAO,OAAA,KAAA,CAAA,CAAA;AAAA,WACT;AAEA,UAAO,OAAA,SAAA,CAAA;AAAA,SACT;AAAA,OACM,CAAA,MAAA;AACN,QAAO,OAAA,KAAA,CAAA;AAAA,OACT;AACA,MAAO,OAAA,KAAA,CAAA;AAAA,KACR,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,YACJ,IACA,EAAA,IAAA,EACA,SACA,cACA,EAAA,SAAA,EACA,eACA,QACA,EAAA;AACA,IAAA,MAAM,YAAY,MAAM,IAAA,CAAK,OAAQ,CAAA,SAAA,CAAU,MAAM,IAAI,CAAA,CAAA;AAEzD,IAAI,IAAA,IAAA,CAAK,aAAa,OAAS,EAAA;AAC7B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,KAAA,EAAQ,KAAK,EAAE,CAAA,EAAA,EAAK,KAAK,IAAI,CAAA,UAAA,EAAa,KAAK,MAAM,CAAA,oBAAA,CAAA;AAAA,OACvD,CAAA;AAAA,KACF;AAEA,IAAI,IAAA;AACF,MAAA,MAAM,SACJ,IAAK,CAAA,OAAA,CAAQ,cAAe,CAAA,GAAA,CAAI,KAAK,MAAM,CAAA,CAAA;AAC7C,MAAA,MAAM,EAAE,UAAA,EAAY,YAAa,EAAA,GAAI,gBAAiB,CAAA;AAAA,QACpD,IAAA;AAAA,QACA,IAAA;AAAA,QACA,UAAA,EAAY,KAAK,OAAQ,CAAA,MAAA;AAAA,OAC1B,CAAA,CAAA;AAED,MAAA,MAAM,kBAAkB,MAAO,CAAA,WAAA;AAAA,QAC7B,MAAO,CAAA,OAAA,CAAQ,IAAK,CAAA,OAAA,IAAW,EAAE,CAAA,CAAE,GAAI,CAAA,CAAA,MAAA,KAAU,CAAC,MAAA,CAAO,CAAC,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,OACrE,CAAA;AACA,MAAM,MAAA,UAAA,GAAA,CACH,IAAK,CAAA,KAAA,IACJ,IAAK,CAAA,MAAA;AAAA,QACH,IAAK,CAAA,KAAA;AAAA,QACL;AAAA,UACE,GAAG,OAAA;AAAA,UACH,OAAS,EAAA,eAAA;AAAA,SACX;AAAA,QACA,cAAA;AAAA,YAEJ,EAAC,CAAA;AACH,MAAA,MAAM,uBAA0B,GAAA;AAAA,QAC9B,WAAa,EAAA,IAAA,CAAK,IAAK,CAAA,YAAA,EAAc,SAAa,IAAA,EAAA;AAAA,QAClD,QAAQ,IAAK,CAAA,MAAA;AAAA,QACb,QAAQ,IAAK,CAAA,EAAA;AAAA,QACb,UAAU,IAAK,CAAA,IAAA;AAAA,QACf,YAAY,IAAK,CAAA,MAAA;AAAA,QACjB,UAAA;AAAA,QACA,iBAAiB,IAAK,CAAA,EAAA;AAAA,QACtB,UAAU,IAAK,CAAA,IAAA;AAAA,QACf,QAAA,EAAU,KAAK,QAAY,IAAA,KAAA;AAAA,OAC7B,CAAA;AACA,MAAA,IAAI,KAAK,EAAI,EAAA;AACX,QAAA,MAAM,WAAW,IAAK,CAAA,MAAA,CAAO,IAAK,CAAA,EAAA,EAAI,SAAS,cAAc,CAAA,CAAA;AAC7D,QAAI,IAAA,CAAC,QAAS,CAAA,QAAQ,CAAG,EAAA;AACvB,UAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,UAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,WAAA,CAAY,QAAS,CAAA;AAAA,YACtC,SAAW,EAAA,wBAAA;AAAA,YACX,OAAS,EAAA,oBAAA;AAAA,YACT,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,WAAA;AAAA,YACR,QAAU,EAAA,uBAAA;AAAA,YACV,OAAA,EAAS,gBAAgB,IAAK,CAAA,IAAI,SAAS,IAAK,CAAA,EAAE,CAAa,UAAA,EAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,WAC3E,CAAA,CAAA;AACD,UAAA,OAAA;AAAA,SACF;AAAA,OACF;AAEA,MAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,WAAA,CAAY,QAAS,CAAA;AAAA,QACtC,OAAS,EAAA,oBAAA;AAAA,QACT,SAAW,EAAA,6BAAA;AAAA,QACX,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA,uBAAA;AAAA,QACV,OAAS,EAAA,CAAA,QAAA,EAAW,IAAK,CAAA,IAAI,CAAS,MAAA,EAAA,IAAA,CAAK,EAAE,CAAA,UAAA,EAAa,IAAK,CAAA,MAAM,CAAmB,gBAAA,EAAA,IAAA,CAAK,MAAM,CAAA,OAAA,CAAA;AAAA,OACpG,CAAA,CAAA;AAED,MAAA,IAAI,KAAK,QAAU,EAAA;AACjB,QAAW,UAAA,CAAA,IAAA;AAAA,UACT,CACE,QAAA,EAAA,MAAA,CAAO,EACT,CAAA,iDAAA,EAAoD,IAAK,CAAA,SAAA;AAAA,YACvD,UAAA;AAAA,YACA,KAAA,CAAA;AAAA,YACA,CAAA;AAAA,WACD,CAAA,CAAA;AAAA,SACH,CAAA;AACA,QAAI,IAAA,CAAC,OAAO,cAAgB,EAAA;AAC1B,UAAM,MAAA,SAAA,CAAU,UAAW,CAAA,IAAA,EAAM,MAAM,CAAA,CAAA;AACvC,UAAM,MAAA,YAAA,GAAe,OAAO,MAAQ,EAAA,MAAA,CAAA;AACpC,UAAA,IAAI,YAAc,EAAA;AAChB,YAAQ,OAAA,CAAA,KAAA,CAAM,IAAK,CAAA,EAAE,CAAI,GAAA;AAAA,cACvB,MAAA,EAAQ,sBAAsB,YAAY,CAAA;AAAA,aAG5C,CAAA;AAAA,WACK,MAAA;AACL,YAAA,OAAA,CAAQ,MAAM,IAAK,CAAA,EAAE,IAAI,EAAE,MAAA,EAAQ,EAAG,EAAA,CAAA;AAAA,WACxC;AACA,UAAA,OAAA;AAAA,SACF;AAAA,OACF;AACA,MAAA,MAAM,UACJ,GAAA,CAAA,IAAA,CAAK,IACD,GAAA,MAAA,CAAO,OAAQ,CAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,IAAM,EAAA,OAAA,EAAS,cAAc,CAAC,CAAE,CAAA,GAAA;AAAA,QAC9D,CAAC,CAAC,GAAK,EAAA,KAAK,CAAO,MAAA;AAAA,UACjB,IAAA,EAAM,EAAE,GAAA,EAAK,KAAM,EAAA;AAAA,SACrB,CAAA;AAAA,UAEF,CAAC,EAAE,CAAA,EACP,IAAI,CAAM,CAAA,MAAA;AAAA,QACV,GAAG,CAAA;AAAA;AAAA,QAEH,KAAA,EAAO,IAAK,CAAA,KAAA,GACR,IAAK,CAAA,MAAA;AAAA,UACH,IAAK,CAAA,KAAA;AAAA,UACL,EAAE,GAAG,OAAS,EAAA,OAAA,EAAS,KAAK,OAAW,IAAA,EAAI,EAAA,GAAG,CAAE,EAAA;AAAA,UAChD,cAAA;AAAA,YAEF,EAAC;AAAA,OACL,CAAA,CAAA,CAAA;AACF,MAAA,KAAA,MAAW,aAAa,UAAY,EAAA;AAClC,QAAA,MAAM,QAAW,GAAA,CAAA,EAAG,MAAO,CAAA,EAAE,CAC3B,EAAA,SAAA,CAAU,IAAO,GAAA,CAAA,CAAA,EAAI,SAAU,CAAA,IAAA,CAAK,GAAG,CAAA,CAAA,CAAA,GAAM,EAC/C,CAAA,CAAA,CAAA;AAEA,QAAI,IAAA,MAAA,CAAO,QAAQ,KAAO,EAAA;AACxB,UAAA,MAAM,cAAiB,GAAAC,mBAAA;AAAA,YACrB,SAAU,CAAA,KAAA;AAAA,YACV,OAAO,MAAO,CAAA,KAAA;AAAA,WAChB,CAAA;AACA,UAAI,IAAA,CAAC,eAAe,KAAO,EAAA;AACzB,YAAA,MAAMC,QAAS,GAAA,cAAA,CAAe,MAAO,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAC9C,YAAA,MAAM,IAAIzE,iBAAA;AAAA,cACR,CAAA,+BAAA,EAAkC,QAAQ,CAAA,EAAA,EAAKyE,QAAM,CAAA,CAAA;AAAA,aACvD,CAAA;AAAA,WACF;AAAA,SACF;AACA,QACE,IAAA,CAAC,mBAAmB,QAAU,EAAA;AAAA,UAC5B,QAAQ,MAAO,CAAA,EAAA;AAAA,UACf,OAAO,SAAU,CAAA,KAAA;AAAA,SAClB,CACD,EAAA;AACA,UAAA,MAAM,IAAIC,sBAAA;AAAA,YACR,CAAA,qBAAA,EAAwB,QAAQ,CAAA,oCAAA,EAAuC,IAAK,CAAA,SAAA;AAAA,cAC1E,SAAU,CAAA,KAAA;AAAA,cACV,IAAA;AAAA,cACA,CAAA;AAAA,aACD,CAAA,CAAA;AAAA,WACH,CAAA;AAAA,SACF;AAAA,OACF;AACA,MAAM,MAAA,OAAA,GAAU,IAAI,KAAc,EAAA,CAAA;AAClC,MAAA,MAAM,aAAkD,EAAC,CAAA;AACzD,MAAM,MAAA,aAAA,GAAgB,MAAM,IAAA,CAAK,YAAe,IAAA,CAAA;AAChD,MAAA,IAAI,cAAyB,GAAA,CAAA,CAAA;AAC7B,MAAA,KAAA,MAAW,aAAa,UAAY,EAAA;AAClC,QAAA,IAAI,UAAU,IAAM,EAAA;AAClB,UAAW,UAAA,CAAA,IAAA;AAAA,YACT,sBAAsB,IAAK,CAAA,SAAA;AAAA,cACzB,SAAU,CAAA,IAAA;AAAA,cACV,CAAC,CAAG,EAAA,CAAA,KAAO,CAAI,GAAA,CAAA,CAAE,UAAa,GAAA,CAAA;AAAA,cAC9B,CAAA;AAAA,aACD,CAAA,CAAA;AAAA,WACH,CAAA;AAEA,UAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,WAAA,CAAY,QAAS,CAAA;AAAA,YACtC,OAAS,EAAA,oBAAA;AAAA,YACT,SAAW,EAAA,6BAAA;AAAA,YACX,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,WAAA;AAAA,YACR,QAAU,EAAA;AAAA,cACR,GAAG,uBAAA;AAAA,cACH,UAAY,EAAA,KAAA,CAAA;AAAA,cACZ,YAAY,CAAG,EAAA,IAAA,CAAK,MAAM,CAAI,CAAA,EAAA,SAAA,CAAU,KAAK,GAAG,CAAA,CAAA,CAAA;AAAA,cAChD,qBAAqB,SAAU,CAAA,KAAA;AAAA,cAC/B,oBAAoB,EAAE,cAAA;AAAA,cACtB,kBAAA,EAAoB,UAAU,IAAK,CAAA,KAAA;AAAA,cACnC,iBAAiB,UAAW,CAAA,MAAA;AAAA,aAC9B;AAAA,YACA,SAAS,CAAa,UAAA,EAAA,cAAc,CAAI,CAAA,EAAA,UAAA,CAAW,MAAM,CAAc,WAAA,EAAA,IAAA,CAAK,MAAM,CAAA,SAAA,EAAY,KAAK,IAAI,CAAA,MAAA,EAAS,KAAK,EAAE,CAAA,UAAA,EAAa,KAAK,MAAM,CAAA,QAAA,CAAA;AAAA,WAChJ,CAAA,CAAA;AAAA,SACH;AAEA,QAAA,MAAM,OAAO,OAAQ,CAAA;AAAA,UACnB,OAAO,SAAU,CAAA,KAAA;AAAA,UACjB,OAAA,EAAS,IAAK,CAAA,OAAA,IAAW,EAAC;AAAA;AAAA,UAE1B,MAAA,EAAQC,oCAAsB,UAAU,CAAA;AAAA,UACxC,SAAW,EAAA,YAAA;AAAA,UACX,aAAA;AAAA,UACA,MAAM,UACJ,CAAA,SAAA,EACA,EACA,EAAA;AACA,YAAM,MAAA,GAAA,GAAM,sBAAsB,SAAS,CAAA,CAAA,CAAA;AAC3C,YAAI,IAAA;AACF,cAAI,IAAA,SAAA,CAAA;AACJ,cAAA,IAAI,aAAe,EAAA;AACjB,gBAAA,MAAM,SACJ,GAAA,aAAA,CAAc,KAAO,EAAA,WAAA,GAGnB,GAAG,CAAA,CAAA;AACP,gBAAI,IAAA,SAAA,IAAa,SAAU,CAAA,MAAA,KAAW,SAAW,EAAA;AAC/C,kBAAA,SAAA,GAAY,SAAU,CAAA,KAAA,CAAA;AAAA,iBACxB;AAAA,eACF;AAEA,cAAA,MAAM,KAAQ,GAAA,SAAA,GAAY,SAAY,GAAA,MAAM,EAAG,EAAA,CAAA;AAE/C,cAAA,IAAI,CAAC,SAAW,EAAA;AACd,gBAAA,IAAA,CAAK,gBAAmB,GAAA;AAAA,kBACtB,GAAA;AAAA,kBACA,MAAQ,EAAA,SAAA;AAAA,kBACR,KAAA;AAAA,iBACD,CAAA,CAAA;AAAA,eACH;AACA,cAAO,OAAA,KAAA,CAAA;AAAA,qBACA,GAAK,EAAA;AACZ,cAAA,IAAA,CAAK,gBAAmB,GAAA;AAAA,gBACtB,GAAA;AAAA,gBACA,MAAQ,EAAA,QAAA;AAAA,gBACR,MAAA,EAAQC,sBAAe,GAAG,CAAA;AAAA,eAC3B,CAAA,CAAA;AACD,cAAM,MAAA,GAAA,CAAA;AAAA,aACN,SAAA;AACA,cAAA,MAAM,IAAK,CAAA,kBAAA,GAAqB,EAAE,IAAA,EAAM,eAAe,CAAA,CAAA;AAAA,aACzD;AAAA,WACF;AAAA,UACA,0BAA0B,YAAY;AACpC,YAAM,MAAA,MAAA,GAAS,MAAMzE,mBAAG,CAAA,OAAA;AAAA,cACtB,CAAG,EAAA,aAAa,CAAS,MAAA,EAAA,IAAA,CAAK,EAAE,CAAA,CAAA,CAAA;AAAA,aAClC,CAAA;AACA,YAAA,OAAA,CAAQ,KAAK,MAAM,CAAA,CAAA;AACnB,YAAO,OAAA,MAAA,CAAA;AAAA,WACT;AAAA,UACA,MAAA,CAAO,MAAc,KAAkB,EAAA;AACrC,YAAA,IAAI,KAAK,IAAM,EAAA;AACb,cAAA,UAAA,CAAW,IAAI,CAAA,GAAI,UAAW,CAAA,IAAI,KAAK,EAAC,CAAA;AACxC,cAAC,UAAW,CAAA,IAAI,CAAgB,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAAA,aACrC,MAAA;AACL,cAAA,UAAA,CAAW,IAAI,CAAI,GAAA,KAAA,CAAA;AAAA,aACrB;AAAA,WACF;AAAA,UACA,YAAA,EAAc,KAAK,IAAK,CAAA,YAAA;AAAA,UACxB,IAAA,EAAM,KAAK,IAAK,CAAA,IAAA;AAAA,UAChB,UAAU,IAAK,CAAA,QAAA;AAAA,UACf,QAAQ,IAAK,CAAA,YAAA;AAAA,UACb,uBAAA,EAAyB,MAAM,IAAA,CAAK,uBAAwB,EAAA;AAAA,SAC7D,CAAA,CAAA;AACD,QAAA,IAAI,UAAU,IAAM,EAAA;AAClB,UAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,WAAA,CAAY,QAAS,CAAA;AAAA,YACtC,OAAS,EAAA,oBAAA;AAAA,YACT,SAAW,EAAA,6BAAA;AAAA,YACX,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,WAAA;AAAA,YACR,QAAU,EAAA;AAAA,cACR,GAAG,uBAAA;AAAA,cACH,UAAY,EAAA,KAAA,CAAA;AAAA,cACZ,YAAY,CAAG,EAAA,IAAA,CAAK,MAAM,CAAI,CAAA,EAAA,SAAA,CAAU,KAAK,GAAG,CAAA,CAAA,CAAA;AAAA,cAChD,kBAAoB,EAAA,cAAA;AAAA,cACpB,kBAAA,EAAoB,UAAU,IAAK,CAAA,KAAA;AAAA,cACnC,qBAAqB,SAAU,CAAA,KAAA;AAAA,cAC/B,iBAAiB,UAAW,CAAA,MAAA;AAAA,aAC9B;AAAA,YACA,SAAS,CAAa,UAAA,EAAA,cAAc,CAAI,CAAA,EAAA,UAAA,CAAW,MAAM,CAAc,WAAA,EAAA,IAAA,CAAK,MAAM,CAAA,SAAA,EAAY,KAAK,IAAI,CAAA,MAAA,EAAS,KAAK,EAAE,CAAA,UAAA,EAAa,KAAK,MAAM,CAAA,UAAA,CAAA;AAAA,WAChJ,CAAA,CAAA;AAAA,SACH;AAAA,OACF;AAGA,MAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,QAAM,MAAAA,mBAAA,CAAG,OAAO,MAAM,CAAA,CAAA;AAAA,OACxB;AAEA,MAAA,OAAA,CAAQ,MAAM,IAAK,CAAA,EAAE,CAAI,GAAA,EAAE,QAAQ,UAAW,EAAA,CAAA;AAE9C,MAAI,IAAA,IAAA,CAAK,aAAa,OAAS,EAAA;AAC7B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,KAAA,EAAQ,KAAK,EAAE,CAAA,EAAA,EAAK,KAAK,IAAI,CAAA,UAAA,EAAa,KAAK,MAAM,CAAA,oBAAA,CAAA;AAAA,SACvD,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,UAAU,cAAe,EAAA,CAAA;AAAA,aACxB,GAAK,EAAA;AACZ,MAAM,MAAA,SAAA,CAAU,UAAW,CAAA,IAAA,EAAM,GAAG,CAAA,CAAA;AACpC,MAAM,MAAA,SAAA,CAAU,WAAW,GAAG,CAAA,CAAA;AAC9B,MAAM,MAAA,GAAA,CAAA;AAAA,KACN,SAAA;AACA,MAAA,MAAM,IAAK,CAAA,kBAAA,GAAqB,EAAE,IAAA,EAAM,eAAe,CAAA,CAAA;AAAA,KACzD;AAAA,GACF;AAAA,EAEA,MAAM,QAAQ,IAA8C,EAAA;AAC1D,IAAA,IAAI,CAAC,eAAA,CAAgB,IAAK,CAAA,IAAI,CAAG,EAAA;AAC/B,MAAA,MAAM,IAAIH,iBAAA;AAAA,QACR,0DAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAM,MAAA,MAAA,GAAS,MAAM,IAAA,CAAK,gBAAiB,EAAA,CAAA;AAE3C,IAAA,MAAM,gBAAgB6E,qBAAK,CAAA,IAAA,CAAK,IAAK,CAAA,OAAA,CAAQ,kBAAkB,MAAM,CAAA,CAAA;AAErE,IAAA,MAAM,EAAE,yBAAA,EAA2B,yBAA0B,EAAA,GAC3D,IAAK,CAAA,OAAA,CAAA;AAEP,IAAM,MAAA,cAAA,GAAiB,MAAM,eAAA,CAAgB,YAAa,CAAA;AAAA,MACxD,eAAiB,EAAA;AAAA,QACf,GAAG,IAAK,CAAA,sBAAA;AAAA,QACR,GAAG,yBAAA;AAAA,OACL;AAAA,MACA,eAAiB,EAAA,yBAAA;AAAA,KAClB,CAAA,CAAA;AAED,IAAI,IAAA;AACF,MAAA,MAAM,KAAK,kBAAqB,GAAA,EAAE,MAAQ,EAAA,UAAA,EAAY,eAAe,CAAA,CAAA;AAErE,MAAA,MAAM,SAAY,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,UAAU,IAAI,CAAA,CAAA;AACnD,MAAM,MAAA1E,mBAAA,CAAG,UAAU,aAAa,CAAA,CAAA;AAEhC,MAAA,MAAM,OAA2B,GAAA;AAAA,QAC/B,UAAA,EAAY,KAAK,IAAK,CAAA,UAAA;AAAA,QACtB,OAAO,EAAC;AAAA,QACR,IAAA,EAAM,KAAK,IAAK,CAAA,IAAA;AAAA,OAClB,CAAA;AAEA,MAAA,MAAM,CAAC,QAAQ,CACb,GAAA,IAAA,CAAK,OAAQ,CAAA,WAAA,IAAe,IAAK,CAAA,IAAA,CAAK,KAAM,CAAA,MAAA,GACxC,MAAM,IAAA,CAAK,QAAQ,WAAY,CAAA,oBAAA;AAAA,QAC7B,CAAC,EAAE,UAAY,EAAA2E,+BAAA,EAAyB,CAAA;AAAA,QACxC,EAAE,WAAA,EAAa,MAAM,IAAA,CAAK,yBAA0B,EAAA;AAAA,UAEtD,CAAC,EAAE,MAAQ,EAAAC,sCAAA,CAAgB,OAAO,CAAA,CAAA;AAExC,MAAW,KAAA,MAAA,IAAA,IAAQ,IAAK,CAAA,IAAA,CAAK,KAAO,EAAA;AAClC,QAAA,MAAM,IAAK,CAAA,WAAA;AAAA,UACT,IAAA;AAAA,UACA,IAAA;AAAA,UACA,OAAA;AAAA,UACA,cAAA;AAAA,UACA,SAAA;AAAA,UACA,aAAA;AAAA,UACA,QAAA;AAAA,SACF,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,SAAS,IAAK,CAAA,MAAA,CAAO,KAAK,IAAK,CAAA,MAAA,EAAQ,SAAS,cAAc,CAAA,CAAA;AACpE,MAAA,MAAM,UAAU,cAAe,EAAA,CAAA;AAE/B,MAAA,OAAO,EAAE,MAAO,EAAA,CAAA;AAAA,KAChB,SAAA;AACA,MAAA,IAAI,aAAe,EAAA;AACjB,QAAA,MAAM,KAAK,cAAiB,IAAA,CAAA;AAC5B,QAAM,MAAA5E,mBAAA,CAAG,OAAO,aAAa,CAAA,CAAA;AAAA,OAC/B;AAAA,KACF;AAAA,GACF;AACF,CAAA;AAEA,SAAS,mBAAmB,WAA0B,EAAA;AACpD,EAAA,MAAM,YAAY,mBAAoB,CAAA;AAAA,IACpC,IAAM,EAAA,uBAAA;AAAA,IACN,IAAM,EAAA,oBAAA;AAAA,IACN,UAAY,EAAA,CAAC,UAAY,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,GAC1C,CAAA,CAAA;AACD,EAAA,MAAM,eAAe,qBAAsB,CAAA;AAAA,IACzC,IAAM,EAAA,0BAAA;AAAA,IACN,IAAM,EAAA,wBAAA;AAAA,IACN,UAAA,EAAY,CAAC,UAAA,EAAY,QAAQ,CAAA;AAAA,GAClC,CAAA,CAAA;AACD,EAAA,MAAM,YAAY,mBAAoB,CAAA;AAAA,IACpC,IAAM,EAAA,uBAAA;AAAA,IACN,IAAM,EAAA,oBAAA;AAAA,IACN,UAAY,EAAA,CAAC,UAAY,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,GAC1C,CAAA,CAAA;AACD,EAAA,MAAM,eAAe,qBAAsB,CAAA;AAAA,IACzC,IAAM,EAAA,0BAAA;AAAA,IACN,IAAM,EAAA,yBAAA;AAAA,IACN,UAAY,EAAA,CAAC,UAAY,EAAA,MAAA,EAAQ,QAAQ,CAAA;AAAA,GAC1C,CAAA,CAAA;AAED,EAAA,eAAe,UAAU,IAAmB,EAAA;AAC1C,IAAA,MAAM,KAAK,OAAQ,CAAA,CAAA,sBAAA,EAAyB,KAAK,IAAK,CAAA,KAAA,CAAM,MAAM,CAAQ,MAAA,CAAA,CAAA,CAAA;AAC1E,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,IAAK,CAAA,YAAA,EAAc,SAAa,IAAA,EAAA,CAAA;AACtD,IAAA,MAAM,IAAO,GAAA,IAAA,CAAK,IAAK,CAAA,IAAA,EAAM,GAAO,IAAA,EAAA,CAAA;AAEpC,IAAM,MAAA,SAAA,GAAY,aAAa,UAAW,CAAA;AAAA,MACxC,QAAA;AAAA,KACD,CAAA,CAAA;AAED,IAAe,eAAA,UAAA,CACb,MACA,MACA,EAAA;AACA,MAAA,IAAA,CAAK,OAAQ,CAAA,CAAA,iBAAA,EAAoB,MAAO,CAAA,EAAE,CAA6B,yBAAA,CAAA,EAAA;AAAA,QACrE,QAAQ,IAAK,CAAA,EAAA;AAAA,QACb,MAAQ,EAAA,SAAA;AAAA,OACT,CAAA,CAAA;AAAA,KACH;AAEA,IAAA,eAAe,cAAiB,GAAA;AAC9B,MAAA,SAAA,CAAU,GAAI,CAAA;AAAA,QACZ,QAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAQ,EAAA,IAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,KAC5B;AAEA,IAAe,eAAA,UAAA,CAAW,MAAgB,GAAY,EAAA;AACpD,MAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,MAAO,CAAA,GAAA,CAAI,KAAK,CAAG,EAAA;AAAA,QACpC,QAAQ,IAAK,CAAA,EAAA;AAAA,QACb,MAAQ,EAAA,QAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAA,SAAA,CAAU,GAAI,CAAA;AAAA,QACZ,QAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAQ,EAAA,QAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,QAAA,EAAU,CAAA,CAAA;AAAA,KAChC;AAEA,IAAA,eAAe,cAAc,IAAgB,EAAA;AAC3C,MAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,CAAQ,KAAA,EAAA,IAAA,CAAK,EAAE,CAAwB,oBAAA,CAAA,EAAA;AAAA,QACxD,QAAQ,IAAK,CAAA,EAAA;AAAA,QACb,MAAQ,EAAA,WAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAA,SAAA,CAAU,GAAI,CAAA;AAAA,QACZ,QAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAQ,EAAA,WAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,WAAA,EAAa,CAAA,CAAA;AAAA,KACnC;AAEA,IAAO,OAAA;AAAA,MACL,UAAA;AAAA,MACA,aAAA;AAAA,MACA,cAAA;AAAA,MACA,UAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAe,eAAA,SAAA,CAAU,MAAmB,IAAgB,EAAA;AAC1D,IAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,CAAkB,eAAA,EAAA,IAAA,CAAK,IAAI,CAAI,CAAA,EAAA;AAAA,MAChD,QAAQ,IAAK,CAAA,EAAA;AAAA,MACb,MAAQ,EAAA,YAAA;AAAA,KACT,CAAA,CAAA;AACD,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,IAAK,CAAA,YAAA,EAAc,SAAa,IAAA,EAAA,CAAA;AAEtD,IAAM,MAAA,SAAA,GAAY,aAAa,UAAW,CAAA;AAAA,MACxC,QAAA;AAAA,MACA,MAAM,IAAK,CAAA,IAAA;AAAA,KACZ,CAAA,CAAA;AAED,IAAA,eAAe,cAAiB,GAAA;AAC9B,MAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,CAAiB,cAAA,EAAA,IAAA,CAAK,IAAI,CAAI,CAAA,EAAA;AAAA,QAC/C,QAAQ,IAAK,CAAA,EAAA;AAAA,QACb,MAAQ,EAAA,WAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAA,SAAA,CAAU,GAAI,CAAA;AAAA,QACZ,QAAA;AAAA,QACA,MAAM,IAAK,CAAA,IAAA;AAAA,QACX,MAAQ,EAAA,IAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,IAAA,EAAM,CAAA,CAAA;AAC1B,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,OAAS,EAAA,oBAAA;AAAA,QACT,SAAW,EAAA,6BAAA;AAAA,QACX,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,WAAa,EAAA,QAAA;AAAA,UACb,QAAQ,IAAK,CAAA,MAAA;AAAA,UACb,QAAQ,IAAK,CAAA,EAAA;AAAA,UACb,UAAU,IAAK,CAAA,IAAA;AAAA,UACf,YAAY,IAAK,CAAA,MAAA;AAAA,UACjB,QAAA,EAAU,KAAK,QAAY,IAAA,KAAA;AAAA,SAC7B;AAAA,QACA,OAAA,EAAS,QAAQ,IAAK,CAAA,IAAI,SAAS,IAAK,CAAA,EAAE,CAAa,UAAA,EAAA,IAAA,CAAK,MAAM,CAAA,UAAA,CAAA;AAAA,OACnE,CAAA,CAAA;AAAA,KACH;AAEA,IAAA,eAAe,aAAgB,GAAA;AAC7B,MAAA,SAAA,CAAU,GAAI,CAAA;AAAA,QACZ,QAAA;AAAA,QACA,MAAM,IAAK,CAAA,IAAA;AAAA,QACX,MAAQ,EAAA,WAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,WAAA,EAAa,CAAA,CAAA;AAAA,KACnC;AAEA,IAAA,eAAe,WAAW,GAAY,EAAA;AACpC,MAAA,SAAA,CAAU,GAAI,CAAA;AAAA,QACZ,QAAA;AAAA,QACA,MAAM,IAAK,CAAA,IAAA;AAAA,QACX,MAAQ,EAAA,QAAA;AAAA,OACT,CAAA,CAAA;AACD,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,QAAA,EAAU,CAAA,CAAA;AAC9B,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,OAAS,EAAA,oBAAA;AAAA,QACT,SAAW,EAAA,6BAAA;AAAA,QACX,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,QAAU,EAAA;AAAA,UACR,WAAa,EAAA,QAAA;AAAA,UACb,QAAQ,IAAK,CAAA,MAAA;AAAA,UACb,QAAQ,IAAK,CAAA,EAAA;AAAA,UACb,UAAU,IAAK,CAAA,IAAA;AAAA,UACf,YAAY,IAAK,CAAA,MAAA;AAAA,UACjB,QAAA,EAAU,KAAK,QAAY,IAAA,KAAA;AAAA,SAC7B;AAAA,QACA,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAA,EAAS,QAAQ,IAAK,CAAA,IAAI,SAAS,IAAK,CAAA,EAAE,CAAa,UAAA,EAAA,IAAA,CAAK,MAAM,CAAA,OAAA,CAAA;AAAA,OACnE,CAAA,CAAA;AAAA,KACH;AAEA,IAAA,eAAe,SAAY,GAAA;AACzB,MAAA,MAAM,IAAK,CAAA,OAAA;AAAA,QACT,CAAA,cAAA,EAAiB,KAAK,EAAE,CAAA,mCAAA,CAAA;AAAA,QACxB,EAAE,MAAA,EAAQ,IAAK,CAAA,EAAA,EAAI,QAAQ,SAAU,EAAA;AAAA,OACvC,CAAA;AACA,MAAU,SAAA,CAAA,EAAE,MAAQ,EAAA,SAAA,EAAW,CAAA,CAAA;AAAA,KACjC;AAEA,IAAO,OAAA;AAAA,MACL,aAAA;AAAA,MACA,UAAA;AAAA,MACA,cAAA;AAAA,MACA,SAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,SAAA;AAAA,IACA,SAAA;AAAA,GACF,CAAA;AACF;;ACrrBO,MAAM,UAAW,CAAA;AAAA,EAMd,YAA6B,OAA4B,EAAA;AAA5B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA,CAAA;AACnC,IAAA,IAAA,CAAK,WAAc,GAAA,KAAA,CAAA;AACnB,IAAA,IAAA,CAAK,SAAS,OAAQ,CAAA,MAAA,CAAA;AACtB,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAC3B,IAAK,IAAA,CAAA,SAAA,GAAY,IAAI6E,uBAAO,CAAA;AAAA,MAC1B,aAAa,OAAQ,CAAA,oBAAA;AAAA,KACtB,CAAA,CAAA;AAAA,GACH;AAAA,EAZQ,SAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EACA,WAAA,CAAA;AAAA,EACA,WAAA,CAAA;AAAA,EAWR,aAAa,OAAO,OAAmD,EAAA;AACrE,IAAM,MAAA;AAAA,MACJ,UAAA;AAAA,MACA,MAAA;AAAA,MACA,cAAA;AAAA,MACA,YAAA;AAAA,MACA,gBAAA;AAAA,MACA,yBAAA;AAAA,MACA,oBAAuB,GAAA,EAAA;AAAA;AAAA,MACvB,yBAAA;AAAA,MACA,WAAA;AAAA,MACA,WAAA;AAAA,KACE,GAAA,OAAA,CAAA;AAEJ,IAAM,MAAA,cAAA,GAAiB,IAAI,sBAAuB,CAAA;AAAA,MAChD,cAAA;AAAA,MACA,YAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,gBAAA;AAAA,MACA,yBAAA;AAAA,MACA,yBAAA;AAAA,MACA,WAAA;AAAA,KACD,CAAA,CAAA;AAED,IAAA,OAAO,IAAI,UAAW,CAAA;AAAA,MACpB,UAAA;AAAA,MACA,OAAA,EAAS,EAAE,cAAe,EAAA;AAAA,MAC1B,oBAAA;AAAA,MACA,WAAA;AAAA,MACA,WAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,YAAe,GAAA;AACnB,IAAI,IAAA;AACF,MAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,UAAA,CAAW,YAAe,IAAA,CAAA;AAAA,aACtC,GAAK,EAAA;AACZ,MAAA,IAAA,CAAK,MAAQ,EAAA,KAAA,CAAMJ,qBAAe,CAAA,GAAG,CAAC,CAAA,CAAA;AAAA,KACxC;AAAA,GACF;AAAA,EAEA,KAAQ,GAAA;AACN,IAAA,CAAC,YAAY;AACX,MAAO,OAAA,CAAC,KAAK,WAAa,EAAA;AACxB,QAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAK,CAAC,CAAA,CAAA;AACvD,QAAA,MAAM,KAAK,YAAa,EAAA,CAAA;AAAA,OAC1B;AAAA,KACC,GAAA,CAAA;AACH,IAAA,CAAC,YAAY;AACX,MAAO,OAAA,CAAC,KAAK,WAAa,EAAA;AACxB,QAAA,MAAM,KAAK,kBAAmB,EAAA,CAAA;AAC9B,QAAI,IAAA,CAAC,KAAK,WAAa,EAAA;AACrB,UAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,WAAW,KAAM,EAAA,CAAA;AACjD,UAAA,KAAK,KAAK,SAAU,CAAA,GAAA,CAAI,MAAM,IAAK,CAAA,UAAA,CAAW,IAAI,CAAC,CAAA,CAAA;AAAA,SACrD;AAAA,OACF;AAAA,KACC,GAAA,CAAA;AAAA,GACL;AAAA,EAEA,IAAO,GAAA;AACL,IAAA,IAAA,CAAK,WAAc,GAAA,IAAA,CAAA;AAAA,GACrB;AAAA,EAEU,kBAAoC,GAAA;AAC5C,IAAA,IAAI,IAAK,CAAA,SAAA,CAAU,OAAU,GAAA,IAAA,CAAK,QAAQ,oBAAsB,EAAA;AAC9D,MAAA,OAAO,QAAQ,OAAQ,EAAA,CAAA;AAAA,KACzB;AACA,IAAO,OAAA,IAAI,QAAQ,CAAW,OAAA,KAAA;AAG5B,MAAK,IAAA,CAAA,SAAA,CAAU,IAAK,CAAA,MAAA,EAAQ,MAAM;AAChC,QAAQ,OAAA,EAAA,CAAA;AAAA,OACT,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,WAAW,IAAmB,EAAA;AAClC,IAAI,IAAA;AACF,MAAM,MAAA,IAAA,CAAK,aAAa,QAAS,CAAA;AAAA,QAC/B,SAAW,EAAA,yBAAA;AAAA,QACX,OAAS,EAAA,oBAAA;AAAA,QACT,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,QAAQ,IAAK,CAAA,MAAA;AAAA,UACb,cAAA,EAAgB,KAAK,IAAK,CAAA,UAAA;AAAA,UAC1B,WAAA,EAAa,IAAK,CAAA,IAAA,CAAK,YAAc,EAAA,SAAA;AAAA,SACvC;AAAA,QACA,OAAA,EAAS,CAAiC,8BAAA,EAAA,IAAA,CAAK,MAAM,CAAA,UAAA,CAAA;AAAA,OACtD,CAAA,CAAA;AACD,MAAI,IAAA,IAAA,CAAK,IAAK,CAAA,UAAA,KAAe,iCAAmC,EAAA;AAC9D,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,gCAAA,EAAmC,IAAK,CAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,SACzD,CAAA;AAAA,OACF;AACA,MAAA,MAAM,EAAE,MAAO,EAAA,GAAI,MAAM,IAAK,CAAA,OAAA,CAAQ,QAAQ,cAAe,CAAA,OAAA;AAAA,QAC3D,IAAA;AAAA,OACF,CAAA;AACA,MAAA,MAAM,IAAK,CAAA,QAAA,CAAS,WAAa,EAAA,EAAE,QAAQ,CAAA,CAAA;AAAA,aACpC,KAAO,EAAA;AACd,MAAAK,kBAAA,CAAY,KAAK,CAAA,CAAA;AACjB,MAAM,MAAA,IAAA,CAAK,SAAS,QAAU,EAAA;AAAA,QAC5B,OAAO,EAAE,IAAA,EAAM,MAAM,IAAM,EAAA,OAAA,EAAS,MAAM,OAAQ,EAAA;AAAA,OACnD,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AACF;;AC1LO,MAAM,iCAAiC,sBAAuB,CAAA;AAAA,EACnE,WAAA,CACmB,eACjB,YACA,EAAA;AACA,IAAM,KAAA,EAAA,CAAA;AAHW,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA,CAAA;AAIjB,IAAA,KAAA,MAAW,UAAU,YAAc,EAAA;AACjC,MAAA,IAAA,CAAK,SAAS,MAAM,CAAA,CAAA;AAAA,KACtB;AAAA,GACF;AAAA,EAEA,IAAI,QAAkC,EAAA;AACpC,IAAI,IAAA;AACF,MAAO,OAAA,KAAA,CAAM,IAAI,QAAQ,CAAA,CAAA;AAAA,KACnB,CAAA,MAAA;AACN,MAAO,OAAA,IAAA,CAAK,aAAc,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAAA,KACxC;AAAA,GACF;AACF;;AC0CO,SAAS,gBAAgB,OAAsC,EAAA;AACpE,EAAO,OAAA,eAAe,OAAO,KAA2C,EAAA;AACtE,IAAI,IAAA,cAAA,CAAA;AAEJ,IAAM,MAAA,cAAA,GAAiB,IAAI,sBAAuB,CAAA;AAAA,MAChD,GAAG,OAAA;AAAA,MACH,cAAgB,EAAA,IAAI,wBAAyB,CAAA,OAAA,CAAQ,cAAgB,EAAA;AAAA,QACnElF,yCAAqB,CAAA;AAAA,UACnB,EAAI,EAAA,iBAAA;AAAA,UACJ,cAAgB,EAAA,IAAA;AAAA,UAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,YAAiB,cAAA,GAAAmF,+CAAA,CAA2B,IAAI,aAAa,CAAA,CAAA;AAC7D,YAAM,MAAA,cAAA,CAAe,MAAM,MAAM;AAAA,aAAE,CAAA,CAAA;AAAA,WACrC;AAAA,SACD,CAAA;AAAA,OACF,CAAA;AAAA,KACF,CAAA,CAAA;AAED,IAAA,MAAM,WAAWpC,OAAK,EAAA,CAAA;AACtB,IAAM,MAAA,GAAA,GAAM,IAAI,KAA4B,EAAA,CAAA;AAC5C,IAAA,MAAM,YAAe,GAAA1C,qCAAA;AAAA,MACnB,OAAQ,CAAA,gBAAA;AAAA,MACR,mBAAmB,QAAQ,CAAA,CAAA;AAAA,KAC7B,CAAA;AAEA,IAAI,IAAA;AACF,MAAM,MAAA+E,iDAAA,CAA6B,YAAc,EAAA,KAAA,CAAM,iBAAiB,CAAA,CAAA;AAExE,MAAM,MAAA,WAAA,GAAc,IAAI,eAAA,EAAkB,CAAA,MAAA,CAAA;AAE1C,MAAM,MAAA,MAAA,GAAS,MAAM,cAAA,CAAe,OAAQ,CAAA;AAAA,QAC1C,MAAQ,EAAA,QAAA;AAAA,QACR,IAAM,EAAA;AAAA,UACJ,GAAG,KAAM,CAAA,IAAA;AAAA,UACT,KAAO,EAAA;AAAA,YACL,GAAG,MAAM,IAAK,CAAA,KAAA;AAAA,YACd;AAAA,cACE,EAAI,EAAA,QAAA;AAAA,cACJ,IAAM,EAAA,iBAAA;AAAA,cACN,MAAQ,EAAA,iBAAA;AAAA,aACV;AAAA,WACF;AAAA,UACA,YAAc,EAAA;AAAA,YACZ,SAAW,EAAA,0BAAA;AAAA,YACX,OAAS,EAAAC,iBAAA;AAAA,cACPhF,qCAAA,CAAqB,cAAc,eAAe,CAAA;AAAA,cAClD,QAAS,EAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,SAAS,KAAM,CAAA,OAAA;AAAA,QACf,uBAAyB,EAAA,MAAM,OAAQ,CAAA,OAAA,CAAQ,MAAM,WAAW,CAAA;AAAA;AAAA,QAEhE,IAAM,EAAA,KAAA;AAAA,QACN,QAAU,EAAA,IAAA;AAAA,QACV,gBAAA,EAAkB,YAAY,CAAA,QAAA,EAAW,QAAQ,CAAA,CAAA;AAAA,QACjD,YAAc,EAAA,WAAA;AAAA,QACd,MAAM,OAAQ,CAAA,OAAA,EAAiB,WAA0B,EAAA;AACvD,UAAI,IAAA,WAAA,EAAa,WAAW,QAAU,EAAA;AACpC,YAAA,OAAA;AAAA,WACF;AACA,UAAA,GAAA,CAAI,IAAK,CAAA;AAAA,YACP,IAAM,EAAA;AAAA,cACJ,GAAG,WAAA;AAAA,cACH,OAAA;AAAA,aACF;AAAA,WACD,CAAA,CAAA;AAAA,SACH;AAAA,QACA,UAAU,YAAY;AACpB,UAAM,MAAA,IAAI,MAAM,iBAAiB,CAAA,CAAA;AAAA,SACnC;AAAA,OACD,CAAA,CAAA;AAED,MAAA,IAAI,CAAC,cAAgB,EAAA;AACnB,QAAM,MAAA,IAAI,MAAM,qCAAqC,CAAA,CAAA;AAAA,OACvD;AACA,MAAA,MAAM,oBAAoB,MAAM,cAAA,CAAA;AAEhC,MAAO,OAAA;AAAA,QACL,GAAA;AAAA,QACA,iBAAA;AAAA,QACA,QAAQ,MAAO,CAAA,MAAA;AAAA,OACjB,CAAA;AAAA,KACA,SAAA;AACA,MAAM,MAAAD,mBAAA,CAAG,OAAO,YAAY,CAAA,CAAA;AAAA,KAC9B;AAAA,GACF,CAAA;AACF;;ACtIsB,eAAA,mBAAA,CACpB,QACA,MACiB,EAAA;AACjB,EAAA,IAAI,CAAC,MAAA,CAAO,GAAI,CAAA,0BAA0B,CAAG,EAAA;AAC3C,IAAA,OAAOkF,oBAAG,MAAO,EAAA,CAAA;AAAA,GACnB;AAEA,EAAM,MAAA,gBAAA,GAAmB,MAAO,CAAA,SAAA,CAAU,0BAA0B,CAAA,CAAA;AACpE,EAAI,IAAA;AAEF,IAAM,MAAAlF,mBAAA,CAAG,OAAO,gBAAkB,EAAAA,mBAAA,CAAG,UAAU,IAAO,GAAAA,mBAAA,CAAG,UAAU,IAAI,CAAA,CAAA;AACvE,IAAO,MAAA,CAAA,IAAA,CAAK,CAA4B,yBAAA,EAAA,gBAAgB,CAAE,CAAA,CAAA,CAAA;AAAA,WACnD,GAAK,EAAA;AACZ,IAAA8E,kBAAA,CAAY,GAAG,CAAA,CAAA;AACf,IAAO,MAAA,CAAA,KAAA;AAAA,MACL,qBAAqB,gBAAgB,CAAA,CAAA,EACnC,IAAI,IAAS,KAAA,QAAA,GAAW,mBAAmB,iBAC7C,CAAA,CAAA;AAAA,KACF,CAAA;AACA,IAAM,MAAA,GAAA,CAAA;AAAA,GACR;AACA,EAAO,OAAA,gBAAA,CAAA;AACT,CAAA;AASO,SAAS,iBAAiB,MAAoC,EAAA;AACnE,EAAA,IAAI,QAAW,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAcK,uCAA0B,CAAA,CAAA;AACvE,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAW,QAAA,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAcC,gCAAmB,CAAA,CAAA;AAAA,GAC9D;AACA,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,MAAO,EAAA,GAAIC,8BAAiB,QAAQ,CAAA,CAAA;AAClD,EAAA,IAAI,SAAS,KAAO,EAAA;AAClB,IAAO,OAAA,MAAA,CAAA;AAAA,GACT,MAAA,IAAW,SAAS,MAAQ,EAAA;AAC1B,IAAA,OAAO,UAAU,MAAM,CAAA,CAAA,CAAA;AAAA,GACzB;AAIA,EAAO,OAAA,KAAA,CAAA,CAAA;AACT,CAAA;AAMA,eAAsB,aAAa,OAIA,EAAA;AACjC,EAAA,MAAM,EAAE,SAAA,EAAW,KAAO,EAAA,UAAA,EAAe,GAAA,OAAA,CAAA;AAEzC,EAAA,IAAI,SAAU,CAAA,IAAA,CAAK,iBAAkB,CAAA,OAAO,MAAM,UAAY,EAAA;AAC5D,IAAM,MAAA,IAAIxF,kBAAW,CAAiD,+CAAA,CAAA,CAAA,CAAA;AAAA,GACxE;AAEA,EAAA,MAAM,WAAW,MAAM,UAAA,CAAW,eAAe,SAAW,EAAA,EAAE,OAAO,CAAA,CAAA;AACrE,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAA,MAAM,IAAI4C,oBAAA;AAAA,MACR,CAAA,SAAA,EAAY3C,+BAAmB,CAAA,SAAS,CAAC,CAAA,UAAA,CAAA;AAAA,KAC3C,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,QAAA,CAAA;AACT;;ACzEA,eAAsB,gBAAgB,OAAiC,EAAA;AACrE,EAAA,MAAM,EAAE,WAAA,EAAa,iBAAmB,EAAA,WAAA,EAAgB,GAAA,OAAA,CAAA;AACxD,EAAA,IAAI,iBAAmB,EAAA;AACrB,IAAM,MAAA,iBAAA,GAAoB,WAAY,CAAA,GAAA,CAAI,CAAe,UAAA,MAAA;AAAA,MACvD,UAAA;AAAA,KACA,CAAA,CAAA,CAAA;AACF,IAAM,MAAA,sBAAA,GAAyB,MAAM,iBAAkB,CAAA,SAAA;AAAA,MACrD,iBAAA;AAAA,MACA,EAAE,WAAyB,EAAA;AAAA,KAC7B,CAAA;AAEA,IAAA,KAAA,MAAW,YAAY,sBAAwB,EAAA;AAC7C,MAAI,IAAA,QAAA,CAAS,MAAW,KAAA8E,sCAAA,CAAgB,IAAM,EAAA;AAC5C,QAAA,MAAM,IAAIL,sBAAgB,EAAA,CAAA;AAAA,OAC5B;AAAA,KACF;AAAA,GACF;AACF;;ACiEA,SAAS,8BACP,cAC+C,EAAA;AAC/C,EAAA,OAAO,eAAe,YAAiB,KAAAhB,yCAAA,CAAA;AACzC,CAAA;AAcA,SAAS,4BACP,cAC6C,EAAA;AAC7C,EAAA,OAAO,eAAe,YAAiB,KAAAC,uCAAA,CAAA;AACzC,CAAA;AA0CA,SAAS,oBAAoB,MAA+B,EAAA;AAC1D,EAAA,OAAO,OAAO,UAAe,KAAA,iCAAA,CAAA;AAC/B,CAAA;AASA,SAAS,2BAA2B,OAAqC,EAAA;AACvE,EAAO,OAAA;AAAA,IACL,WAAa,EAAA,OAAO,EAAE,OAAA,EAA6C,KAAA;AACjE,MAAM,MAAA,MAAA,GAAS,QAAQ,OAAQ,CAAA,aAAA,CAAA;AAC/B,MAAM,MAAA,EAAE,QAAW,GAAA,OAAA,CAAA;AAEnB,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAO,OAAA,KAAA,CAAA,CAAA;AAAA,OACT;AAEA,MAAI,IAAA;AACF,QAAA,MAAM,KAAQ,GAAA,MAAA,CAAO,KAAM,CAAA,4BAA4B,IAAI,CAAC,CAAA,CAAA;AAC5D,QAAA,IAAI,CAAC,KAAO,EAAA;AACV,UAAM,MAAA,IAAI,UAAU,0BAA0B,CAAA,CAAA;AAAA,SAChD;AAEA,QAAA,MAAM,CAAC,OAAS,EAAA,UAAA,EAAY,UAAU,CAAI,GAAA,KAAA,CAAM,MAAM,GAAG,CAAA,CAAA;AACzD,QAAA,MAAM,UAAqB,IAAK,CAAA,KAAA;AAAA,UAC9B,MAAO,CAAA,IAAA,CAAK,UAAY,EAAA,QAAQ,EAAE,QAAS,EAAA;AAAA,SAC7C,CAAA;AAEA,QACE,IAAA,OAAO,YAAY,QACnB,IAAA,OAAA,KAAY,QACZ,KAAM,CAAA,OAAA,CAAQ,OAAO,CACrB,EAAA;AACA,UAAM,MAAA,IAAI,UAAU,uBAAuB,CAAA,CAAA;AAAA,SAC7C;AAEA,QAAA,MAAM,MAAM,OAAQ,CAAA,GAAA,CAAA;AACpB,QAAI,IAAA,OAAO,QAAQ,QAAU,EAAA;AAC3B,UAAM,MAAA,IAAI,UAAU,2BAA2B,CAAA,CAAA;AAAA,SACjD;AAEA,QAAA,IAAI,QAAQ,kBAAoB,EAAA;AAC9B,UAAO,OAAA,KAAA,CAAA,CAAA;AAAA,SACT;AAGA,QAAAtD,2BAAA,CAAe,GAAG,CAAA,CAAA;AAElB,QAAO,OAAA;AAAA,UACL,QAAU,EAAA;AAAA,YACR,aAAe,EAAA,GAAA;AAAA,YACf,qBAAqB,EAAC;AAAA,YACtB,IAAM,EAAA,MAAA;AAAA,WACR;AAAA,UACA,KAAA;AAAA,SACF,CAAA;AAAA,eACO,CAAG,EAAA;AACV,QAAA,MAAA,CAAO,KAAM,CAAA,CAAA,8BAAA,EAAiCuE,qBAAe,CAAA,CAAC,CAAC,CAAE,CAAA,CAAA,CAAA;AACjE,QAAO,OAAA,KAAA,CAAA,CAAA;AAAA,OACT;AAAA,KACF;AAAA,GACF,CAAA;AACF,CAAA;AAEA,MAAM,YAAe,GAAA,CACnBzB,QACA,EAAA,GAAA,EACA,YACG,KAAA;AACH,EAAI,IAAAA,QAAA,CAAO,GAAI,CAAA,GAAG,CAAG,EAAA;AACnB,IAAA,OAAOC,6BAAuB,CAAAD,QAAA,EAAQ,EAAE,GAAA,EAAK,CAAA,CAAA;AAAA,GAC/C;AACA,EAAO,OAAA,YAAA,CAAA;AACT,CAAA,CAAA;AAMA,eAAsB,aACpB,OACyB,EAAA;AACzB,EAAA,MAAM,SAASsC,uBAAO,EAAA,CAAA;AAEtB,EAAA,MAAA,CAAO,IAAIC,wBAAQ,CAAA,IAAA,CAAK,EAAE,KAAO,EAAA,MAAA,EAAQ,CAAC,CAAA,CAAA;AAE1C,EAAM,MAAA;AAAA,IACJ,MAAQ,EAAA,YAAA;AAAA,IACR,MAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,yBAAA;AAAA,IACA,yBAAA;AAAA,IACA,4BAAA;AAAA,IACA,WAAA;AAAA,IACA,eAAA;AAAA,IACA,SAAA,GAAYC,2BAAc,CAAA,UAAA,CAAW,MAAM,CAAA;AAAA,IAC3C,QAAA,GAAW,2BAA2B,OAAO,CAAA;AAAA,IAC7C,uBAAuB,EAAC;AAAA,GACtB,GAAA,OAAA,CAAA;AAEJ,EAAA,MAAM,EAAE,IAAA,EAAM,QAAS,EAAA,GAAIC,sCAAyB,CAAA;AAAA,IAClD,GAAG,OAAA;AAAA,IACH,QAAA;AAAA,IACA,SAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,MAAM,uBACJ,OAAQ,CAAA,oBAAA,IACR,OAAQ,CAAA,MAAA,CAAO,kBAAkB,iCAAiC,CAAA,CAAA;AAEpE,EAAA,MAAM,SAAS,YAAa,CAAA,KAAA,CAAM,EAAE,MAAA,EAAQ,cAAc,CAAA,CAAA;AAC1D,EAAM,MAAA,WAAA,GAAc,IAAIC,8CAAmB,CAAA;AAAA,IACzC,MAAA;AAAA,IACA,WAAa,EAAA,IAAA;AAAA,IACb,eAAiB,EAAA,QAAA;AAAA,GAClB,CAAA,CAAA;AAED,EAAA,MAAM,gBAAmB,GAAA,MAAM,mBAAoB,CAAA,MAAA,EAAQ,MAAM,CAAA,CAAA;AACjE,EAAM,MAAA,YAAA,GAAeC,2BAAgB,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AAEtD,EAAI,IAAA,UAAA,CAAA;AACJ,EAAI,IAAA,CAAC,QAAQ,UAAY,EAAA;AACvB,IAAA,MAAM,oBAAoB,MAAM,iBAAA,CAAkB,MAAO,CAAA,EAAE,UAAU,CAAA,CAAA;AACrE,IAAA,UAAA,GAAa,IAAI,iBAAA;AAAA,MACf,iBAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA;AAAA,MACA,4BAAA;AAAA,KACF,CAAA;AAEA,IAAI,IAAA,SAAA,IAAa,kBAAkB,cAAgB,EAAA;AACjD,MAAA,MAAM,UAAU,YAAa,CAAA;AAAA,QAC3B,EAAI,EAAA,mBAAA;AAAA,QACJ,SAAW,EAAA,YAAA;AAAA,UACT,MAAA;AAAA,UACA,wCAAA;AAAA,UACA;AAAA,YACE,OAAS,EAAA,CAAA;AAAA,WACX;AAAA,SACF;AAAA,QACA,OAAA,EAAS,EAAE,OAAA,EAAS,EAAG,EAAA;AAAA,QACvB,IAAI,YAAY;AACd,UAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,kBAAkB,cAAe,CAAA;AAAA,YACvD,UAAUpF,cAAS,CAAA,UAAA;AAAA,cACjB,YAAA,CAAa,QAAQ,wBAA0B,EAAA;AAAA,gBAC7C,KAAO,EAAA,EAAA;AAAA,eACR,CAAA;AAAA,aACH,CAAE,GAAG,SAAS,CAAA;AAAA,WACf,CAAA,CAAA;AAED,UAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,YAAM,MAAA,iBAAA,CAAkB,aAAa,IAAI,CAAA,CAAA;AACzC,YAAA,MAAA,CAAO,IAAK,CAAA,CAAA,+BAAA,EAAkC,IAAK,CAAA,MAAM,CAAE,CAAA,CAAA,CAAA;AAAA,WAC7D;AAAA,SACF;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAAA,GACK,MAAA;AACL,IAAA,UAAA,GAAa,OAAQ,CAAA,UAAA,CAAA;AAAA,GACvB;AAEA,EAAM,MAAA,cAAA,GAAiB,IAAI,sBAAuB,EAAA,CAAA;AAElD,EAAA,MAAM,UAAwB,EAAC,CAAA;AAC/B,EAAA,IAAI,yBAAyB,CAAG,EAAA;AAC9B,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAK,IAAA,WAAA,IAAe,IAAI,CAAK,EAAA,EAAA;AAC3C,MAAM,MAAA,MAAA,GAAS,MAAM,UAAA,CAAW,MAAO,CAAA;AAAA,QACrC,UAAA;AAAA,QACA,cAAA;AAAA,QACA,YAAA;AAAA,QACA,MAAA;AAAA,QACA,gBAAA;AAAA,QACA,yBAAA;AAAA,QACA,yBAAA;AAAA,QACA,oBAAA;AAAA,QACA,WAAA;AAAA,QACA,WAAA;AAAA,OACD,CAAA,CAAA;AACD,MAAA,OAAA,CAAQ,KAAK,MAAM,CAAA,CAAA;AAAA,KACrB;AAAA,GACF;AAEA,EAAA,MAAM,oBAAoB,KAAM,CAAA,OAAA,CAAQ,OAAO,CAAA,GAC3C,UACA,oBAAqB,CAAA;AAAA,IACnB,YAAA;AAAA,IACA,aAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,yBAAA;AAAA,IACA,yBAAA;AAAA,IACA,IAAA;AAAA,GACD,CAAA,CAAA;AAEL,EAAA,iBAAA,CAAkB,OAAQ,CAAA,CAAA,MAAA,KAAU,cAAe,CAAA,QAAA,CAAS,MAAM,CAAC,CAAA,CAAA;AAEnE,EAAA,MAAM,gBAAgB,MAAM,OAAA,CAAQ,QAAQ,CAAU,MAAA,KAAA,MAAA,CAAO,OAAO,CAAA,CAAA;AAEpE,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,OAAA,CAAQ,OAAQ,CAAA,CAAA,MAAA,KAAU,MAAO,CAAA,IAAA,EAAM,CAAA,CAAA;AAAA,GACzC,CAAA;AAEA,EAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,IAAQ,OAAA,CAAA,SAAA,CAAU,eAAe,aAAa,CAAA,CAAA;AAC9C,IAAQ,OAAA,CAAA,SAAA,CAAU,gBAAgB,eAAe,CAAA,CAAA;AAAA,GAC5C,MAAA;AACL,IAAc,aAAA,EAAA,CAAA;AAAA,GAChB;AAEA,EAAA,MAAM,YAAY,eAAgB,CAAA;AAAA,IAChC,cAAA;AAAA,IACA,YAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,yBAAA;AAAA,IACA,yBAAA;AAAA,IACA,WAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,MAAM,gBAA+C,MAAO,CAAA,MAAA;AAAA,IAC1D,uBAAA;AAAA,GACF,CAAA;AACA,EAAA,MAAM,cAA2C,MAAO,CAAA,MAAA;AAAA,IACtD,qBAAA;AAAA,GACF,CAAA;AAEA,EAAA,IAAI,eAAiB,EAAA;AACnB,IAAc,aAAA,CAAA,IAAA;AAAA,MACZ,GAAG,eAAgB,CAAA,MAAA,CAAO,6BAA6B,CAAA;AAAA,KACzD,CAAA;AACA,IAAA,WAAA,CAAY,IAAK,CAAA,GAAG,eAAgB,CAAA,MAAA,CAAO,2BAA2B,CAAC,CAAA,CAAA;AAAA,GACzE;AAEA,EAAA,MAAM,YAAe,GAAA2D,8CAAA,CAA0B,MAAO,CAAA,MAAA,CAAO,aAAa,CAAC,CAAA,CAAA;AAE3E,EAAA,MAAM,8BAA8B0B,sDAAkC,CAAA;AAAA,IACpE,SAAW,EAAA;AAAA,MACT;AAAA,QACE,YAAc,EAAArC,yCAAA;AAAA,QACd,WAAa,EAAAsC,qCAAA;AAAA,QACb,KAAO,EAAA,aAAA;AAAA,OACT;AAAA,MACA;AAAA,QACE,YAAc,EAAArC,uCAAA;AAAA,QACd,WAAa,EAAAsC,mCAAA;AAAA,QACb,KAAO,EAAA,WAAA;AAAA,OACT;AAAA,KACF;AAAA,IACA,WAAa,EAAAC,iCAAA;AAAA,GACd,CAAA,CAAA;AAED,EAAA,MAAA,CAAO,IAAI,2BAA2B,CAAA,CAAA;AAEtC,EACG,MAAA,CAAA,GAAA;AAAA,IACC,uDAAA;AAAA,IACA,OAAO,KAAK,GAAQ,KAAA;AAClB,MAAA,MAAM,oBAAuB,GAAA,CAAA,EAAG,GAAI,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA,EAAI,GAAI,CAAA,MAAA,CAAO,SAAS,CAAA,CAAA,EAAI,GAAI,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA,CAAA;AAC1F,MAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,MAAI,IAAA;AACF,QAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAElD,QAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,UACjD,UAAY,EAAA,WAAA;AAAA,UACZ,cAAgB,EAAA,SAAA;AAAA,SACjB,CAAA,CAAA;AACD,QAAA,MAAM,YAAY,QAAS,CAAA;AAAA,UACzB,SAAW,EAAA,gCAAA;AAAA,UACX,OAAA;AAAA,UACA,KAAO,EAAA,YAAA;AAAA,UACP,MAAQ,EAAA,WAAA;AAAA,UACR,QAAU,EAAA;AAAA,YACR,WAAa,EAAA,oBAAA;AAAA,WACf;AAAA,UACA,OAAS,EAAA,GAAA;AAAA,UACT,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,oCAAA,EAAuC,oBAAoB,CAAA,CAAA;AAAA,SAC/E,CAAA,CAAA;AACD,QAAA,MAAM,WAAW,MAAM,iBAAA;AAAA,UACrB,GAAI,CAAA,MAAA;AAAA,UACJ,KAAA;AAAA,UACA,WAAA;AAAA,SACF,CAAA;AAEA,QAAM,MAAA,UAAA,GAAa,CAAC,QAAS,CAAA,IAAA,CAAK,cAAc,EAAE,EAAE,IAAK,EAAA,CAAA;AAEzD,QAAM,MAAA,YAAA,GAAe,SAAS,IAAK,CAAA,YAAA,CAAA;AACnC,QAAA,MAAM,WAAc,GAAA,CAAA,EAAG,QAAS,CAAA,IAAI,CAClC,CAAA,EAAA,QAAA,CAAS,QAAS,CAAA,SAAA,IAAa,SACjC,CAAA,CAAA,EAAI,QAAS,CAAA,QAAA,CAAS,IAAI,CAAA,CAAA,CAAA;AAE1B,QAAA,MAAM,YAAe,GAAA;AAAA,UACnB,KAAO,EAAA,QAAA,CAAS,QAAS,CAAA,KAAA,IAAS,SAAS,QAAS,CAAA,IAAA;AAAA,UACpD,GAAI,YAAA,GAAe,EAAE,YAAA,KAAiB,EAAC;AAAA,UACvC,WAAA,EAAa,SAAS,QAAS,CAAA,WAAA;AAAA,UAC/B,YAAA,EAAc,QAAS,CAAA,QAAA,CAAS,YAAY,CAAA;AAAA,UAC5C,KAAA,EAAO,UAAW,CAAA,GAAA,CAAI,CAAW,MAAA,MAAA;AAAA,YAC/B,KAAA,EAAO,OAAO,KAAS,IAAA,wCAAA;AAAA,YACvB,aAAa,MAAO,CAAA,WAAA;AAAA,YACpB,MAAA;AAAA,WACA,CAAA,CAAA;AAAA,SACJ,CAAA;AACA,QAAA,MAAM,YAAY,QAAS,CAAA;AAAA,UACzB,SAAW,EAAA,gCAAA;AAAA,UACX,OAAA;AAAA,UACA,KAAO,EAAA,YAAA;AAAA,UACP,MAAQ,EAAA,WAAA;AAAA,UACR,QAAU,EAAA;AAAA,YACR,WAAA;AAAA,WACF;AAAA,UACA,OAAS,EAAA,GAAA;AAAA,UACT,QAAU,EAAA;AAAA,YACR,MAAQ,EAAA,GAAA;AAAA,YACR,IAAM,EAAA,YAAA;AAAA,WACR;AAAA,UACA,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,iDAAA,EAAoD,WAAW,CAAA,CAAA;AAAA,SACnF,CAAA,CAAA;AAED,QAAA,GAAA,CAAI,KAAK,YAAY,CAAA,CAAA;AAAA,eACd,GAAK,EAAA;AACZ,QAAA,MAAM,YAAY,QAAS,CAAA;AAAA,UACzB,SAAW,EAAA,gCAAA;AAAA,UACX,OAAA;AAAA,UACA,KAAO,EAAA,YAAA;AAAA,UACP,MAAQ,EAAA,QAAA;AAAA,UACR,KAAO,EAAA,OAAA;AAAA,UACP,OAAS,EAAA,GAAA;AAAA,UACT,QAAU,EAAA;AAAA,YACR,WAAa,EAAA,oBAAA;AAAA,WACf;AAAA,UACA,MAAQ,EAAA;AAAA,YACN;AAAA,cACE,MAAM,GAAI,CAAA,IAAA;AAAA,cACV,SAAS,GAAI,CAAA,OAAA;AAAA,cACb,OAAO,GAAI,CAAA,KAAA;AAAA,aACb;AAAA,WACF;AAAA,UACA,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,4CAAA,EAA+C,oBAAoB,CAAA,CAAA;AAAA,SACvF,CAAA,CAAA;AACD,QAAM,MAAA,GAAA,CAAA;AAAA,OACR;AAAA,KACF;AAAA,GAED,CAAA,GAAA,CAAI,aAAe,EAAA,OAAO,KAAK,GAAQ,KAAA;AACtC,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,IAAI,IAAA;AACF,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,iCAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,GAAA;AAAA,QACT,OAAA,EAAS,GAAG,OAAO,CAAA,wCAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,cAAA,CAAe,IAAK,EAAA,CAAE,IAAI,CAAU,MAAA,KAAA;AACtD,QAAO,OAAA;AAAA,UACL,IAAI,MAAO,CAAA,EAAA;AAAA,UACX,aAAa,MAAO,CAAA,WAAA;AAAA,UACpB,UAAU,MAAO,CAAA,QAAA;AAAA,UACjB,QAAQ,MAAO,CAAA,MAAA;AAAA,SACjB,CAAA;AAAA,OACD,CAAA,CAAA;AACD,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,iCAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,GAAA;AAAA,UACR,IAAM,EAAA,WAAA;AAAA,SACR;AAAA,QACA,OAAA,EAAS,GAAG,OAAO,CAAA,qDAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAA,GAAA,CAAI,KAAK,WAAW,CAAA,CAAA;AAAA,aACb,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,iCAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,OAAS,EAAA,GAAA;AAAA,QACT,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAA,EAAS,GAAG,OAAO,CAAA,oDAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,IAAA,CAAK,WAAa,EAAA,OAAO,KAAK,GAAQ,KAAA;AACrC,IAAM,MAAA,WAAA,GAAsB,IAAI,IAAK,CAAA,WAAA,CAAA;AACrC,IAAA,MAAM,EAAE,IAAM,EAAA,SAAA,EAAW,IAAK,EAAA,GAAI7F,4BAAe,WAAa,EAAA;AAAA,MAC5D,WAAa,EAAA,UAAA;AAAA,KACd,CAAA,CAAA;AACD,IAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAElD,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,MACjD,UAAY,EAAA,WAAA;AAAA,MACZ,cAAgB,EAAA,SAAA;AAAA,KACjB,CAAA,CAAA;AACD,IAAM,MAAA,aAAA,GAAgB,KAAK,WAAY,CAAA,WAAA,EAAa,MAAM,CACtD,GAAA,WAAA,CAAY,UAAU,aACtB,GAAA,KAAA,CAAA,CAAA;AAEJ,IAAM,MAAA,UAAA,GAAa,gBACf,MAAM,aAAA,CAAc,eAAe,aAAe,EAAA,EAAE,KAAM,EAAC,CAC3D,GAAA,KAAA,CAAA,CAAA;AACJ,IAAM,MAAA,MAAA,GAAS,IAAI,IAAK,CAAA,MAAA,CAAA;AACxB,IAAM,MAAA,eAAA,GAAkB8F,iBAAU,GAAG,CAAA,CAAA;AAGrC,IAAO,MAAA,CAAA,cAAA,CAAe,iBAAiB,IAAM,EAAA;AAAA,MAC3C,KAAK,MAAM;AACT,QAAA,OAAO,GAAI,CAAA,EAAA,CAAA;AAAA,OACb;AAAA,KACD,CAAA,CAAA;AACD,IAAI,IAAA,GAAA,CAAI,KAAK,OAAS,EAAA;AACpB,MAAA,MAAM,YAAe,GAAA;AAAA,QACnB,GAAG,GAAI,CAAA,IAAA;AAAA,QACP,OAAA,EAAS,MAAO,CAAA,IAAA,CAAK,GAAI,CAAA,IAAA,CAAK,OAAO,CAAE,CAAA,MAAA,CAAO,CAAC,GAAA,EAAK,GAAQ,KAAA;AAC1D,UAAO,OAAA;AAAA,YACL,GAAG,GAAA;AAAA,YACH,CAAC,GAAG,GAAG,KAAA;AAAA,WACT,CAAA;AAAA,SACF,EAAG,EAAiB,CAAA;AAAA,OACtB,CAAA;AACA,MAAA,eAAA,CAAgB,IAAO,GAAA,YAAA,CAAA;AAAA,KACzB;AACA,IAAI,IAAA;AACF,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,wBAAA;AAAA,QACX,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,aAAA;AAAA,QACT,OAAS,EAAA,eAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,WAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,CAAA,qBAAA,EAAwB,WAAW,CAAA,qBAAA,EAAwB,aAAa,CAAA,UAAA,CAAA;AAAA,OAClF,CAAA,CAAA;AACD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAACC,4BAAoB,CAAA;AAAA,QAClC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAA,MAAM,WAAW,MAAM,iBAAA;AAAA,QACrB,EAAE,IAAM,EAAA,SAAA,EAAW,IAAK,EAAA;AAAA,QACxB,KAAA;AAAA,QACA,WAAA;AAAA,OACF,CAAA;AACA,MAAW,KAAA,MAAA,UAAA,IAAc,CAAC,QAAS,CAAA,IAAA,CAAK,cAAc,EAAE,CAAE,CAAA,IAAA,EAAQ,EAAA;AAChE,QAAMC,MAAAA,OAAAA,GAASC,mBAAS,CAAA,MAAA,EAAQ,UAAU,CAAA,CAAA;AAC1C,QAAI,IAAA,CAACD,QAAO,KAAO,EAAA;AACjB,UAAA,MAAM,YAAY,QAAS,CAAA;AAAA,YACzB,SAAW,EAAA,wBAAA;AAAA,YACX,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,QAAA;AAAA,YACR,KAAO,EAAA,OAAA;AAAA,YACP,OAAS,EAAA,aAAA;AAAA,YACT,OAAS,EAAA,eAAA;AAAA,YACT,QAAU,EAAA;AAAA,cACR,WAAA;AAAA,aACF;AAAA,YACA,QAAU,EAAA;AAAA,cACR,MAAQ,EAAA,GAAA;AAAA,cACR,IAAM,EAAA,EAAE,MAAQA,EAAAA,OAAAA,CAAO,MAAO,EAAA;AAAA,aAChC;AAAA,YACA,QAAQA,OAAO,CAAA,MAAA;AAAA,YACf,OAAS,EAAA,CAAA,qBAAA,EAAwB,WAAW,CAAA,qBAAA,EAAwB,aAAa,CAAA,OAAA,CAAA;AAAA,WAClF,CAAA,CAAA;AACD,UAAO,OAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,MAAA,EAAQA,OAAO,CAAA,MAAA,EAAQ,CAAA,CAAA;AAAA,SACvD;AAAA,OACF;AAEA,MAAM,MAAA,OAAA,GAAU,iBAAiB,QAAQ,CAAA,CAAA;AAEzC,MAAA,MAAM,QAAqB,GAAA;AAAA,QACzB,YAAY,QAAS,CAAA,UAAA;AAAA,QACrB,OAAO,QAAS,CAAA,IAAA,CAAK,MAAM,GAAI,CAAA,CAAC,MAAM,KAAW,MAAA;AAAA,UAC/C,GAAG,IAAA;AAAA,UACH,EAAI,EAAA,IAAA,CAAK,EAAM,IAAA,CAAA,KAAA,EAAQ,QAAQ,CAAC,CAAA,CAAA;AAAA,UAChC,IAAA,EAAM,IAAK,CAAA,IAAA,IAAQ,IAAK,CAAA,MAAA;AAAA,SACxB,CAAA,CAAA;AAAA,QACF,qBAAA,EAAuB,SAAS,IAAK,CAAA,qBAAA;AAAA,QACrC,MAAQ,EAAA,QAAA,CAAS,IAAK,CAAA,MAAA,IAAU,EAAC;AAAA,QACjC,UAAY,EAAA,MAAA;AAAA,QACZ,IAAM,EAAA;AAAA,UACJ,MAAQ,EAAA,UAAA;AAAA,UACR,GAAK,EAAA,aAAA;AAAA,SACP;AAAA,QACA,YAAc,EAAA;AAAA,UACZ,WAAWpG,+BAAmB,CAAA,EAAE,IAAM,EAAA,IAAA,EAAM,WAAW,CAAA;AAAA,UACvD,OAAA;AAAA,UACA,MAAQ,EAAA;AAAA,YACN,UAAU,QAAS,CAAA,QAAA;AAAA,WACrB;AAAA,SACF;AAAA,OACF,CAAA;AAEA,MAAA,MAAM,OAA+B,GAAA;AAAA,QACnC,GAAG,IAAI,IAAK,CAAA,OAAA;AAAA,QACZ,cAAgB,EAAA,KAAA;AAAA,QAChB,sBAAA,EAAwB,IAAK,CAAA,SAAA,CAAU,WAAW,CAAA;AAAA,OACpD,CAAA;AAEA,MAAM,MAAA,MAAA,GAAS,MAAM,UAAA,CAAW,QAAS,CAAA;AAAA,QACvC,IAAM,EAAA,QAAA;AAAA,QACN,SAAW,EAAA,aAAA;AAAA,QACX,OAAA;AAAA,OACD,CAAA,CAAA;AAED,MAAI,IAAA,QAAA,GAAW,wBAAwB,WAAW,CAAA,CAAA,CAAA;AAClD,MAAA,IAAI,aAAe,EAAA;AACjB,QAAA,QAAA,IAAY,eAAe,aAAa,CAAA,CAAA,CAAA;AAAA,OAC1C;AAEA,MAAA,MAAA,CAAO,KAAK,QAAQ,CAAA,CAAA;AACpB,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,wBAAA;AAAA,QACX,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,aAAA;AAAA,QACT,OAAS,EAAA,eAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,QAAQ,MAAO,CAAA,MAAA;AAAA,UACf,WAAA;AAAA,SACF;AAAA,QACA,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,GAAA;AAAA,UACR,IAAM,EAAA,EAAE,EAAI,EAAA,MAAA,CAAO,MAAO,EAAA;AAAA,SAC5B;AAAA,QACA,SAAS,CAAwB,qBAAA,EAAA,WAAW,iBAAiB,MAAO,CAAA,MAAM,4BAA4B,aAAa,CAAA,CAAA;AAAA,OACpH,CAAA,CAAA;AACD,MAAO,OAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,EAAA,EAAI,MAAO,CAAA,MAAA,EAAQ,CAAA,CAAA;AAAA,aAC1C,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,wBAAA;AAAA,QACX,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,OAAS,EAAA,aAAA;AAAA,QACT,OAAS,EAAA,eAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,WAAA;AAAA,SACF;AAAA,QACA,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAS,EAAA,CAAA,qBAAA,EAAwB,WAAW,CAAA,qBAAA,EAAwB,aAAa,CAAA,OAAA,CAAA;AAAA,OAClF,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,GAAA,CAAI,WAAa,EAAA,OAAO,KAAK,GAAQ,KAAA;AACpC,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAEhD,IAAI,IAAA;AACF,MAAM,MAAA,CAAC,aAAa,CAAI,GAAA,CAAC,IAAI,KAAM,CAAA,SAAS,EAAE,IAAK,EAAA,CAAA;AACnD,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,yBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,GAAA;AAAA,QACT,OAAA,EAAS,GAAG,OAAO,CAAA,2CAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAElD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAACsG,0BAAkB,CAAA;AAAA,QAChC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAA,IACE,OAAO,aAAA,KAAkB,QACzB,IAAA,OAAO,kBAAkB,WACzB,EAAA;AACA,QAAM,MAAA,IAAIvG,kBAAW,4CAA4C,CAAA,CAAA;AAAA,OACnE;AAEA,MAAI,IAAA,CAAC,WAAW,IAAM,EAAA;AACpB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,gGAAA;AAAA,SACF,CAAA;AAAA,OACF;AAEA,MAAM,MAAA,KAAA,GAAQ,MAAM,UAAA,CAAW,IAAK,CAAA;AAAA,QAClC,SAAW,EAAA,aAAA;AAAA,OACZ,CAAA,CAAA;AACD,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,yBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,GAAA;AAAA,UACR,IAAM,EAAA,KAAA;AAAA,SACR;AAAA,QACA,OAAA,EAAS,GAAG,OAAO,CAAA,wDAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAA,GAAA,CAAI,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAAA,aACnB,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,yBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,OAAS,EAAA,GAAA;AAAA,QACT,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAA,EAAS,GAAG,OAAO,CAAA,gDAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,GAAA,CAAI,mBAAqB,EAAA,OAAO,KAAK,GAAQ,KAAA;AAC5C,IAAM,MAAA,EAAE,MAAO,EAAA,GAAI,GAAI,CAAA,MAAA,CAAA;AACvB,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,IAAI,IAAA;AACF,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,qBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,+BAAA,EAAkC,MAAM,CAAA,CAAA;AAAA,OAC5D,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAClD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAACuG,0BAAkB,CAAA;AAAA,QAChC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AAED,MAAA,MAAM,IAAO,GAAA,MAAM,UAAW,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AACxC,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,MAAM,IAAI3D,oBAAA,CAAc,CAAgB,aAAA,EAAA,MAAM,CAAiB,eAAA,CAAA,CAAA,CAAA;AAAA,OACjE;AAEA,MAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,qBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,GAAA;AAAA,UACR,IAAM,EAAA,IAAA;AAAA,SACR;AAAA,QACA,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,6CAAA,EAAgD,MAAM,CAAA,CAAA;AAAA,OAC1E,CAAA,CAAA;AACD,MAAA,GAAA,CAAI,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,aAClB,GAAK,EAAA;AACZ,MAAA,IAAI,MAAS,GAAA,GAAA,CAAA;AACb,MAAI,IAAA,GAAA,CAAI,SAAS,eAAiB,EAAA;AAChC,QAAS,MAAA,GAAA,GAAA,CAAA;AAAA,OACX;AACA,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,qBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,8BAAA,EAAiC,MAAM,CAAA,OAAA,CAAA;AAAA,OAC3D,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,IAAA,CAAK,0BAA4B,EAAA,OAAO,KAAK,GAAQ,KAAA;AACpD,IAAM,MAAA,EAAE,MAAO,EAAA,GAAI,GAAI,CAAA,MAAA,CAAA;AACvB,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,IAAI,IAAA;AACF,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,4BAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,OAAS,EAAA,CAAA,uDAAA,EAA0D,MAAM,CAAA,MAAA,EAAS,OAAO,CAAA,SAAA,CAAA;AAAA,OAC1F,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAClD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAAC4D,4BAAoB,CAAA;AAAA,QAClC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAM,MAAA,UAAA,CAAW,SAAS,MAAM,CAAA,CAAA;AAChC,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,4BAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,GAAA;AAAA,UACR,IAAA,EAAM,EAAE,MAAA,EAAQ,WAAY,EAAA;AAAA,SAC9B;AAAA,QACA,OAAS,EAAA,CAAA,8BAAA,EAAiC,MAAM,CAAA,2BAAA,EAA8B,OAAO,CAAA,CAAA;AAAA,OACtF,CAAA,CAAA;AACD,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,MAAA,EAAQ,aAAa,CAAA,CAAA;AAAA,aACrC,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,4BAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,OAAS,EAAA,GAAA;AAAA,QACT,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAS,EAAA,CAAA,EAAG,OAAO,CAAA,2BAAA,EAA8B,MAAM,CAAA,OAAA,CAAA;AAAA,OACxD,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,GAAA,CAAI,+BAAiC,EAAA,OAAO,KAAK,GAAQ,KAAA;AACxD,IAAM,MAAA,EAAE,MAAO,EAAA,GAAI,GAAI,CAAA,MAAA,CAAA;AACvB,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GACJ,IAAI,KAAM,CAAA,KAAA,KAAU,SAAY,MAAO,CAAA,GAAA,CAAI,KAAM,CAAA,KAAK,CAAI,GAAA,KAAA,CAAA,CAAA;AAE5D,MAAO,MAAA,CAAA,KAAA,CAAM,CAAkC,+BAAA,EAAA,MAAM,CAAU,QAAA,CAAA,CAAA,CAAA;AAC/D,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,sBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,OAAS,EAAA,CAAA,+CAAA,EAAkD,MAAM,CAAA,eAAA,EAAkB,OAAO,CAAA,CAAA;AAAA,OAC3F,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAClD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAACD,0BAAkB,CAAA;AAAA,QAChC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AAGD,MAAA,GAAA,CAAI,UAAU,GAAK,EAAA;AAAA,QACjB,UAAY,EAAA,YAAA;AAAA,QACZ,eAAiB,EAAA,UAAA;AAAA,QACjB,cAAgB,EAAA,mBAAA;AAAA,OACjB,CAAA,CAAA;AAGD,MAAM,MAAA,YAAA,GAAe,WAAW,MAAO,CAAA,EAAE,QAAQ,KAAM,EAAC,EAAE,SAAU,CAAA;AAAA,QAClE,KAAA,EAAO,OAAM,KAAS,KAAA;AACpB,UAAO,MAAA,CAAA,KAAA;AAAA,YACL,CAAA,wDAAA,EAA2D,MAAM,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA;AAAA,WAC9E,CAAA;AACA,UAAA,MAAM,YAAY,QAAS,CAAA;AAAA,YACzB,SAAW,EAAA,sBAAA;AAAA,YACX,OAAA;AAAA,YACA,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,QAAA;AAAA,YACR,KAAO,EAAA,OAAA;AAAA,YACP,QAAU,EAAA;AAAA,cACR,MAAA;AAAA,aACF;AAAA,YACA,OAAS,EAAA,GAAA;AAAA,YACT,MAAQ,EAAA;AAAA,cACN;AAAA,gBACE,MAAM,KAAM,CAAA,IAAA;AAAA,gBACZ,SAAS,KAAM,CAAA,OAAA;AAAA,gBACf,OAAO,KAAM,CAAA,KAAA;AAAA,gBACb,OAAO,KAAM,CAAA,KAAA;AAAA,eACf;AAAA,aACF;AAAA,YACA,OAAS,EAAA,CAAA,yEAAA,EAA4E,MAAM,CAAA,cAAA,EAAiB,OAAO,CAAA,CAAA;AAAA,WACpH,CAAA,CAAA;AACD,UAAA,GAAA,CAAI,GAAI,EAAA,CAAA;AAAA,SACV;AAAA,QACA,IAAM,EAAA,CAAC,EAAE,MAAA,EAAa,KAAA;AACpB,UAAA,IAAI,iBAAoB,GAAA,KAAA,CAAA;AACxB,UAAA,KAAA,MAAW,SAAS,MAAQ,EAAA;AAC1B,YAAI,GAAA,CAAA,KAAA;AAAA,cACF,CAAA,OAAA,EAAU,MAAM,IAAI,CAAA;AAAA,MAAW,EAAA,IAAA,CAAK,SAAU,CAAA,KAAK,CAAC,CAAA;AAAA;AAAA,CAAA;AAAA,aACtD,CAAA;AACA,YAAI,IAAA,KAAA,CAAM,SAAS,YAAc,EAAA;AAC/B,cAAoB,iBAAA,GAAA,IAAA,CAAA;AAAA,aACtB;AAAA,WACF;AAEA,UAAA,GAAA,CAAI,KAAQ,IAAA,CAAA;AACZ,UAAA,IAAI,iBAAmB,EAAA;AACrB,YAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AACzB,YAAA,GAAA,CAAI,GAAI,EAAA,CAAA;AAAA,WACV;AAAA,SACF;AAAA,OACD,CAAA,CAAA;AAID,MAAI,GAAA,CAAA,EAAA,CAAG,SAAS,YAAY;AAC1B,QAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AACzB,QAAO,MAAA,CAAA,KAAA,CAAM,CAAkC,+BAAA,EAAA,MAAM,CAAU,QAAA,CAAA,CAAA,CAAA;AAC/D,QAAA,MAAM,YAAY,QAAS,CAAA;AAAA,UACzB,SAAW,EAAA,sBAAA;AAAA,UACX,OAAA;AAAA,UACA,KAAO,EAAA,YAAA;AAAA,UACP,MAAQ,EAAA,WAAA;AAAA,UACR,QAAU,EAAA;AAAA,YACR,MAAA;AAAA,WACF;AAAA,UACA,OAAS,EAAA,GAAA;AAAA,UACT,OAAS,EAAA,CAAA,qDAAA,EAAwD,MAAM,CAAA,eAAA,EAAkB,OAAO,CAAA,CAAA;AAAA,SACjG,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AAAA,aACM,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,sBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAS,EAAA,CAAA,yEAAA,EAA4E,MAAM,CAAA,cAAA,EAAiB,OAAO,CAAA,CAAA;AAAA,OACpH,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,GAAA,CAAI,0BAA4B,EAAA,OAAO,KAAK,GAAQ,KAAA;AACnD,IAAM,MAAA,EAAE,MAAO,EAAA,GAAI,GAAI,CAAA,MAAA,CAAA;AACvB,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,IAAI,IAAA;AACF,MAAA,MAAM,KAAQ,GAAA,MAAA,CAAO,GAAI,CAAA,KAAA,CAAM,KAAK,CAAK,IAAA,KAAA,CAAA,CAAA;AAEzC,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,0BAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,OAAS,EAAA,CAAA,4DAAA,EAA+D,MAAM,CAAA,cAAA,EAAiB,OAAO,CAAA,CAAA;AAAA,OACvG,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAClD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAACA,0BAAkB,CAAA;AAAA,QAChC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AAGD,MAAM,MAAA,OAAA,GAAU,WAAW,MAAM;AAC/B,QAAI,GAAA,CAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,SACV,GAAM,CAAA,CAAA;AAGT,MAAM,MAAA,YAAA,GAAe,WAAW,MAAO,CAAA,EAAE,QAAQ,KAAM,EAAC,EAAE,SAAU,CAAA;AAAA,QAClE,KAAA,EAAO,OAAM,KAAS,KAAA;AACpB,UAAO,MAAA,CAAA,KAAA;AAAA,YACL,CAAA,wDAAA,EAA2D,MAAM,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA;AAAA,WAC9E,CAAA;AACA,UAAA,MAAM,YAAY,QAAS,CAAA;AAAA,YACzB,SAAW,EAAA,0BAAA;AAAA,YACX,OAAA;AAAA,YACA,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,QAAA;AAAA,YACR,KAAO,EAAA,OAAA;AAAA,YACP,QAAU,EAAA;AAAA,cACR,MAAA;AAAA,aACF;AAAA,YACA,OAAS,EAAA,GAAA;AAAA,YACT,MAAQ,EAAA;AAAA,cACN;AAAA,gBACE,MAAM,KAAM,CAAA,IAAA;AAAA,gBACZ,SAAS,KAAM,CAAA,OAAA;AAAA,gBACf,OAAO,KAAM,CAAA,KAAA;AAAA,eACf;AAAA,aACF;AAAA,YACA,OAAS,EAAA,CAAA,4DAAA,EAA+D,MAAM,CAAA,cAAA,EAAiB,OAAO,CAAA,OAAA,CAAA;AAAA,WACvG,CAAA,CAAA;AAAA,SACH;AAAA,QACA,IAAM,EAAA,OAAO,EAAE,MAAA,EAAa,KAAA;AAC1B,UAAA,YAAA,CAAa,OAAO,CAAA,CAAA;AACpB,UAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AACzB,UAAA,MAAM,YAAY,QAAS,CAAA;AAAA,YACzB,SAAW,EAAA,0BAAA;AAAA,YACX,OAAA;AAAA,YACA,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,WAAA;AAAA,YACR,QAAU,EAAA;AAAA,cACR,MAAA;AAAA,aACF;AAAA,YACA,OAAS,EAAA,GAAA;AAAA,YACT,QAAU,EAAA;AAAA,cACR,MAAQ,EAAA,GAAA;AAAA,cACR,IAAM,EAAA,MAAA;AAAA,aACR;AAAA,YACA,OAAS,EAAA,CAAA,4DAAA,EAA+D,MAAM,CAAA,IAAA,EAAO,OAAO,CAAA,UAAA,CAAA;AAAA,WAC7F,CAAA,CAAA;AACD,UAAA,GAAA,CAAI,KAAK,MAAM,CAAA,CAAA;AAAA,SACjB;AAAA,OACD,CAAA,CAAA;AAID,MAAI,GAAA,CAAA,EAAA,CAAG,SAAS,MAAM;AACpB,QAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AACzB,QAAA,YAAA,CAAa,OAAO,CAAA,CAAA;AAAA,OACrB,CAAA,CAAA;AAAA,aACM,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,0BAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,QAAU,EAAA;AAAA,UACR,MAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAS,EAAA,CAAA,4DAAA,EAA+D,MAAM,CAAA,cAAA,EAAiB,OAAO,CAAA,OAAA,CAAA;AAAA,OACvG,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,IAAA,CAAK,aAAe,EAAA,OAAO,KAAK,GAAQ,KAAA;AACvC,IAAA,MAAM,OAAU,GAAA,MAAM,WAAY,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAChD,IAAI,IAAA;AACF,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,sBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,QAAU,EAAA,IAAA;AAAA,SACZ;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,OAAA,EAAS,wCAAwC,OAAO,CAAA,CAAA;AAAA,OACzD,CAAA,CAAA;AACD,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AAElD,MAAA,MAAM,eAAgB,CAAA;AAAA,QACpB,WAAA;AAAA,QACA,WAAA,EAAa,CAACH,4BAAoB,CAAA;AAAA,QAClC,iBAAmB,EAAA,WAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAM,MAAA,UAAA,GAAalG,MAAE,MAAO,CAAA;AAAA,QAC1B,QAAA,EAAUA,MAAE,OAAQ,EAAA;AAAA,QACpB,MAAQ,EAAAA,KAAA,CAAE,MAAO,CAAAA,KAAA,CAAE,SAAS,CAAA;AAAA,QAC5B,SAASA,KAAE,CAAA,MAAA,CAAOA,MAAE,MAAO,EAAC,EAAE,QAAS,EAAA;AAAA,QACvC,mBAAmBA,KAAE,CAAA,KAAA;AAAA,UACnBA,KAAA,CAAE,MAAO,CAAA,EAAE,IAAM,EAAAA,KAAA,CAAE,MAAO,EAAA,EAAG,aAAe,EAAAA,KAAA,CAAE,MAAO,EAAA,EAAG,CAAA;AAAA,SAC1D;AAAA,OACD,CAAA,CAAA;AACD,MAAM,MAAA,IAAA,GAAO,MAAM,UAAW,CAAA,UAAA,CAAW,IAAI,IAAI,CAAA,CAAE,MAAM,CAAK,CAAA,KAAA;AAC5D,QAAA,MAAM,IAAIF,iBAAA,CAAW,CAAsB,mBAAA,EAAA,CAAC,CAAE,CAAA,CAAA,CAAA;AAAA,OAC/C,CAAA,CAAA;AAED,MAAA,MAAM,WAAW,IAAK,CAAA,QAAA,CAAA;AACtB,MAAA,IAAI,CAAE,MAAMyG,qDAA+B,CAAA,KAAA,CAAM,QAAQ,CAAI,EAAA;AAC3D,QAAM,MAAA,IAAIzG,kBAAW,kCAAkC,CAAA,CAAA;AAAA,OACzD;AACA,MAAA,MAAM,WAAsB,GAAA,CAAA,EAAG,QAAS,CAAA,IAAI,CAC1C,CAAA,EAAA,QAAA,CAAS,QAAS,CAAA,SAAA,IAAa,SACjC,CAAA,CAAA,EAAI,QAAS,CAAA,QAAA,CAAS,IAAI,CAAA,CAAA,CAAA;AAE1B,MAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,QACjD,UAAY,EAAA,WAAA;AAAA,QACZ,cAAgB,EAAA,SAAA;AAAA,OACjB,CAAA,CAAA;AAED,MAAM,MAAA,aAAA,GAAgB,KAAK,WAAY,CAAA,WAAA,EAAa,MAAM,CACtD,GAAA,WAAA,CAAY,UAAU,aACtB,GAAA,KAAA,CAAA,CAAA;AACJ,MAAM,MAAA,UAAA,GAAa,gBACf,MAAM,aAAA,CAAc,eAAe,aAAe,EAAA,EAAE,KAAM,EAAC,CAC3D,GAAA,KAAA,CAAA,CAAA;AACJ,MAAW,KAAA,MAAA,UAAA,IAAc,CAAC,QAAS,CAAA,IAAA,CAAK,cAAc,EAAE,CAAE,CAAA,IAAA,EAAQ,EAAA;AAChE,QAAA,MAAMqG,OAAS,GAAAC,mBAAA,CAAS,IAAK,CAAA,MAAA,EAAQ,UAAU,CAAA,CAAA;AAC/C,QAAI,IAAA,CAACD,QAAO,KAAO,EAAA;AACjB,UAAA,MAAM,YAAY,QAAS,CAAA;AAAA,YACzB,SAAW,EAAA,sBAAA;AAAA,YACX,OAAA;AAAA,YACA,KAAO,EAAA,YAAA;AAAA,YACP,MAAQ,EAAA,QAAA;AAAA,YACR,KAAO,EAAA,OAAA;AAAA,YACP,QAAU,EAAA;AAAA,cACR,WAAA;AAAA,cACA,UAAA,EAAY,SAAS,IAAK,CAAA,UAAA;AAAA,cAC1B,QAAU,EAAA,IAAA;AAAA,aACZ;AAAA,YACA,QAAQA,OAAO,CAAA,MAAA;AAAA,YACf,OAAS,EAAA,GAAA;AAAA,YACT,QAAU,EAAA;AAAA,cACR,MAAQ,EAAA,GAAA;AAAA,cACR,IAAM,EAAA,EAAE,MAAQA,EAAAA,OAAAA,CAAO,MAAO,EAAA;AAAA,aAChC;AAAA,YACA,OAAS,EAAA,CAAA,4BAAA,EAA+B,WAAW,CAAA,cAAA,EAAiB,OAAO,CAAA,OAAA,CAAA;AAAA,WAC5E,CAAA,CAAA;AACD,UAAO,OAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,MAAA,EAAQA,OAAO,CAAA,MAAA,EAAQ,CAAA,CAAA;AAAA,SACvD;AAAA,OACF;AAEA,MAAA,MAAM,QAAQ,QAAS,CAAA,IAAA,CAAK,MAAM,GAAI,CAAA,CAAC,MAAM,KAAW,MAAA;AAAA,QACtD,GAAG,IAAA;AAAA,QACH,EAAI,EAAA,IAAA,CAAK,EAAM,IAAA,CAAA,KAAA,EAAQ,QAAQ,CAAC,CAAA,CAAA;AAAA,QAChC,IAAA,EAAM,IAAK,CAAA,IAAA,IAAQ,IAAK,CAAA,MAAA;AAAA,OACxB,CAAA,CAAA,CAAA;AAEF,MAAM,MAAA,MAAA,GAAS,MAAM,SAAU,CAAA;AAAA,QAC7B,IAAM,EAAA;AAAA,UACJ,YAAY,QAAS,CAAA,UAAA;AAAA,UACrB,KAAA;AAAA,UACA,MAAQ,EAAA,QAAA,CAAS,IAAK,CAAA,MAAA,IAAU,EAAC;AAAA,UACjC,YAAY,IAAK,CAAA,MAAA;AAAA,UACjB,IAAM,EAAA;AAAA,YACJ,MAAQ,EAAA,UAAA;AAAA,YACR,GAAK,EAAA,aAAA;AAAA,WACP;AAAA,SACF;AAAA,QACA,oBAAoB,IAAK,CAAA,iBAAA,IAAqB,EAAC,EAAG,IAAI,CAAS,IAAA,MAAA;AAAA,UAC7D,MAAM,IAAK,CAAA,IAAA;AAAA,UACX,OAAS,EAAA,MAAA,CAAO,IAAK,CAAA,IAAA,CAAK,eAAe,QAAQ,CAAA;AAAA,SACjD,CAAA,CAAA;AAAA,QACF,OAAS,EAAA;AAAA,UACP,GAAG,IAAK,CAAA,OAAA;AAAA,UACR,GAAI,KAAA,IAAS,EAAE,cAAA,EAAgB,KAAM,EAAA;AAAA,SACvC;AAAA,QACA,WAAA;AAAA,OACD,CAAA,CAAA;AAED,MAAA,MAAM,aAAgB,GAAA;AAAA,QACpB,GAAG,MAAA;AAAA,QACH,KAAA;AAAA,QACA,iBAAmB,EAAA,MAAA,CAAO,iBAAkB,CAAA,GAAA,CAAI,CAAS,IAAA,MAAA;AAAA,UACvD,MAAM,IAAK,CAAA,IAAA;AAAA,UACX,YAAY,IAAK,CAAA,UAAA;AAAA,UACjB,aAAe,EAAA,IAAA,CAAK,OAAQ,CAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,SAC7C,CAAA,CAAA;AAAA,OACJ,CAAA;AACA,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,sBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,WAAA;AAAA,QACR,QAAU,EAAA;AAAA,UACR,WAAA;AAAA,UACA,UAAA,EAAY,SAAS,IAAK,CAAA,UAAA;AAAA,UAC1B,QAAU,EAAA,IAAA;AAAA,SACZ;AAAA,QACA,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA,GAAA;AAAA,UACR,IAAM,EAAA,aAAA;AAAA,SACR;AAAA,QACA,OAAS,EAAA,CAAA,4BAAA,EAA+B,WAAW,CAAA,cAAA,EAAiB,OAAO,CAAA,uBAAA,CAAA;AAAA,OAC5E,CAAA,CAAA;AACD,MAAA,OAAO,GAAI,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,aAAa,CAAA,CAAA;AAAA,aAClC,GAAK,EAAA;AACZ,MAAA,MAAM,YAAY,QAAS,CAAA;AAAA,QACzB,SAAW,EAAA,sBAAA;AAAA,QACX,OAAA;AAAA,QACA,KAAO,EAAA,YAAA;AAAA,QACP,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,OAAS,EAAA,GAAA;AAAA,QACT,QAAU,EAAA;AAAA,UACR,QAAU,EAAA,IAAA;AAAA,SACZ;AAAA,QACA,MAAQ,EAAA;AAAA,UACN;AAAA,YACE,MAAM,GAAI,CAAA,IAAA;AAAA,YACV,SAAS,GAAI,CAAA,OAAA;AAAA,YACb,OAAO,GAAI,CAAA,KAAA;AAAA,WACb;AAAA,SACF;AAAA,QACA,OAAA,EAAS,wCAAwC,OAAO,CAAA,OAAA,CAAA;AAAA,OACzD,CAAA,CAAA;AACD,MAAM,MAAA,GAAA,CAAA;AAAA,KACR;AAAA,GACD,CACA,CAAA,IAAA,CAAK,sCAAwC,EAAA,OAAO,KAAK,GAAQ,KAAA;AAChE,IAAA,MAAM,EAAE,KAAA,EAAO,OAAQ,EAAA,GAAI,GAAI,CAAA,IAAA,CAAA;AAC/B,IAAA,MAAM,EAAE,QAAA,EAAU,QAAS,EAAA,GAAI,GAAI,CAAA,MAAA,CAAA;AAEnC,IAAA,IAAI,CAAC,KAAA,EAAa,MAAA,IAAIrG,kBAAW,+BAA+B,CAAA,CAAA;AAEhE,IAAI,IAAA,CAAC,oBAAqB,CAAA,QAAQ,CAAG,EAAA;AACnC,MAAA,MAAM,IAAIA,iBAAA,CAAW,CAAyB,sBAAA,EAAA,QAAQ,CAAE,CAAA,CAAA,CAAA;AAAA,KAC1D;AAEA,IAAA,MAAM,EAAE,OAAQ,EAAA,GAAI,MAAM,oBAAA,CAAqB,QAAQ,CAAE,CAAA;AAAA,MACvD,QAAA;AAAA,MACA,KAAA;AAAA,MACA,OAAA;AAAA,KACD,CAAA,CAAA;AAED,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,IAAK,CAAA,EAAE,SAAS,CAAA,CAAA;AAAA,GACjC,CAAA,CAAA;AAEH,EAAA,MAAM,MAAM0F,wBAAQ,EAAA,CAAA;AACpB,EAAI,GAAA,CAAA,GAAA,CAAI,UAAU,MAAM,CAAA,CAAA;AACxB,EAAI,GAAA,CAAA,GAAA,CAAI,KAAK,MAAM,CAAA,CAAA;AAEnB,EAAe,eAAA,iBAAA,CACb,SACA,EAAA,KAAA,EACA,WACA,EAAA;AACA,IAAM,MAAA,QAAA,GAAW,MAAM,YAAa,CAAA;AAAA,MAClC,UAAY,EAAA,aAAA;AAAA,MACZ,SAAA;AAAA,MACA,KAAA;AAAA,KACD,CAAA,CAAA;AAED,IAAI,IAAA,CAAC,mBAAoB,CAAA,QAAQ,CAAG,EAAA;AAClC,MAAA,MAAM,IAAI1F,iBAAA;AAAA,QACR,CAAA,+CAAA,EACG,SAAoB,UACvB,CAAA,CAAA;AAAA,OACF,CAAA;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,WAAa,EAAA;AAChB,MAAO,OAAA,QAAA,CAAA;AAAA,KACT;AAEA,IAAA,MAAM,CAAC,iBAAA,EAAmB,YAAY,CAAA,GACpC,MAAM,WAAY,CAAA,oBAAA;AAAA,MAChB;AAAA,QACE,EAAE,YAAY0G,uCAAgC,EAAA;AAAA,QAC9C,EAAE,YAAYC,kCAA2B,EAAA;AAAA,OAC3C;AAAA,MACA,EAAE,WAAY,EAAA;AAAA,KAChB,CAAA;AAGF,IAAA,IAAI,KAAM,CAAA,OAAA,CAAQ,QAAS,CAAA,IAAA,CAAK,UAAU,CAAG,EAAA;AAC3C,MAAA,QAAA,CAAS,IAAK,CAAA,UAAA,GAAa,QAAS,CAAA,IAAA,CAAK,UAAW,CAAA,MAAA;AAAA,QAAO,CAAA,IAAA,KACzD,YAAa,CAAA,iBAAA,EAAmB,IAAI,CAAA;AAAA,OACtC,CAAA;AAAA,KACF,MAAA,IACE,QAAS,CAAA,IAAA,CAAK,UACd,IAAA,CAAC,aAAa,iBAAmB,EAAA,QAAA,CAAS,IAAK,CAAA,UAAU,CACzD,EAAA;AACA,MAAA,QAAA,CAAS,KAAK,UAAa,GAAA,KAAA,CAAA,CAAA;AAAA,KAC7B;AAGA,IAAA,QAAA,CAAS,IAAK,CAAA,KAAA,GAAQ,QAAS,CAAA,IAAA,CAAK,KAAM,CAAA,MAAA;AAAA,MAAO,CAAA,IAAA,KAC/C,YAAa,CAAA,YAAA,EAAc,IAAI,CAAA;AAAA,KACjC,CAAA;AAEA,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,GAAA,CAAA;AACT;;;;;;;;;;;;;;;;;;;;;"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js b/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js -index 60e060d..425c731 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js -@@ -46,6 +46,7 @@ require('winston-transport'); - require('triple-beam'); - require('url'); - require('os'); -+require('@janus-idp/backstage-plugin-audit-log-node'); - - function _interopNamespaceCompat(e) { - if (e && typeof e === 'object' && 'default' in e) return e; -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js.map b/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js.map -index 09db63c..a7a2801 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js.map -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/index.cjs.js.map -@@ -1 +1 @@ --{"version":3,"file":"index.cjs.js","sources":["../src/scaffolder/actions/deprecated.ts","../src/deprecated.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as github from '@backstage/plugin-scaffolder-backend-module-github';\nimport * as gitlab from '@backstage/plugin-scaffolder-backend-module-gitlab';\nimport * as azure from '@backstage/plugin-scaffolder-backend-module-azure';\nimport * as bitbucket from '@backstage/plugin-scaffolder-backend-module-bitbucket';\nimport * as bitbucketCloud from '@backstage/plugin-scaffolder-backend-module-bitbucket-cloud';\nimport * as bitbucketServer from '@backstage/plugin-scaffolder-backend-module-bitbucket-server';\nimport * as gerrit from '@backstage/plugin-scaffolder-backend-module-gerrit';\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubActionsDispatchAction =\n github.createGithubActionsDispatchAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubDeployKeyAction = github.createGithubDeployKeyAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubEnvironmentAction =\n github.createGithubEnvironmentAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubIssuesLabelAction =\n github.createGithubIssuesLabelAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport type CreateGithubPullRequestActionOptions =\n github.CreateGithubPullRequestActionOptions;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubRepoCreateAction = github.createGithubRepoCreateAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubRepoPushAction = github.createGithubRepoPushAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubWebhookAction = github.createGithubWebhookAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createPublishGithubAction = github.createPublishGithubAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createPublishGithubPullRequestAction =\n github.createPublishGithubPullRequestAction;\n\n/**\n * @public @deprecated use \"createPublishBitbucketCloudAction\" from \\@backstage/plugin-scaffolder-backend-module-bitbucket-cloud or \"createPublishBitbucketServerAction\" from \\@backstage/plugin-scaffolder-backend-module-bitbucket-server instead\n */\nexport const createPublishBitbucketAction =\n bitbucket.createPublishBitbucketAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead\n */\nexport const createPublishBitbucketCloudAction =\n bitbucketCloud.createPublishBitbucketCloudAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-bitbucket-server instead\n */\nexport const createPublishBitbucketServerAction =\n bitbucketServer.createPublishBitbucketServerAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-bitbucket-server instead\n */\nexport const createPublishBitbucketServerPullRequestAction =\n bitbucketServer.createPublishBitbucketServerPullRequestAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-azure instead\n */\nexport const createPublishAzureAction = azure.createPublishAzureAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gerrit instead\n */\nexport const createPublishGerritAction = gerrit.createPublishGerritAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gerrit instead\n */\nexport const createPublishGerritReviewAction =\n gerrit.createPublishGerritReviewAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gitlab instead\n */\nexport const createPublishGitlabAction = gitlab.createPublishGitlabAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gitlab instead\n */\nexport const createPublishGitlabMergeRequestAction =\n gitlab.createPublishGitlabMergeRequestAction;\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ActionContext as ActionContextNode,\n createTemplateAction as createTemplateActionNode,\n TaskSecrets as TaskSecretsNode,\n TemplateAction as TemplateActionNode,\n executeShellCommand as executeShellCommandNode,\n ExecuteShellCommandOptions as ExecuteShellCommandOptionsNode,\n fetchContents as fetchContentsNode,\n} from '@backstage/plugin-scaffolder-node';\nimport { JsonObject } from '@backstage/types';\nimport { ScaffolderEntitiesProcessor as ScaffolderEntitiesProcessorModule } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model';\n\n/**\n * @public\n * @deprecated Import from {@link @backstage/plugin-scaffolder-node#ActionContext} instead\n */\nexport type ActionContext =\n ActionContextNode;\n\n/**\n * @public\n * @deprecated Use `createTemplateAction` from `@backstage/plugin-scaffolder-node` instead\n */\nexport const createTemplateAction = createTemplateActionNode;\n\n/**\n * @public\n * @deprecated Use `TaskSecrets` from `@backstage/plugin-scaffolder-node` instead\n */\nexport type TaskSecrets = TaskSecretsNode;\n\n/**\n * @public\n * @deprecated Use `TemplateAction` from `@backstage/plugin-scaffolder-node` instead\n */\nexport type TemplateAction =\n TemplateActionNode;\n\n/**\n * Options for {@link executeShellCommand}.\n *\n * @public\n * @deprecated Use `ExecuteShellCommandOptions` from `@backstage/plugin-scaffolder-node` instead\n */\nexport type RunCommandOptions = ExecuteShellCommandOptionsNode;\n\n/**\n * Run a command in a sub-process, normally a shell command.\n *\n * @public\n * @deprecated Use `executeShellCommand` from `@backstage/plugin-scaffolder-node` instead\n */\nexport const executeShellCommand = executeShellCommandNode;\n\n/**\n * A helper function that reads the contents of a directory from the given URL.\n * Can be used in your own actions, and also used behind fetch:template and fetch:plain\n *\n * @public\n * @deprecated Use `fetchContents` from `@backstage/plugin-scaffolder-node` instead\n */\nexport const fetchContents = fetchContentsNode;\n\n/**\n * Adds support for scaffolder specific entity kinds to the catalog.\n *\n * @public\n * @deprecated Import from `@backstage/plugin-catalog-backend-module-scaffolder-entity-model` instead\n */\nexport const ScaffolderEntitiesProcessor = ScaffolderEntitiesProcessorModule;\n"],"names":["github","bitbucket","bitbucketCloud","bitbucketServer","azure","gerrit","gitlab","createTemplateActionNode","executeShellCommandNode","fetchContentsNode","ScaffolderEntitiesProcessorModule"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BO,MAAM,oCACXA,iBAAO,CAAA,kCAAA;AAKF,MAAM,8BAA8BA,iBAAO,CAAA,4BAAA;AAK3C,MAAM,gCACXA,iBAAO,CAAA,8BAAA;AAKF,MAAM,gCACXA,iBAAO,CAAA,8BAAA;AAWF,MAAM,+BAA+BA,iBAAO,CAAA,6BAAA;AAK5C,MAAM,6BAA6BA,iBAAO,CAAA,2BAAA;AAK1C,MAAM,4BAA4BA,iBAAO,CAAA,0BAAA;AAKzC,MAAM,4BAA4BA,iBAAO,CAAA,0BAAA;AAKzC,MAAM,uCACXA,iBAAO,CAAA,qCAAA;AAKF,MAAM,+BACXC,oBAAU,CAAA,6BAAA;AAKL,MAAM,oCACXC,yBAAe,CAAA,kCAAA;AAKV,MAAM,qCACXC,0BAAgB,CAAA,mCAAA;AAKX,MAAM,gDACXA,0BAAgB,CAAA,8CAAA;AAKX,MAAM,2BAA2BC,gBAAM,CAAA,yBAAA;AAKvC,MAAM,4BAA4BC,iBAAO,CAAA,0BAAA;AAKzC,MAAM,kCACXA,iBAAO,CAAA,gCAAA;AAKF,MAAM,4BAA4BC,iBAAO,CAAA,0BAAA;AAKzC,MAAM,wCACXA,iBAAO,CAAA;;ACxFF,MAAM,oBAAuB,GAAAC,0CAAA;AA6B7B,MAAM,mBAAsB,GAAAC,yCAAA;AAS5B,MAAM,aAAgB,GAAAC,mCAAA;AAQtB,MAAM,2BAA8B,GAAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} -\ No newline at end of file -+{"version":3,"file":"index.cjs.js","sources":["../src/scaffolder/actions/deprecated.ts","../src/deprecated.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as github from '@backstage/plugin-scaffolder-backend-module-github';\nimport * as gitlab from '@backstage/plugin-scaffolder-backend-module-gitlab';\nimport * as azure from '@backstage/plugin-scaffolder-backend-module-azure';\nimport * as bitbucket from '@backstage/plugin-scaffolder-backend-module-bitbucket';\nimport * as bitbucketCloud from '@backstage/plugin-scaffolder-backend-module-bitbucket-cloud';\nimport * as bitbucketServer from '@backstage/plugin-scaffolder-backend-module-bitbucket-server';\nimport * as gerrit from '@backstage/plugin-scaffolder-backend-module-gerrit';\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubActionsDispatchAction =\n github.createGithubActionsDispatchAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubDeployKeyAction = github.createGithubDeployKeyAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubEnvironmentAction =\n github.createGithubEnvironmentAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubIssuesLabelAction =\n github.createGithubIssuesLabelAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport type CreateGithubPullRequestActionOptions =\n github.CreateGithubPullRequestActionOptions;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubRepoCreateAction = github.createGithubRepoCreateAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubRepoPushAction = github.createGithubRepoPushAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createGithubWebhookAction = github.createGithubWebhookAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createPublishGithubAction = github.createPublishGithubAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-github instead\n */\nexport const createPublishGithubPullRequestAction =\n github.createPublishGithubPullRequestAction;\n\n/**\n * @public @deprecated use \"createPublishBitbucketCloudAction\" from \\@backstage/plugin-scaffolder-backend-module-bitbucket-cloud or \"createPublishBitbucketServerAction\" from \\@backstage/plugin-scaffolder-backend-module-bitbucket-server instead\n */\nexport const createPublishBitbucketAction =\n bitbucket.createPublishBitbucketAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead\n */\nexport const createPublishBitbucketCloudAction =\n bitbucketCloud.createPublishBitbucketCloudAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-bitbucket-server instead\n */\nexport const createPublishBitbucketServerAction =\n bitbucketServer.createPublishBitbucketServerAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-bitbucket-server instead\n */\nexport const createPublishBitbucketServerPullRequestAction =\n bitbucketServer.createPublishBitbucketServerPullRequestAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-azure instead\n */\nexport const createPublishAzureAction = azure.createPublishAzureAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gerrit instead\n */\nexport const createPublishGerritAction = gerrit.createPublishGerritAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gerrit instead\n */\nexport const createPublishGerritReviewAction =\n gerrit.createPublishGerritReviewAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gitlab instead\n */\nexport const createPublishGitlabAction = gitlab.createPublishGitlabAction;\n\n/**\n * @public @deprecated use import from \\@backstage/plugin-scaffolder-backend-module-gitlab instead\n */\nexport const createPublishGitlabMergeRequestAction =\n gitlab.createPublishGitlabMergeRequestAction;\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ActionContext as ActionContextNode,\n createTemplateAction as createTemplateActionNode,\n TaskSecrets as TaskSecretsNode,\n TemplateAction as TemplateActionNode,\n executeShellCommand as executeShellCommandNode,\n ExecuteShellCommandOptions as ExecuteShellCommandOptionsNode,\n fetchContents as fetchContentsNode,\n} from '@backstage/plugin-scaffolder-node';\nimport { JsonObject } from '@backstage/types';\nimport { ScaffolderEntitiesProcessor as ScaffolderEntitiesProcessorModule } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model';\n\n/**\n * @public\n * @deprecated Import from {@link @backstage/plugin-scaffolder-node#ActionContext} instead\n */\nexport type ActionContext =\n ActionContextNode;\n\n/**\n * @public\n * @deprecated Use `createTemplateAction` from `@backstage/plugin-scaffolder-node` instead\n */\nexport const createTemplateAction = createTemplateActionNode;\n\n/**\n * @public\n * @deprecated Use `TaskSecrets` from `@backstage/plugin-scaffolder-node` instead\n */\nexport type TaskSecrets = TaskSecretsNode;\n\n/**\n * @public\n * @deprecated Use `TemplateAction` from `@backstage/plugin-scaffolder-node` instead\n */\nexport type TemplateAction =\n TemplateActionNode;\n\n/**\n * Options for {@link executeShellCommand}.\n *\n * @public\n * @deprecated Use `ExecuteShellCommandOptions` from `@backstage/plugin-scaffolder-node` instead\n */\nexport type RunCommandOptions = ExecuteShellCommandOptionsNode;\n\n/**\n * Run a command in a sub-process, normally a shell command.\n *\n * @public\n * @deprecated Use `executeShellCommand` from `@backstage/plugin-scaffolder-node` instead\n */\nexport const executeShellCommand = executeShellCommandNode;\n\n/**\n * A helper function that reads the contents of a directory from the given URL.\n * Can be used in your own actions, and also used behind fetch:template and fetch:plain\n *\n * @public\n * @deprecated Use `fetchContents` from `@backstage/plugin-scaffolder-node` instead\n */\nexport const fetchContents = fetchContentsNode;\n\n/**\n * Adds support for scaffolder specific entity kinds to the catalog.\n *\n * @public\n * @deprecated Import from `@backstage/plugin-catalog-backend-module-scaffolder-entity-model` instead\n */\nexport const ScaffolderEntitiesProcessor = ScaffolderEntitiesProcessorModule;\n"],"names":["github","bitbucket","bitbucketCloud","bitbucketServer","azure","gerrit","gitlab","createTemplateActionNode","executeShellCommandNode","fetchContentsNode","ScaffolderEntitiesProcessorModule"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BO,MAAM,oCACXA,iBAAO,CAAA,kCAAA;AAKF,MAAM,8BAA8BA,iBAAO,CAAA,4BAAA;AAK3C,MAAM,gCACXA,iBAAO,CAAA,8BAAA;AAKF,MAAM,gCACXA,iBAAO,CAAA,8BAAA;AAWF,MAAM,+BAA+BA,iBAAO,CAAA,6BAAA;AAK5C,MAAM,6BAA6BA,iBAAO,CAAA,2BAAA;AAK1C,MAAM,4BAA4BA,iBAAO,CAAA,0BAAA;AAKzC,MAAM,4BAA4BA,iBAAO,CAAA,0BAAA;AAKzC,MAAM,uCACXA,iBAAO,CAAA,qCAAA;AAKF,MAAM,+BACXC,oBAAU,CAAA,6BAAA;AAKL,MAAM,oCACXC,yBAAe,CAAA,kCAAA;AAKV,MAAM,qCACXC,0BAAgB,CAAA,mCAAA;AAKX,MAAM,gDACXA,0BAAgB,CAAA,8CAAA;AAKX,MAAM,2BAA2BC,gBAAM,CAAA,yBAAA;AAKvC,MAAM,4BAA4BC,iBAAO,CAAA,0BAAA;AAKzC,MAAM,kCACXA,iBAAO,CAAA,gCAAA;AAKF,MAAM,4BAA4BC,iBAAO,CAAA,0BAAA;AAKzC,MAAM,wCACXA,iBAAO,CAAA;;ACxFF,MAAM,oBAAuB,GAAAC,0CAAA;AA6B7B,MAAM,mBAAsB,GAAAC,yCAAA;AAS5B,MAAM,aAAgB,GAAAC,mCAAA;AAQtB,MAAM,2BAA8B,GAAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} -\ No newline at end of file -diff --git a/node_modules/@backstage/plugin-scaffolder-backend/dist/index.d.ts b/node_modules/@backstage/plugin-scaffolder-backend/dist/index.d.ts -index 0b52bb5..d76843d 100644 ---- a/node_modules/@backstage/plugin-scaffolder-backend/dist/index.d.ts -+++ b/node_modules/@backstage/plugin-scaffolder-backend/dist/index.d.ts -@@ -22,14 +22,15 @@ import * as _backstage_plugin_scaffolder_common from '@backstage/plugin-scaffold - import { TaskSpec, TaskRecovery, TemplateEntityStepV1beta3, TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; - import { Logger } from 'winston'; - import { WorkspaceProvider, AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; -+import { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node'; - import { PermissionEvaluator, PermissionRuleParams } from '@backstage/plugin-permission-common'; - import { PluginTaskScheduler } from '@backstage/backend-tasks'; - import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, RESOURCE_TYPE_SCAFFOLDER_ACTION } from '@backstage/plugin-scaffolder-common/alpha'; - import express from 'express'; - import { PermissionRule } from '@backstage/plugin-permission-node'; - import { IdentityApi } from '@backstage/plugin-auth-node'; --import * as jsonschema from 'jsonschema'; - import * as zod from 'zod'; -+import * as jsonschema from 'jsonschema'; - import { ScaffolderEntitiesProcessor as ScaffolderEntitiesProcessor$1 } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'; - - /** -@@ -67,14 +68,14 @@ declare function createFetchCatalogEntityAction(options: { - catalogClient: CatalogApi; - auth?: AuthService; - }): _backstage_plugin_scaffolder_node.TemplateAction<{ -- optional?: boolean | undefined; -+ entityRef?: string | undefined; - defaultKind?: string | undefined; - defaultNamespace?: string | undefined; -- entityRef?: string | undefined; - entityRefs?: string[] | undefined; -+ optional?: boolean | undefined; - }, { -- entities?: any[] | undefined; - entity?: any; -+ entities?: any[] | undefined; - }>; - - /** -@@ -331,7 +332,7 @@ declare const createPublishGitlabMergeRequestAction: (options: { - sourcePath?: string | undefined; - targetPath?: string | undefined; - token?: string | undefined; -- commitAction?: "update" | "delete" | "create" | undefined; -+ commitAction?: "update" | "create" | "delete" | undefined; - projectid?: string | undefined; - removeSourceBranch?: boolean | undefined; - assignee?: string | undefined; -@@ -609,11 +610,13 @@ declare class TaskManager implements TaskContext$1 { - private readonly signal; - private readonly logger; - private readonly workspaceService; -+ private readonly auditLogger; - private readonly auth?; - private isDone; - private heartbeatTimeoutId?; -- static create(task: CurrentClaimedTask, storage: TaskStore, abortSignal: AbortSignal, logger: Logger, auth?: AuthService, config?: Config, additionalWorkspaceProviders?: Record): TaskManager; -+ static create(task: CurrentClaimedTask, storage: TaskStore, abortSignal: AbortSignal, logger: Logger, auditLogger: AuditLogger, auth?: AuthService, config?: Config, additionalWorkspaceProviders?: Record): TaskManager; - private constructor(); -+ get taskId(): string; - get spec(): _backstage_plugin_scaffolder_common.TaskSpecV1beta3; - get cancelSignal(): AbortSignal; - get secrets(): TaskSecrets$1 | undefined; -@@ -685,6 +688,7 @@ type CreateWorkerOptions = { - integrations: ScmIntegrations; - workingDirectory: string; - logger: Logger; -+ auditLogger: AuditLogger; - additionalTemplateFilters?: Record; - /** - * The number of tasks that can be executed at the same time by the worker -@@ -712,6 +716,7 @@ declare class TaskWorker { - private taskQueue; - private logger; - private stopWorkers; -+ private auditLogger; - private constructor(); - static create(options: CreateWorkerOptions): Promise; - recoverTasks(): Promise; -@@ -793,7 +798,7 @@ type ActionContext = ActionContext$1; - * @public - * @deprecated Use `createTemplateAction` from `@backstage/plugin-scaffolder-node` instead - */ --declare const createTemplateAction: | jsonschema.Schema = {}, TOutputSchema extends zod.ZodType | jsonschema.Schema = {}, TActionInput extends JsonObject = TInputSchema extends zod.ZodType ? IReturn : TInputParams, TActionOutput extends JsonObject = TOutputSchema extends zod.ZodType ? IReturn_1 : TOutputParams>(action: _backstage_plugin_scaffolder_node.TemplateActionOptions) => TemplateAction$1; -+declare const createTemplateAction: = {}, TOutputSchema extends jsonschema.Schema | zod.ZodType = {}, TActionInput extends JsonObject = TInputSchema extends zod.ZodType ? IReturn : TInputParams, TActionOutput extends JsonObject = TOutputSchema extends zod.ZodType ? IReturn_1 : TOutputParams>(action: _backstage_plugin_scaffolder_node.TemplateActionOptions) => TemplateAction$1; - /** - * @public - * @deprecated Use `TaskSecrets` from `@backstage/plugin-scaffolder-node` instead diff --git a/patches/@backstage+plugin-scaffolder-node+0.4.8.patch b/patches/@backstage+plugin-scaffolder-node+0.4.8.patch deleted file mode 100644 index ef5c49781c..0000000000 --- a/patches/@backstage+plugin-scaffolder-node+0.4.8.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/node_modules/@backstage/plugin-scaffolder-node/dist/index.d.ts b/node_modules/@backstage/plugin-scaffolder-node/dist/index.d.ts -index a2648fb..4f587b1 100644 ---- a/node_modules/@backstage/plugin-scaffolder-node/dist/index.d.ts -+++ b/node_modules/@backstage/plugin-scaffolder-node/dist/index.d.ts -@@ -89,6 +89,7 @@ type TaskBrokerDispatchOptions = { - * @public - */ - interface TaskContext { -+ taskId: string; - cancelSignal: AbortSignal; - spec: TaskSpec; - secrets?: TaskSecrets; -@@ -234,7 +235,7 @@ type TemplateActionOptions | Schema = {}, TOutputSchema extends z.ZodType | Schema = {}, TActionInput extends JsonObject = TInputSchema extends z.ZodType ? IReturn : TInputParams, TActionOutput extends JsonObject = TOutputSchema extends z.ZodType ? IReturn_1 : TOutputParams>(action: TemplateActionOptions) => TemplateAction; -+declare const createTemplateAction: = {}, TOutputSchema extends Schema | z.ZodType = {}, TActionInput extends JsonObject = TInputSchema extends z.ZodType ? IReturn : TInputParams, TActionOutput extends JsonObject = TOutputSchema extends z.ZodType ? IReturn_1 : TOutputParams>(action: TemplateActionOptions) => TemplateAction; - - /** - * Options for {@link executeShellCommand}. diff --git a/plugins/auth-backend-module-oidc-provider/README.md b/plugins/auth-backend-module-oidc-provider/README.md deleted file mode 100644 index 23aedc2541..0000000000 --- a/plugins/auth-backend-module-oidc-provider/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Auth Module: Oidc Provider - -**This is a forked version of the Upstream Backstage Auth Backend Module OIDC Provider** - -This module provides an Oidc auth provider implementation for `@backstage/plugin-auth-backend`. - -## Links - -- [Repository](https://oidc.com/backstage/backstage/tree/master/plugins/auth-backend-module-oidc-provider) -- [Backstage Project Homepage](https://backstage.io) diff --git a/plugins/auth-backend-module-oidc-provider/config.d.ts b/plugins/auth-backend-module-oidc-provider/config.d.ts deleted file mode 100644 index 9c96e7ea28..0000000000 --- a/plugins/auth-backend-module-oidc-provider/config.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020 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 interface Config { - auth?: { - providers?: { - /** @visibility frontend */ - oidc?: { - [authEnv: string]: { - clientId: string; - /** - * @visibility secret - */ - clientSecret: string; - metadataUrl: string; - callbackUrl?: string; - tokenEndpointAuthMethod?: string; - tokenSignedResponseAlg?: string; - scope?: string; - prompt?: string; - signIn?: { - resolvers?: Array<{ resolver: string }>; - }; - }; - }; - }; - }; -} diff --git a/plugins/auth-backend-module-oidc-provider/dev/index.ts b/plugins/auth-backend-module-oidc-provider/dev/index.ts deleted file mode 100644 index d3c18c1d48..0000000000 --- a/plugins/auth-backend-module-oidc-provider/dev/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 { createBackend } from '@backstage/backend-defaults'; - -const backend = createBackend(); - -backend.add(import('@backstage/plugin-auth-backend')); -backend.add(import('../src')); - -backend.start(); diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json deleted file mode 100644 index 79b218ae8c..0000000000 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@internal/plugin-auth-backend-module-oidc-provider", - "description": "The oidc-provider backend module for the auth plugin.", - "version": "0.1.0", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "publishConfig": { - "access": "public", - "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" - }, - "repository": { - "type": "git", - "url": "https://github.com/backstage/backstage", - "directory": "plugins/auth-backend-module-oidc-provider" - }, - "backstage": { - "role": "backend-plugin-module", - "pluginId": "auth", - "pluginPackage": "@backstage/plugin-auth-backend" - }, - "scripts": { - "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-common": "0.23.3", - "@backstage/backend-plugin-api": "0.7.0", - "@backstage/plugin-auth-backend": "0.22.9", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.2.3", - "@backstage/plugin-auth-node": "0.4.17", - "express": "4.19.2", - "openid-client": "5.6.5", - "passport": "0.7.0" - }, - "devDependencies": { - "@backstage/backend-defaults": "0.4.1", - "@backstage/backend-test-utils": "0.4.4", - "@backstage/cli": "0.26.11", - "@backstage/config": "1.2.0", - "cookie-parser": "1.4.6", - "express-promise-router": "4.1.1", - "express-session": "1.18.0", - "jose": "5.7.0", - "msw": "1.3.3", - "supertest": "6.3.4" - }, - "configSchema": "config.d.ts", - "files": [ - "dist", - "config.d.ts" - ] -} diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts deleted file mode 100644 index c6e2c2d461..0000000000 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts +++ /dev/null @@ -1,437 +0,0 @@ -/* - * 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 { registerMswTestHooks } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; -import { - OAuthAuthenticatorAuthenticateInput, - OAuthAuthenticatorRefreshInput, - OAuthAuthenticatorStartInput, - OAuthState, - decodeOAuthState, - encodeOAuthState, -} from '@backstage/plugin-auth-node'; -import express from 'express'; -import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; -import { oidcAuthenticator } from './authenticator'; - -describe('oidcAuthenticator', () => { - let implementation: any; - let oauthState: OAuthState; - let idToken: string; - let publicKey: JWK; - - const mswServer = setupServer(); - registerMswTestHooks(mswServer); - - const issuerMetadata = { - issuer: 'https://oidc.test', - authorization_endpoint: 'https://oidc.test/oauth2/authorize', - token_endpoint: 'https://oidc.test/oauth2/token', - revocation_endpoint: 'https://oidc.test/oauth2/revoke_token', - userinfo_endpoint: 'https://oidc.test/idp/userinfo.openid', - introspection_endpoint: 'https://oidc.test/introspect.oauth2', - jwks_uri: 'https://oidc.test/jwks.json', - scopes_supported: [ - 'openid', - 'offline_access', - 'oidc:request-audience', - 'username', - 'groups', - ], - claims_supported: ['email', 'username', 'groups', 'additionalClaims'], - response_types_supported: ['code'], - id_token_signing_alg_values_supported: ['RS256', 'RS512', 'HS256'], - token_endpoint_auth_signing_alg_values_supported: [ - 'RS256', - 'RS512', - 'HS256', - ], - request_object_signing_alg_values_supported: ['RS256', 'RS512', 'HS256'], - }; - - beforeAll(async () => { - const keyPair = await generateKeyPair('RS256'); - const privateKey = await exportJWK(keyPair.privateKey); - publicKey = await exportJWK(keyPair.publicKey); - publicKey.alg = privateKey.alg = 'RS256'; - - idToken = await new SignJWT({ - sub: 'test', - iss: 'https://oidc.test', - iat: Date.now(), - aud: 'clientId', - exp: Date.now() + 10000, - }) - .setProtectedHeader({ alg: privateKey.alg, kid: privateKey.kid }) - .sign(keyPair.privateKey); - }); - - beforeEach(() => { - mswServer.use( - rest.get( - 'https://oidc.test/.well-known/openid-configuration', - (_req, res, ctx) => - res( - ctx.status(200), - ctx.set('Content-Type', 'application/json'), - ctx.json(issuerMetadata), - ), - ), - rest.get('https://oidc.test/jwks.json', async (_req, res, ctx) => - res(ctx.status(200), ctx.json({ keys: [{ ...publicKey }] })), - ), - rest.post('https://oidc.test/oauth2/token', async (req, res, ctx) => { - return res( - req.headers.get('Authorization') - ? ctx.json({ - access_token: 'accessToken', - id_token: idToken, - refresh_token: 'refreshToken', - scope: 'testScope', - expires_in: 3600, - }) - : ctx.status(401), - ); - }), - rest.get( - 'https://oidc.test/idp/userinfo.openid', - async (_req, res, ctx) => - res( - ctx.status(200), - ctx.json({ - sub: 'test', - name: 'Alice Adams', - given_name: 'Alice', - family_name: 'Adams', - email: 'alice@test.com', - picture: 'http://testPictureUrl/photo.jpg', // NOSONAR - }), - ), - ), - ); - - implementation = oidcAuthenticator.initialize({ - callbackUrl: 'https://backstage.test/callback', - config: new ConfigReader({ - metadataUrl: 'https://oidc.test/.well-known/openid-configuration', - clientId: 'clientId', - clientSecret: 'clientSecret', - }), - }); - - oauthState = { - nonce: 'nonce', - env: 'env', - }; - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('#start', () => { - let fakeSession: Record; - let startRequest: OAuthAuthenticatorStartInput; - - beforeEach(() => { - fakeSession = {}; - startRequest = { - state: encodeOAuthState(oauthState), - req: { - method: 'GET', - url: 'test', - session: fakeSession, - }, - } as unknown as OAuthAuthenticatorStartInput; - }); - - it('redirects to authorization endpoint returned from OIDC metadata endpoint', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const url = new URL(startResponse.url); - - expect(url.protocol).toBe('https:'); - expect(url.hostname).toBe('oidc.test'); - expect(url.pathname).toBe('/oauth2/authorize'); - }); - - it('initiates authorization code grant', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const { searchParams } = new URL(startResponse.url); - - expect(searchParams.get('response_type')).toBe('code'); - }); - - it('passes client ID from config', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const { searchParams } = new URL(startResponse.url); - - expect(searchParams.get('client_id')).toBe('clientId'); - }); - - it('passes callback URL from config', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const { searchParams } = new URL(startResponse.url); - - expect(searchParams.get('redirect_uri')).toBe( - 'https://backstage.test/callback', - ); - }); - - it('generates PKCE challenge', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const { searchParams } = new URL(startResponse.url); - - expect(searchParams.get('code_challenge_method')).toBe('S256'); - expect(searchParams.get('code_challenge')).not.toBeNull(); - }); - - it('stores PKCE verifier in session', async () => { - await oidcAuthenticator.start(startRequest, implementation); - expect(fakeSession['oidc:oidc.test'].code_verifier).toBeDefined(); - }); - - it('requests default scopes if none are provided in config', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const { searchParams } = new URL(startResponse.url); - const scopes = searchParams.get('scope')?.split(' ') ?? []; - - expect(scopes).toEqual( - expect.arrayContaining(['openid', 'profile', 'email']), - ); - }); - - it('encodes OAuth state in query param', async () => { - const startResponse = await oidcAuthenticator.start( - startRequest, - implementation, - ); - const { searchParams } = new URL(startResponse.url); - const stateParam = searchParams.get('state'); - const decodedState = decodeOAuthState(stateParam!); - - expect(decodedState).toMatchObject(oauthState); - }); - - it('fails when request has no session', async () => { - return expect( - oidcAuthenticator.start( - { - state: encodeOAuthState(oauthState), - req: { - method: 'GET', - url: 'test', - }, - } as unknown as OAuthAuthenticatorStartInput, - implementation, - ), - ).rejects.toThrow('authentication requires session support'); - }); - }); - - describe('#authenticate', () => { - let handlerRequest: OAuthAuthenticatorAuthenticateInput; - - beforeEach(() => { - handlerRequest = { - req: { - method: 'GET', - url: `https://test?code=authorization_code&state=${encodeOAuthState( - oauthState, - )}`, - session: { - 'oidc:oidc.test': { - state: encodeOAuthState(oauthState), - }, - }, - } as unknown as express.Request, - }; - }); - - it('exchanges authorization code for access token', async () => { - const authenticatorResult = await oidcAuthenticator.authenticate( - handlerRequest, - implementation, - ); - const accessToken = authenticatorResult.session.accessToken; - - expect(accessToken).toEqual('accessToken'); - }); - - it('exchanges authorization code for refresh token', async () => { - const authenticatorResult = await oidcAuthenticator.authenticate( - handlerRequest, - implementation, - ); - const refreshToken = authenticatorResult.session.refreshToken; - - expect(refreshToken).toEqual('refreshToken'); - }); - - it('returns granted scope', async () => { - const authenticatorResult = await oidcAuthenticator.authenticate( - handlerRequest, - implementation, - ); - const responseScope = authenticatorResult.session.scope; - - expect(responseScope).toEqual('testScope'); - }); - - it('returns a default session.tokentype field', async () => { - const authenticatorResult = await oidcAuthenticator.authenticate( - handlerRequest, - implementation, - ); - const tokenType = authenticatorResult.session.tokenType; - - expect(tokenType).toEqual('bearer'); - }); - - it('returns picture and email', async () => { - const authenticatorResult = await oidcAuthenticator.authenticate( - handlerRequest, - implementation, - ); - - expect(authenticatorResult).toMatchObject({ - fullProfile: { - userinfo: { - email: 'alice@test.com', - picture: 'http://testPictureUrl/photo.jpg', // NOSONAR - name: 'Alice Adams', - }, - }, - }); - }); - - it('returns idToken', async () => { - const authenticatorResult = await oidcAuthenticator.authenticate( - handlerRequest, - implementation, - ); - - expect(authenticatorResult).toMatchObject({ - session: { - idToken, - }, - }); - expect( - Math.abs(authenticatorResult.session.expiresInSeconds! - 3600), - ).toBeLessThan(5); - }); - - it('fails without authorization code', async () => { - handlerRequest.req.url = 'https://test.com'; - return expect( - oidcAuthenticator.authenticate(handlerRequest, implementation), - ).rejects.toThrow('Unexpected redirect'); - }); - - it('fails without oauth state', async () => { - return expect( - oidcAuthenticator.authenticate( - { - req: { - method: 'GET', - url: `https://test?code=authorization_code}`, - session: { - ['oidc:pinniped.test']: { - state: { handle: 'sessionid', code_verifier: 'foo' }, - }, - }, - } as unknown as express.Request, - }, - implementation, - ), - ).rejects.toThrow( - 'Authentication failed, did not find expected authorization request details in session, req.session["oidc:oidc.test"] is undefined', - ); - }); - - it('fails when request has no session', async () => { - return expect( - oidcAuthenticator.authenticate( - { - req: { - method: 'GET', - url: 'https://test.com', - } as unknown as express.Request, - }, - implementation, - ), - ).rejects.toThrow('authentication requires session support'); - }); - }); - - describe('#refresh', () => { - let refreshRequest: OAuthAuthenticatorRefreshInput; - - beforeEach(() => { - refreshRequest = { - scope: '', - refreshToken: 'otherRefreshToken', - req: {} as express.Request, - }; - }); - - it('gets new refresh token', async () => { - const refreshResponse = await oidcAuthenticator.refresh( - refreshRequest, - implementation, - ); - - expect(refreshResponse.session.refreshToken).toBe('refreshToken'); - }); - - it('gets access token', async () => { - const refreshResponse = await oidcAuthenticator.refresh( - refreshRequest, - implementation, - ); - - expect(refreshResponse.session.accessToken).toBe('accessToken'); - }); - - it('gets id token', async () => { - const refreshResponse = await oidcAuthenticator.refresh( - refreshRequest, - implementation, - ); - - expect(refreshResponse.session.idToken).toBe(idToken); - }); - }); -}); diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.ts deleted file mode 100644 index 317cb7269e..0000000000 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.ts +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 { - custom, - CustomHttpOptionsProvider, - Issuer, - ClientAuthMethod, - TokenSet, - UserinfoResponse, - Strategy as OidcStrategy, -} from 'openid-client'; -import { - createOAuthAuthenticator, - OAuthAuthenticatorResult, - PassportDoneCallback, - PassportHelpers, - PassportOAuthAuthenticatorHelper, - PassportOAuthPrivateInfo, -} from '@backstage/plugin-auth-node'; - -const HTTP_OPTION_TIMEOUT = 10000; -const httpOptionsProvider: CustomHttpOptionsProvider = (_url, options) => { - return { - ...options, - timeout: HTTP_OPTION_TIMEOUT, - }; -}; - -/** - * authentication result for the OIDC which includes the token set and user - * profile response - * @public - */ -export type OidcAuthResult = { - tokenset: TokenSet; - userinfo: UserinfoResponse; -}; - -/** @public */ -export const oidcAuthenticator = createOAuthAuthenticator({ - shouldPersistScopes: true, - defaultProfileTransform: async ( - input: OAuthAuthenticatorResult, - ) => ({ - profile: { - email: input.fullProfile.userinfo.email, - picture: input.fullProfile.userinfo.picture, - displayName: input.fullProfile.userinfo.name, - }, - }), - initialize({ callbackUrl, config }) { - const clientId = config.getString('clientId'); - const clientSecret = config.getString('clientSecret'); - const metadataUrl = config.getString('metadataUrl'); - const customCallbackUrl = config.getOptionalString('callbackUrl'); - const tokenEndpointAuthMethod = config.getOptionalString( - 'tokenEndpointAuthMethod', - ) as ClientAuthMethod; - const tokenSignedResponseAlg = config.getOptionalString( - 'tokenSignedResponseAlg', - ); - const initializedScope = config.getOptionalString('scope'); - const initializedPrompt = config.getOptionalString('prompt'); - - Issuer[custom.http_options] = httpOptionsProvider; - const promise = Issuer.discover(metadataUrl).then(issuer => { - issuer[custom.http_options] = httpOptionsProvider; - issuer.Client[custom.http_options] = httpOptionsProvider; - - const client = new issuer.Client({ - access_type: 'offline', // this option must be passed to provider to receive a refresh token - client_id: clientId, - client_secret: clientSecret, - redirect_uris: [customCallbackUrl || callbackUrl], - response_types: ['code'], - token_endpoint_auth_method: - tokenEndpointAuthMethod || 'client_secret_basic', - id_token_signed_response_alg: tokenSignedResponseAlg || 'RS256', - scope: initializedScope || '', - }); - client[custom.http_options] = httpOptionsProvider; - - const strategy = new OidcStrategy( - { - client, - passReqToCallback: false, - }, - ( - tokenset: TokenSet, - userinfo: UserinfoResponse, - done: PassportDoneCallback, - ) => { - if (typeof done !== 'function') { - throw new Error( - 'OIDC IdP must provide a userinfo_endpoint in the metadata response', - ); - } - - done( - undefined, - { tokenset, userinfo }, - { refreshToken: tokenset.refresh_token }, - ); - }, - ); - - const helper = PassportOAuthAuthenticatorHelper.from(strategy); - return { helper, client, strategy }; - }); - - return { initializedScope, initializedPrompt, promise }; - }, - - async start(input, ctx) { - const { initializedScope, initializedPrompt, promise } = ctx; - const { helper, strategy } = await promise; - const options: Record = { - scope: input.scope || initializedScope || 'openid profile email', - state: input.state, - }; - const prompt = initializedPrompt || 'none'; - if (prompt !== 'auto') { - options.prompt = prompt; - } - - return new Promise((resolve, reject) => { - strategy.error = reject; - - return helper - .start(input, { - ...options, - }) - .then(resolve); - }); - }, - - async authenticate( - input, - ctx, - ): Promise> { - const { strategy } = await ctx.promise; - const { result, privateInfo } = - await PassportHelpers.executeFrameHandlerStrategy< - OidcAuthResult, - PassportOAuthPrivateInfo - >(input.req, strategy); - - return { - fullProfile: result, - session: { - accessToken: result.tokenset.access_token!, - tokenType: result.tokenset.token_type ?? 'bearer', - scope: result.tokenset.scope!, - expiresInSeconds: result.tokenset.expires_in, - idToken: result.tokenset.id_token, - refreshToken: privateInfo.refreshToken, - }, - }; - }, - - async refresh(input, ctx) { - const { client } = await ctx.promise; - const tokenset = await client.refresh(input.refreshToken); - if (!tokenset.access_token) { - throw new Error('Refresh failed'); - } - const userinfo = await client.userinfo(tokenset.access_token); - - return new Promise((resolve, reject) => { - if (!tokenset.access_token) { - reject(new Error('Refresh Failed')); - } - resolve({ - fullProfile: { userinfo, tokenset }, - session: { - accessToken: tokenset.access_token!, - tokenType: tokenset.token_type ?? 'bearer', - scope: tokenset.scope!, - expiresInSeconds: tokenset.expires_in, - idToken: tokenset.id_token, - refreshToken: tokenset.refresh_token, - }, - }); - }); - }, - - async logout(input, ctx) { - const { client } = await ctx.promise; - - if (input.refreshToken) { - await client.revoke(input.refreshToken); - } - }, -}); diff --git a/plugins/auth-backend-module-oidc-provider/src/index.ts b/plugins/auth-backend-module-oidc-provider/src/index.ts deleted file mode 100644 index 4e951382bb..0000000000 --- a/plugins/auth-backend-module-oidc-provider/src/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -/** - * The oidc-provider backend module for the auth plugin. - * - * @packageDocumentation - */ - -export { oidcAuthenticator } from './authenticator'; -export type { OidcAuthResult } from './authenticator'; -export { authModuleOidcProvider as default } from './module'; -export { oidcSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend-module-oidc-provider/src/module.test.ts b/plugins/auth-backend-module-oidc-provider/src/module.test.ts deleted file mode 100644 index 20553cb522..0000000000 --- a/plugins/auth-backend-module-oidc-provider/src/module.test.ts +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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 { - mockServices, - registerMswTestHooks, - startTestBackend, -} from '@backstage/backend-test-utils'; -import { decodeOAuthState } from '@backstage/plugin-auth-node'; -import { Server } from 'http'; -import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; -import request from 'supertest'; -import { authModuleOidcProvider } from './module'; - -describe('authModuleOidcProvider', () => { - let backstageServer: Server; - let appUrl: string; - let idToken: string; - let publicKey: JWK; - - const mswServer = setupServer(); - registerMswTestHooks(mswServer); - - const issuerMetadata = { - issuer: 'https://oidc.test', - authorization_endpoint: 'https://oidc.test/oauth2/authorize', - token_endpoint: 'https://oidc.test/oauth2/token', - revocation_endpoint: 'https://oidc.test/oauth2/revoke_token', - userinfo_endpoint: 'https://oidc.test/idp/userinfo.openid', - introspection_endpoint: 'https://oidc.test/as/introspect.oauth2', - jwks_uri: 'https://oidc.test/jwks.json', - scopes_supported: ['openid'], - claims_supported: ['email'], - response_types_supported: ['code'], - id_token_signing_alg_values_supported: ['RS256', 'RS512', 'HS256'], - token_endpoint_auth_signing_alg_values_supported: [ - 'RS256', - 'RS512', - 'HS256', - ], - request_object_signing_alg_values_supported: ['RS256', 'RS512', 'HS256'], - }; - - beforeAll(async () => { - const keyPair = await generateKeyPair('RS256'); - const privateKey = await exportJWK(keyPair.privateKey); - publicKey = await exportJWK(keyPair.publicKey); - publicKey.alg = privateKey.alg = 'RS256'; - - idToken = await new SignJWT({ - sub: 'test', - iss: 'https://oidc.test', - iat: Date.now(), - aud: 'clientId', - exp: Date.now() + 10000, - }) - .setProtectedHeader({ alg: privateKey.alg, kid: privateKey.kid }) - .sign(keyPair.privateKey); - }); - - beforeEach(async () => { - jest.clearAllMocks(); - - mswServer.use( - rest.get( - 'https://oidc.test/.well-known/openid-configuration', - (_req, res, ctx) => - res( - ctx.status(200), - ctx.set('Content-Type', 'application/json'), - ctx.json(issuerMetadata), - ), - ), - rest.get('https://oidc.test/oauth2/authorize', async (req, res, ctx) => { - const callbackUrl = new URL(req.url.searchParams.get('redirect_uri')!); - callbackUrl.searchParams.set('code', 'authorization_code'); - callbackUrl.searchParams.set( - 'state', - req.url.searchParams.get('state')!, - ); - callbackUrl.searchParams.set('scope', 'test-scope'); - return res( - ctx.status(302), - ctx.set('Location', callbackUrl.toString()), - ); - }), - rest.get('https://oidc.test/jwks.json', async (_req, res, ctx) => - res(ctx.status(200), ctx.json({ keys: [{ ...publicKey }] })), - ), - rest.post('https://oidc.test/oauth2/token', async (req, res, ctx) => { - return res( - req.headers.get('Authorization') - ? ctx.json({ - access_token: 'accessToken', - id_token: idToken, - refresh_token: 'refreshToken', - scope: 'testScope', - token_type: '', - expires_in: 3600, - }) - : ctx.status(401), - ); - }), - rest.get( - 'https://oidc.test/idp/userinfo.openid', - async (_req, res, ctx) => - res( - ctx.status(200), - ctx.json({ - sub: 'test', - name: 'Alice Adams', - given_name: 'Alice', - family_name: 'Adams', - email: 'alice@test.com', - picture: 'http://testPictureUrl/photo.jpg', // NOSONAR - }), - ), - ), - ); - - const backend = await startTestBackend({ - features: [ - authModuleOidcProvider, - import('@backstage/plugin-auth-backend'), - mockServices.rootConfig.factory({ - data: { - app: { baseUrl: 'http://localhost' }, - auth: { - session: { secret: 'test' }, - providers: { - oidc: { - development: { - metadataUrl: - 'https://oidc.test/.well-known/openid-configuration', - clientId: 'clientId', - clientSecret: 'clientSecret', - }, - }, - }, - }, - }, - }), - ], - }); - - backstageServer = backend.server; - const port = backend.server.port(); - appUrl = `http://localhost:${port}`; - mswServer.use(rest.all(`http://*:${port}/*`, req => req.passthrough())); - }); - - afterEach(() => { - backstageServer.close(); - }); - - it('should start', async () => { - const agent = request.agent(backstageServer); - - const startResponse = await agent.get( - `/api/auth/oidc/start?env=development`, - ); - expect(startResponse.status).toEqual(302); - - const nonceCookie = agent.jar.getCookie('oidc-nonce', { - domain: 'localhost', - path: '/api/auth/oidc/handler', - script: false, - secure: false, - }); - expect(nonceCookie).toBeDefined(); - - const startUrl = new URL(startResponse.get('location') ?? ''); - expect(startUrl.origin).toBe('https://oidc.test'); - expect(startUrl.pathname).toBe('/oauth2/authorize'); - expect(Object.fromEntries(startUrl.searchParams)).toEqual({ - response_type: 'code', - scope: 'openid profile email', - client_id: 'clientId', - redirect_uri: `${appUrl}/api/auth/oidc/handler/frame`, - state: expect.any(String), - prompt: 'none', - code_challenge: expect.any(String), - code_challenge_method: `S256`, - }); - - expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ - env: 'development', - nonce: decodeURIComponent(nonceCookie!.value), - scope: '', - }); - }); - - it('#authenticate exchanges authorization code for a access_token', async () => { - const agent = request.agent(''); - const startResponse = await agent.get( - `${appUrl}/api/auth/oidc/start?env=development`, - ); - const authorizationResponse = await agent.get( - startResponse.header.location, - ); - const handlerResponse = await agent.get( - authorizationResponse.header.location, - ); - - expect(handlerResponse.text).toContain( - encodeURIComponent(`"accessToken":"accessToken"`), - ); - }); -}); diff --git a/plugins/auth-backend-module-oidc-provider/src/module.ts b/plugins/auth-backend-module-oidc-provider/src/module.ts deleted file mode 100644 index 5e4daf20c3..0000000000 --- a/plugins/auth-backend-module-oidc-provider/src/module.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 { createBackendModule } from '@backstage/backend-plugin-api'; -import { - authProvidersExtensionPoint, - createOAuthProviderFactory, -} from '@backstage/plugin-auth-node'; -import { oidcAuthenticator } from './authenticator'; -import { oidcSignInResolvers } from './resolvers'; - -/** @public */ -export const authModuleOidcProvider = createBackendModule({ - pluginId: 'auth', - moduleId: 'oidc-provider', - register(reg) { - reg.registerInit({ - deps: { - providers: authProvidersExtensionPoint, - }, - async init({ providers }) { - providers.registerProvider({ - providerId: 'oidc', - factory: createOAuthProviderFactory({ - authenticator: oidcAuthenticator, - signInResolverFactories: { - ...oidcSignInResolvers, - }, - }), - }); - }, - }); - }, -}); diff --git a/plugins/auth-backend-module-oidc-provider/src/resolvers.ts b/plugins/auth-backend-module-oidc-provider/src/resolvers.ts deleted file mode 100644 index 67641fac0e..0000000000 --- a/plugins/auth-backend-module-oidc-provider/src/resolvers.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 { OidcAuthResult } from '@backstage/plugin-auth-backend-module-oidc-provider'; -import { - AuthResolverContext, - OAuthAuthenticatorResult, - SignInInfo, - commonSignInResolvers, - createSignInResolverFactory, -} from '@backstage/plugin-auth-node'; - -/** - * Available sign-in resolvers for the Oidc auth provider. - * - * @public - */ -export namespace oidcSignInResolvers { - /** - * A oidc resolver that looks up the user using the local part of - * their email address as the entity name. - */ - export const emailLocalPartMatchingUserEntityName = - commonSignInResolvers.emailLocalPartMatchingUserEntityName; - - /** - * A oidc resolver that looks up the user using their email address - * as email of the entity. - */ - export const emailMatchingUserEntityProfileEmail = - commonSignInResolvers.emailMatchingUserEntityProfileEmail; - - /** - * A oidc resolver that looks up the user using their preferred username - * as the entity name - */ - export const preferredUsernameMatchingUserEntityName = - createSignInResolverFactory({ - create() { - return async ( - info: SignInInfo>, - ctx: AuthResolverContext, - ) => { - const userId = info.result.fullProfile.userinfo.preferred_username; - - if (!userId) { - throw new Error(`OIDC user profile does not contain a username`); - } - return ctx.signInWithCatalogUser({ entityRef: { name: userId } }); - }; - }, - }); -} diff --git a/plugins/dynamic-plugins-info-backend/.lintstagedrc.json b/plugins/dynamic-plugins-info-backend/.lintstagedrc.json new file mode 100644 index 0000000000..14b2263def --- /dev/null +++ b/plugins/dynamic-plugins-info-backend/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*": "prettier --ignore-unknown --write", + "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" +} diff --git a/plugins/dynamic-plugins-info-backend/.prettierignore b/plugins/dynamic-plugins-info-backend/.prettierignore new file mode 100644 index 0000000000..3f6fff7b2b --- /dev/null +++ b/plugins/dynamic-plugins-info-backend/.prettierignore @@ -0,0 +1,2 @@ +dist +coverage \ No newline at end of file diff --git a/plugins/dynamic-plugins-info-backend/.prettierrc.js b/plugins/dynamic-plugins-info-backend/.prettierrc.js new file mode 100644 index 0000000000..84cbac65b5 --- /dev/null +++ b/plugins/dynamic-plugins-info-backend/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@janus-idp/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/plugins/dynamic-plugins-info-backend/package.json b/plugins/dynamic-plugins-info-backend/package.json index 94eb79a9e5..450712c088 100644 --- a/plugins/dynamic-plugins-info-backend/package.json +++ b/plugins/dynamic-plugins-info-backend/package.json @@ -21,28 +21,32 @@ "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", - "lint": "backstage-cli package lint", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", "test": "backstage-cli package test --passWithNoTests --coverage", "clean": "backstage-cli package clean", "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" + "postpack": "backstage-cli package postpack", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." }, "dependencies": { - "@backstage/backend-common": "0.23.3", - "@backstage/backend-defaults": "0.4.1", - "@backstage/backend-dynamic-feature-service": "0.2.15", - "@backstage/backend-plugin-api": "0.7.0", + "@backstage/backend-defaults": "0.5.2", + "@backstage/backend-dynamic-feature-service": "0.4.4", + "@backstage/backend-plugin-api": "1.0.1", "@backstage/config": "1.2.0", - "@types/express": "4.17.21", - "express": "4.19.2", + "express": "4.21.0", "node-fetch": "2.7.0", "winston": "3.14.2" }, "devDependencies": { - "@backstage/backend-test-utils": "0.4.4", - "@backstage/cli": "0.26.11", + "@backstage/backend-test-utils": "1.0.2", + "@backstage/cli": "0.28.2", + "@types/express": "4.17.21", "@types/supertest": "6.0.2", - "msw": "2.3.5", + "msw": "1.3.4", + "prettier": "3.4.1", "supertest": "6.3.4" }, "files": [ diff --git a/plugins/dynamic-plugins-info-backend/src/plugin.ts b/plugins/dynamic-plugins-info-backend/src/plugin.ts index 7069cd8317..e86f106316 100644 --- a/plugins/dynamic-plugins-info-backend/src/plugin.ts +++ b/plugins/dynamic-plugins-info-backend/src/plugin.ts @@ -1,9 +1,10 @@ +import { dynamicPluginsServiceRef } from '@backstage/backend-dynamic-feature-service'; import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; + import { createRouter } from './service/router'; -import { dynamicPluginsServiceRef } from '@backstage/backend-dynamic-feature-service'; export const dynamicPluginsInfoPlugin = createBackendPlugin({ pluginId: 'dynamic-plugins-info', @@ -11,6 +12,7 @@ export const dynamicPluginsInfoPlugin = createBackendPlugin({ env.registerInit({ deps: { http: coreServices.httpRouter, + // TODO: Replace type pluginProvider: dynamicPluginsServiceRef, httpAuth: coreServices.httpAuth, discovery: coreServices.discovery, diff --git a/plugins/dynamic-plugins-info-backend/src/service/router.test.ts b/plugins/dynamic-plugins-info-backend/src/service/router.test.ts index 874356eaf1..d0f4a58292 100644 --- a/plugins/dynamic-plugins-info-backend/src/service/router.test.ts +++ b/plugins/dynamic-plugins-info-backend/src/service/router.test.ts @@ -1,10 +1,12 @@ +import { DynamicPluginManager } from '@backstage/backend-dynamic-feature-service'; +import { mockServices } from '@backstage/backend-test-utils'; + import express from 'express'; import request from 'supertest'; + import { plugins } from '../../__fixtures__/data'; import { expectedList } from '../../__fixtures__/expected_result'; import { createRouter } from './router'; -import { DynamicPluginManager } from '@backstage/backend-dynamic-feature-service'; -import { mockServices } from '@backstage/backend-test-utils'; describe('createRouter', () => { let app: express.Express; diff --git a/plugins/dynamic-plugins-info-backend/src/service/router.ts b/plugins/dynamic-plugins-info-backend/src/service/router.ts index 7c0042e044..0e5b677e7f 100644 --- a/plugins/dynamic-plugins-info-backend/src/service/router.ts +++ b/plugins/dynamic-plugins-info-backend/src/service/router.ts @@ -1,4 +1,3 @@ -import { createLegacyAuthAdapters } from '@backstage/backend-common'; import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { BaseDynamicPlugin, @@ -10,12 +9,13 @@ import { LoggerService, } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; + import express, { Router } from 'express'; export interface RouterOptions { pluginProvider: DynamicPluginProvider; discovery: DiscoveryService; - httpAuth?: HttpAuthService; + httpAuth: HttpAuthService; logger: LoggerService; config: Config; } @@ -23,8 +23,7 @@ export interface RouterOptions { export async function createRouter( options: RouterOptions, ): Promise { - const { logger, pluginProvider, config } = options; - const { httpAuth } = createLegacyAuthAdapters(options); + const { logger, pluginProvider, config, httpAuth } = options; const router = Router(); router.use(express.json()); diff --git a/plugins/dynamic-plugins-info-backend/tsconfig.json b/plugins/dynamic-plugins-info-backend/tsconfig.json new file mode 100644 index 0000000000..d5d25353f5 --- /dev/null +++ b/plugins/dynamic-plugins-info-backend/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@backstage/cli/config/tsconfig.json", + "include": ["src", "dev", "migrations"], + "exclude": ["node_modules"], + "compilerOptions": { + "outDir": "../../dist-types/plugins/dynamic-plugins-info-backend", + "rootDir": "." + } +} diff --git a/plugins/dynamic-plugins-info-backend/turbo.json b/plugins/dynamic-plugins-info-backend/turbo.json new file mode 100644 index 0000000000..1716fefa20 --- /dev/null +++ b/plugins/dynamic-plugins-info-backend/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "tasks": { + "tsc": { + "outputs": ["../../dist-types/plugins/dynamic-plugins-info-backend/**"] + } + } +} diff --git a/plugins/dynamic-plugins-info/.eslintrc.js b/plugins/dynamic-plugins-info/.eslintrc.js index e2a53a6ad2..07630f21af 100644 --- a/plugins/dynamic-plugins-info/.eslintrc.js +++ b/plugins/dynamic-plugins-info/.eslintrc.js @@ -1 +1,12 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +const backstageConfig = require('@backstage/cli/config/eslint-factory')( + __dirname, +); + +module.exports = { + ...backstageConfig, + rules: { + ...backstageConfig.rules, + 'react/react-in-jsx-scope': 'off', + 'react/jsx-uses-react': 'off', + }, +}; diff --git a/plugins/dynamic-plugins-info/.lintstagedrc.json b/plugins/dynamic-plugins-info/.lintstagedrc.json new file mode 100644 index 0000000000..14b2263def --- /dev/null +++ b/plugins/dynamic-plugins-info/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*": "prettier --ignore-unknown --write", + "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" +} diff --git a/plugins/dynamic-plugins-info/.prettierignore b/plugins/dynamic-plugins-info/.prettierignore new file mode 100644 index 0000000000..3f6fff7b2b --- /dev/null +++ b/plugins/dynamic-plugins-info/.prettierignore @@ -0,0 +1,2 @@ +dist +coverage \ No newline at end of file diff --git a/plugins/dynamic-plugins-info/.prettierrc.js b/plugins/dynamic-plugins-info/.prettierrc.js new file mode 100644 index 0000000000..84cbac65b5 --- /dev/null +++ b/plugins/dynamic-plugins-info/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@janus-idp/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/plugins/dynamic-plugins-info/app-config.janus-idp.yaml b/plugins/dynamic-plugins-info/app-config.janus-idp.yaml index 490c0123a9..392bef6991 100644 --- a/plugins/dynamic-plugins-info/app-config.janus-idp.yaml +++ b/plugins/dynamic-plugins-info/app-config.janus-idp.yaml @@ -1,3 +1,4 @@ +# please keep this in sync with packages/app/src/App.tsx dynamicPlugins: frontend: janus-idp.backstage-plugin-dynamic-plugins-info: diff --git a/plugins/dynamic-plugins-info/dev/index.tsx b/plugins/dynamic-plugins-info/dev/index.tsx index 05f66811ff..76054d37e3 100644 --- a/plugins/dynamic-plugins-info/dev/index.tsx +++ b/plugins/dynamic-plugins-info/dev/index.tsx @@ -1,6 +1,3 @@ -import React from 'react'; - -import { Content, Header, HeaderTabs, Page } from '@backstage/core-components'; import { createDevApp } from '@backstage/dev-utils'; import { TestApiProvider } from '@backstage/test-utils'; @@ -20,25 +17,7 @@ createDevApp() .addPage({ element: ( - -
- - - - - + ), title: 'Root Page', diff --git a/plugins/dynamic-plugins-info/package.json b/plugins/dynamic-plugins-info/package.json index 00e7db5795..3c8c2024fc 100644 --- a/plugins/dynamic-plugins-info/package.json +++ b/plugins/dynamic-plugins-info/package.json @@ -4,7 +4,6 @@ "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", - "private": "true", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -22,35 +21,43 @@ "scripts": { "build": "backstage-cli package build", "clean": "backstage-cli package clean", - "lint": "backstage-cli package lint", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", "postpack": "backstage-cli package postpack", "postversion": "yarn run export-dynamic", "prepack": "backstage-cli package prepack", "dev": "backstage-cli package start", "test": "backstage-cli package test --passWithNoTests --coverage", - "tsc": "tsc" + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." }, "dependencies": { - "@backstage/core-components": "0.14.9", - "@backstage/core-plugin-api": "1.9.3", - "@backstage/theme": "0.5.6", + "@backstage/core-components": "0.15.1", + "@backstage/core-plugin-api": "1.10.0", + "@backstage/theme": "0.6.0", "@material-table/core": "3.2.5", + "@mui/icons-material": "5.16.7", "@mui/material": "5.16.7", "react-use": "17.5.1" }, "peerDependencies": { "react": "16.13.1 || ^17.0.0 || ^18.2.0", - "react-router-dom": "6.26.1" + "react-router-dom": "6.26.2" }, "devDependencies": { - "@backstage/cli": "0.26.11", - "@backstage/core-app-api": "1.14.1", - "@backstage/dev-utils": "1.0.36", - "@backstage/test-utils": "1.5.9", - "@testing-library/jest-dom": "6.5.0", + "@backstage/cli": "0.28.2", + "@backstage/core-app-api": "1.15.1", + "@backstage/dev-utils": "1.1.2", + "@backstage/test-utils": "1.7.0", + "@testing-library/jest-dom": "6.6.3", "@testing-library/react": "14.3.1", "@testing-library/user-event": "14.5.2", - "msw": "1.3.3" + "glob": "11.0.0", + "msw": "1.3.4", + "prettier": "3.4.1", + "react": "18.3.1", + "react-router-dom": "6.26.2" }, "files": [ "dist" diff --git a/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoContent/DynamicPluginsInfoContent.tsx b/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoContent/DynamicPluginsInfoContent.tsx index 589ab1fcf0..8284b40164 100644 --- a/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoContent/DynamicPluginsInfoContent.tsx +++ b/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoContent/DynamicPluginsInfoContent.tsx @@ -1,4 +1,3 @@ -import React from 'react'; -import { DynamicPluginsTable } from '../DynamicPluginsTable/DynamicPluginsTable'; +import { DynamicPluginsInfoPage } from '../DynamicPluginsInfoPage'; -export const DynamicPluginsInfoContent = () => ; +export const DynamicPluginsInfoContent = () => ; diff --git a/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoPage.tsx b/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoPage.tsx new file mode 100644 index 0000000000..c9f61efa37 --- /dev/null +++ b/plugins/dynamic-plugins-info/src/components/DynamicPluginsInfoPage.tsx @@ -0,0 +1,14 @@ +import { Content, Header, Page } from '@backstage/core-components'; + +import { DynamicPluginsTable } from './DynamicPluginsTable/DynamicPluginsTable'; + +export const DynamicPluginsInfoPage = () => { + return ( + +
+ + + + + ); +}; diff --git a/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.test.tsx b/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.test.tsx index 733d97adf5..c77d1bd150 100644 --- a/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.test.tsx +++ b/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.test.tsx @@ -1,13 +1,26 @@ -import React from 'react'; - import { renderWithEffects } from '@backstage/test-utils'; -import { act, fireEvent, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - import { listLoadedPluginsResult } from '../../__fixtures__/listLoadedPluginsResult'; +import { InternalPluginsMap } from '../InternalPluginsMap'; import { DynamicPluginsTable } from './DynamicPluginsTable'; +const DEFAULT_ROWS_DISPLAYED = 5; + +// 6 mockapi returned external(enabled) + 53 internal(not enabled) +// mockapi returns enabled plugins +// keys from InternalPluginsMap are internal plugins +const plugins = [ + ...Object.keys(InternalPluginsMap).map(name => ({ + name, + version: undefined, + role: undefined, + platform: undefined, + internal: true, + enabled: true, + })), + ...listLoadedPluginsResult, +]; + jest.mock('@backstage/core-plugin-api', () => { const actual = jest.requireActual('@backstage/core-plugin-api'); return { @@ -23,17 +36,20 @@ jest.mock('@backstage/core-plugin-api', () => { }); describe('DynamicPluginsTable', () => { - it('should render a list of plugins sorted by name', async () => { + beforeEach(() => { + // sort by the plugin name + plugins.sort((a, b) => { + return a.name.localeCompare(b.name); + }); + }); + + it('should display the plugins', async () => { const { findByText, container } = await renderWithEffects( , ); - // 6 mockapi returned external(enabled) + 53 internal(not enabled) - // mockapi returns enabled plugins - // keys from InternalPluginsMap are internal plugins - expect(await findByText('Plugins (61)')).toBeInTheDocument(); - expect( - await findByText('@janus-idp/backstage-plugin-3scale-backend-dynamic'), - ).toBeInTheDocument(); + + expect(await findByText(`Plugins (${plugins.length})`)).toBeInTheDocument(); + expect(await findByText(plugins.at(0)?.name ?? '')).toBeInTheDocument(); const nameCells = Array.from( container.querySelectorAll('tbody tr > td:first-child'), ); @@ -46,104 +62,22 @@ describe('DynamicPluginsTable', () => { const internalCells = Array.from( container.querySelectorAll('tbody tr > td:nth-child(4)'), ); - expect(nameCells.length).toBe(5); - expect(nameCells[0].textContent).toBe( - '@janus-idp/backstage-plugin-3scale-backend-dynamic', - ); - expect(nameCells[4].textContent).toBe('@janus-idp/backstage-plugin-argocd'); - expect(versionCells[0].textContent).toBe(''); - expect(versionCells[4].textContent).toBe(''); - expect(enabledCells[0].textContent).toBe('No'); - expect(enabledCells[4].textContent).toBe('No'); - expect(internalCells[0].textContent).toBe('Yes'); - expect(internalCells[4].textContent).toBe('Yes'); - }); - - it('supports filtering by a simple text search', async () => { - const user = userEvent.setup({ delay: 300 }); - const { container } = await renderWithEffects(); - const filterInput = container.querySelector('input[placeholder="Filter"]')!; - expect(filterInput).toBeDefined(); - await act(() => user.type(filterInput, 'plugin-f\n')); - const nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(2); - expect(nameCells[0].textContent).toBe('api-returned-some-plugin-five'); - expect(nameCells[1].textContent).toBe('api-returned-some-plugin-four'); - }); - - it('supports sorting by name, version and rhdh embedded columns', async () => { - const { findByText, container } = await renderWithEffects( - , - ); - // descending by name - let nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(5); - expect(nameCells[0].textContent).toBe( - '@janus-idp/backstage-plugin-3scale-backend-dynamic', - ); - expect(nameCells[4].textContent).toBe('@janus-idp/backstage-plugin-argocd'); - await act(() => findByText('Name').then(el => el.click())); - // ascending by name - nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(5); - expect(nameCells[0].textContent).toBe( - 'roadiehq-scaffolder-backend-module-utils-dynamic', - ); - expect(nameCells[4].textContent).toBe('roadiehq-backstage-plugin-jira'); - // ascending by version - await act(() => findByText('Version').then(el => el.click())); - nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(5); - expect(nameCells[0].textContent).toBe('api-returned-some-plugin-five'); - expect(nameCells[4].textContent).toBe('api-returned-some-plugin-three'); - - // ascending by enabled - await act(() => findByText('Enabled').then(el => el.click())); - nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(5); - expect(nameCells[0].textContent).toBe('api-returned-some-plugin-six'); - expect(nameCells[4].textContent).toBe('api-returned-some-plugin-two'); - - // ascending by Preinstalled - await act(() => findByText('Preinstalled').then(el => el.click())); - nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(5); - expect(nameCells[0].textContent).toBe( - '@janus-idp/backstage-plugin-analytics-provider-segment', - ); - expect(nameCells[4].textContent).toBe( - '@janus-idp/backstage-plugin-jfrog-artifactory', - ); - }); - it('supports changing the number of items per page', async () => { - const { findByText, container } = await renderWithEffects( - , - ); - let nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(5); - await act(async () => { - const select = await findByText('5 rows'); - fireEvent.mouseDown(select); - }); - await act(() => screen.findByText('10').then(el => el.click())); - nameCells = Array.from( - container.querySelectorAll('tbody tr > td:first-child'), - ); - expect(nameCells.length).toBe(10); + const displayedPlugins = plugins.slice(0, DEFAULT_ROWS_DISPLAYED); + expect(nameCells.length).toBe(displayedPlugins.length); + for (let i = 0; i < DEFAULT_ROWS_DISPLAYED; i++) { + expect(nameCells[i].textContent).toBe(displayedPlugins[i].name); + try { + expect(versionCells[i].textContent).toBe(displayedPlugins[i].version); + expect(enabledCells[i].textContent).toBe( + displayedPlugins[i].enabled ? 'Yes' : 'No', + ); + expect(internalCells[i].textContent).toBe( + displayedPlugins[i].internal ? 'Yes' : 'No', + ); + } catch (e) { + throw new Error(`${displayedPlugins[i].name}: ${(e as Error).message}`); + } + } }); }); diff --git a/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.tsx b/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.tsx index 53b741268b..41712ab020 100644 --- a/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.tsx +++ b/plugins/dynamic-plugins-info/src/components/DynamicPluginsTable/DynamicPluginsTable.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { ResponseErrorPanel, @@ -11,8 +11,8 @@ import { Query, QueryResult } from '@material-table/core'; import { DynamicPluginInfo, dynamicPluginsInfoApiRef } from '../../api/types'; import { - InternalPluginsMap, getNotEnabledInternalPlugins, + InternalPluginsMap, } from '../InternalPluginsMap'; export const DynamicPluginsTable = () => { @@ -72,7 +72,7 @@ export const DynamicPluginsTable = () => { enabled: true, }; } - return { ...plugin, internal: false, enabled: true }; + return plugin; }, ); const notEnabledInternalPlugins = getNotEnabledInternalPlugins( diff --git a/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.test.ts b/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.test.ts new file mode 100644 index 0000000000..719b45426e --- /dev/null +++ b/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.test.ts @@ -0,0 +1,117 @@ +import { glob } from 'glob'; + +import fs from 'node:fs'; +import path from 'node:path'; + +import { InternalPluginsMap } from './InternalPluginsMap'; + +const PACKAGE_JSON_GLOB = '**/package.json'; +const IGNORE_GLOB = ['**/node_modules/**', '**/dist-dynamic/**']; + +const ROOT_DIR = path.join(__dirname, '../../../..'); +const DYNAMIC_PLUGINS_DIR = path.join(ROOT_DIR, 'dynamic-plugins/wrappers'); + +type WrapperFrontendPackageJson = { + name: string; + backstage: { + role: 'frontend-plugin'; + }; + scalprum: { + name: string; + }; + repository: { + directory: string; + }; +}; + +type WrapperBackendPackageJson = { + name: string; + backstage: { + role: 'backend-plugin' | 'backend-plugin-module'; + }; + repository: { + directory: string; + }; +}; + +type WrapperPackageJson = + | WrapperFrontendPackageJson + | WrapperBackendPackageJson; + +function isFrontendPlugin( + packageJson: WrapperPackageJson, +): packageJson is WrapperFrontendPackageJson { + return packageJson.backstage.role === 'frontend-plugin'; +} + +function isBackendPlugin( + packageJson: WrapperPackageJson, +): packageJson is WrapperBackendPackageJson { + return ( + packageJson.backstage.role === 'backend-plugin' || + packageJson.backstage.role === 'backend-plugin-module' + ); +} + +function getDifference(arrA: T[], arrB: T[]): T[] { + return arrA.filter(x => !arrB.includes(x)); +} + +describe('InternalPluginsMap', () => { + const wrapperPackageJsonPaths = glob.sync(PACKAGE_JSON_GLOB, { + cwd: DYNAMIC_PLUGINS_DIR, // Search only within DYNAMIC_PLUGINS_DIR + ignore: IGNORE_GLOB, + }); + + const wrapperDirNames = wrapperPackageJsonPaths.map(path.dirname); + + const wrapperPackageJsonFiles = wrapperPackageJsonPaths.map( + packageJsonPath => { + const packageJson = fs.readFileSync( + path.join(DYNAMIC_PLUGINS_DIR, packageJsonPath), + ); + return JSON.parse(packageJson.toString()) as WrapperPackageJson; + }, + ); + const frontendPackageJsonFiles = wrapperPackageJsonFiles.filter(packageJson => + isFrontendPlugin(packageJson), + ); + const backendPackageJsonFiles = wrapperPackageJsonFiles.filter(packageJson => + isBackendPlugin(packageJson), + ); + + it('should have a valid map', () => { + const difference = getDifference( + Object.keys(InternalPluginsMap), + wrapperDirNames, + ); + + try { + expect(difference).toStrictEqual([]); + } catch { + throw new Error( + `The following plugins are missing: ${difference.join(', ')}`, + ); + } + }); + + it.each(backendPackageJsonFiles)( + '$name should have a `-dynamic` suffix in the directory name', + ({ name }) => { + const hasDynamicSuffix = Object.values(InternalPluginsMap).some(value => + value.includes(`${name}-dynamic`), + ); + expect(hasDynamicSuffix).toBeTruthy(); + }, + ); + + it.each(frontendPackageJsonFiles)( + '$name should have a matching directory name', + ({ name }) => { + const hasMatchingDirName = Object.values(InternalPluginsMap).some(value => + value.includes(name), + ); + expect(hasMatchingDirName).toBeTruthy(); + }, + ); +}); diff --git a/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.ts b/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.ts new file mode 100644 index 0000000000..2e3a9d657b --- /dev/null +++ b/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.ts @@ -0,0 +1,166 @@ +import { DynamicPluginInfo } from '../api/types'; + +// This is a mapping of internal plugins to their package path based off dynamic-plugins.default.yaml +export const InternalPluginsMap: Record = { + 'backstage-plugin-scaffolder-backend-module-github-dynamic': + './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-github-dynamic', + 'backstage-plugin-catalog-backend-module-github-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic', + 'backstage-plugin-catalog-backend-module-github-org-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic', + 'backstage-community-plugin-github-actions': + './dynamic-plugins/dist/backstage-community-plugin-github-actions', + 'backstage-community-plugin-github-issues': + './dynamic-plugins/dist/backstage-community-plugin-github-issues', + 'roadiehq-backstage-plugin-github-insights': + './dynamic-plugins/dist/roadiehq-backstage-plugin-github-insights', + 'roadiehq-backstage-plugin-github-pull-requests': + './dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests', + 'roadiehq-backstage-plugin-security-insights': + './dynamic-plugins/dist/roadiehq-backstage-plugin-security-insights', + 'backstage-plugin-scaffolder-backend-module-gitlab-dynamic': + './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-gitlab-dynamic', + 'backstage-plugin-kubernetes-backend-dynamic': + './dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic', + 'backstage-plugin-kubernetes': + './dynamic-plugins/dist/backstage-plugin-kubernetes', + 'backstage-community-plugin-topology': + './dynamic-plugins/dist/backstage-community-plugin-topology', + 'roadiehq-scaffolder-backend-argocd-dynamic': + './dynamic-plugins/dist/roadiehq-scaffolder-backend-argocd-dynamic', + 'roadiehq-backstage-plugin-argo-cd': + './dynamic-plugins/dist/roadiehq-backstage-plugin-argo-cd', + 'roadiehq-backstage-plugin-argo-cd-backend-dynamic': + './dynamic-plugins/dist/roadiehq-backstage-plugin-argo-cd-backend-dynamic', + 'backstage-plugin-scaffolder-backend-module-azure-dynamic': + './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-azure-dynamic', + 'backstage-community-plugin-azure-devops-backend-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-azure-devops-backend-dynamic', + 'backstage-community-plugin-azure-devops': + './dynamic-plugins/dist/backstage-community-plugin-azure-devops', + 'backstage-community-plugin-jenkins-backend-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-jenkins-backend-dynamic', + 'backstage-community-plugin-jenkins': + './dynamic-plugins/dist/backstage-community-plugin-jenkins', + 'backstage-plugin-notifications': + './dynamic-plugins/dist/backstage-plugin-notifications', + 'backstage-plugin-notifications-backend-dynamic': + './dynamic-plugins/dist/backstage-plugin-notifications-backend-dynamic', + 'backstage-plugin-notifications-backend-module-email-dynamic': + './dynamic-plugins/dist/backstage-plugin-notifications-backend-module-email-dynamic', + 'backstage-plugin-signals-backend-dynamic': + './dynamic-plugins/dist/backstage-plugin-signals-backend-dynamic', + 'backstage-plugin-signals': './dynamic-plugins/dist/backstage-plugin-signals', + 'backstage-community-plugin-sonarqube-backend-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-sonarqube-backend-dynamic', + 'backstage-community-plugin-sonarqube': + './dynamic-plugins/dist/backstage-community-plugin-sonarqube', + 'backstage-community-plugin-ocm-backend-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-ocm-backend-dynamic', + 'backstage-community-plugin-ocm': + './dynamic-plugins/dist/backstage-community-plugin-ocm', + 'red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic': + './dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic', + 'red-hat-developer-hub-backstage-plugin-bulk-import': + './dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import', + 'red-hat-developer-hub-backstage-plugin-dynamic-home-page': + './dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page', + 'backstage-plugin-techdocs-backend-dynamic': + './dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic', + 'backstage-plugin-techdocs': + './dynamic-plugins/dist/backstage-plugin-techdocs', + 'backstage-plugin-scaffolder-backend-module-gerrit-dynamic': + './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-gerrit-dynamic', + 'roadiehq-scaffolder-backend-module-utils-dynamic': + './dynamic-plugins/dist/roadiehq-scaffolder-backend-module-utils-dynamic', + 'roadiehq-scaffolder-backend-module-http-request-dynamic': + './dynamic-plugins/dist/roadiehq-scaffolder-backend-module-http-request-dynamic', + 'backstage-community-plugin-scaffolder-backend-module-quay-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-quay-dynamic', + 'backstage-community-plugin-rbac': + './dynamic-plugins/dist/backstage-community-plugin-rbac', + 'backstage-community-plugin-scaffolder-backend-module-regex-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-regex-dynamic', + 'backstage-community-plugin-scaffolder-backend-module-servicenow-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-servicenow-dynamic', + 'backstage-community-plugin-scaffolder-backend-module-sonarqube-dynamic': + '/dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-sonarqube-dynamic', + 'janus-idp-backstage-plugin-aap-backend-dynamic': + './dynamic-plugins/dist/janus-idp-backstage-plugin-aap-backend-dynamic', + 'backstage-community-plugin-3scale-backend-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-3scale-backend-dynamic', + 'backstage-community-plugin-catalog-backend-module-keycloak-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-keycloak-dynamic', + 'backstage-community-plugin-redhat-argocd': + './dynamic-plugins/dist/backstage-community-plugin-redhat-argocd', + 'backstage-plugin-scaffolder-backend-module-bitbucket-cloud-dynamic': + './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-bitbucket-cloud-dynamic', + 'backstage-plugin-catalog-backend-module-bitbucket-cloud-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-bitbucket-cloud-dynamic', + 'backstage-plugin-scaffolder-backend-module-bitbucket-server-dynamic': + './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-bitbucket-server-dynamic', + 'backstage-plugin-catalog-backend-module-bitbucket-server-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-bitbucket-server-dynamic', + 'backstage-community-plugin-dynatrace': + './dynamic-plugins/dist/backstage-community-plugin-dynatrace', + 'roadiehq-backstage-plugin-jira': + './dynamic-plugins/dist/roadiehq-backstage-plugin-jira', + 'roadiehq-backstage-plugin-datadog': + './dynamic-plugins/dist/roadiehq-backstage-plugin-datadog', + 'backstage-community-plugin-tekton': + './dynamic-plugins/dist/backstage-community-plugin-tekton', + 'backstage-community-plugin-quay': + './dynamic-plugins/dist/backstage-community-plugin-quay', + 'backstage-community-plugin-nexus-repository-manager': + './dynamic-plugins/dist/backstage-community-plugin-nexus-repository-manager', + 'backstage-community-plugin-acr': + './dynamic-plugins/dist/backstage-community-plugin-acr', + 'backstage-community-plugin-jfrog-artifactory': + './dynamic-plugins/dist/backstage-community-plugin-jfrog-artifactory', + 'pagerduty-backstage-plugin': + './dynamic-plugins/dist/pagerduty-backstage-plugin', + 'pagerduty-backstage-plugin-backend-dynamic': + './dynamic-plugins/dist/pagerduty-backstage-plugin-backend-dynamic', + 'backstage-community-plugin-lighthouse': + './dynamic-plugins/dist/backstage-community-plugin-lighthouse', + 'backstage-community-plugin-tech-radar': + './dynamic-plugins/dist/backstage-community-plugin-tech-radar', + 'backstage-community-plugin-tech-radar-backend-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic', + 'backstage-community-plugin-analytics-provider-segment': + './dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment', + 'parfuemerie-douglas-scaffolder-backend-module-azure-repositories-dynamic': + './dynamic-plugins/dist/parfuemerie-douglas-scaffolder-backend-module-azure-repositories-dynamic', + 'immobiliarelabs-backstage-plugin-gitlab-backend-dynamic': + './dynamic-plugins/dist/immobiliarelabs-backstage-plugin-gitlab-backend-dynamic', + 'backstage-community-plugin-catalog-backend-module-pingidentity-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-pingidentity-dynamic', + 'backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic': + './dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic', + 'backstage-plugin-catalog-backend-module-gitlab-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-dynamic', + 'backstage-plugin-catalog-backend-module-gitlab-org-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-org-dynamic', + 'backstage-plugin-catalog-backend-module-ldap-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-ldap-dynamic', + 'backstage-plugin-catalog-backend-module-msgraph-dynamic': + './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-msgraph-dynamic', +}; + +export const getNotEnabledInternalPlugins = (enabledPlugins: string[]) => { + const plugins: DynamicPluginInfo[] = []; + if (!enabledPlugins || enabledPlugins?.length === 0) return []; + Object.keys(InternalPluginsMap).forEach(internalPlugin => { + if (!enabledPlugins.includes(internalPlugin)) { + plugins.push({ + name: internalPlugin, + version: '', + internal: true, + enabled: false, + role: '', + platform: '', + }); + } + }); + return plugins; +}; diff --git a/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.tsx b/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.tsx deleted file mode 100644 index c2ff10ad30..0000000000 --- a/plugins/dynamic-plugins-info/src/components/InternalPluginsMap.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { DynamicPluginInfo } from '../api/types'; - -// This is a mapping of internal plugins to their package path based off dynamic-plugins.default.yaml -export const InternalPluginsMap: Record = { - 'backstage-plugin-scaffolder-backend-module-github-dynamic': - './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-github-dynamic', - 'backstage-plugin-catalog-backend-module-github-dynamic': - './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic', - 'backstage-plugin-catalog-backend-module-github-org-dynamic': - './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic', - 'backstage-plugin-github-actions': - './dynamic-plugins/dist/backstage-plugin-github-actions', - 'backstage-plugin-github-issues': - './dynamic-plugins/dist/backstage-plugin-github-issues', - 'roadiehq-backstage-plugin-github-insights': - './dynamic-plugins/dist/roadiehq-backstage-plugin-github-insights', - 'roadiehq-backstage-plugin-github-pull-requests': - './dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests', - 'roadiehq-backstage-plugin-security-insights': - './dynamic-plugins/dist/roadiehq-backstage-plugin-security-insights', - 'backstage-plugin-scaffolder-backend-module-gitlab-dynamic': - './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-gitlab-dynamic', - 'backstage-plugin-kubernetes-backend-dynamic': - './dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic', - 'backstage-plugin-kubernetes': - './dynamic-plugins/dist/backstage-plugin-kubernetes', - '@janus-idp/backstage-plugin-topology': - './dynamic-plugins/dist/janus-idp-backstage-plugin-topology', - 'roadiehq-scaffolder-backend-argocd-dynamic': - './dynamic-plugins/dist/roadiehq-scaffolder-backend-argocd-dynamic', - 'roadiehq-backstage-plugin-argo-cd': - './dynamic-plugins/dist/roadiehq-backstage-plugin-argo-cd', - 'backstage-plugin-scaffolder-backend-module-azure-dynamic': - './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-azure-dynamic', - 'backstage-plugin-azure-devops-backend-dynamic': - './dynamic-plugins/dist/backstage-plugin-azure-devops-backend-dynamic', - 'backstage-plugin-azure-devops': - './dynamic-plugins/dist/backstage-plugin-azure-devops', - 'backstage-plugin-jenkins-backend-dynamic': - './dynamic-plugins/dist/backstage-plugin-jenkins-backend-dynamic', - 'backstage-plugin-jenkins': './dynamic-plugins/dist/backstage-plugin-jenkins', - 'backstage-plugin-sonarqube-backend-dynamic': - './dynamic-plugins/dist/backstage-plugin-sonarqube-backend-dynamic', - 'backstage-plugin-sonarqube': - './dynamic-plugins/dist/backstage-plugin-sonarqube', - '@janus-idp/backstage-plugin-ocm-backend-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-plugin-ocm-backend-dynamic', - '@janus-idp/backstage-plugin-ocm': - './dynamic-plugins/dist/janus-idp-backstage-plugin-ocm', - '@janus-idp/backstage-plugin-bulk-import-backend-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-plugin-bulk-import-backend-dynamic', - '@janus-idp/backstage-plugin-bulk-import': - './dynamic-plugins/dist/janus-idp-backstage-plugin-bulk-import', - 'backstage-plugin-techdocs-backend-dynamic': - './dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic', - 'backstage-plugin-techdocs': - './dynamic-plugins/dist/backstage-plugin-techdocs', - 'backstage-plugin-scaffolder-backend-module-gerrit-dynamic': - './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-gerrit-dynamic', - 'roadiehq-scaffolder-backend-module-utils-dynamic': - './dynamic-plugins/dist/roadiehq-scaffolder-backend-module-utils-dynamic', - 'roadiehq-scaffolder-backend-module-http-request-dynamic': - './dynamic-plugins/dist/roadiehq-scaffolder-backend-module-http-request-dynamic', - '@janus-idp/backstage-scaffolder-backend-module-quay-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-scaffolder-backend-module-quay-dynamic', - '@janus-idp/backstage-scaffolder-backend-module-regex-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-scaffolder-backend-module-regex-dynamic', - '@janus-idp/backstage-plugin-rbac': - './dynamic-plugins/dist/janus-idp-backstage-plugin-rbac', - '@janus-idp/backstage-scaffolder-backend-module-servicenow-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-scaffolder-backend-module-servicenow-dynamic', - '@janus-idp/backstage-scaffolder-backend-module-sonarqube-dynamic': - '/dynamic-plugins/dist/janus-idp-backstage-scaffolder-backend-module-sonarqube-dynamic', - '@janus-idp/backstage-plugin-aap-backend-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-plugin-aap-backend-dynamic', - '@janus-idp/backstage-plugin-3scale-backend-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-plugin-3scale-backend-dynamic', - '@janus-idp/backstage-plugin-keycloak-backend-dynamic': - './dynamic-plugins/dist/janus-idp-backstage-plugin-keycloak-backend-dynamic', - '@janus-idp/backstage-plugin-argocd': - './dynamic-plugins/dist/janus-idp-backstage-plugin-argocd', - 'backstage-plugin-scaffolder-backend-module-bitbucket-cloud-dynamic': - './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-bitbucket-cloud-dynamic', - 'backstage-plugin-catalog-backend-module-bitbucket-cloud-dynamic': - './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-bitbucket-cloud-dynamic', - 'backstage-plugin-scaffolder-backend-module-bitbucket-server-dynamic': - './dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-bitbucket-server-dynamic', - 'backstage-plugin-catalog-backend-module-bitbucket-server-dynamic': - './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-bitbucket-server-dynamic', - 'backstage-plugin-dynatrace': - '/dynamic-plugins/dist/backstage-plugin-dynatrace', - 'roadiehq-backstage-plugin-jira': - './dynamic-plugins/dist/roadiehq-backstage-plugin-jira', - 'roadiehq-backstage-plugin-datadog': - './dynamic-plugins/dist/roadiehq-backstage-plugin-datadog', - '@janus-idp/backstage-plugin-tekton': - './dynamic-plugins/dist/janus-idp-backstage-plugin-tekton', - '@janus-idp/backstage-plugin-quay': - './dynamic-plugins/dist/janus-idp-backstage-plugin-quay', - '@janus-idp/backstage-plugin-nexus-repository-manager': - './dynamic-plugins/dist/janus-idp-backstage-plugin-nexus-repository-manager', - '@janus-idp/backstage-plugin-acr': - './dynamic-plugins/dist/janus-idp-backstage-plugin-acr', - '@janus-idp/backstage-plugin-jfrog-artifactory': - './dynamic-plugins/dist/janus-idp-backstage-plugin-jfrog-artifactory', - 'pagerduty-backstage-plugin': - './dynamic-plugins/dist/pagerduty-backstage-plugin', - 'backstage-plugin-lighthouse': - './dynamic-plugins/dist/backstage-plugin-lighthouse', - 'backstage-plugin-tech-radar': - './dynamic-plugins/dist/backstage-plugin-tech-radar', - '@janus-idp/backstage-plugin-analytics-provider-segment': - './dynamic-plugins/dist/janus-idp-backstage-plugin-analytics-provider-segment', -}; - -export const getNotEnabledInternalPlugins = (enabledPlugins: string[]) => { - const plugins: DynamicPluginInfo[] = []; - if (!enabledPlugins || enabledPlugins?.length === 0) return []; - Object.keys(InternalPluginsMap).forEach(internalPlugin => { - if (!enabledPlugins.includes(internalPlugin)) { - plugins.push({ - name: internalPlugin, - version: '', - internal: true, - enabled: false, - role: '', - platform: '', - }); - } - }); - return plugins; -}; diff --git a/plugins/dynamic-plugins-info/src/index.ts b/plugins/dynamic-plugins-info/src/index.ts index 46440887c3..f1d73dafc3 100644 --- a/plugins/dynamic-plugins-info/src/index.ts +++ b/plugins/dynamic-plugins-info/src/index.ts @@ -1 +1,3 @@ export { dynamicPluginsInfoPlugin, DynamicPluginsInfo } from './plugin'; +export { default as PluginsInfoIcon } from '@mui/icons-material/PowerOutlined'; +export { default as AdminIcon } from '@mui/icons-material/GppMaybeOutlined'; diff --git a/plugins/dynamic-plugins-info/tsconfig.json b/plugins/dynamic-plugins-info/tsconfig.json index c81a299b6e..89537c775b 100644 --- a/plugins/dynamic-plugins-info/tsconfig.json +++ b/plugins/dynamic-plugins-info/tsconfig.json @@ -4,6 +4,7 @@ "exclude": ["node_modules"], "compilerOptions": { "outDir": "../../dist-types/plugins/dynamic-plugins-info", - "rootDir": "." + "rootDir": ".", + "jsx": "preserve" } } diff --git a/plugins/dynamic-plugins-info/turbo.json b/plugins/dynamic-plugins-info/turbo.json index aad6de81a6..aaf87bed7c 100644 --- a/plugins/dynamic-plugins-info/turbo.json +++ b/plugins/dynamic-plugins-info/turbo.json @@ -1,9 +1,8 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "tsc": { - "outputs": ["../../dist-types/plugins/dynamic-plugins-info/**"], - "dependsOn": ["^tsc"] + "outputs": ["../../dist-types/plugins/dynamic-plugins-info/**"] } } } diff --git a/plugins/licensed-users-info-backend/.lintstagedrc.json b/plugins/licensed-users-info-backend/.lintstagedrc.json new file mode 100644 index 0000000000..14b2263def --- /dev/null +++ b/plugins/licensed-users-info-backend/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*": "prettier --ignore-unknown --write", + "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" +} diff --git a/plugins/licensed-users-info-backend/.prettierignore b/plugins/licensed-users-info-backend/.prettierignore new file mode 100644 index 0000000000..3f6fff7b2b --- /dev/null +++ b/plugins/licensed-users-info-backend/.prettierignore @@ -0,0 +1,2 @@ +dist +coverage \ No newline at end of file diff --git a/plugins/licensed-users-info-backend/.prettierrc.js b/plugins/licensed-users-info-backend/.prettierrc.js new file mode 100644 index 0000000000..84cbac65b5 --- /dev/null +++ b/plugins/licensed-users-info-backend/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@janus-idp/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/plugins/licensed-users-info-backend/package.json b/plugins/licensed-users-info-backend/package.json index dea3623d34..c734539efc 100644 --- a/plugins/licensed-users-info-backend/package.json +++ b/plugins/licensed-users-info-backend/package.json @@ -11,44 +11,51 @@ "types": "dist/index.d.ts" }, "backstage": { - "role": "backend-plugin" + "role": "backend-plugin", + "pluginId": "licensed-users-info", + "pluginPackages": [ + "@internal/plugin-licensed-users-info-backend" + ] }, "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", - "lint": "backstage-cli package lint", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", "test": "backstage-cli package test", "clean": "backstage-cli package clean", "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" + "postpack": "backstage-cli package postpack", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." }, "dependencies": { - "@backstage/backend-common": "^0.23.3", - "@backstage/backend-defaults": "^0.4.1", - "@backstage/backend-plugin-api": "^0.7.0", - "@janus-idp/backstage-plugin-rbac-common": "1.8.2", - "@backstage/catalog-client": "^1.6.5", - "@backstage/catalog-model": "1.5.0", - "@backstage/config": "^1.2.0", - "@backstage/errors": "^1.2.4", - "@backstage/plugin-auth-backend": "^0.22.5", + "@backstage-community/plugin-rbac-common": "1.12.2", + "@backstage/backend-defaults": "0.5.2", + "@backstage/backend-plugin-api": "1.0.1", + "@backstage/catalog-client": "1.7.1", + "@backstage/catalog-model": "1.7.0", + "@backstage/config": "1.2.0", + "@backstage/errors": "1.2.4", + "@backstage/plugin-auth-backend": "0.23.1", "@backstage/plugin-permission-common": "0.8.1", - "@backstage/types": "^1.1.1", - "express": "4.19.2", + "@backstage/types": "1.1.1", + "express": "4.21.0", "express-promise-router": "4.1.1", - "json-2-csv": "5.5.5", + "json-2-csv": "5.5.6", "knex": "3.1.0", "luxon": "3.5.0", "node-fetch": "2.7.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.4.4", - "@backstage/cli": "^0.26.11", - "@backstage/plugin-auth-backend": "^0.22.5", - "@backstage/plugin-auth-backend-module-guest-provider": "^0.1.8", + "@backstage/backend-test-utils": "1.0.2", + "@backstage/cli": "0.28.2", + "@backstage/plugin-auth-backend-module-guest-provider": "0.2.1", "@types/express": "4.17.21", - "@types/supertest": "2.0.16", - "msw": "2.3.5", + "@types/supertest": "6.0.2", + "msw": "1.3.4", + "prettier": "3.4.1", "supertest": "6.3.4" }, "files": [ diff --git a/plugins/licensed-users-info-backend/src/plugin.ts b/plugins/licensed-users-info-backend/src/plugin.ts index 5692c0d658..8179504f07 100644 --- a/plugins/licensed-users-info-backend/src/plugin.ts +++ b/plugins/licensed-users-info-backend/src/plugin.ts @@ -2,6 +2,7 @@ import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; + import { createRouter } from './service/router'; /** @@ -21,6 +22,7 @@ export const licensedUsersInfoPlugin = createBackendPlugin({ discovery: coreServices.discovery, permissions: coreServices.permissions, httpAuth: coreServices.httpAuth, + lifecycle: coreServices.lifecycle, }, async init({ httpRouter, @@ -30,6 +32,7 @@ export const licensedUsersInfoPlugin = createBackendPlugin({ discovery, permissions, httpAuth, + lifecycle, }) { httpRouter.use( await createRouter({ @@ -39,6 +42,7 @@ export const licensedUsersInfoPlugin = createBackendPlugin({ discovery, permissions, httpAuth, + lifecycle, }), ); httpRouter.addAuthPolicy({ diff --git a/plugins/licensed-users-info-backend/src/service/catalogStore.ts b/plugins/licensed-users-info-backend/src/service/catalogStore.ts index 69cbb762db..33fe706ca0 100644 --- a/plugins/licensed-users-info-backend/src/service/catalogStore.ts +++ b/plugins/licensed-users-info-backend/src/service/catalogStore.ts @@ -1,6 +1,6 @@ -import { Entity } from '@backstage/catalog-model'; -import { CatalogClient } from '@backstage/catalog-client'; import { AuthService } from '@backstage/backend-plugin-api'; +import { CatalogClient } from '@backstage/catalog-client'; +import { Entity } from '@backstage/catalog-model'; export class CatalogEntityStore { constructor( diff --git a/plugins/licensed-users-info-backend/src/service/router.test.ts b/plugins/licensed-users-info-backend/src/service/router.test.ts index 334e9fb155..036119530e 100644 --- a/plugins/licensed-users-info-backend/src/service/router.test.ts +++ b/plugins/licensed-users-info-backend/src/service/router.test.ts @@ -1,4 +1,5 @@ import { mockServices } from '@backstage/backend-test-utils'; + import express from 'express'; import request from 'supertest'; @@ -18,6 +19,7 @@ describe('createRouter', () => { let app: express.Express; beforeAll(async () => { + // TODO: Replace with module const router = await createRouter({ logger: mockServices.logger.mock(), config: mockServices.rootConfig(), @@ -25,6 +27,7 @@ describe('createRouter', () => { discovery: mockServices.discovery.mock(), permissions: mockServices.permissions.mock(), httpAuth: mockServices.httpAuth.mock(), + lifecycle: mockServices.lifecycle.mock(), }); app = express().use(router); }); diff --git a/plugins/licensed-users-info-backend/src/service/router.ts b/plugins/licensed-users-info-backend/src/service/router.ts index 9af01002b8..5aa57de504 100644 --- a/plugins/licensed-users-info-backend/src/service/router.ts +++ b/plugins/licensed-users-info-backend/src/service/router.ts @@ -1,28 +1,31 @@ +import { DatabaseManager } from '@backstage/backend-defaults/database'; import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; -import { +import type { AuthService, BackstageCredentials, DiscoveryService, HttpAuthService, + LifecycleService, LoggerService, PermissionsService, RootConfigService, } from '@backstage/backend-plugin-api'; +import { CatalogClient } from '@backstage/catalog-client'; +import { NotAllowedError } from '@backstage/errors'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; + +import { policyEntityReadPermission } from '@backstage-community/plugin-rbac-common'; import express from 'express'; import Router from 'express-promise-router'; -import { DatabaseManager } from '@backstage/backend-defaults/database'; +import { json2csv } from 'json-2-csv'; +import { DateTime } from 'luxon'; + import { DatabaseUserInfoStore, UserInfoRow, } from '../database/databaseUserInfoStore'; import { CatalogEntityStore } from './catalogStore'; import { readBackstageTokenExpiration } from './readBackstageTokenExpiration'; -import { json2csv } from 'json-2-csv'; -import { CatalogClient } from '@backstage/catalog-client'; -import { NotAllowedError } from '@backstage/errors'; -import { AuthorizeResult } from '@backstage/plugin-permission-common'; -import { policyEntityReadPermission } from '@janus-idp/backstage-plugin-rbac-common'; -import { DateTime } from 'luxon'; export interface RouterOptions { logger: LoggerService; @@ -31,6 +34,7 @@ export interface RouterOptions { discovery: DiscoveryService; permissions: PermissionsService; httpAuth: HttpAuthService; + lifecycle: LifecycleService; } export type UserInfoResponse = { @@ -44,12 +48,13 @@ export type UserInfoResponse = { export async function createRouter( options: RouterOptions, ): Promise { - const { logger, config, auth, discovery, permissions, httpAuth } = options; + const { logger, config, auth, discovery, permissions, httpAuth, lifecycle } = + options; const tokenExpiration = readBackstageTokenExpiration(config); const authDB = await DatabaseManager.fromConfig(options.config) - .forPlugin('auth') + .forPlugin('auth', { logger, lifecycle }) .getClient(); const catalogClient = new CatalogClient({ discoveryApi: discovery }); @@ -98,7 +103,7 @@ export async function createRouter( if (request.headers['content-type']?.includes('text/csv')) { try { - const csv = await json2csv(users, { + const csv = json2csv(users, { keys: ['userEntityRef', 'displayName', 'email', 'lastAuthTime'], }); response.header('Content-Type', 'text/csv'); diff --git a/plugins/licensed-users-info-backend/tsconfig.json b/plugins/licensed-users-info-backend/tsconfig.json new file mode 100644 index 0000000000..5804f50d75 --- /dev/null +++ b/plugins/licensed-users-info-backend/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@backstage/cli/config/tsconfig.json", + "include": ["src", "dev", "migrations"], + "exclude": ["node_modules"], + "compilerOptions": { + "outDir": "../../dist-types/plugins/licensed-users-info-backend", + "rootDir": "." + } +} diff --git a/plugins/licensed-users-info-backend/turbo.json b/plugins/licensed-users-info-backend/turbo.json new file mode 100644 index 0000000000..ed863930a2 --- /dev/null +++ b/plugins/licensed-users-info-backend/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "tasks": { + "tsc": { + "outputs": ["../../dist-types/plugins/licensed-users-info-backend/**"] + } + } +} diff --git a/plugins/scalprum-backend/.lintstagedrc.json b/plugins/scalprum-backend/.lintstagedrc.json new file mode 100644 index 0000000000..14b2263def --- /dev/null +++ b/plugins/scalprum-backend/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*": "prettier --ignore-unknown --write", + "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" +} diff --git a/plugins/scalprum-backend/.prettierignore b/plugins/scalprum-backend/.prettierignore new file mode 100644 index 0000000000..3f6fff7b2b --- /dev/null +++ b/plugins/scalprum-backend/.prettierignore @@ -0,0 +1,2 @@ +dist +coverage \ No newline at end of file diff --git a/plugins/scalprum-backend/.prettierrc.js b/plugins/scalprum-backend/.prettierrc.js new file mode 100644 index 0000000000..84cbac65b5 --- /dev/null +++ b/plugins/scalprum-backend/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@janus-idp/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/plugins/scalprum-backend/package.json b/plugins/scalprum-backend/package.json index f9faaff398..482278e9d6 100644 --- a/plugins/scalprum-backend/package.json +++ b/plugins/scalprum-backend/package.json @@ -20,30 +20,34 @@ "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", - "lint": "backstage-cli package lint", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", "test": "backstage-cli package test --passWithNoTests --coverage", "clean": "backstage-cli package clean", "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" + "postpack": "backstage-cli package postpack", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." }, "dependencies": { - "@backstage/backend-common": "0.23.3", - "@backstage/backend-defaults": "0.4.1", - "@backstage/backend-dynamic-feature-service": "0.2.15", - "@backstage/backend-plugin-api": "0.7.0", + "@backstage/backend-defaults": "0.5.2", + "@backstage/backend-dynamic-feature-service": "0.4.4", + "@backstage/backend-plugin-api": "1.0.1", "@backstage/config": "1.2.0", - "@types/express": "4.17.21", - "express": "4.19.2", + "express": "4.21.0", "node-fetch": "2.7.0", "winston": "3.14.2" }, "devDependencies": { - "@backstage/backend-test-utils": "0.4.4", - "@backstage/cli": "0.26.11", + "@backstage/backend-test-utils": "1.0.2", + "@backstage/cli": "0.28.2", + "@types/express": "4.17.21", "@types/mock-fs": "4.13.4", "@types/supertest": "6.0.2", - "mock-fs": "5.2.0", - "msw": "2.3.5", + "mock-fs": "5.4.1", + "msw": "1.3.4", + "prettier": "3.4.1", "supertest": "6.3.4" }, "files": [ diff --git a/plugins/scalprum-backend/src/plugin.ts b/plugins/scalprum-backend/src/plugin.ts index 58e551d2e8..b3c07b719b 100644 --- a/plugins/scalprum-backend/src/plugin.ts +++ b/plugins/scalprum-backend/src/plugin.ts @@ -1,12 +1,13 @@ +import { + DynamicPluginManager, + dynamicPluginsServiceRef, +} from '@backstage/backend-dynamic-feature-service'; import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; + import { createRouter } from './service/router'; -import { - DynamicPluginManager, - dynamicPluginsServiceRef, -} from '@backstage/backend-dynamic-feature-service'; export const scalprumPlugin = createBackendPlugin({ pluginId: 'scalprum', diff --git a/plugins/scalprum-backend/src/service/router.test.ts b/plugins/scalprum-backend/src/service/router.test.ts index 2f6840a332..c373838912 100644 --- a/plugins/scalprum-backend/src/service/router.test.ts +++ b/plugins/scalprum-backend/src/service/router.test.ts @@ -1,18 +1,21 @@ -import express, { Router } from 'express'; -import request from 'supertest'; -import url from 'url'; -import path from 'path'; -import { createRouter } from './router'; import { DynamicPluginManager, ScannedPluginManifest, ScannedPluginPackage, } from '@backstage/backend-dynamic-feature-service'; +import { LoggerService } from '@backstage/backend-plugin-api'; import { createMockDirectory, mockServices, } from '@backstage/backend-test-utils'; -import { LoggerService } from '@backstage/backend-plugin-api'; + +import express, { Router } from 'express'; +import request from 'supertest'; + +import path from 'path'; +import url from 'url'; + +import { createRouter } from './router'; describe('createRouter', () => { let app: express.Express; diff --git a/plugins/scalprum-backend/src/service/router.ts b/plugins/scalprum-backend/src/service/router.ts index 01600157f3..31bddefb80 100644 --- a/plugins/scalprum-backend/src/service/router.ts +++ b/plugins/scalprum-backend/src/service/router.ts @@ -2,7 +2,9 @@ import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; import { DynamicPluginManager } from '@backstage/backend-dynamic-feature-service'; import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; + import express, { Router } from 'express'; + import * as fs from 'fs'; import * as path from 'path'; import * as url from 'url'; diff --git a/plugins/scalprum-backend/tsconfig.json b/plugins/scalprum-backend/tsconfig.json new file mode 100644 index 0000000000..d32e7138db --- /dev/null +++ b/plugins/scalprum-backend/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@backstage/cli/config/tsconfig.json", + "include": ["src", "dev", "migrations"], + "exclude": ["node_modules"], + "compilerOptions": { + "outDir": "../../dist-types/plugins/scalprum-backend", + "rootDir": "." + } +} diff --git a/plugins/scalprum-backend/turbo.json b/plugins/scalprum-backend/turbo.json new file mode 100644 index 0000000000..dab3b0694a --- /dev/null +++ b/plugins/scalprum-backend/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "tasks": { + "tsc": { + "outputs": ["../../dist-types/plugins/scalprum-backend/**"] + } + } +} diff --git a/scripts/keycloak-setup/auth/database-secrets.yaml b/scripts/keycloak-setup/auth/database-secrets.yaml new file mode 100644 index 0000000000..72a48c47f4 --- /dev/null +++ b/scripts/keycloak-setup/auth/database-secrets.yaml @@ -0,0 +1,9 @@ +kind: Secret +apiVersion: v1 +metadata: + name: keycloak-db-secret + namespace: keycloak +data: + password: + username: +type: Opaque diff --git a/scripts/keycloak-setup/database/postgres.yaml b/scripts/keycloak-setup/database/postgres.yaml new file mode 100644 index 0000000000..1b0ed56241 --- /dev/null +++ b/scripts/keycloak-setup/database/postgres.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: postgresql-db +spec: + serviceName: postgresql-db-service + selector: + matchLabels: + app: postgresql-db + replicas: 1 + template: + metadata: + labels: + app: postgresql-db + spec: + containers: + - name: postgresql-db + image: postgres:latest + volumeMounts: + - mountPath: /data + name: cache-volume + env: + - name: POSTGRES_PASSWORD + value: testpassword + - name: PGDATA + value: /data/pgdata + - name: POSTGRES_DB + value: keycloak + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + volumes: + - name: cache-volume + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: postgres-db +spec: + selector: + app: postgresql-db + type: LoadBalancer + ports: + - port: 5432 + targetPort: 5432 diff --git a/scripts/keycloak-setup/deploy-keycloak.sh b/scripts/keycloak-setup/deploy-keycloak.sh new file mode 100755 index 0000000000..09e3fef0e8 --- /dev/null +++ b/scripts/keycloak-setup/deploy-keycloak.sh @@ -0,0 +1,140 @@ +#!/bin/bash +# Guide: https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/22.0/html-single/operator_guide/index#basic-deployment-database +# Prerequisite: Install Keycloak Operator (https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/22.0/html-single/operator_guide/index#installation-) + +set -e + +KEYCLOAK_NAMESPACE=keycloak +CERT_HOSTNAME="" # Ex: keycloak.apps-crc.testing +DELETE=false + +# TODO: add method to deploy without operator for ARM systems that don't have access to the keycloak operator. +usage() { + echo " +This script uses the Red Hat Keycloak operator to quickly setup an instance of keycloak with TLS enabled and a persistent postgresql database on Openshift Container Platform (OCP). +Prerequisites: + - Keycloak Operator needs to be installed on the cluster (https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/22.0/html-single/operator_guide/index#installation-) + - Be logged in to the cluster on the CLI +Usage: + $0 [OPTIONS] + +OPTIONS: + -gc, --generate-certificates : Generates an SSL certificate for the specified hostname. Returns a key.pem and a certificate.pem file in the ${PWD}/tls directory + -n, --namespace : The namespace the keycloak resources are installed onto. Default: keycloak + --uninstall : Uninstall specified keycloak resources. Options: database, keycloak, secrets, all + -h, --help : Prints this help message and exits + +" +} +PWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +echo "${PWD}" + +deployDB(){ + oc apply -f ${PWD}/database/postgres.yaml -n ${KEYCLOAK_NAMESPACE} +} + +generateSSLCerts(){ + openssl req -subj "/CN=${CERT_HOSTNAME}/O=RHDH/C=CA" -newkey rsa:2048 -nodes -keyout "${PWD}/tls/key.pem" -x509 -days 365 -out "${PWD}/tls/" certificate.pem -addext "subjectAltName = DNS:${CERT_HOSTNAME}" +} +deployTLSKeys(){ + oc create secret tls example-tls-secret --cert ${PWD}/tls/certificate.pem --key ${PWD}/tls/key.pem -n ${KEYCLOAK_NAMESPACE} +} + +deploySecrets(){ + oc apply -f ${PWD}/auth/database-secrets.local.yaml -n ${KEYCLOAK_NAMESPACE} +} + +deployKeyCloak(){ + oc apply -f ${PWD}/keycloak.yaml -n ${KEYCLOAK_NAMESPACE} +} + +deleteKeyCloak(){ + oc delete keycloak development-keycloak -n ${KEYCLOAK_NAMESPACE} +} + +deleteDB(){ + oc delete statefulset postgresql-db + oc delete service postgres-db +} + +deleteSecrets(){ + oc delete secret keycloak-db-secret + oc delete secret example-tls-secret +} + +deleteAll(){ + deleteSecrets + deleteDB + deleteKeyCloak +} + +deployAll(){ + deployTLSKeys + deploySecrets + deployDB + deployKeyCloak +} + +while [[ "$#" -gt 0 ]]; do + case $1 in + --generate-certs | -gc) + CERT_HOSTNAME="$2" + shift + ;; + --namespace | -n) + KEYCLOAK_NAMESPACE="$2" + shift + ;; + --uninstall) + DELETE="$2" + shift + ;; + --help | -h) + usage + exit 0 + ;; + esac + shift +done + +# Create Namespace and switch to it +oc new-project ${KEYCLOAK_NAMESPACE} +if [ $? -ne 0 ]; then + # Switch to it if it already exists + oc project ${KEYCLOAK_NAMESPACE} +fi + +case "${DELETE}" in + "") + : # noop if $DELETE is empty + ;; + keycloak) + deleteKeyCloak + exit 0 + ;; + database) + deleteDB + exit 0 + ;; + secrets) + deleteSecrets + exit 0 + ;; + all) + deleteAll + exit 0 + ;; + *) + echo "Invalid option, please provide one of: keycloak, database, secrets, all" + exit 1 + ;; +esac + +if [[ -n "${CERT_HOSTNAME}" ]]; then + generateSSLCerts +else + echo "Please provide a valid hostname for the SSL certificate" + exit 1 +fi + +deployAll diff --git a/scripts/keycloak-setup/keycloak.yaml b/scripts/keycloak-setup/keycloak.yaml new file mode 100644 index 0000000000..5b4f058123 --- /dev/null +++ b/scripts/keycloak-setup/keycloak.yaml @@ -0,0 +1,24 @@ +apiVersion: k8s.keycloak.org/v2alpha1 +kind: Keycloak +metadata: + name: development-keycloak + labels: + app: sso + namespace: keycloak +spec: + db: + host: postgres-db + passwordSecret: + key: password + name: keycloak-db-secret + usernameSecret: + key: username + name: keycloak-db-secret + vendor: postgres + hostname: + hostname: keycloak.apps-crc.testing + http: + httpEnabled: true + httpPort: 8080 + tlsSecret: example-tls-secret + instances: 1 diff --git a/scripts/patch-package.sh b/scripts/patch-package.sh new file mode 100755 index 0000000000..c03e78a1c6 --- /dev/null +++ b/scripts/patch-package.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +generate_backstage_package(){ + PKG_NAME=$1 + if [[ $PKG_NAME =~ ^plugin-(.*) ]]; then + cd ${SRC_REPO_PATH}/plugins/${PKG_NAME:7} || return 1 + echo "Changed directory to $(pwd)" + else + cd ${SRC_REPO_PATH}/packages/${PKG_NAME} || return 1 + echo "Changed directory to $(pwd)" + fi + + echo "Building ${PKG_NAME}" + yarn build || return 1 + # Extract the name of the resultant tar file + PACKAGE_TAR=$(npm pack . | tail -1) + echo "Generated Tar File: ${PACKAGE_TAR}" + tar -xvzf ${PACKAGE_TAR} + # Remove old extracted tar file if it exists + rm -rf ./${PKG_NAME} + # Extracted tar file will be a `package/` directory + mv -vf ./package ./${PKG_NAME} + + # Remove the tar file + rm ${PACKAGE_TAR} + + patch_backstage_package ${PKG_NAME} + + # Remove extracted tar file after the patches are generated + rm -rf ./${PKG_NAME} +} + +replace_references(){ + SRC_PACKAGE_PATH=$1 + DEST_PACKAGE_PATH=$2 + MODULE_TYPE=$3 # cjs or esm + + + SRC_CJS_PATH="${SRC_PACKAGE_PATH}/dist/${MODULE_TYPE}" + DEST_CJS_PATH="${DEST_PACKAGE_PATH}/dist/${MODULE_TYPE}" + + if [ -d "${DEST_CJS_PATH}" ] && [ -d "${SRC_CJS_PATH}" ]; then + # TODO: Grab ALL cjs file names + if [ $(find ${SRC_CJS_PATH} -type f | wc -l) -ne 2 ] || [ $(find ${DEST_CJS_PATH} -type f | wc -l) -ne 2 ]; then + echo "This script only supports file renaming for one pair of files in the dist/${MODULE_TYPE} directory" >&2 + echo "It may be necessary to manually rename and update references in ${DEST_CJS_PATH}" >&2 + return 1 + fi + + # FIXME: Add support for when there are more than one pair in the `cjs` directory + FILE_NAME=$(ls "${DEST_PACKAGE_PATH}/dist/${MODULE_TYPE}" | tail -1 | cut -d '.' -f 1); + NEWLY_BUILT_FILE_NAME=$(ls "${SRC_PACKAGE_PATH}/dist/${MODULE_TYPE}" | tail -1 | cut -d '.' -f 1); + + echo "Original File Name: ${FILE_NAME}" + echo "Newly Generated File Name: ${NEWLY_BUILT_FILE_NAME}" + + + echo "Renaming files in the ${SRC_CJS_PATH} directory" + # This makes the assumption that file names do not contains spaces or glob characters + filePair=($(find ${SRC_CJS_PATH} -type f -name ${NEWLY_BUILT_FILE_NAME}.*)); + for file in ${filePair[@]}; do + mv -vf "${file}" "${SRC_CJS_PATH}/${FILE_NAME}.${file#*.}" + done; + + # Update references to the cjs files + find ${SRC_PACKAGE_PATH} -type f -exec sed -i "s/${NEWLY_BUILT_FILE_NAME}/${FILE_NAME}/g" {} \; + fi +} +patch_backstage_package(){ + PKG_NAME=$1 + + if [[ $PKG_NAME =~ ^plugin-(.*) ]]; then + SRC_PACKAGE_PATH="${SRC_REPO_PATH}/plugins/${PKG_NAME:7}/${PKG_NAME}" + else + SRC_PACKAGE_PATH="${SRC_REPO_PATH}/packages/${PKG_NAME}/${PKG_NAME}" + fi + + DEST_PACKAGE_PATH="${DEST_REPO_PATH}/node_modules/@backstage/${PKG_NAME}" + + # We want to preserve the name of the files. The only files that have name changes with each rebuilt are + # the files in the `/dist/cjs` directories from backend plugins + # See https://github.com/ds300/patch-package/issues/518 + # FIXME: Currently function does not work when there are more than one pair of files in the folder + replace_references ${SRC_PACKAGE_PATH} ${DEST_PACKAGE_PATH} 'cjs' + + echo "Performing a diff before the merge (after the file renaming attempt)" + echo "=============================================================" + diff -r --brief ${DEST_PACKAGE_PATH} ${SRC_PACKAGE_PATH} + + # Snapshot the unpatched package before merging + DEST_PACKAGE_COPY=/tmp/${PKG_NAME}-copy + mkdir ${DEST_PACKAGE_COPY} + rsync -a ${DEST_PACKAGE_PATH}/* ${DEST_PACKAGE_COPY} + + echo "=============================================================" + echo "Attempt to merge the package contents" + # Merge the packages. + # Note: This will replace the package.json with the one from `yarn build` which may include `^workspace` versions + # This should not matter since the `patch-package` package does not apply diff for `package.json` + if [ -d "${SRC_PACKAGE_PATH}" ] && [ "$(ls -A ${SRC_PACKAGE_PATH})" ]; then + cp -Rv ${SRC_PACKAGE_PATH}/* ${DEST_PACKAGE_PATH} + else + echo "Source directory does not exist or is empty" >&2 + fi + + echo "Performing a diff between unpatched and patched package after the merge" + echo "=============================================================" + diff -r --brief ${DEST_PACKAGE_PATH} ${DEST_PACKAGE_COPY} + rm -rf ${DEST_PACKAGE_COPY} +} + +patch_packages(){ + cd ${SRC_REPO_PATH} || return 1 + echo "Changed directory to $(pwd)" + # Run to regenerates dist types and such. + echo "Running yarn tsc, this might take a minute or two..." + yarn tsc + + echo "Generating Patches for the following plugins/packages: ${targetPcks[*]}" + for pck in ${targetPcks[@]}; do + cd ${SRC_REPO_PATH} || continue + echo "Changed directory to $(pwd)" + echo "Generating patches for ${pck}" + + generate_backstage_package ${pck} + + cd ${DEST_REPO_PATH} || continue + echo "Changed directory to $(pwd)" + + yarn patch-package "@backstage/${pck}" + echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" + done; + +} + +function display_help() { + echo "A utility script to create patches for packages in the backstage/backstage repository for your backstage instance" + echo + echo "Usage: $0 [src] [dest] [package-name-1] [package-name-2] ..." + echo + echo "src: The root of the backstage monorepo with the patched changes." + echo "dest: The root of the target backstage monorepo containing the node_modules that are to be patched." + echo "package-name-n: a list of package names separated by a space. These should match the package names in the \`node_modules/@backstage\` directory" + printf "\tIf patching a plugin, append a \`plugin-\` to the package name, ex: \`plugin-scaffolder-backend\`." + printf "\n\tIf patching a package, just provide the package name that matches the corresponding package name in the \`node_modules\`, ex: \`integration\`\n" + echo "Please note that if the resultant package has a dist/cjs directory containing more than 2 files, the user may need to manually update file names and references" +} + +for arg in "$@" +do + if [[ $arg == "--help" ]]; then + display_help + exit 0 + fi +done + +if [[ $# -lt 3 ]]; then + echo "Error: Invalid number of arguments." >&2 + display_help + exit 1 +fi + +# Convert to absolute path (if relative path is provided) +SRC_REPO_PATH=$(readlink -f $1) +DEST_REPO_PATH=$(readlink -f $2) + +# Shift the first 2 arguments (src and dest) +shift 2 + +# Store the remaining arguments as package names +targetPcks=("$@") + +patch_packages diff --git a/scripts/ping-identity-setup/ping-identity-secrets.env b/scripts/ping-identity-setup/ping-identity-secrets.env new file mode 100644 index 0000000000..7bf00cec8b --- /dev/null +++ b/scripts/ping-identity-setup/ping-identity-secrets.env @@ -0,0 +1,5 @@ +PING_IDENTITY_API_PATH="https://api.pingone.ca/v1" +PING_IDENTITY_AUTH_PATH="https://auth.pingone.ca" +PING_IDENTITY_ENV_ID="your-env-id" +PING_IDENTITY_CLIENT_ID="your-client-id" +PING_IDENTITY_CLIENT_SECRET="your-client-secret" \ No newline at end of file diff --git a/scripts/ping-identity-setup/ping-identity-setup.sh b/scripts/ping-identity-setup/ping-identity-setup.sh new file mode 100755 index 0000000000..922345a30a --- /dev/null +++ b/scripts/ping-identity-setup/ping-identity-setup.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# Check for expected args +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +secretsFile=$1 +numUsers=$2 +numGroups=$3 + +# Load env vars +if [ ! -f "$secretsFile" ]; then + echo "Secrets file not found." + exit 1 +fi +source "$secretsFile" + +# Check if env vars are all set +if [ -z "$PING_IDENTITY_API_PATH" ] || [ -z "$PING_IDENTITY_AUTH_PATH" ] || [ -z "$PING_IDENTITY_ENV_ID" ] || [ -z "$PING_IDENTITY_CLIENT_ID" ] || [ -z "$PING_IDENTITY_CLIENT_SECRET" ]; then + echo "One or more required variables is missing from the secrets file." + exit 1 +fi + +# Fetch access token +credentials=$(echo -n "$PING_IDENTITY_CLIENT_ID:$PING_IDENTITY_CLIENT_SECRET" | base64) +response=$(curl -s --request POST \ + --url "$PING_IDENTITY_AUTH_PATH/$PING_IDENTITY_ENV_ID/as/token" \ + --header "Authorization: Basic $credentials" \ + --header "Content-Type: application/x-www-form-urlencoded" \ + --data-urlencode "grant_type=client_credentials") +access_token=$(echo $response | jq -r .access_token) + +if [ "$access_token" == "null" ]; then + echo "Error retrieving access token: $response" + exit 1 +fi + +# Delete all existing users and groups +group_ids=$(curl -s --location --request GET "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/groups" \ + --header "Authorization: Bearer $access_token" \ + --header "Content-Type: application/json" | jq -r '._embedded.groups[].id') + +for group_id in $group_ids; do + if [ -n "$group_id" ]; then + curl -s --location --request DELETE "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/groups/$group_id" \ + --header "Authorization: Bearer $access_token" + fi +done + +user_ids=$(curl -s --location --request GET "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/users" \ + --header "Authorization: Bearer $access_token" \ + --header "Content-Type: application/json" | jq -r '._embedded.users[].id') + +for user_id in $user_ids; do + if [ -n "$user_id" ]; then + curl -s --location --request DELETE "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/users/$user_id" \ + --header "Authorization: Bearer $access_token" + fi +done + +# Create Users +echo "Adding $numUsers users..." + +user_ids=() +for i in $(seq 1 $numUsers); do + user="tester$i" + create_user_response=$(curl -s --request POST \ + --url "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/users" \ + --header "Authorization: Bearer $access_token" \ + --header "Content-Type: application/json" \ + --data-raw "{ + \"email\": \"$user@example.com\", + \"name\": { + \"given\": \"$user\", + \"family\": \"User\" + }, + \"username\": \"$user\" + }") + user_id=$(echo "$create_user_response" | jq -r '.id') + user_ids+=("$user_id") + echo "Created user: $user, ID: $user_id" +done + +# Create Groups +echo "Adding $numGroups groups..." + +group_ids=() +for i in $(seq 1 $numGroups); do + group="group$i" + create_group_response=$(curl -s --request POST \ + --url "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/groups" \ + --header "Authorization: Bearer $access_token" \ + --header "Content-Type: application/json" \ + --data-raw "{ + \"name\": \"$group\", + \"description\": \"This is $group\" + }") + group_id=$(echo "$create_group_response" | jq -r '.id') + group_ids+=("$group_id") + echo "Created group: $group, ID: $group_id" +done + +# Set up group memberships and subgroups - modify as needed for testing +# Example: Add tester1 and tester2 to group1 +for user_id in "${user_ids[@]:0:2}"; do + add_user_to_group_response=$(curl -s --request POST \ + --url "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/users/$user_id/memberOfGroups" \ + --header "Authorization: Bearer $access_token" \ + --header "Content-Type: application/json" \ + --data-raw "{ + \"id\": \"${group_ids[0]}\" + }") + echo "Added user ID: $user_id to group1 (ID: ${group_ids[0]})" +done + +# Example: Set group3 as a subgroup of group1 +nest_group_response=$(curl -s --request POST \ + --url "$PING_IDENTITY_API_PATH/environments/$PING_IDENTITY_ENV_ID/groups/${group_ids[2]}/memberOfGroups" \ + --header "Authorization: Bearer $access_token" \ + --header "Content-Type: application/json" \ + --data-raw "{ + \"id\": \"${group_ids[0]}\" + }") +echo "Nested group3 (ID: ${group_ids[2]}) into group1 (ID: ${group_ids[0]})" \ No newline at end of file diff --git a/scripts/rhdh-openshift-setup/auth/rhdh-secrets.yaml b/scripts/rhdh-openshift-setup/auth/rhdh-secrets.yaml new file mode 100644 index 0000000000..306848ae1c --- /dev/null +++ b/scripts/rhdh-openshift-setup/auth/rhdh-secrets.yaml @@ -0,0 +1,27 @@ +kind: Secret +apiVersion: v1 +metadata: + name: rhdh-secrets +data: + GITHUB_APP_PRIVATE_KEY: >- + + GITHUB_APP_CLIENT_SECRET: + GITHUB_APP_WEBHOOK_URL: + GITHUB_APP_WEBHOOK_SECRET: + GITHUB_APP_APP_ID: + GITHUB_APP_CLIENT_ID: + GITHUB_ORG_URL: + GITLAB_CLIENT_ID: + GITLAB_CLIENT_SECRET: + GITLAB_TOKEN: + K8S_CLUSTER_NAME: + K8S_CLUSTER_TOKEN: + K8S_CLUSTER_URL: + KEYCLOAK_CLIENT_ID: + KEYCLOAK_LOGIN_REALM: + KEYCLOAK_REALM: + KEYCLOAK_CLIENT_SECRET: + OIDC_METADATA_URL: + KEYCLOAK_BASE_URL: +type: Opaque + diff --git a/scripts/rhdh-openshift-setup/auth/service-account-rhdh-secret.yaml b/scripts/rhdh-openshift-setup/auth/service-account-rhdh-secret.yaml new file mode 100644 index 0000000000..85580895b3 --- /dev/null +++ b/scripts/rhdh-openshift-setup/auth/service-account-rhdh-secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: rhdh-k8s-plugin-secret + annotations: + kubernetes.io/service-account.name: rhdh-k8s-plugin +type: kubernetes.io/service-account-token diff --git a/scripts/rhdh-openshift-setup/quick-start-rhdh.sh b/scripts/rhdh-openshift-setup/quick-start-rhdh.sh new file mode 100755 index 0000000000..b8a8d28710 --- /dev/null +++ b/scripts/rhdh-openshift-setup/quick-start-rhdh.sh @@ -0,0 +1,347 @@ +#!/bin/sh + +# Defaults to the https://github.com/redhat-developer/rhdh-chart helm chart +HELM_REPO_NAME=rhdh-chart +HELM_REPO_URL=https://redhat-developer.github.io/rhdh-chart +DEFAULT_VALUES_FILE="${PWD}/values.yaml" +HELM_CHART_NAME=backstage + +usage() { + echo " +This script simplifies and automates the installation process of Helm charts on OpenShift Container Platform (OCP) clusters. +User should be logged into a cluster to use this script. This allows you to deploy resources into openshift for usage with backstage plugins that require kubernetes resources. Please provide your secret file in the form of 'rhdh-secrets.local.yaml' in the auth directory. + +Usage: + $0 [OPTIONS] + +Options: + -n, --namespace : Specify the namespace for the Helm release. Default: 'rhdh' + --router-base : Manually provide the cluster router base for the helm deployment to use. Autodetects if not provided. + --release-name : Specify a custom release name for the Helm chart. Auto-generates if not provided, which will always generate a new helm release instead of upgrading an existing one. + --values : Specify your own values file for the Helm chart. Default: 'values.yaml' in the script's current directory. + --uninstall