From 37ca8ced83c70dea55dc73f9c89b98a2d7533c8a Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 25 Oct 2024 15:40:31 -0600 Subject: [PATCH 01/12] feat: add unicorn flavor --- .github/workflows/release.yaml | 2 +- .github/workflows/test.yaml | 2 +- values/unicorn-config-values.yaml | 5 +++++ values/unicorn-values.yaml | 12 ++++++++++++ zarf.yaml | 26 ++++++++++++++++++++++++-- 5 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 values/unicorn-config-values.yaml create mode 100644 values/unicorn-values.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c466927..d41d3e8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -36,7 +36,7 @@ jobs: if: ${{ needs.tag-new-version.outputs.release_created == 'true' }} strategy: matrix: - flavor: [upstream, registry1] + flavor: [upstream, registry1, unicorn] architecture: [amd64, arm64] exclude: - flavor: registry1 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1d277ce..77ea436 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -54,7 +54,7 @@ jobs: strategy: fail-fast: true matrix: - type: [install, upgrade] + type: [install, upgrade, unicorn] flavor: [upstream, registry1] uses: defenseunicorns/uds-common/.github/workflows/callable-test.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 with: diff --git a/values/unicorn-config-values.yaml b/values/unicorn-config-values.yaml new file mode 100644 index 0000000..9b2303a --- /dev/null +++ b/values/unicorn-config-values.yaml @@ -0,0 +1,5 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +metrics: + image: "cgr.dev/du-uds-defenseunicorns/prometheus-postgres-exporter-fips:0.15.0" diff --git a/values/unicorn-values.yaml b/values/unicorn-values.yaml new file mode 100644 index 0000000..a411ccd --- /dev/null +++ b/values/unicorn-values.yaml @@ -0,0 +1,12 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +image: + registry: cgr.dev + repository: du-uds-defenseunicorns/postgres-operator-fips +configConnectionPooler: + connection_pooler_image: "cgr.dev/du-uds-defenseunicorns/pgbouncer-fips:1.22.1" +configLogicalBackup: + logical_backup_docker_image: "ghcr.io/zalando/postgres-operator/logical-backup:v1.13.0" +configGeneral: + docker_image: "ghcr.io/zalando/spilo-15:3.2-p1" diff --git a/zarf.yaml b/zarf.yaml index f744dfb..b5e1adc 100644 --- a/zarf.yaml +++ b/zarf.yaml @@ -43,7 +43,7 @@ components: - registry1.dso.mil/ironbank/opensource/zalando/pgbouncer:1.21.0 # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA - ghcr.io/zalando/spilo-15:3.2-p1 - # Container iamge that provides the postgres-exporter sidecar to create a metrics endpoint + # Container image that provides the postgres-exporter sidecar to create a metrics endpoint - registry1.dso.mil/ironbank/opensource/prometheus/postgres-exporter:v0.15.0 - name: postgres-operator @@ -65,5 +65,27 @@ components: - docker.io/bitnami/pgbouncer:1.23.1 # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA - ghcr.io/zalando/spilo-15:3.2-p1 - # Container iamge that provides the postgres-exporter sidecar to create a metrics endpoint + # Container image that provides the postgres-exporter sidecar to create a metrics endpoint - quay.io/prometheuscommunity/postgres-exporter:v0.15.0 + + - name: postgres-operator + required: true + only: + flavor: unicorn + import: + path: common + charts: + - name: postgres-operator + valuesFiles: + - ./values/unicorn-values.yaml + - name: uds-postgres-config + valuesFiles: + - ./values/unicorn-config-values.yaml + images: + - cgr.dev/du-uds-defenseunicorns/postgres-operator-fips:1.13.0 + - ghcr.io/zalando/postgres-operator/logical-backup:v1.13.0 + - cgr.dev/du-uds-defenseunicorns/pgbouncer-fips:1.22.1 + # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA + - ghcr.io/zalando/spilo-15:3.2-p1 + # Container image that provides the postgres-exporter sidecar to create a metrics endpoint + - cgr.dev/du-uds-defenseunicorns/prometheus-postgres-exporter-fips:0.15.0 From cfe7f6d9bffd10a6c770852c7398427103290b4b Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 25 Oct 2024 15:48:38 -0600 Subject: [PATCH 02/12] fix my dumb --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 77ea436..944b691 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -54,8 +54,8 @@ jobs: strategy: fail-fast: true matrix: - type: [install, upgrade, unicorn] - flavor: [upstream, registry1] + type: [install, upgrade] + flavor: [upstream, registry1, unicorn] uses: defenseunicorns/uds-common/.github/workflows/callable-test.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 with: upgrade-flavors: ${{ needs.check-flavor.outputs.upgrade-flavors }} From d40942f4cfde9178569062e21c2801bd7aaade20 Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Mon, 28 Oct 2024 09:21:11 -0600 Subject: [PATCH 03/12] fix image --- values/registry1-values.yaml | 1 + values/unicorn-values.yaml | 1 + values/upstream-values.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/values/registry1-values.yaml b/values/registry1-values.yaml index d467a0c..4ad5c26 100644 --- a/values/registry1-values.yaml +++ b/values/registry1-values.yaml @@ -4,6 +4,7 @@ image: registry: registry1.dso.mil repository: ironbank/opensource/zalando/postgres-operator + tag: v1.13.0 configConnectionPooler: connection_pooler_image: "registry1.dso.mil/ironbank/opensource/zalando/pgbouncer:1.21.0" configLogicalBackup: diff --git a/values/unicorn-values.yaml b/values/unicorn-values.yaml index a411ccd..ecc2d85 100644 --- a/values/unicorn-values.yaml +++ b/values/unicorn-values.yaml @@ -4,6 +4,7 @@ image: registry: cgr.dev repository: du-uds-defenseunicorns/postgres-operator-fips + tag: "1.13.0" configConnectionPooler: connection_pooler_image: "cgr.dev/du-uds-defenseunicorns/pgbouncer-fips:1.22.1" configLogicalBackup: diff --git a/values/upstream-values.yaml b/values/upstream-values.yaml index 30973c7..07fd344 100644 --- a/values/upstream-values.yaml +++ b/values/upstream-values.yaml @@ -4,6 +4,7 @@ image: registry: ghcr.io repository: zalando/postgres-operator + tag: v1.13.0 configConnectionPooler: connection_pooler_image: "docker.io/bitnami/pgbouncer:1.23.1" configLogicalBackup: From 51478f040751c23e2a559fe3e93c164b30bde558 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Wed, 3 Jun 2026 21:15:16 -0400 Subject: [PATCH 04/12] feat(pepr): add pgbouncer module with configuration and custom Pepr module --- .github/ISSUE_TEMPLATE/tech_debt.md | 2 +- .github/pull_request_template.md | 2 +- .github/workflows/auto-update.yaml | 24 + .github/workflows/ci-docs-shim.yaml | 25 - .github/workflows/commitlint.yaml | 2 +- .github/workflows/lint.yaml | 4 +- .github/workflows/release.yaml | 22 +- .github/workflows/scan.yaml | 22 + .github/workflows/scorecard.yaml | 2 +- .github/workflows/test.yaml | 43 +- .gitignore | 4 +- .release-please-manifest.json | 3 - .serena/.gitignore | 2 + .serena/project.yml | 132 + CHANGELOG.md | 160 +- CODEOWNERS | 4 +- CONTRIBUTING.md | 2 +- README.md | 12 +- SECURITY.md | 2 +- bundle/uds-bundle.yaml | 20 +- bundle/uds-config.yaml | 2 - chart/templates/extension-job.yaml | 56 + chart/templates/patroni-svc.yaml | 19 + chart/templates/pgbouncer-config.yaml | 39 + chart/templates/postgres-minimal.yaml | 49 +- chart/templates/postgres-monitor.yaml | 22 - chart/templates/secret-namespaces.yaml | 15 + chart/templates/uds-package-postgres.yaml | 50 +- chart/templates/uds-package.yaml | 18 +- chart/values.yaml | 22 +- common/zarf.yaml | 18 +- docs/configuration.md | 129 +- .../2026-06-03-pgbouncer-fips-pooler-pepr.md | 625 ++ ...06-03-pgbouncer-fips-pooler-pepr-design.md | 191 + manifests/pepr-module-pgbouncer.yaml | 360 + oscal-component.yaml | 47 - release-please-config.json | 24 - releaser.yaml | 13 + renovate.json | 93 +- src/namespace/gitlab-ns.yaml | 11 - src/namespace/mattermost-ns.yaml | 11 - src/namespace/sonarqube-ns.yaml | 11 - src/namespace/zarf.yaml | 18 - src/pepr/.gitignore | 4 + src/pepr/.prettierrc | 14 + src/pepr/README.md | 21 + .../capabilities/pgbouncer-pooler.test.ts | 82 + src/pepr/capabilities/pgbouncer-pooler.ts | 151 + src/pepr/eslint.config.mjs | 45 + src/pepr/package-lock.json | 6274 +++++++++++++++++ src/pepr/package.json | 57 + src/pepr/pepr.ts | 5 + src/pepr/tsconfig.json | 28 + tasks.yaml | 52 +- tasks/dependencies.yaml | 8 - tests/postgres/bad-password-test.yaml | 40 + tests/postgres/db-seed-cross-namespace.yaml | 2 +- tests/postgres/db-seed.yaml | 2 +- tests/postgres/pooler-connection-test.yaml | 103 + tests/postgres/postgres-minimal.yaml | 22 +- .../postgres/uds-package-cross-namespace.yaml | 19 + tests/zarf.yaml | 23 +- values/registry1-config-values.yaml | 5 +- values/registry1-values.yaml | 8 +- values/unicorn-config-values.yaml | 11 +- values/unicorn-values.yaml | 10 +- values/upstream-config-values.yaml | 5 +- values/upstream-values.yaml | 8 +- version.txt | 1 - zarf.yaml | 58 +- 70 files changed, 8963 insertions(+), 427 deletions(-) create mode 100644 .github/workflows/auto-update.yaml delete mode 100644 .github/workflows/ci-docs-shim.yaml create mode 100644 .github/workflows/scan.yaml delete mode 100644 .release-please-manifest.json create mode 100644 .serena/.gitignore create mode 100644 .serena/project.yml create mode 100644 chart/templates/extension-job.yaml create mode 100644 chart/templates/patroni-svc.yaml create mode 100644 chart/templates/pgbouncer-config.yaml delete mode 100644 chart/templates/postgres-monitor.yaml create mode 100644 chart/templates/secret-namespaces.yaml create mode 100644 docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md create mode 100644 docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md create mode 100644 manifests/pepr-module-pgbouncer.yaml delete mode 100644 oscal-component.yaml delete mode 100644 release-please-config.json create mode 100644 releaser.yaml delete mode 100644 src/namespace/gitlab-ns.yaml delete mode 100644 src/namespace/mattermost-ns.yaml delete mode 100644 src/namespace/sonarqube-ns.yaml delete mode 100644 src/namespace/zarf.yaml create mode 100644 src/pepr/.gitignore create mode 100644 src/pepr/.prettierrc create mode 100644 src/pepr/README.md create mode 100644 src/pepr/capabilities/pgbouncer-pooler.test.ts create mode 100644 src/pepr/capabilities/pgbouncer-pooler.ts create mode 100644 src/pepr/eslint.config.mjs create mode 100644 src/pepr/package-lock.json create mode 100644 src/pepr/package.json create mode 100644 src/pepr/pepr.ts create mode 100644 src/pepr/tsconfig.json delete mode 100644 tasks/dependencies.yaml create mode 100644 tests/postgres/bad-password-test.yaml create mode 100644 tests/postgres/pooler-connection-test.yaml create mode 100644 tests/postgres/uds-package-cross-namespace.yaml delete mode 100644 version.txt diff --git a/.github/ISSUE_TEMPLATE/tech_debt.md b/.github/ISSUE_TEMPLATE/tech_debt.md index 052f5ff..96b6278 100644 --- a/.github/ISSUE_TEMPLATE/tech_debt.md +++ b/.github/ISSUE_TEMPLATE/tech_debt.md @@ -10,7 +10,7 @@ assignees: '' A clear and concise description of what should be changed/researched. Ex. This piece of the code is not DRY enough [...] ### Links to any relevant code -(optional) i.e. - https://github.com/defenseunicorns/uds-package-postgres-operator/blob/main/README.md?plain=1#L1 +(optional) i.e. - https://github.com/uds-packages/postgres-operator/blob/main/README.md?plain=1#L1 ### Additional context Add any other context or screenshots about the technical debt here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 120927e..386cf17 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,4 +17,4 @@ Relates to # ## Checklist before merging - [ ] Test, docs, adr added or updated as needed -- [ ] [Contributor Guide Steps](https://github.com/defenseunicorns/uds-package-postgres-operator/blob/main/CONTRIBUTING.md#developer-workflow) followed +- [ ] [Contributor Guide Steps](https://github.com/uds-packages/postgres-operator/blob/main/CONTRIBUTING.md#developer-workflow) followed diff --git a/.github/workflows/auto-update.yaml b/.github/workflows/auto-update.yaml new file mode 100644 index 0000000..930d845 --- /dev/null +++ b/.github/workflows/auto-update.yaml @@ -0,0 +1,24 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +name: Auto Update + +on: + schedule: + - cron: 0 14 * * * # daily at 8 AM Central (CST = UTC−6) + +# Permissions for the GITHUB_TOKEN used by the workflow. +permissions: + contents: write # Allows writing content to the repository. + packages: read # Allows reading the content of the repository's packages. + pull-requests: write # Allows creating or updating pull requests. + +# Abort prior jobs in the same workflow / PR +concurrency: + group: auto-update-${{ github.ref }} + cancel-in-progress: true + +jobs: + auto-update: + uses: defenseunicorns/uds-common/.github/workflows/callable-auto-update.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 + secrets: inherit # Inherits all secrets from the parent workflow. diff --git a/.github/workflows/ci-docs-shim.yaml b/.github/workflows/ci-docs-shim.yaml deleted file mode 100644 index 25d3f50..0000000 --- a/.github/workflows/ci-docs-shim.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -name: CI Doc Shim - -on: - pull_request: - branches: [main] - types: [milestoned, opened, synchronize] - -# Permissions for the GITHUB_TOKEN used by the workflow. -permissions: - contents: read # Allows reading the content of the repository. - -jobs: - validate: - strategy: - matrix: - type: [install, upgrade] - flavor: [upstream, registry1] - uses: defenseunicorns/uds-common/.github/workflows/callable-ci-docs-shim.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 - with: - flavor: ${{ matrix.flavor }} - type: ${{ matrix.type }} - secrets: inherit # Inherits all secrets from the parent workflow. diff --git a/.github/workflows/commitlint.yaml b/.github/workflows/commitlint.yaml index 03c4917..1a0ebe8 100644 --- a/.github/workflows/commitlint.yaml +++ b/.github/workflows/commitlint.yaml @@ -15,4 +15,4 @@ permissions: jobs: validate: - uses: defenseunicorns/uds-common/.github/workflows/callable-commitlint.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 + uses: defenseunicorns/uds-common/.github/workflows/callable-commitlint.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index ee594a2..8e78439 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -6,7 +6,7 @@ name: Lint on: # This workflow is triggered on pull requests to the main branch. pull_request: - # milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow). + # milestoned is added here as a way to retrigger workflows that are stuck or otherwise didn't run correctly types: [milestoned, opened, reopened, synchronize] # Permissions for the GITHUB_TOKEN used by the workflow. @@ -15,5 +15,5 @@ permissions: jobs: validate: - uses: defenseunicorns/uds-common/.github/workflows/callable-lint.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 + uses: defenseunicorns/uds-common/.github/workflows/callable-lint.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 secrets: inherit diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d41d3e8..1c9ea95 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,25 +15,11 @@ permissions: id-token: write jobs: - tag-new-version: - permissions: write-all - runs-on: ubuntu-latest - outputs: - release_created: ${{ steps.release-flag.outputs.release_created }} - steps: - - name: Create Release Tag - id: tag - uses: googleapis/release-please-action@7987652d64b4581673a76e33ad5e98e3dd56832f # v4.1.3 - - id: release-flag - run: echo "release_created=${{ steps.tag.outputs.release_created || false }}" >> "$GITHUB_OUTPUT" - publish: permissions: - contents: read # Allows reading the content of the repository. + contents: write # Allows reading the content of the repository. packages: write # Allows reading the content of the repository's packages. id-token: write - needs: tag-new-version - if: ${{ needs.tag-new-version.outputs.release_created == 'true' }} strategy: matrix: flavor: [upstream, registry1, unicorn] @@ -41,8 +27,10 @@ jobs: exclude: - flavor: registry1 architecture: arm64 - uses: defenseunicorns/uds-common/.github/workflows/callable-publish.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 + uses: defenseunicorns/uds-common/.github/workflows/callable-publish.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 with: flavor: ${{ matrix.flavor }} - runsOn: ${{ matrix.architecture == 'arm64' && 'uds-swf-ubuntu-arm64-4-core' || 'ubuntu-latest' }} + options: --set BASE_REPO="ghcr.io/uds-packages" + runsOn: ${{ matrix.architecture == 'arm64' && 'appstore-4-core-arm64' || 'appstore-4-core-amd64' }} + uds-releaser: true secrets: inherit # Inherits all secrets from the parent workflow. diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml new file mode 100644 index 0000000..0c5673f --- /dev/null +++ b/.github/workflows/scan.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +name: Scan + +on: + # This workflow is triggered on pull requests to the main branch. + pull_request: + paths: + - zarf.yaml + - releaser.yaml + - .release-please-manifest.json + +jobs: + scan: + permissions: + contents: read # Allows reading the content of the repository. + packages: read # Allows reading the content of the repository's packages. + id-token: write # Allows authentication to Chainguard via OIDC. + pull-requests: write # Allows writing the scan results comment to the pull request. + uses: defenseunicorns/uds-common/.github/workflows/callable-scan.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 + secrets: inherit # Inherits all secrets from the parent workflow. diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index 1d7a6a5..d9f9d6e 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -32,5 +32,5 @@ jobs: security-events: write # Used to receive a badge. id-token: write - uses: defenseunicorns/uds-common/.github/workflows/callable-scorecard.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 + uses: defenseunicorns/uds-common/.github/workflows/callable-scorecard.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 secrets: inherit diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 944b691..29d58c5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -6,30 +6,15 @@ name: Test on: # This workflow is triggered on pull requests to the main branch. pull_request: - # milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow). + # milestoned is added here as a way to retrigger workflows that are stuck or otherwise didn't run correctly types: [milestoned, opened, reopened, synchronize] - paths-ignore: - - "**.md" - - "**.jpg" - - "**.png" - - "**.gif" - - "**.svg" - - adr/** - - docs/** - - .gitignore - - renovate.json - - .release-please-config.json - - release-please-config.json - - CODEOWNERS - - LICENSE - - CONTRIBUTING.md - - SECURITY.md # Permissions for the GITHUB_TOKEN used by the workflow. permissions: contents: read # Allows reading the content of the repository. packages: read # Allows reading the content of the repository's packages. id-token: write + pull-requests: read # Abort prior jobs in the same workflow / PR concurrency: @@ -41,10 +26,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: test-flavor - uses: defenseunicorns/uds-common/.github/actions/test-flavor@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 + uses: defenseunicorns/uds-common/.github/actions/test-flavor@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 id: test-flavor outputs: upgrade-flavors: ${{ steps.test-flavor.outputs.upgrade-flavors }} @@ -56,9 +41,27 @@ jobs: matrix: type: [install, upgrade] flavor: [upstream, registry1, unicorn] - uses: defenseunicorns/uds-common/.github/workflows/callable-test.yaml@c52077c870a576d01f169f96d74d1b393c6488ba # v1.1.2 + uses: defenseunicorns/uds-common/.github/workflows/callable-test.yaml@99fd276835257a9608656380d1d453356fe7539e # v1.24.8 with: + options: --set BASE_REPO="ghcr.io/uds-packages" upgrade-flavors: ${{ needs.check-flavor.outputs.upgrade-flavors }} flavor: ${{ matrix.flavor }} type: ${{ matrix.type }} + runsOn: appstore-4-core-amd64 secrets: inherit # Inherits all secrets from the parent workflow. + + verify-test: + runs-on: ubuntu-latest + needs: validate + if: always() + steps: + - name: Check validate result + run: | + echo "validate result: ${{ needs.validate.result }}" + + if [ "${{ needs.validate.result }}" != "success" ]; then + echo "One or more tests failed." + exit 1 + fi + + echo "All tests passed successfully!" diff --git a/.gitignore b/.gitignore index 08e4b4e..8283dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ build/ zarf-sbom tmp/ .vscode/ - - +oscal-assessment-results.yaml +upgrade-test \ No newline at end of file diff --git a/.release-please-manifest.json b/.release-please-manifest.json deleted file mode 100644 index 4e2cdf5..0000000 --- a/.release-please-manifest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - ".": "1.13.0-uds.2" -} \ No newline at end of file diff --git a/.serena/.gitignore b/.serena/.gitignore new file mode 100644 index 0000000..2e510af --- /dev/null +++ b/.serena/.gitignore @@ -0,0 +1,2 @@ +/cache +/project.local.yml diff --git a/.serena/project.yml b/.serena/project.yml new file mode 100644 index 0000000..5ba3331 --- /dev/null +++ b/.serena/project.yml @@ -0,0 +1,132 @@ +# the name by which the project can be referenced within Serena +project_name: "postgres-operator" + + +# list of languages for which language servers are started; choose from: +# al angular ansible bash clojure +# cpp cpp_ccls crystal csharp csharp_omnisharp +# dart elixir elm erlang fortran +# fsharp go groovy haskell haxe +# hlsl html java json julia +# kotlin lean4 lua luau markdown +# matlab msl nix ocaml pascal +# perl php php_phpactor powershell python +# python_jedi python_ty r rego ruby +# ruby_solargraph rust scala scss solidity +# svelte swift systemverilog terraform toml +# typescript typescript_vts vue yaml zig +# (This list may be outdated. For the current list, see values of Language enum here: +# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py +# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) +# Note: +# - For C, use cpp +# - For JavaScript, use typescript +# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) +# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) +# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) +# - For Free Pascal/Lazarus, use pascal +# Special requirements: +# Some languages require additional setup/installations. +# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers +# When using multiple languages, the first language server that supports a given file will be used for that file. +# The first language is the default language and the respective language server will be used as a fallback. +# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. +languages: [] + +# the encoding used by text files in the project +# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings +encoding: "utf-8" + +# line ending convention to use when writing source files. +# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) +# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. +line_ending: + +# The language backend to use for this project. +# If not set, the global setting from serena_config.yml is used. +# Valid values: LSP, JetBrains +# Note: the backend is fixed at startup. If a project with a different backend +# is activated post-init, an error will be returned. +language_backend: + +# whether to use project's .gitignore files to ignore files +ignore_all_files_in_gitignore: true + +# advanced configuration option allowing to configure language server-specific options. +# Maps the language key to the options. +# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. +# No documentation on options means no options are available. +ls_specific_settings: {} + +# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). +# Paths can be absolute or relative to the project root. +# Each folder is registered as an LSP workspace folder, enabling language servers to discover +# symbols and references across package boundaries. +# Currently supported for: TypeScript. +# Example: +# additional_workspace_folders: +# - ../sibling-package +# - ../shared-lib +additional_workspace_folders: [] + +# list of additional paths to ignore in this project. +# Same syntax as gitignore, so you can use * and **. +# Note: global ignored_paths from serena_config.yml are also applied additively. +ignored_paths: [] + +# whether the project is in read-only mode +# If set to true, all editing tools will be disabled and attempts to use them will result in an error +# Added on 2025-04-18 +read_only: false + +# list of tool names to exclude. +# This extends the existing exclusions (e.g. from the global configuration) +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html +excluded_tools: [] + +# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). +# This extends the existing inclusions (e.g. from the global configuration). +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html +included_optional_tools: [] + +# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. +# This cannot be combined with non-empty excluded_tools or included_optional_tools. +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html +fixed_tools: [] + +# list of mode names that are to be activated by default, overriding the setting in the global configuration. +# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. +# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. +# Otherwise, this overrides the setting from the global configuration (serena_config.yml). +# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply +# for this project. +# This setting can, in turn, be overridden by CLI parameters (--mode). +# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes +default_modes: + +# list of mode names to be activated additionally for this project, e.g. ["query-projects"] +# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. +# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes +added_modes: + +# initial prompt for the project. It will always be given to the LLM upon activating the project +# (contrary to the memories, which are loaded on demand). +initial_prompt: "" + +# time budget (seconds) per tool call for the retrieval of additional symbol information +# such as docstrings or parameter information. +# This overrides the corresponding setting in the global configuration; see the documentation there. +# If null or missing, use the setting from the global configuration. +symbol_info_budget: + +# list of regex patterns which, when matched, mark a memory entry as read‑only. +# Extends the list from the global configuration, merging the two lists. +read_only_memory_patterns: [] + +# list of regex patterns for memories to completely ignore. +# Matching memories will not appear in list_memories or activate_project output +# and cannot be accessed via read_memory or write_memory. +# To access ignored memory files, use the read_file tool on the raw file path. +# Extends the list from the global configuration, merging the two lists. +# Example: ["_archive/.*", "_episodes/.*"] +ignored_memory_patterns: [] diff --git a/CHANGELOG.md b/CHANGELOG.md index e649df2..8c10cff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,157 +2,207 @@ All notable changes to this project will be documented in this file. -## [1.13.0-uds.2](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.13.0-uds.1...v1.13.0-uds.2) (2024-09-25) +## [1.13.0-uds.5](https://github.com/uds-packages/postgres-operator/compare/v1.13.0-uds.4...v1.13.0-uds.5) (2024-12-02) + + +### Features + +* handle namespaces internally without a shim package ([#80](https://github.com/uds-packages/postgres-operator/issues/80)) ([35512ab](https://github.com/uds-packages/postgres-operator/commit/35512abe8d0124a09d70c77b33411ba35c77ea90)) + + +### Miscellaneous + +* **deps:** update package-deps to v17 ([#19](https://github.com/uds-packages/postgres-operator/issues/19)) ([d442085](https://github.com/uds-packages/postgres-operator/commit/d442085a48d12e93e8f102e3611981d2c34fd53b)) +* **deps:** update prometheus postgres exporter to v0.16.0 ([#81](https://github.com/uds-packages/postgres-operator/issues/81)) ([dd24e9b](https://github.com/uds-packages/postgres-operator/commit/dd24e9bfbca0f39250e9c32a0857cf0a35b699b9)) +* update CODEOWNERS file ([#84](https://github.com/uds-packages/postgres-operator/issues/84)) ([50d805f](https://github.com/uds-packages/postgres-operator/commit/50d805f185acc854dc1d902b17b950dc42b81f89)) +* update README.md ([#82](https://github.com/uds-packages/postgres-operator/issues/82)) ([cd4e709](https://github.com/uds-packages/postgres-operator/commit/cd4e70978374639282212d18f430271be77bdcfe)) + +## [1.13.0-uds.4](https://github.com/uds-packages/postgres-operator/compare/v1.13.0-uds.3...v1.13.0-uds.4) (2024-11-04) + + +### Features + +* tls certificate from secret ([#79](https://github.com/uds-packages/postgres-operator/issues/79)) ([6f43464](https://github.com/uds-packages/postgres-operator/commit/6f43464a2827e6937d3f5027e5e6efdd5c19483f)) + + +### Miscellaneous + +* **deps:** update postgres support dependencies ([#74](https://github.com/uds-packages/postgres-operator/issues/74)) ([a7dbb04](https://github.com/uds-packages/postgres-operator/commit/a7dbb04902ed3e913347615094dabb4d45c002f3)) + +## [1.13.0-uds.3](https://github.com/uds-packages/postgres-operator/compare/v1.13.0-uds.2...v1.13.0-uds.3) (2024-10-28) + + +### Features + +* add unicorn flavor ([#77](https://github.com/uds-packages/postgres-operator/issues/77)) ([3f740e3](https://github.com/uds-packages/postgres-operator/commit/3f740e3f94a26b6c2b06c15e5c225ce56594c860)) + + +### Bug Fixes + +* postgress-operator validation ([#67](https://github.com/uds-packages/postgres-operator/issues/67)) ([133a1c7](https://github.com/uds-packages/postgres-operator/commit/133a1c7f28b74756f558c65a2d99345271dc8ce7)) +* validate package with full resource name ([#69](https://github.com/uds-packages/postgres-operator/issues/69)) ([ad69811](https://github.com/uds-packages/postgres-operator/commit/ad6981150033aac60d59c1686170161a512952df)) + + +### Miscellaneous + +* **deps:** update package-deps to v1.13.0 ([#72](https://github.com/uds-packages/postgres-operator/issues/72)) ([3648417](https://github.com/uds-packages/postgres-operator/commit/3648417eadc11b246f58ff3e42e5a984d4272936)) +* **deps:** update postgres support dependencies ([#60](https://github.com/uds-packages/postgres-operator/issues/60)) ([10fb7c4](https://github.com/uds-packages/postgres-operator/commit/10fb7c4aa93b582b5bf260b6e41227595ea45ec4)) +* **deps:** update support-deps to v1 ([#70](https://github.com/uds-packages/postgres-operator/issues/70)) ([babace2](https://github.com/uds-packages/postgres-operator/commit/babace2ee72587f2438aa584ec352061e54b5414)) +* **deps:** update support-deps to v1.1.2 ([#73](https://github.com/uds-packages/postgres-operator/issues/73)) ([e578edd](https://github.com/uds-packages/postgres-operator/commit/e578edd3ab97870d86157dbcbaf1bb971001801b)) +* set fail-fast to true on test matrix ([#76](https://github.com/uds-packages/postgres-operator/issues/76)) ([575f539](https://github.com/uds-packages/postgres-operator/commit/575f53966e747fa57642cd86b5351da57953618d)) +* silver badge, streamline the README and GH permissions ([#75](https://github.com/uds-packages/postgres-operator/issues/75)) ([14f4536](https://github.com/uds-packages/postgres-operator/commit/14f45364a875f7873087654aa6a3c778e16d3f75)) + +## [1.13.0-uds.2](https://github.com/uds-packages/postgres-operator/compare/v1.13.0-uds.1...v1.13.0-uds.2) (2024-09-25) ### ⚠ BREAKING CHANGES -* add additional config options and update default pasword encryption for fips ([#65](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/65)) +* add additional config options and update default pasword encryption for fips ([#65](https://github.com/uds-packages/postgres-operator/issues/65)) ### Features -* add additional config options and update default pasword encryption for fips ([#65](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/65)) ([a3e23b4](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/a3e23b4d75f67832d1d2452c068e0155805d12f0)) +* add additional config options and update default pasword encryption for fips ([#65](https://github.com/uds-packages/postgres-operator/issues/65)) ([a3e23b4](https://github.com/uds-packages/postgres-operator/commit/a3e23b4d75f67832d1d2452c068e0155805d12f0)) -## [1.13.0-uds.1](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.13.0-uds.0...v1.13.0-uds.1) (2024-09-19) +## [1.13.0-uds.1](https://github.com/uds-packages/postgres-operator/compare/v1.13.0-uds.0...v1.13.0-uds.1) (2024-09-19) ### Features -* expose resources and additionalVolumes for HugePages ([#63](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/63)) ([49152b3](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/49152b36cee10c7314f04811a7a9e2341f122ccb)) +* expose resources and additionalVolumes for HugePages ([#63](https://github.com/uds-packages/postgres-operator/issues/63)) ([49152b3](https://github.com/uds-packages/postgres-operator/commit/49152b36cee10c7314f04811a7a9e2341f122ccb)) -## [1.13.0-uds.0](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.12.2-uds.2...v1.13.0-uds.0) (2024-08-27) +## [1.13.0-uds.0](https://github.com/uds-packages/postgres-operator/compare/v1.12.2-uds.2...v1.13.0-uds.0) (2024-08-27) ### Miscellaneous -* **deps:** update postgres package dependencies ([#59](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/59)) ([cae5ab8](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/cae5ab894e7b203b73ef3b7d3f57d5f04be93caf)) +* **deps:** update postgres package dependencies ([#59](https://github.com/uds-packages/postgres-operator/issues/59)) ([cae5ab8](https://github.com/uds-packages/postgres-operator/commit/cae5ab894e7b203b73ef3b7d3f57d5f04be93caf)) -## [1.12.2-uds.2](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.12.2-uds.1...v1.12.2-uds.2) (2024-07-31) +## [1.12.2-uds.2](https://github.com/uds-packages/postgres-operator/compare/v1.12.2-uds.1...v1.12.2-uds.2) (2024-07-31) ### Features -* **metrics:** building blocks for postgres exporter ([#53](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/53)) ([c2a47bc](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/c2a47bc77ccf3fda6f302a11968d879337ff4957)) +* **metrics:** building blocks for postgres exporter ([#53](https://github.com/uds-packages/postgres-operator/issues/53)) ([c2a47bc](https://github.com/uds-packages/postgres-operator/commit/c2a47bc77ccf3fda6f302a11968d879337ff4957)) ### Miscellaneous -* add `Made for UDS` badge ([#57](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/57)) ([2aa0328](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/2aa032862718c462f51032a2951f26249e344f98)) -* **deps:** update postgres support dependencies ([#50](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/50)) ([18c6c03](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/18c6c03b5dc1fdc583277f40b1233779ac43ec9a)) -* **deps:** update postgres support dependencies ([#56](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/56)) ([a79c9c6](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/a79c9c68e18fdf0b7d97852b9a2af3615f911428)) -* **deps:** update support-deps to v3.25.15 ([#55](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/55)) ([84d4c33](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/84d4c33818eaefa72b241d733b937620b627762c)) +* add `Made for UDS` badge ([#57](https://github.com/uds-packages/postgres-operator/issues/57)) ([2aa0328](https://github.com/uds-packages/postgres-operator/commit/2aa032862718c462f51032a2951f26249e344f98)) +* **deps:** update postgres support dependencies ([#50](https://github.com/uds-packages/postgres-operator/issues/50)) ([18c6c03](https://github.com/uds-packages/postgres-operator/commit/18c6c03b5dc1fdc583277f40b1233779ac43ec9a)) +* **deps:** update postgres support dependencies ([#56](https://github.com/uds-packages/postgres-operator/issues/56)) ([a79c9c6](https://github.com/uds-packages/postgres-operator/commit/a79c9c68e18fdf0b7d97852b9a2af3615f911428)) +* **deps:** update support-deps to v3.25.15 ([#55](https://github.com/uds-packages/postgres-operator/issues/55)) ([84d4c33](https://github.com/uds-packages/postgres-operator/commit/84d4c33818eaefa72b241d733b937620b627762c)) -## [1.12.2-uds.1](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.12.2-uds.0...v1.12.2-uds.1) (2024-07-09) +## [1.12.2-uds.1](https://github.com/uds-packages/postgres-operator/compare/v1.12.2-uds.0...v1.12.2-uds.1) (2024-07-09) ### Bug Fixes -* netpol selector correction for ingress to pg-cluster ([#48](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/48)) ([8c28aea](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/8c28aea517b087093b509636c0e47ef37ad7141d)) +* netpol selector correction for ingress to pg-cluster ([#48](https://github.com/uds-packages/postgres-operator/issues/48)) ([8c28aea](https://github.com/uds-packages/postgres-operator/commit/8c28aea517b087093b509636c0e47ef37ad7141d)) ### Miscellaneous -* **deps:** update support-deps to v4.3.4 ([#47](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/47)) ([54c533b](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/54c533b3befbd7330abec4c84e2644e18beb7eb0)) -* fix arm runner name ([#45](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/45)) ([298ef55](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/298ef5519d24eca3b13550b966db7eb6dbe3c6f1)) +* **deps:** update support-deps to v4.3.4 ([#47](https://github.com/uds-packages/postgres-operator/issues/47)) ([54c533b](https://github.com/uds-packages/postgres-operator/commit/54c533b3befbd7330abec4c84e2644e18beb7eb0)) +* fix arm runner name ([#45](https://github.com/uds-packages/postgres-operator/issues/45)) ([298ef55](https://github.com/uds-packages/postgres-operator/commit/298ef5519d24eca3b13550b966db7eb6dbe3c6f1)) -## [1.12.2-uds.0](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.11.0-uds.2...v1.12.2-uds.0) (2024-07-03) +## [1.12.2-uds.0](https://github.com/uds-packages/postgres-operator/compare/v1.11.0-uds.2...v1.12.2-uds.0) (2024-07-03) ### Miscellaneous -* add architecture to publish job name ([#42](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/42)) ([5a6d73f](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/5a6d73f5d7731d919493e6d29614c1bf3739fc9b)) -* add pre release testing ([#40](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/40)) ([ac40af4](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/ac40af4a8b24885f2cb8dac81d45a8e8caae0f50)) -* **deps:** update postgres package dependencies ([#30](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/30)) ([034910c](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/034910cb2ff1fb13cf8a711931204aa5fc0dcd49)) -* **deps:** update postgres support dependencies ([#39](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/39)) ([597c22e](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/597c22e8e4b06187ed77d77d4ad94c60c0ae5fab)) -* normalize the repository README and remove `.vscode` ([#43](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/43)) ([aa54ab8](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/aa54ab8882e317bc53092d3c1ef44a44bd72f7ad)) -* update license ([#38](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/38)) ([a8180ac](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/a8180ac5c54e6733c3bbc715a04ad588e8864bbe)) +* add architecture to publish job name ([#42](https://github.com/uds-packages/postgres-operator/issues/42)) ([5a6d73f](https://github.com/uds-packages/postgres-operator/commit/5a6d73f5d7731d919493e6d29614c1bf3739fc9b)) +* add pre release testing ([#40](https://github.com/uds-packages/postgres-operator/issues/40)) ([ac40af4](https://github.com/uds-packages/postgres-operator/commit/ac40af4a8b24885f2cb8dac81d45a8e8caae0f50)) +* **deps:** update postgres package dependencies ([#30](https://github.com/uds-packages/postgres-operator/issues/30)) ([034910c](https://github.com/uds-packages/postgres-operator/commit/034910cb2ff1fb13cf8a711931204aa5fc0dcd49)) +* **deps:** update postgres support dependencies ([#39](https://github.com/uds-packages/postgres-operator/issues/39)) ([597c22e](https://github.com/uds-packages/postgres-operator/commit/597c22e8e4b06187ed77d77d4ad94c60c0ae5fab)) +* normalize the repository README and remove `.vscode` ([#43](https://github.com/uds-packages/postgres-operator/issues/43)) ([aa54ab8](https://github.com/uds-packages/postgres-operator/commit/aa54ab8882e317bc53092d3c1ef44a44bd72f7ad)) +* update license ([#38](https://github.com/uds-packages/postgres-operator/issues/38)) ([a8180ac](https://github.com/uds-packages/postgres-operator/commit/a8180ac5c54e6733c3bbc715a04ad588e8864bbe)) -## [1.11.0-uds.2](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.11.0-uds.1...v1.11.0-uds.2) (2024-06-12) +## [1.11.0-uds.2](https://github.com/uds-packages/postgres-operator/compare/v1.11.0-uds.1...v1.11.0-uds.2) (2024-06-12) ### ⚠ BREAKING CHANGES -* enable istio and netpols for everything ([#37](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/37)) +* enable istio and netpols for everything ([#37](https://github.com/uds-packages/postgres-operator/issues/37)) ### Features -* enable istio and netpols for everything ([#37](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/37)) ([642a38d](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/642a38d91f07e5564e9c74742c8a8f0be2a860cf)) +* enable istio and netpols for everything ([#37](https://github.com/uds-packages/postgres-operator/issues/37)) ([642a38d](https://github.com/uds-packages/postgres-operator/commit/642a38d91f07e5564e9c74742c8a8f0be2a860cf)) ### Miscellaneous -* cleanup the repo ([#34](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/34)) ([6fa6840](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/6fa6840f61b3fca289fd0e2b8a4a42f807bd850e)) -* **deps:** update postgres support dependencies ([#29](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/29)) ([1c55b70](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/1c55b7010c9efc5f2c3e8a18d7d63a82b61e27e8)) -* **deps:** update postgres support dependencies ([#36](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/36)) ([87c07ab](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/87c07ab27de9703cb6bd8cb15cc076dbdb870956)) +* cleanup the repo ([#34](https://github.com/uds-packages/postgres-operator/issues/34)) ([6fa6840](https://github.com/uds-packages/postgres-operator/commit/6fa6840f61b3fca289fd0e2b8a4a42f807bd850e)) +* **deps:** update postgres support dependencies ([#29](https://github.com/uds-packages/postgres-operator/issues/29)) ([1c55b70](https://github.com/uds-packages/postgres-operator/commit/1c55b7010c9efc5f2c3e8a18d7d63a82b61e27e8)) +* **deps:** update postgres support dependencies ([#36](https://github.com/uds-packages/postgres-operator/issues/36)) ([87c07ab](https://github.com/uds-packages/postgres-operator/commit/87c07ab27de9703cb6bd8cb15cc076dbdb870956)) -## [1.11.0-uds.1](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.11.0-uds.0...v1.11.0-uds.1) (2024-06-07) +## [1.11.0-uds.1](https://github.com/uds-packages/postgres-operator/compare/v1.11.0-uds.0...v1.11.0-uds.1) (2024-06-07) ### Features -* add wait for PGO package CR readiness ([#32](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/32)) ([1d8056a](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/1d8056ab7ca35f15a7870055829f6ad28998a2d2)) +* add wait for PGO package CR readiness ([#32](https://github.com/uds-packages/postgres-operator/issues/32)) ([1d8056a](https://github.com/uds-packages/postgres-operator/commit/1d8056ab7ca35f15a7870055829f6ad28998a2d2)) ### Miscellaneous -* change image refs to support multi arch ([#33](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/33)) ([963a962](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/963a9629fb5392b549544fdd5340fbca0a3f1d2c)) -* **deps:** update postgres support dependencies ([#24](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/24)) ([e08e679](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/e08e67942f8c502a3819c15be5eb35407b53c7de)) -* **deps:** update postgres support dependencies ([#26](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/26)) ([7d02d31](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/7d02d3171cb02b69e515f56199de9ae12a43eb0f)) -* fix the allowed versions of postgres ([#28](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/28)) ([4839d50](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/4839d5080189428a4b8d977fb718c3b9f6ba3638)) +* change image refs to support multi arch ([#33](https://github.com/uds-packages/postgres-operator/issues/33)) ([963a962](https://github.com/uds-packages/postgres-operator/commit/963a9629fb5392b549544fdd5340fbca0a3f1d2c)) +* **deps:** update postgres support dependencies ([#24](https://github.com/uds-packages/postgres-operator/issues/24)) ([e08e679](https://github.com/uds-packages/postgres-operator/commit/e08e67942f8c502a3819c15be5eb35407b53c7de)) +* **deps:** update postgres support dependencies ([#26](https://github.com/uds-packages/postgres-operator/issues/26)) ([7d02d31](https://github.com/uds-packages/postgres-operator/commit/7d02d3171cb02b69e515f56199de9ae12a43eb0f)) +* fix the allowed versions of postgres ([#28](https://github.com/uds-packages/postgres-operator/issues/28)) ([4839d50](https://github.com/uds-packages/postgres-operator/commit/4839d5080189428a4b8d977fb718c3b9f6ba3638)) -## [1.11.0-uds.0](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.5...v1.11.0-uds.0) (2024-04-05) +## [1.11.0-uds.0](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.5...v1.11.0-uds.0) (2024-04-05) ### Miscellaneous -* add formatting to make the warning stand out more ([#23](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/23)) ([42fca2f](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/42fca2fbb0aa58bfc895215cbeee94721ac2b6b1)) -* **deps:** update postgres package dependencies ([#16](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/16)) ([b91ec33](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/b91ec332e0f73973b98c0b31af0915e0900b85a8)) -* **deps:** update postgres support dependencies ([#22](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/22)) ([a7fefa8](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/a7fefa8f321b9898e5754a2ccba916991ddd9b18)) -* fix missing import in publish task ([#20](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/20)) ([ff35f91](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/ff35f9183f3eb3757e339f6e2c0472eb5f1fc971)) +* add formatting to make the warning stand out more ([#23](https://github.com/uds-packages/postgres-operator/issues/23)) ([42fca2f](https://github.com/uds-packages/postgres-operator/commit/42fca2fbb0aa58bfc895215cbeee94721ac2b6b1)) +* **deps:** update postgres package dependencies ([#16](https://github.com/uds-packages/postgres-operator/issues/16)) ([b91ec33](https://github.com/uds-packages/postgres-operator/commit/b91ec332e0f73973b98c0b31af0915e0900b85a8)) +* **deps:** update postgres support dependencies ([#22](https://github.com/uds-packages/postgres-operator/issues/22)) ([a7fefa8](https://github.com/uds-packages/postgres-operator/commit/a7fefa8f321b9898e5754a2ccba916991ddd9b18)) +* fix missing import in publish task ([#20](https://github.com/uds-packages/postgres-operator/issues/20)) ([ff35f91](https://github.com/uds-packages/postgres-operator/commit/ff35f9183f3eb3757e339f6e2c0472eb5f1fc971)) -## [1.10.1-uds.5](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.4...v1.10.1-uds.5) (2024-03-29) +## [1.10.1-uds.5](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.4...v1.10.1-uds.5) (2024-03-29) ### Miscellaneous -* **deps:** update postgres support dependencies ([#17](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/17)) ([0a37841](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/0a3784196133d7495b4f38b4a4edea7e4c5dc632)) -* hotfix renovate config registries ([6238f93](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/6238f9367ebb3d0a42b20722eb4a8186c6705137)) -* update to uds-common v0.3.9 and add upgrade-tests ([5a581ca](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/5a581ca1914eb185312905ad2dbe057dd382b370)) +* **deps:** update postgres support dependencies ([#17](https://github.com/uds-packages/postgres-operator/issues/17)) ([0a37841](https://github.com/uds-packages/postgres-operator/commit/0a3784196133d7495b4f38b4a4edea7e4c5dc632)) +* hotfix renovate config registries ([6238f93](https://github.com/uds-packages/postgres-operator/commit/6238f9367ebb3d0a42b20722eb4a8186c6705137)) +* update to uds-common v0.3.9 and add upgrade-tests ([5a581ca](https://github.com/uds-packages/postgres-operator/commit/5a581ca1914eb185312905ad2dbe057dd382b370)) -## [1.10.1-uds.4](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.3...v1.10.1-uds.4) (2024-03-05) +## [1.10.1-uds.4](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.3...v1.10.1-uds.4) (2024-03-05) ### ci -* fix oci publish issue ([#11](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/11)) ([6ab7735](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/6ab7735dce5b61de9f4589f51ad5c7a14397e8d4)) +* fix oci publish issue ([#11](https://github.com/uds-packages/postgres-operator/issues/11)) ([6ab7735](https://github.com/uds-packages/postgres-operator/commit/6ab7735dce5b61de9f4589f51ad5c7a14397e8d4)) -## [1.10.1-uds.3](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.2...v1.10.1-uds.3) (2024-03-04) +## [1.10.1-uds.3](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.2...v1.10.1-uds.3) (2024-03-04) ### ci -* update remote publish task to latest ([#9](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/9)) ([046d961](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/046d96157bc22dfc1164685eb9d6f2c84fde2302)) +* update remote publish task to latest ([#9](https://github.com/uds-packages/postgres-operator/issues/9)) ([046d961](https://github.com/uds-packages/postgres-operator/commit/046d96157bc22dfc1164685eb9d6f2c84fde2302)) -## [1.10.1-uds.2](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.1...v1.10.1-uds.2) (2024-03-04) +## [1.10.1-uds.2](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.1...v1.10.1-uds.2) (2024-03-04) ### ci -* fix publish create task ([#7](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/7)) ([567301f](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/567301f92b6be6f705532fd332087422521a82dc)) +* fix publish create task ([#7](https://github.com/uds-packages/postgres-operator/issues/7)) ([567301f](https://github.com/uds-packages/postgres-operator/commit/567301f92b6be6f705532fd332087422521a82dc)) -## [1.10.1-uds.1](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.0...v1.10.1-uds.1) (2024-03-04) +## [1.10.1-uds.1](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.0...v1.10.1-uds.1) (2024-03-04) ### Miscellaneous -* release 1.10.1-uds.1 ([#5](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/5)) ([5ebac86](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/5ebac865bd256ec9a3e5dc9518acf5843b707abe)) +* release 1.10.1-uds.1 ([#5](https://github.com/uds-packages/postgres-operator/issues/5)) ([5ebac86](https://github.com/uds-packages/postgres-operator/commit/5ebac865bd256ec9a3e5dc9518acf5843b707abe)) -## [1.10.1-uds.0](https://github.com/defenseunicorns/uds-package-postgres-operator/compare/v1.10.1-uds.0...v1.10.1-uds.0) (2024-03-02) +## [1.10.1-uds.0](https://github.com/uds-packages/postgres-operator/compare/v1.10.1-uds.0...v1.10.1-uds.0) (2024-03-02) ### Features -* initial uds postgres operator with optional database deployment chart ([#2](https://github.com/defenseunicorns/uds-package-postgres-operator/issues/2)) ([344b8ea](https://github.com/defenseunicorns/uds-package-postgres-operator/commit/344b8eaf412c864344411de0d6a62ef01e6f7485)) +* initial uds postgres operator with optional database deployment chart ([#2](https://github.com/uds-packages/postgres-operator/issues/2)) ([344b8ea](https://github.com/uds-packages/postgres-operator/commit/344b8eaf412c864344411de0d6a62ef01e6f7485)) ## [0.0.0] - YYYY-MM-DD PRE RELEASE diff --git a/CODEOWNERS b/CODEOWNERS index 17880f0..912103a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,5 @@ -# This repository is owned by the Software Factory Team -/* @defenseunicorns/swf +# This repository is owned by the UDS Foundry Team +* @uds-packages/maintainers @uds-packages/uds-foundry @uds-packages/federal-swf # Additional privileged files /CODEOWNERS @jeff-mccoy @daveworth diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad263af..f5e1aef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,4 +2,4 @@ Thank you for your interest in this Defense Unicorns UDS Package! -This package is part of Defense Unicorns' UDS Software Factory and follows the contributing guidelines outlined in that repositories' [CONTRIBUTING.md](https://github.com/defenseunicorns/uds-software-factory/blob/main/CONTRIBUTING.md) file. +This package is part of Defense Unicorns' Unicorn Delivery Service and follows the contributing guidelines outlined in [uds-common's CONTRIBUTING.md](https://github.com/defenseunicorns/uds-common/blob/main/CONTRIBUTING.md). diff --git a/README.md b/README.md index 4cb60cb..10b9c14 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # 🏭 UDS Postgres Operator Package [Made for UDS](https://github.com/defenseunicorns/uds-core) -[![Latest Release](https://img.shields.io/github/v/release/defenseunicorns/uds-package-postgres-operator)](https://github.com/defenseunicorns/uds-package-postgres-operator/releases) -[![Build Status](https://img.shields.io/github/actions/workflow/status/defenseunicorns/uds-package-postgres-operator/release.yaml)](https://github.com/defenseunicorns/uds-package-postgres-operator/actions/workflows/release.yaml) -[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/defenseunicorns/uds-package-postgres-operator/badge)](https://api.securityscorecards.dev/projects/github.com/defenseunicorns/uds-package-postgres-operator) +[![Latest Release](https://img.shields.io/github/v/release/uds-packages/postgres-operator)](https://github.com/uds-packages/postgres-operator/releases) +[![Build Status](https://img.shields.io/github/actions/workflow/status/uds-packages/postgres-operator/release.yaml)](https://github.com/uds-packages/postgres-operator/actions/workflows/release.yaml) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/uds-packages/postgres-operator/badge)](https://api.securityscorecards.dev/projects/github.com/uds-packages/postgres-operator) -This package is designed for use as part of a [UDS Software Factory](https://github.com/defenseunicorns/uds-software-factory) bundle deployed on [UDS Core](https://github.com/defenseunicorns/uds-core). +This package is designed for use as part of a [UDS Bundle](https://docs.defenseunicorns.com/core/concepts/configuration--packaging/bundles/) bundle deployed on [UDS Core](https://github.com/defenseunicorns/uds-core). + +> The Postgres Operator is a software tool that automates the deployment and management of PostgreSQL databases on Kubernetes, simplifying the process of setting up and maintaining highly available and scalable PostgreSQL clusters. ## Prerequisites @@ -13,7 +15,7 @@ This package requires a Kubernetes Cluster providing a Storage Class that has [U ## Releases -The released packages can be found in [ghcr](https://github.com/defenseunicorns/uds-package-postgres-operator/pkgs/container/packages%2Fuds%2Fpostgres-operator). +The released packages can be found in [ghcr](https://github.com/uds-packages/postgres-operator/pkgs/container/postgres-operator)). ## UDS Tasks (for local dev and CI) diff --git a/SECURITY.md b/SECURITY.md index 558eb01..fd5c166 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported Versions -As [UDS Software Factory](https://github.com/defenseunicorns/uds-software-factory) has not yet reached v1.0.0, only the current latest minor release is supported. +Only the current latest minor release is supported. ## Reporting a Vulnerability diff --git a/bundle/uds-bundle.yaml b/bundle/uds-bundle.yaml index 51fa2d7..ccb256b 100644 --- a/bundle/uds-bundle.yaml +++ b/bundle/uds-bundle.yaml @@ -5,21 +5,12 @@ kind: UDSBundle metadata: name: postgres-operator-test description: A UDS bundle for deploying Zalando Postgres Operator and on a development cluster - # x-release-please-start-version - version: 1.13.0-uds.2 - # x-release-please-end + version: dev packages: - # this sets up the namespaces that we will need in order to configure the default databases (and corresponding secrets) that are setup below - - name: dev-namespaces - path: ../ - ref: 0.1.0 - - name: postgres-operator path: ../ - # x-release-please-start-version - ref: 1.13.0-uds.2 - # x-release-please-end + ref: dev overrides: postgres-operator: uds-postgres-config: @@ -41,12 +32,17 @@ packages: gitlabdb: gitlab.gitlab mattermostdb: mattermost.mattermost sonarqubedb: sonarqube.sonarqube + extensions: + gitlabdb: ["hstore"] version: "14" + parameters: + - name: log_rotation_age + value: 2d ingress: - remoteNamespace: gitlab - name: ACID_PG_CLUSTER_NETWORKING description: "Allow connectivity to the acid pg cluster for testing (see tests/ folder)" - path: custom + path: additionalNetworkAllow default: - direction: Egress selector: diff --git a/bundle/uds-config.yaml b/bundle/uds-config.yaml index 2067cc5..e69de29 100644 --- a/bundle/uds-config.yaml +++ b/bundle/uds-config.yaml @@ -1,2 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial diff --git a/chart/templates/extension-job.yaml b/chart/templates/extension-job.yaml new file mode 100644 index 0000000..53c09e2 --- /dev/null +++ b/chart/templates/extension-job.yaml @@ -0,0 +1,56 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +{{- if and .Values.postgresql.enabled .Values.postgresql.extensions }} +apiVersion: batch/v1 +kind: Job +metadata: + name: enable-extensions-{{ now | unixEpoch }} + namespace: postgres +spec: + ttlSecondsAfterFinished: 5 + template: + spec: + restartPolicy: OnFailure + containers: + - name: extension-setup + image: {{ .Values.job.image | quote }} + command: ["/bin/bash", "-c"] + args: + - | + # Wait for each database to be ready + for db in {{- range $db, $_ := .Values.postgresql.extensions }} {{ $db }} {{- end }}; do + echo "Waiting for database $db to become available..." + until PGPASSWORD=$PGPASSWORD psql \ + -h pg-cluster.postgres.svc.cluster.local \ + -U "$PGUSERNAME" \ + -d "$db" \ + -c '\q' 2>/dev/null; do + sleep 3 + done + done + + # Install extensions per database + {{- range $db, $exts := .Values.postgresql.extensions }} + echo "Installing extensions in database: {{ $db }}" + for ext in {{- range $exts }} {{ . }} {{- end }}; do + echo "Creating extension: $ext" + PGPASSWORD=$PGPASSWORD psql \ + -h pg-cluster.postgres.svc.cluster.local \ + -U "$PGUSERNAME" \ + -d "{{ $db }}" \ + -c "CREATE EXTENSION IF NOT EXISTS $ext;" + done + {{- end }} + env: + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: postgres.pg-cluster.credentials.postgresql.acid.zalan.do + key: password + - name: PGUSERNAME + valueFrom: + secretKeyRef: + name: postgres.pg-cluster.credentials.postgresql.acid.zalan.do + key: username +{{- end }} diff --git a/chart/templates/patroni-svc.yaml b/chart/templates/patroni-svc.yaml new file mode 100644 index 0000000..4af4675 --- /dev/null +++ b/chart/templates/patroni-svc.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +{{- if not .Values.ambient }} +apiVersion: v1 +kind: Service +metadata: + name: pg-cluster-patroni + namespace: postgres +spec: + clusterIP: None + selector: + application: spilo + cluster-name: pg-cluster + ports: + - name: patroni + port: 8008 + targetPort: 8008 +{{- end }} diff --git a/chart/templates/pgbouncer-config.yaml b/chart/templates/pgbouncer-config.yaml new file mode 100644 index 0000000..33e5270 --- /dev/null +++ b/chart/templates/pgbouncer-config.yaml @@ -0,0 +1,39 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +{{- /* poolerConfig has no defaults in values.yaml; gate is nil-safe and each value + falls back to a sensible default below, overridable via postgresql.poolerConfig.* */}} +{{- if and .Values.postgresql.enabled (dig "poolerConfig" "enabled" false .Values.postgresql) }} +{{- $p := .Values.postgresql.poolerConfig | default dict }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: pgbouncer-config + namespace: postgres +data: + pgbouncer.ini: | + [databases] + * = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler + postgres = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler + + [pgbouncer] + pool_mode = {{ $p.poolMode | default "transaction" }} + listen_port = {{ $p.listenPort | default 5432 }} + listen_addr = * + admin_users = pooler + auth_dbname = postgres + auth_file = /etc/pgbouncer/userlist.txt + auth_query = SELECT * FROM pooler.user_lookup($1) + auth_type = scram-sha-256 + server_tls_sslmode = require + log_connections = 0 + log_disconnections = 0 + max_prepared_statements = 200 + default_pool_size = {{ $p.defaultPoolSize | default 20 }} + reserve_pool_size = {{ $p.reservePoolSize | default 10 }} + max_client_conn = {{ $p.maxClientConn | default 10000 }} + max_db_connections = {{ $p.maxDBConnections | default 60 }} + idle_transaction_timeout = 600 + server_login_retry = 5 + ignore_startup_parameters = extra_float_digits,options +{{- end }} diff --git a/chart/templates/postgres-minimal.yaml b/chart/templates/postgres-minimal.yaml index 2c00de5..efa474b 100644 --- a/chart/templates/postgres-minimal.yaml +++ b/chart/templates/postgres-minimal.yaml @@ -14,15 +14,56 @@ spec: volume: size: {{ .Values.postgresql.volume.size | quote }} numberOfInstances: {{ .Values.postgresql.numberOfInstances }} + {{- if hasKey .Values.postgresql "enableConnectionPooler" }} + enableConnectionPooler: {{ .Values.postgresql.enableConnectionPooler }} + {{- end }} + {{- if hasKey .Values.postgresql "enableReplicaConnectionPooler" }} + enableReplicaConnectionPooler: {{ .Values.postgresql.enableReplicaConnectionPooler }} + {{- end }} + {{- with .Values.postgresql.connectionPooler }} + connectionPooler: + {{- toYaml . | nindent 4 }} + {{- end }} users: {{- toYaml .Values.postgresql.users | nindent 4 }} # database owner databases: {{- toYaml .Values.postgresql.databases | nindent 4 }} patroni: - {{- toYaml .Values.postgresql.patroni | nindent 4 }} + initdb: + auth-host: scram-sha-256 + auth-local: trust + pg_hba: + {{- $defaultPgHba := list + "local all all trust" + "hostssl all +zalandos 127.0.0.1/32 pam" + "host all all 127.0.0.1/32 scram-sha-256" + "hostssl all +zalandos ::1/128 pam" + "host all all ::1/128 scram-sha-256" + "local replication standby trust" + "hostssl replication standby all scram-sha-256" + "host all all 10.0.0.0/8 scram-sha-256" + "host all all 172.16.0.0/12 scram-sha-256" + "host all all 192.168.0.0/16 scram-sha-256" + "hostnossl all all all reject" + "hostssl all +zalandos all pam" + "hostssl all all all scram-sha-256" + }} + {{- if and (hasKey .Values.postgresql "patroni") (hasKey .Values.postgresql.patroni "pg_hba") }} + {{- toYaml .Values.postgresql.patroni.pg_hba | nindent 6 }} + {{- else }} + {{- toYaml $defaultPgHba | nindent 6 }} + {{- end }} + {{- with (omit (.Values.postgresql.patroni | default dict) "pg_hba") }} + {{- toYaml . | nindent 4 }} + {{- end }} postgresql: parameters: - password_encryption: {{ .Values.postgresql.password_encryption | quote }} + password_encryption: scram-sha-256 + {{- range .Values.postgresql.parameters | default list }} + {{- if ne .name "password_encryption" }} + {{ .name }}: {{ .value | quote }} + {{- end }} + {{- end }} version: {{ .Values.postgresql.version | quote }} resources: {{- toYaml .Values.postgresql.resources | nindent 4 }} @@ -32,6 +73,10 @@ spec: - {{ . | toYaml | nindent 6 }} {{- end }} {{- end }} + {{- if .Values.postgresql.tls }} + tls: + {{- toYaml .Values.postgresql.tls | nindent 4 }} + {{- end }} sidecars: - name: "exporter" image: {{ .Values.metrics.image | quote }} diff --git a/chart/templates/postgres-monitor.yaml b/chart/templates/postgres-monitor.yaml deleted file mode 100644 index 202de1c..0000000 --- a/chart/templates/postgres-monitor.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -{{- if .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" }} -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: postgres-exporter - namespace: postgres -spec: - scrapeClass: istio-certs - namespaceSelector: - matchNames: - - postgres - podMetricsEndpoints: - - port: exporter - scheme: https - enableHttp2: false - selector: - matchLabels: - application: spilo -{{- end }} diff --git a/chart/templates/secret-namespaces.yaml b/chart/templates/secret-namespaces.yaml new file mode 100644 index 0000000..cf011a5 --- /dev/null +++ b/chart/templates/secret-namespaces.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +{{- $uniqueNamespaces := dict }} +{{- range $user, $_ := .Values.postgresql.users }} + {{- $namespace := (splitList "." $user | first) }} + {{- if not (hasKey $uniqueNamespaces $namespace) }} + {{- $_ := set $uniqueNamespaces $namespace true }} +--- +kind: Namespace +apiVersion: v1 +metadata: + name: {{ $namespace | quote }} + {{- end }} +{{- end }} diff --git a/chart/templates/uds-package-postgres.yaml b/chart/templates/uds-package-postgres.yaml index 8eae77c..76bf802 100644 --- a/chart/templates/uds-package-postgres.yaml +++ b/chart/templates/uds-package-postgres.yaml @@ -8,7 +8,16 @@ metadata: name: postgres namespace: postgres spec: + monitor: + - selector: + application: spilo + portName: exporter + targetPort: 9187 + kind: PodMonitor + description: "Postgres Exporter Port" network: + serviceMesh: + mode: {{ if .Values.ambient }}ambient{{ else }}sidecar{{ end }} allow: - direction: Ingress remoteGenerated: IntraNamespace @@ -16,19 +25,19 @@ spec: - direction: Egress remoteGenerated: IntraNamespace - {{- if kindIs "slice" .Values.postgresql.ingress -}} + {{- if kindIs "slice" .Values.postgresql.ingress -}} {{- range .Values.postgresql.ingress }} - direction: Ingress selector: cluster-name: pg-cluster {{ . | toYaml | nindent 8 }} {{- end }} - {{- else }} + {{- else }} - direction: Ingress selector: cluster-name: pg-cluster {{- .Values.postgresql.ingress | toYaml | nindent 8 }} - {{- end }} + {{- end }} - direction: Ingress selector: @@ -37,17 +46,34 @@ spec: remoteSelector: app.kubernetes.io/name: postgres-operator - - direction: Ingress - selector: - application: spilo - remoteNamespace: monitoring - remoteSelector: - app: prometheus - port: 9187 - description: "Postgres Exporter Port" - - direction: Egress selector: cluster-name: pg-cluster remoteGenerated: KubeAPI + + {{- /* Pooler (pgbouncer) traffic. Zalando labels pooler pods with + `application=db-connection-pooler`. IntraNamespace rules above + already cover pooler <-> spilo traffic within this namespace. */}} + {{- if or (.Values.postgresql.enableConnectionPooler | default false) (.Values.postgresql.enableReplicaConnectionPooler | default false) }} + {{- if kindIs "slice" .Values.postgresql.ingress -}} + {{- range .Values.postgresql.ingress }} + - direction: Ingress + selector: + application: db-connection-pooler + {{ . | toYaml | nindent 8 }} + {{- end }} + {{- else }} + - direction: Ingress + selector: + application: db-connection-pooler + {{- .Values.postgresql.ingress | toYaml | nindent 8 }} + {{- end }} + + - direction: Ingress + selector: + application: db-connection-pooler + remoteNamespace: {{ .Release.Namespace }} + remoteSelector: + app.kubernetes.io/name: postgres-operator + {{- end }} {{- end }} diff --git a/chart/templates/uds-package.yaml b/chart/templates/uds-package.yaml index 535b933..d37fdf3 100644 --- a/chart/templates/uds-package.yaml +++ b/chart/templates/uds-package.yaml @@ -8,6 +8,8 @@ metadata: namespace: {{ .Release.Namespace }} spec: network: + serviceMesh: + mode: {{ if .Values.ambient }}ambient{{ else }}sidecar{{ end }} allow: {{- if .Values.postgresql.enabled }} - direction: Egress @@ -22,17 +24,31 @@ spec: selector: app.kubernetes.io/name: postgres-operator remoteGenerated: KubeAPI + {{- if or (.Values.postgresql.enableConnectionPooler | default false) (.Values.postgresql.enableReplicaConnectionPooler | default false) }} + - direction: Egress + selector: + app.kubernetes.io/name: postgres-operator + remoteNamespace: postgres + remoteSelector: + application: db-connection-pooler + {{- end }} # Custom rules for other scenarios (such as connecting to a non-default pg cluster) - {{- range .Values.custom }} + {{- range .Values.additionalNetworkAllow }} - direction: {{ .direction }} + {{- if .selector}} selector: {{ .selector | toYaml | nindent 10 }} + {{- end }} {{- if not .remoteGenerated }} remoteNamespace: {{ .remoteNamespace }} + {{- if .remoteSelector }} remoteSelector: {{ .remoteSelector | toYaml | nindent 10 }} + {{- end }} + {{- if .port }} port: {{ .port }} + {{- end }} {{- else }} remoteGenerated: {{ .remoteGenerated }} {{- end }} diff --git a/chart/values.yaml b/chart/values.yaml index 7ee91b3..7525cd6 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -1,9 +1,11 @@ # Copyright 2024 Defense Unicorns # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial +ambient: true + postgresql: enabled: false - password_encryption: scram-sha-256 + parameters: [] ingress: [] resources: limits: @@ -15,6 +17,16 @@ postgresql: additionalVolumes: [] env: [] + # Connection pooler options + # Ref: https://opensource.zalando.com/postgres-operator/docs/user.html#connection-pooler + enableConnectionPooler: true + enableReplicaConnectionPooler: false + connectionPooler: {} + +# Example values for postgresql +# +# postgresql: +# enabled: true # teamId: "uds" # volume: # size: "1Gi" @@ -25,6 +37,8 @@ postgresql: # databases: # mydb: mynamespace.myuser # yourdb: yournamespace.youruser +# extensions: +# mydb: ["postgis","hstore"] # database extensions # version: "14" # ingress: # - remoteGenerated: Anywhere @@ -34,7 +48,11 @@ postgresql: # remoteSelector: # app.kubernetes.io/name: tempo -custom: [] +job: + # Job image to use for running extension loading jobs (e.g. ghcr.io/zalando/spilo-17:4.0-p2 - needs the psql client) + image: "" + +additionalNetworkAllow: [] # - direction: Egress # selector: # app.kubernetes.io/name: postgres-operator diff --git a/common/zarf.yaml b/common/zarf.yaml index cb5a3ce..b454be0 100644 --- a/common/zarf.yaml +++ b/common/zarf.yaml @@ -16,7 +16,7 @@ components: version: 0.1.0 localPath: ../chart - name: postgres-operator - version: 1.13.0 + version: 1.15.1 namespace: postgres-operator url: https://opensource.zalando.com/postgres-operator/charts/postgres-operator valuesFiles: @@ -34,9 +34,15 @@ components: wait: cluster: kind: packages.uds.dev - name: postgres - namespace: postgres + name: postgres-operator + namespace: postgres-operator condition: "'{.status.phase}'=Ready" + - description: Validate Postgres Package + maxTotalSeconds: 300 + cmd: | + if ./zarf tools kubectl get packages.uds.dev postgres -n postgres; then + ./zarf tools wait-for packages.uds.dev postgres -n postgres '{.status.phase}'=Ready + fi - description: Postgres Operator to be Healthy maxTotalSeconds: 90 wait: @@ -45,3 +51,9 @@ components: name: app.kubernetes.io/name=postgres-operator namespace: postgres-operator condition: Ready + - description: Wait for Postgres cluster to be Running if postgresql.enabled is true + maxTotalSeconds: 300 + cmd: | + if ./zarf tools kubectl get postgresql pg-cluster -n postgres; then + ./zarf tools wait-for postgresql pg-cluster -n postgres '{.status.PostgresClusterStatus}'=Running + fi diff --git a/docs/configuration.md b/docs/configuration.md index 7e64057..4344fdb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,12 +1,12 @@ # Configuration -Postgres Operator is configured through the upstream [Zalando Postgres Operator chart](https://github.com/zalando/postgres-operator/tree/master/charts/postgres-operator) as well as a UDS configuration chart. It implements a database for many [applications within UDS Software Factory](https://github.com/defenseunicorns/uds-software-factory/blob/main/docs/database.md#uds-postgres-operator-package) when one is not available in your cloud provider. +Postgres Operator is configured through the upstream [Zalando Postgres Operator chart](https://github.com/zalando/postgres-operator/tree/master/charts/postgres-operator) as well as a UDS configuration chart. It implements a database for many [applications within a UDS Bundle](https://docs.defenseunicorns.com/core/concepts/configuration--packaging/bundles/) when one is not available in your cloud provider. ## Networking -Network policies are controlled via the `uds-postgres-config` chart in accordance with the [common patterns for networking within UDS Software Factory](https://github.com/defenseunicorns/uds-software-factory/blob/main/docs/networking.md). Because Postgres does not interact with external resources like object storage it only implements `custom` networking for the `postgres-operator` namespace: +Network policies are controlled via the `uds-postgres-config` chart and follow [similar networking patterns as the Reference Package](https://github.com/uds-packages/reference-package/blob/main/docs/networking-patterns.md). Because Postgres does not interact with external resources like object storage it only implements `custom` networking for the `postgres-operator` namespace: -- `custom`: sets custom network policies for the `postgres-operator` namespace (as a break glass in case you deploy your own postgres cluster custom resources - see below) +- `additionalNetworkAllow`: sets custom network policies for the `postgres-operator` namespace (as a break glass in case you deploy your own postgres cluster custom resources - see below) ## Postgres Clusters @@ -18,10 +18,99 @@ Postgres Operator is configured through [`acid.zalan.do/v1` `Postgresql` custom - `postgresql.numberOfInstances`: The number of cluster Pods to run in the cluster (i.e. `2`) - `postgresql.users`: The users to create for the database in the form `{namespace}.{username}` (i.e. `gitlab.gitlab: []`) - `postgresql.databases`: The database names to create and the users they map to (i.e. `gitlabdb: gitlab.gitlab`) +- `postgresql.extensions`: A map of database names to lists of extensions to enable for that database (i.e. `mydb: ["postgis", "hstore"]`) - `postgresql.version`: The version of Postgres to run (i.e. `14`) -- `postgresql.ingress`: A list of ingress entries to create for this cluster (follows the [custom networking definition](https://github.com/defenseunicorns/uds-software-factory/blob/main/docs/networking.md) except for `direction` which is always `Ingress` and `selector` which is always `cluster-name: pg-cluster`) +- `postgresql.ingress`: A list of ingress entries to create for this cluster (follows the [custom networking definition](https://github.com/uds-packages/reference-package/blob/main/docs/networking-patterns.md) except for `direction` which is always `Ingress` and `selector` which is always `cluster-name: pg-cluster`) - `postgresql.resources`: A Kubernetes Pod resource specification to define requests and limits - `postgresql.additionalVolumes`: A list of additional volumes to map into the Postgres container if needed (see below) +- `postgresql.tls`: TLS configuration for the Postgres cluster to use (follows the [`tls` section of the Zalando Postgres CR](https://github.com/zalando/postgres-operator/blob/master/docs/reference/cluster_manifest.md#custom-tls-certificates)) +- `postgresql.parameters`: A list of database parameters to set as name/value pairs, if needed. `password_encryption` parameter defaults to `scram-sha-256` and cannot be overridden. + +```yaml + parameters: + - name: max_slot_wal_keep_size + value: 1GB + - name: + value: +``` + +## Connection Pooler (Unicorn Flavor) + +The Zalando operator can front a cluster with a [PgBouncer connection pooler](https://github.com/zalando/postgres-operator/blob/master/docs/reference/cluster_manifest.md#connection-pooler). On the `registry1` and `upstream` flavors the pooler uses Zalando-derived images that build their own `pgbouncer.ini` at startup, so no extra configuration is required. The `unicorn` flavor instead uses Chainguard's distroless `pgbouncer` image, which has no entrypoint to self-configure and therefore crash-loops on its own. To make it work, the unicorn flavor bundles a Pepr module plus a static `pgbouncer.ini` `ConfigMap` (`pgbouncer-config`) that configure the pooler externally. This behavior applies to the unicorn flavor only. + +When `postgresql.poolerConfig.enabled` is `true` (the default in the unicorn flavor's values), the chart renders the `pgbouncer.ini` `ConfigMap` and the bundled Pepr module: +- reconciles the operator-created pooler credential secret into a derived `pgbouncer-userlist` secret (a `userlist.txt` auth file in the form `"pooler" ""`), and +- mutates each pooler `Deployment` (`pg-cluster-pooler`, `pg-cluster-pooler-repl`) to mount `pgbouncer.ini` and the auth file at `/etc/pgbouncer` and set the PgBouncer launch command. + +Encryption and authentication for the FIPS pooler: +- **App → PgBouncer**: there is no client-side TLS on PgBouncer; in-transit encryption between applications and the pooler is provided by the Istio service mesh (mTLS). +- **PgBouncer → Postgres**: enforced TLS via `server_tls_sslmode = require` (non-SSL connections are rejected by `pg_hba`). +- **Authentication**: `scram-sha-256` with an `auth_query` (`SELECT * FROM pooler.user_lookup($1)`) executed as the `pooler` user. + +Pool sizing is configured statically through `postgresql.poolerConfig.*` chart values (rather than the operator's dynamic sizing): + +- `postgresql.poolerConfig.enabled`: whether to render the FIPS pooler `ConfigMap` and enable the Pepr-driven configuration (default `false`; set `true` on the unicorn flavor) +- `postgresql.poolerConfig.listenPort`: the port PgBouncer listens on (default `5432`) +- `postgresql.poolerConfig.poolMode`: the PgBouncer pool mode (default `transaction`) +- `postgresql.poolerConfig.defaultPoolSize`: server connections per user/database pair (default `20`) +- `postgresql.poolerConfig.reservePoolSize`: extra connections allowed when a pool is exhausted (default `10`) +- `postgresql.poolerConfig.maxClientConn`: maximum client connections accepted by PgBouncer (default `10000`) +- `postgresql.poolerConfig.maxDBConnections`: maximum server connections per database (default `60`) + +> **Limitation — replica pooler:** the rendered `pgbouncer.ini` targets the primary service (`pg-cluster.postgres.svc`). Only the primary pooler (`enableConnectionPooler`) is supported on the FIPS flavor. Do not enable `enableReplicaConnectionPooler` here: the same config would be applied to `pg-cluster-pooler-repl`, routing replica-pooler traffic to the primary. Role-aware (primary/replica) configuration is a follow-up. + +### Building and deploying the Pepr module + +The Pepr module lives in `src/pepr/` and is built into a Kubernetes manifest at `src/pepr/dist/pepr-module-pgbouncer.yaml`. That `dist/` directory is git-ignored, so the manifest is generated at build time rather than committed. + +**It is built and deployed automatically as part of the package — no separate step is required.** The unicorn component in `zarf.yaml` has an `onCreate.before` action that runs `pepr build` whenever the unicorn package is created (`zarf package create --flavor unicorn`, `uds run create-dev-package`, or the release/test CI which call these tasks). The generated manifest is then included as a component `manifests:` entry, and the Pepr controller image (`ghcr.io/defenseunicorns/pepr/private/controller`) is pulled into the package like any other image. Deploying the unicorn package (or a bundle containing it) therefore deploys the module into the `pepr-system` namespace alongside `pepr-uds-core`; there is nothing extra to deploy. + +> **Build prerequisite:** the build host (your machine or the CI runner) needs **Node.js 20+** and network access to install dependencies (`npm ci`). This applies only to *creating* the unicorn package, not to *deploying* it in an air-gapped environment — the rendered manifest and the controller image are baked into the package at create time. + +For local iteration on the module without creating a full package, run the build directly: + +```bash +uds run build-pepr +# equivalent to: +# cd src/pepr && npm ci && npx pepr build --custom-image ghcr.io/defenseunicorns/pepr/private/controller:v1.2.1 +``` + +Unit tests for the module: + +```bash +cd src/pepr && npx vitest run +``` + +> Keep the `--custom-image` tag in the `zarf.yaml` `onCreate` action, the `build-pepr` task, and the component `images:` list in sync (all reference the same Pepr controller image). + +### Lifecycle (install and removal) + +The Pepr module is bundled inside the postgres-operator package (a `manifests:` entry on the unicorn component), so its lifecycle is coupled to the package: + +- **Install:** deploying the unicorn package deploys the module into the existing `pepr-system` namespace (alongside `pepr-uds-core`), as its own Zarf-managed release. +- **Removal:** `uds`/`zarf package remove` of postgres-operator uninstalls the module release, deleting all of its resources — the Deployments/Services/Secrets/RBAC in `pepr-system` **and** the cluster-scoped `pepr-pgbouncer` `ClusterRole`, `ClusterRoleBinding`, and `MutatingWebhookConfiguration`. Nothing dangling is left behind. + +The module's manifest deliberately does **not** include the `pepr-system` `Namespace` object (the build strips it via `yq`). That namespace is created and owned by uds-core and shared with `pepr-uds-core`; excluding it ensures removing this package never cascade-deletes the shared namespace (which would tear down uds-core's Pepr). Consequently the package depends on uds-core having already created `pepr-system` at deploy time, which is always the case in a UDS cluster. + +Runtime-created resources are cleaned up too: the derived `pgbouncer-userlist` secret carries an `ownerReference` to the operator's pooler credential secret (garbage-collected when the cluster/secret is removed), and the pooler Deployment mutation disappears with the operator-managed pooler Deployment when the cluster is torn down. + +### Verifying the pooler (unicorn) + +```bash +# pooler pods should be Running (not CrashLoopBackOff / usage-exit) +kubectl -n postgres rollout status deployment/pg-cluster-pooler --timeout=180s +# the pepr module should have created the derived auth secret +kubectl -n postgres get secret pgbouncer-userlist +# the pooler Deployment should carry the injected command + /etc/pgbouncer mount +kubectl -n postgres get deploy pg-cluster-pooler -o jsonpath='{.spec.template.spec.containers[0].command}'; echo +# end-to-end: connect through the pooler service and run a query (use your app/pooler user) +# kubectl -n postgres run pooler-check --rm -it --image= --restart=Never -- \ +# psql "host=pg-cluster-pooler.postgres.svc port=5432 dbname= user=" -c 'select 1;' +``` + +## Secrets Creation + +The operator creates credentials secrets in the namespace defined by the `{namespace}.{username}` prefix in `postgresql.users`. See the [Reference Package configuration](https://github.com/uds-packages/reference-package/blob/main/docs/configuration.md#secrets-creation) for an example of how to consume these secrets within an application chart. ## Postgres HugePages @@ -37,3 +126,35 @@ Postgres Operator can also support HugePages by setting the following keys appro emptyDir: medium: HugePages-2Mi ``` + +## Postgres Extensions + +Postgres Operator supports enabling PostgreSQL extensions for specific databases using the `postgresql.extensions` configuration. Extensions are enabled via a Kubernetes Job that runs after the database cluster is created. + +- `postgresql.extensions`: A map of database names to arrays of extension names to enable + +Example: + +```yaml +postgresql: + extensions: + mydb: ["postgis", "hstore", "pg_trgm"] + anotherdb: ["uuid-ossp", "pgcrypto"] +``` + +The Spilo PostgreSQL image includes 100+ extensions. You can view the complete list by running: + +```bash +docker run --rm ghcr.io/zalando/spilo-17:4.0-p2 bash -c "ls -1 /usr/share/postgresql/17/extension/*.control | xargs -n1 basename | sed 's/.control$//' | sort" +``` + +> [!NOTE] +> You may need to swap the above image to match the package flavor you are using. + +Commonly used extensions include: +- **Spatial/GIS**: `postgis`, `address_standardizer`, `earthdistance` +- **Data Types**: `hstore`, `citext`, `uuid-ossp`, `vector`, `ltree` +- **Full Text Search**: `pg_trgm`, `fuzzystrmatch`, `unaccent` +- **Crypto**: `pgcrypto` +- **Time Series**: `timescaledb` +- **Monitoring**: `pg_stat_statements` diff --git a/docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md b/docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md new file mode 100644 index 0000000..90665fa --- /dev/null +++ b/docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md @@ -0,0 +1,625 @@ +# FIPS Connection Pooler via Pepr Module — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make the Zalando connection pooler work on the `unicorn` flavor's distroless `pgbouncer-fips` image by shipping a Pepr module that supplies pgbouncer's config + auth and sets its launch command. + +**Architecture:** The Helm chart ships a static `pgbouncer.ini` ConfigMap (unicorn-gated). A flavor-gated Pepr module (1) reconciles the operator's pooler credential Secret into a derived `userlist.txt` Secret, and (2) mutates each operator-created pooler Deployment to mount both via a projected volume at `/etc/pgbouncer` and set `command: ["/usr/bin/pgbouncer","/etc/pgbouncer/pgbouncer.ini"]`. Admission mutation re-applies on every operator write, so there is no reconcile-drift window. + +**Tech Stack:** Pepr (TypeScript admission/reconcile framework), Helm, Zarf, the Zalando postgres-operator, pgbouncer. + +**Source of truth:** Design spec at `docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md`. Upstream reference: `zalando/postgres-operator` `pooler/pgbouncer.ini.tmpl` + `pooler/entrypoint.sh`. + +**Note on commits:** Commit steps below are written per the skill's TDD cadence for execution time. The current session has been instructed not to commit — honor that; the executor commits per repo/user preference. + +--- + +## Pre-flight facts (do not re-derive) + +- Pooler container is `containers[0]`, name `connection-pooler`; pods labeled `application: db-connection-pooler`. Deployments: `pg-cluster-pooler`, `pg-cluster-pooler-repl`. Namespace `postgres`. +- Pooler user/schema = `pooler`/`pooler`; source Secret `pooler.pg-cluster.credentials.postgresql.acid.zalan.do` (keys `username`, `password`, base64). +- Cluster is `scram-sha-256`; pg_hba rejects non-SSL, so `server_tls_sslmode = require`. +- Distroless binary path: `/usr/bin/pgbouncer`. We omit `logfile`/`pidfile` (log to stderr, run in foreground) so the container needs no writable dirs; config mounts are read-only. +- Operator installs `pooler.user_lookup(...)` in each DB regardless of image, so `auth_query` works. + +--- + +## File structure + +- Create `src/pepr/package.json` — module manifest + Pepr dep + scripts. +- Create `src/pepr/pepr.ts` — module entrypoint registering the capability. +- Create `src/pepr/capabilities/pgbouncer-fips-pooler.ts` — Reconciler + Mutator. +- Create `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts` — unit tests. +- Create `chart/templates/pgbouncer-config.yaml` — `pgbouncer.ini` ConfigMap (unicorn-gated). +- Modify `chart/values.yaml` — add `postgresql.poolerFipsConfig` defaults block. +- Modify `values/unicorn-values.yaml` — enable `postgresql.poolerFipsConfig`. +- Modify `zarf.yaml` — add Pepr component + image, gated `only.flavor: unicorn`. +- Modify `docs/configuration.md` — document FIPS-flavor pooler behavior. +- Modify `renovate.json` — track the Pepr controller image. +- Modify `tests/postgres/` + `tasks/test.yaml` — e2e regression for unicorn pooler. + +--- + +## Task 0: Confirm FIPS Pepr controller image (prerequisite gate) + +**Files:** none (investigation; record result in the spec's Risks section). + +- [ ] **Step 1: Identify the Pepr image uds-core ships** + +Run: +```bash +# Inspect a running uds-core install or its package definition for the pepr image +kubectl -n pepr-system get deploy -o jsonpath='{.items[*].spec.template.spec.containers[*].image}' 2>/dev/null; echo +# and/or check the pepr controller image tag uds-core pins +``` +Expected: a `ghcr.io/defenseunicorns/pepr/controller:vX.Y.Z` (or registry1/cgr FIPS variant) reference. + +- [ ] **Step 2: Decide image source** + +If a FIPS/registry1 Pepr controller image is available, record its reference for use in `zarf.yaml` (Task 5). If NOT available, STOP and revisit the design with the user — the lift/image-sourcing changes. Do not proceed past this gate without a usable image. + +**GATE RESULT (2026-06-03):** PASSED. uds-core runs `ghcr.io/defenseunicorns/pepr/controller:v1.2.0` in the live `k3d-uds` cluster (`pepr-system/pepr-uds-core`). Use that image for dev/test; the unicorn-flavor FIPS variant (cgr/registry1 Pepr controller) is a `zarf.yaml` packaging detail to finalize in Task 5, non-blocking for build/test. **Pepr is v1.x — pin the npm `pepr` dep to `1.2.0`, not `0.x`.** The live `pg-cluster-pooler` is in CrashLoopBackOff, so the fix is verifiable end-to-end here. + +--- + +## Task 1: Scaffold the Pepr module + +**Files:** +- Create: `src/pepr/package.json` +- Create: `src/pepr/pepr.ts` + +- [ ] **Step 1: Create `src/pepr/package.json`** + +```json +{ + "name": "pepr-pgbouncer-fips", + "version": "0.0.1", + "description": "Configures the distroless pgbouncer-fips connection pooler for the Zalando postgres-operator", + "keywords": ["pepr", "k8s", "policy-engine"], + "pepr": { + "uuid": "pgbouncer-fips", + "onError": "ignore", + "webhookTimeout": 10, + "alwaysIgnore": { "namespaces": [] }, + "includedFiles": [] + }, + "scripts": { + "test": "vitest run", + "build": "pepr build" + }, + "dependencies": { + "pepr": "1.2.0" + }, + "devDependencies": { + "vitest": "^1.6.0" + } +} +``` + +Note: Prefer scaffolding with `npx pepr@1.2.0 init` (non-interactive flags: `--name pepr-pgbouncer-fips --uuid pgbouncer-fips --errorBehavior ignore --skip-post-init --yes` — adjust flags to the 1.2.0 CLI) so the generated `package.json`/`pepr.ts` match the v1.2.0 format exactly; then reconcile with the fields shown above. `onError: ignore` maps to `failurePolicy: Ignore` per the design. Pin `pepr` to `1.2.0` to match the controller image from Task 0. + +- [ ] **Step 2: Create `src/pepr/pepr.ts`** + +```typescript +import { PeprModule } from "pepr"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +import cfg from "./package.json"; +import { PgbouncerFips } from "./capabilities/pgbouncer-fips-pooler"; + +new PeprModule(cfg, [PgbouncerFips]); +``` + +- [ ] **Step 3: Install deps and verify Pepr CLI works** + +Run: +```bash +cd src/pepr && npm install && npx pepr --version +``` +Expected: prints the Pepr version (matches Task 0 image). + +- [ ] **Step 4: Commit** + +```bash +git add src/pepr/package.json src/pepr/pepr.ts src/pepr/package-lock.json +git commit -m "feat(pepr): scaffold pgbouncer-fips module" +``` + +--- + +## Task 2: Ship the static `pgbouncer.ini` ConfigMap (chart) + +**Files:** +- Create: `chart/templates/pgbouncer-config.yaml` +- Modify: `chart/values.yaml` +- Modify: `values/unicorn-values.yaml` + +- [ ] **Step 1: Add values defaults to `chart/values.yaml`** + +Under the `postgresql:` block, add: + +```yaml + # FIPS pooler config: rendered only when true (set by the unicorn flavor). + # The distroless pgbouncer-fips image has no entrypoint to build pgbouncer.ini, + # so we ship it here and the pepr module mounts it. + poolerFipsConfig: + enabled: false + listenPort: 5432 + poolMode: transaction + defaultPoolSize: 20 + reservePoolSize: 10 + maxClientConn: 10000 + maxDBConnections: 60 +``` + +- [ ] **Step 2: Enable it in `values/unicorn-values.yaml`** + +Under `postgresql:` add: + +```yaml + poolerFipsConfig: + enabled: true +``` + +- [ ] **Step 3: Create `chart/templates/pgbouncer-config.yaml`** + +```yaml +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +{{- if and .Values.postgresql.enabled .Values.postgresql.poolerFipsConfig.enabled }} +{{- $p := .Values.postgresql.poolerFipsConfig }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: pgbouncer-config + namespace: postgres +data: + pgbouncer.ini: | + [databases] + * = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler + postgres = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler + + [pgbouncer] + pool_mode = {{ $p.poolMode }} + listen_port = {{ $p.listenPort }} + listen_addr = * + admin_users = pooler + auth_dbname = postgres + auth_file = /etc/pgbouncer/userlist.txt + auth_query = SELECT * FROM pooler.user_lookup($1) + auth_type = scram-sha-256 + server_tls_sslmode = require + log_connections = 0 + log_disconnections = 0 + max_prepared_statements = 200 + default_pool_size = {{ $p.defaultPoolSize }} + reserve_pool_size = {{ $p.reservePoolSize }} + max_client_conn = {{ $p.maxClientConn }} + max_db_connections = {{ $p.maxDBConnections }} + idle_transaction_timeout = 600 + server_login_retry = 5 + ignore_startup_parameters = extra_float_digits,options +{{- end }} +``` + +Notes vs upstream template: `auth_type` is `scram-sha-256` (cluster uses scram, not md5); client TLS lines and `server_tls_ca_file` removed (mesh mTLS for clients; `require` needs no CA); `logfile`/`pidfile` removed (stderr + foreground, no writable dirs); `min_pool_size` left out (upstream comments it out). + +- [ ] **Step 4: Render-test ConfigMap presence (unicorn) and absence (upstream)** + +Run: +```bash +helm template chart -f chart/values.yaml -f values/unicorn-values.yaml \ + --set postgresql.enabled=true --set postgresql.volume.size=10Gi \ + --set metrics.image=foo --set metrics.tag=bar \ + --show-only templates/pgbouncer-config.yaml 2>&1 | grep -c "auth_type = scram-sha-256" +``` +Expected: `1`. + +Run: +```bash +helm template chart -f chart/values.yaml -f values/upstream-values.yaml \ + --set postgresql.enabled=true --set postgresql.volume.size=10Gi \ + --set metrics.image=foo --set metrics.tag=bar \ + --show-only templates/pgbouncer-config.yaml 2>&1 | grep -c "kind: ConfigMap" || true +``` +Expected: `0` (template renders empty for non-unicorn). + +- [ ] **Step 5: Commit** + +```bash +git add chart/templates/pgbouncer-config.yaml chart/values.yaml values/unicorn-values.yaml +git commit -m "feat(chart): add unicorn-gated pgbouncer.ini ConfigMap for FIPS pooler" +``` + +--- + +## Task 3: Pepr Reconciler — derived `userlist.txt` Secret + +**Files:** +- Create: `src/pepr/capabilities/pgbouncer-fips-pooler.ts` (Reconciler portion) +- Create: `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts` + +- [ ] **Step 1: Write the failing unit test for userlist rendering** + +`src/pepr/capabilities/pgbouncer-fips-pooler.test.ts`: + +```typescript +import { describe, it, expect } from "vitest"; +import { renderUserlist } from "./pgbouncer-fips-pooler"; + +describe("renderUserlist", () => { + it("formats a pgbouncer auth_file line from username/password", () => { + expect(renderUserlist("pooler", "s3cr3t")).toBe('"pooler" "s3cr3t"\n'); + }); + + it("escapes embedded double quotes in the password", () => { + expect(renderUserlist("pooler", 'pa"ss')).toBe('"pooler" "pa""ss"\n'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` +Expected: FAIL — `renderUserlist` is not exported / not defined. + +- [ ] **Step 3: Create the capability file with the Reconciler + `renderUserlist`** + +`src/pepr/capabilities/pgbouncer-fips-pooler.ts`: + +```typescript +import { Capability, a, K8s, kind, Log } from "pepr"; + +export const PgbouncerFips = new Capability({ + name: "pgbouncer-fips-pooler", + description: "Configures the distroless pgbouncer-fips connection pooler.", + namespaces: ["postgres"], +}); + +const { When } = PgbouncerFips; + +const SOURCE_SECRET = "pooler.pg-cluster.credentials.postgresql.acid.zalan.do"; +const DERIVED_SECRET = "pgbouncer-fips-userlist"; +const NS = "postgres"; + +// pgbouncer auth_file format: `"user" "password"` with "" escaping inside quotes. +export function renderUserlist(username: string, password: string): string { + const esc = (s: string) => s.replace(/"/g, '""'); + return `"${esc(username)}" "${esc(password)}"\n`; +} + +// Reconcile the operator's pooler credential Secret into a derived userlist Secret. +When(a.Secret) + .IsCreatedOrUpdated() + .InNamespace(NS) + .WithName(SOURCE_SECRET) + // Reconcile (not Watch): ordered, idempotent queue — the operator pattern for + // creating/owning derived resources. + .Reconcile(async secret => { + const data = secret.data ?? {}; + if (!data.username || !data.password) { + Log.warn(`${SOURCE_SECRET} missing username/password; skipping`); + return; + } + const username = Buffer.from(data.username, "base64").toString("utf8"); + const password = Buffer.from(data.password, "base64").toString("utf8"); + + await K8s(kind.Secret).Apply({ + metadata: { + name: DERIVED_SECRET, + namespace: NS, + ownerReferences: [ + { + apiVersion: "v1", + kind: "Secret", + name: secret.metadata!.name!, + uid: secret.metadata!.uid!, + controller: false, + blockOwnerDeletion: false, + }, + ], + }, + stringData: { "userlist.txt": renderUserlist(username, password) }, + }); + Log.info(`reconciled ${DERIVED_SECRET} from ${SOURCE_SECRET}`); + }); +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` +Expected: PASS (both `renderUserlist` cases). + +- [ ] **Step 5: Commit** + +```bash +git add src/pepr/capabilities/pgbouncer-fips-pooler.ts src/pepr/capabilities/pgbouncer-fips-pooler.test.ts +git commit -m "feat(pepr): reconcile pooler secret into pgbouncer userlist secret" +``` + +--- + +## Task 4: Pepr Mutator — inject config + command into the pooler Deployment + +**Files:** +- Modify: `src/pepr/capabilities/pgbouncer-fips-pooler.ts` (add Mutator + helper) +- Modify: `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts` (add mutation tests) + +- [ ] **Step 1: Write failing tests for the mutation helper** + +Append to `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts`: + +```typescript +import { applyPoolerPatch } from "./pgbouncer-fips-pooler"; + +function poolerDeployment(): any { + return { + spec: { + template: { + spec: { + volumes: [], + containers: [{ name: "connection-pooler", image: "cgr.dev/x/pgbouncer-fips:v1", volumeMounts: [] }], + }, + }, + }, + }; +} + +describe("applyPoolerPatch", () => { + it("sets the pgbouncer command on containers[0]", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + expect(d.spec.template.spec.containers[0].command).toEqual([ + "/usr/bin/pgbouncer", + "/etc/pgbouncer/pgbouncer.ini", + ]); + }); + + it("adds a projected /etc/pgbouncer volume + mount", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + const vol = d.spec.template.spec.volumes.find((v: any) => v.name === "pgbouncer-fips"); + expect(vol.projected.sources).toHaveLength(2); + const mount = d.spec.template.spec.containers[0].volumeMounts.find( + (m: any) => m.name === "pgbouncer-fips", + ); + expect(mount.mountPath).toBe("/etc/pgbouncer"); + expect(mount.readOnly).toBe(true); + }); + + it("is idempotent (no duplicate volume/mount on second apply)", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + applyPoolerPatch(d); + expect(d.spec.template.spec.volumes.filter((v: any) => v.name === "pgbouncer-fips")).toHaveLength(1); + expect( + d.spec.template.spec.containers[0].volumeMounts.filter((m: any) => m.name === "pgbouncer-fips"), + ).toHaveLength(1); + }); +}); +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` +Expected: FAIL — `applyPoolerPatch` not exported. + +- [ ] **Step 3: Add `applyPoolerPatch` + the Mutator to the capability file** + +Append to `src/pepr/capabilities/pgbouncer-fips-pooler.ts`: + +```typescript +const VOLUME = "pgbouncer-fips"; +const CONFIG_MAP = "pgbouncer-config"; + +// Pure, idempotent mutation of a pooler Deployment object. +export function applyPoolerPatch(d: any): void { + const podSpec = d?.spec?.template?.spec; + if (!podSpec || !Array.isArray(podSpec.containers) || podSpec.containers.length === 0) { + return; + } + podSpec.volumes = podSpec.volumes ?? []; + if (!podSpec.volumes.some((v: any) => v.name === VOLUME)) { + podSpec.volumes.push({ + name: VOLUME, + projected: { + sources: [ + { configMap: { name: CONFIG_MAP, items: [{ key: "pgbouncer.ini", path: "pgbouncer.ini" }] } }, + { secret: { name: DERIVED_SECRET, items: [{ key: "userlist.txt", path: "userlist.txt" }] } }, + ], + }, + }); + } + + const c = podSpec.containers[0]; // connection-pooler is containers[0] + c.volumeMounts = c.volumeMounts ?? []; + if (!c.volumeMounts.some((m: any) => m.name === VOLUME)) { + c.volumeMounts.push({ name: VOLUME, mountPath: "/etc/pgbouncer", readOnly: true }); + } + c.command = ["/usr/bin/pgbouncer", "/etc/pgbouncer/pgbouncer.ini"]; +} + +// Mutate every pooler Deployment in the postgres namespace (unicorn-only deploy). +When(a.Deployment) + .IsCreatedOrUpdated() + .InNamespace(NS) + .WithLabel("application", "db-connection-pooler") + .Mutate(request => { + applyPoolerPatch(request.Raw); + }); +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` +Expected: PASS (all 5 tests: 2 userlist + 3 mutation). + +- [ ] **Step 5: Commit** + +```bash +git add src/pepr/capabilities/pgbouncer-fips-pooler.ts src/pepr/capabilities/pgbouncer-fips-pooler.test.ts +git commit -m "feat(pepr): mutate pooler deployment to mount config and set pgbouncer command" +``` + +--- + +## Task 5: Build the module and wire it into Zarf (unicorn-gated) + +**Files:** +- Modify: `zarf.yaml` + +- [ ] **Step 1: Build the Pepr module** + +Run: +```bash +cd src/pepr && npx pepr build +``` +Expected: produces `src/pepr/dist/` containing `pepr-module-pgbouncer-fips.yaml` (manifests) and prints the controller image used. + +- [ ] **Step 2: Add a flavor-gated component to `zarf.yaml`** + +Add a component (place near the existing config component). Use the manifests produced by `pepr build` and the controller image confirmed in Task 0: + +```yaml + - name: pgbouncer-fips-pooler + description: "Pepr module configuring the distroless pgbouncer-fips pooler" + required: false + only: + flavor: unicorn + manifests: + - name: pepr-pgbouncer-fips + namespace: pepr-pgbouncer-fips + files: + - src/pepr/dist/pepr-module-pgbouncer-fips.yaml + images: + - "" +``` + +Replace `` with the exact reference recorded in Task 0. If `pepr build` emits a different manifest filename, use that exact path. + +- [ ] **Step 3: Validate the package builds for unicorn and excludes the component elsewhere** + +Run: +```bash +zarf dev inspect manifests . --flavor unicorn 2>&1 | grep -c "pepr-module-pgbouncer-fips" || true +``` +Expected: `>= 1` for unicorn. + +Run: +```bash +zarf dev inspect manifests . --flavor upstream 2>&1 | grep -c "pepr-pgbouncer-fips" || true +``` +Expected: `0`. + +(If `zarf dev inspect manifests` cannot resolve the component, fall back to `zarf package create . --flavor unicorn --confirm -o /tmp` and inspect the built package's `zarf.yaml`.) + +- [ ] **Step 4: Commit** + +```bash +git add zarf.yaml src/pepr/dist +git commit -m "feat(zarf): deploy pgbouncer-fips pepr module on unicorn flavor" +``` + +--- + +## Task 6: e2e regression test (unicorn pooler runs and proxies) + +**Files:** +- Modify: `tests/postgres/postgres-minimal.yaml` or add `tests/postgres/pooler-fips-test.yaml` +- Modify: `tasks/test.yaml` + +- [ ] **Step 1: Add an e2e assertion that the pooler pod runs (not usage-exit)** + +Add a test task in `tasks/test.yaml` (match existing task style). The assertion: after deploying the unicorn flavor with pooling enabled, the pooler pods become Ready. + +```yaml + - name: validate-fips-pooler + description: "pgbouncer-fips pooler pods start and accept connections" + actions: + - cmd: | + kubectl -n postgres rollout status deployment/pg-cluster-pooler --timeout=180s + - description: "Pooler proxies a query (auth via auth_query)" + cmd: | + kubectl -n postgres run pooler-smoke-$RANDOM --rm -i --restart=Never \ + --image=$(yq '.postgresql.connection_pooler_image' values/unicorn-values.yaml) \ + --command -- /usr/bin/pgbouncer --version +``` + +Note: the second action only proves the binary runs; the authoritative check is the existing through-pooler psql connectivity test in `tests/postgres/`. Wire `validate-fips-pooler` to run after the existing pooler routing test in the unicorn test flow. + +- [ ] **Step 2: Extend/confirm the existing pooler connectivity test targets the pooler service** + +Confirm `tests/postgres/` pooler routing test connects via the pooler Service (`pg-cluster-pooler.postgres.svc`) and runs a `SELECT`. If it currently only runs for non-unicorn, add a unicorn invocation in `tasks/test.yaml`. + +- [ ] **Step 3: Run the unicorn e2e flow locally (if a cluster is available)** + +Run: +```bash +uds run test: # match the actual task name in tasks/test.yaml +``` +Expected: pooler rollout succeeds; through-pooler `SELECT` returns rows (no usage-exit, no auth failure). + +- [ ] **Step 4: Commit** + +```bash +git add tasks/test.yaml tests/postgres +git commit -m "test: verify pgbouncer-fips pooler runs and proxies on unicorn" +``` + +--- + +## Task 7: Docs + automation wiring + +**Files:** +- Modify: `docs/configuration.md` +- Modify: `renovate.json` + +- [ ] **Step 1: Document the FIPS pooler behavior** + +In `docs/configuration.md`, in the connection pooler section, add a subsection: on the `unicorn` (FIPS) flavor the pooler image is distroless and is configured by the bundled Pepr module (`pgbouncer-fips-pooler`); client→pooler encryption is provided by the service mesh (mTLS), pooler→postgres uses `server_tls_sslmode=require`, and auth uses `scram-sha-256` via `auth_query`. Note that pool sizes are set via `postgresql.poolerFipsConfig.*` rather than the operator's dynamic sizing. + +- [ ] **Step 2: Track the Pepr controller image in renovate** + +In `renovate.json`, add a rule (matching existing patterns) so the Pepr controller image reference in `zarf.yaml` is updated by renovate. If the repo pins images via a custom manager/regex, mirror that for the new image. + +- [ ] **Step 3: Lint** + +Run: +```bash +uds run lint # or the repo's lint task; match tasks.yaml +``` +Expected: passes. + +- [ ] **Step 4: Commit** + +```bash +git add docs/configuration.md renovate.json +git commit -m "docs: document FIPS pooler; chore: track pepr image in renovate" +``` + +--- + +## Self-Review + +**Spec coverage:** +- Image-compatibility root cause → Tasks 2–5 (config + mutation + command). +- Module scope (unicorn-only, mutate all poolers) → Task 5 `only.flavor: unicorn`; Mutator has no image gate (Task 4). +- Client TLS via mesh / server `require` → Task 2 ConfigMap. +- Pepr-derived userlist Secret → Task 3. +- `failurePolicy: Ignore` → Task 1 `onError: ignore`. +- Static `pgbouncer.ini` in chart, unicorn-gated → Task 2. +- Data-flow/ordering (by-name refs, kubelet volume-wait) → Task 4 (refs by name) + Task 6 (cold-deploy). +- Idempotency → Task 4 Step 1 test. +- Testing (unit + e2e + flavor gating) → Tasks 3, 4, 6; gating assertions Task 2 Step 4 / Task 5 Step 3. +- Packaging/layout/docs/renovate → Tasks 1, 5, 7. +- FIPS Pepr image risk → Task 0 gate. + +**Placeholder scan:** One intentional placeholder — `` (resolved by Task 0) and the test/lint task names which must match `tasks/test.yaml`/`tasks.yaml`. All code steps contain real code. + +**Type consistency:** `DERIVED_SECRET`, `CONFIG_MAP`, `VOLUME`, `renderUserlist`, `applyPoolerPatch`, `PgbouncerFips` are used consistently across Tasks 3–4 and tests. Container index 0 / name `connection-pooler` consistent with pre-flight facts. + +## Open items the executor must resolve against the live repo +- Exact `pepr` package version + matching controller image (Task 0/1/5). +- Exact `pepr build` output filename (Task 5 Step 2). +- Actual task names in `tasks/test.yaml` / `tasks.yaml` for lint + e2e (Tasks 6, 7). +- Confirm `tests/postgres/` pooler routing test's connection target (Task 6 Step 2). diff --git a/docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md b/docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md new file mode 100644 index 0000000..a126d68 --- /dev/null +++ b/docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md @@ -0,0 +1,191 @@ +# Design: FIPS Connection Pooler via Pepr Module + +- **Date:** 2026-06-03 +- **Status:** Approved (design); pending implementation plan +- **Scope:** `unicorn` flavor only + +## Problem + +On the `unicorn` flavor, `connection_pooler_image` is set to Chainguard's +**distroless** `cgr.dev/defenseunicorns.com/pgbouncer-fips`. The Zalando +postgres-operator launches the pooler container with **only an image + env vars +and no `command`/`args`** (confirmed in `pkg/cluster/connection_pooler.go`, +v1.15.1). It depends on the image's ENTRYPOINT to render +`/etc/pgbouncer/pgbouncer.ini` (+ `userlist.txt`) from those env vars via +`envsubst` and then `exec pgbouncer `. + +The canonical Zalando image (`registry.opensource.zalan.do/acid/pgbouncer`) and +the Iron Bank rebuild (`registry1.dso.mil/.../zalando/pgbouncer`) carry that +entrypoint script + template. Chainguard's distroless image is the bare +`/usr/bin/pgbouncer` binary — no entrypoint script, no template, no shell — so +the operator's argument-less launch yields `pgbouncer` with no `CONFIG_FILE`, +which prints usage and exits. + +This is an **image-compatibility** problem, not a chart/values bug. + +## Why not the simpler options + +- **One-shot Job/Zarf patch (rejected).** The operator's + `syncConnectionPoolerWorker` regenerates the entire pod spec and `Update()`s + the Deployment whenever a *tracked* field drifts (image, resources, replicas, + `PGUSER`/`PGSCHEMA`, owner refs). It does not track + `command`/`initContainers`/`volumes`, so a patch survives steady-state 5-min + resyncs but is **silently wiped** on the next operator-driven update (image + bump, CR edit, operator restart perceiving drift). Latent breakage; also races + the operator on first create. Wrong for a shipped feature. +- **Swap to an operator-compatible FIPS image (rejected).** Would be cleanest if + such an image existed, but it requires the Zalando entrypoint glue that the + distroless FIPS image deliberately omits. The requirement is to use the + distroless Chainguard FIPS image. + +## Chosen approach + +A standalone **Pepr module**, deployed only for the `unicorn` flavor, that: + +1. **Mutates** the operator-created pooler Deployment on every create/update to + mount a config ConfigMap + a derived auth Secret and set the pgbouncer + `command`. Because admission mutation re-applies on every operator write, + there is no drift window. +2. **Reconciles** the operator's pooler credential Secret into a derived + `userlist.txt` Secret (the distroless image cannot transform the raw password + into pgbouncer's `auth_file` format at runtime). + +No new images beyond the Pepr controller, which **reuses the FIPS Pepr image +uds-core already runs** (prerequisite — see Risks). + +## Key environment facts (verified) + +- Cluster uses **`scram-sha-256`** (`chart/templates/postgres-minimal.yaml`: + `password_encryption: scram-sha-256`, pg_hba). The rendered config MUST use + `auth_type = scram-sha-256` (not the upstream template's `md5`). +- pg_hba contains `hostnossl all all all reject` → **pgbouncer→postgres must use + SSL** (`server_tls_sslmode = require`; `require` encrypts without needing a CA). +- Pooler container is `containers[0]`, name **`connection-pooler`** + (`k8sres.go`), runs as uid 100 / gid 101. +- Pooler Deployments: `pg-cluster-pooler` (primary), `pg-cluster-pooler-repl` + (replica); pods labeled `application: db-connection-pooler`. +- Pooler user/schema default **`pooler`/`pooler`**; credential Secret + `pooler.pg-cluster.credentials.postgresql.acid.zalan.do` (keys `username`, + `password`). +- Operator sets on `containers[0]`: `PGHOST`, `PGPORT`, `PGUSER`, `PGSCHEMA`, + `PGPASSWORD`, `CONNECTION_POOLER_{PORT,MODE,DEFAULT_SIZE,MIN_SIZE,RESERVE_SIZE,MAX_CLIENT_CONN,MAX_DB_CONN}`. +- Operator installs the `pooler.user_lookup` SECURITY DEFINER function in each + database regardless of pooler image, so `auth_query` works. + +## Decisions + +| Topic | Decision | +|---|---| +| Module scope | Deployed for `unicorn` flavor only; mutates **all** pooler Deployments unconditionally (no runtime image gate). | +| Client TLS (app→pgbouncer) | Disabled in pgbouncer; rely on Istio mesh mTLS for encryption-in-transit. | +| Server TLS (pgbouncer→postgres) | `server_tls_sslmode = require` (mandatory; non-SSL rejected by pg_hba). | +| `userlist.txt` | Pepr-derived Secret; no init container, no extra image. | +| `failurePolicy` | `Ignore` (a webhook outage must not block the operator). | +| Static `pgbouncer.ini` | Shipped by the Helm chart (gated by a unicorn-only values flag). | + +## Architecture & components + +New Pepr module in `src/pepr/`, built with `pepr build`, deployed as a +flavor-gated Zarf component (`only.flavor: unicorn`). One capability, +`pgbouncer-fips-pooler`, with two parts: + +- **Reconciler** — `When(a.Secret).IsCreatedOrUpdated().InNamespace("postgres")` + filtered to `pooler.pg-cluster.credentials.postgresql.acid.zalan.do`. Writes a + derived Secret `pgbouncer-fips-userlist` with key `userlist.txt` = + `"pooler" ""`, owner-referenced to the source Secret for GC. +- **Mutator** — + `When(a.Deployment).IsCreatedOrUpdated().InNamespace("postgres")` filtered to + `application: db-connection-pooler` (covers `-pooler` and `-pooler-repl`). + Idempotently mounts the `pgbouncer-config` ConfigMap and the + `pgbouncer-fips-userlist` Secret into `containers[0]`, and sets + `command: ["/usr/bin/pgbouncer", "/etc/pgbouncer/pgbouncer.ini"]`. + +The static `pgbouncer.ini` ConfigMap (`pgbouncer-config`) is rendered by +the Helm chart from chart values: `pool_mode`, pool sizes, `auth_type = +scram-sha-256`, `auth_query = SELECT * FROM pooler.user_lookup($1)`, +`auth_user = pooler`, `auth_file = /etc/pgbouncer/userlist.txt`, +`server_tls_sslmode = require`, client TLS disabled, plus +`ignore_startup_parameters = extra_float_digits,options`. + +## Data flow & ordering + +1. Operator creates the pooler Secret → Reconciler writes + `pgbouncer-fips-userlist`. +2. Operator creates/updates the pooler Deployment → Mutator injects + volumes/mounts + command. Mutation references ConfigMap/Secret **by name** + only (does not read contents), so it succeeds regardless of ordering. +3. If the pod starts before the derived Secret exists, the kubelet holds it in + `ContainerCreating` until the Secret volume resolves — no crash-loop. +4. Every later operator reconcile re-triggers the Mutator → injected fields are + restored; drift is impossible. +5. Password rotation: operator updates source Secret → Reconciler rewrites + derived Secret. Baseline is pod restart to pick up; live `RELOAD` is a + possible follow-up. + +Idempotency: the Mutator checks for its own volume/mount/command before adding, +so repeated mutations are no-ops and there is no operator↔webhook hot-loop. + +## Error handling & edge cases + +- Derived Secret missing/slow → kubelet volume-wait; self-heals on next Secret + event (Reconciler is idempotent, single writer). +- Reconciler can't read source Secret (RBAC/timing) → logged + retried; nothing + acts on stale data (Mutator references by name). +- Replica pooler → same labels, covered automatically; one derived + Secret/ConfigMap serves both. +- Missing `user_lookup` → pgbouncer auth fails clearly in its log (surfaced). +- Wrong flavor/image → module not shipped outside unicorn, so it can't touch + Zalando-image poolers. +- Webhook down → `failurePolicy: Ignore`; a pooler created during the outage + runs unconfigured until the next operator write re-triggers the recovered + mutation. + +## Testing + +- **Pepr unit tests** — Mutator produces expected volumes/mounts/command and is + a no-op when already mutated; Reconciler renders correct `userlist.txt` from a + fake source Secret. No cluster required. +- **e2e (unicorn)** — extend existing `tests/postgres/` pooler tests: deploy + unicorn flavor with `enableConnectionPooler: true`, assert pooler pods reach + `Running` (not usage-exit), then run the existing through-pooler psql + connectivity check. Regression guard for the original bug. +- **Ordering** — cold-deploy e2e implicitly covers pod-before-Secret via the + kubelet volume-wait path. +- **Flavor gating** — assert the Pepr component is absent from `registry1` / + `upstream` builds. +- CI: module builds in the existing pipeline; `pepr build` output (image + + manifests) wired into `zarf.yaml`; matches current lint/test/scan workflows. + +## Packaging & repo layout + +- `src/pepr/` (new): `package.json`, `pepr.ts`, + `capabilities/pgbouncer-fips-pooler.ts`. +- Pepr controller image: reuse uds-core's FIPS image (prerequisite to confirm). +- `zarf.yaml`: Pepr component gated `only.flavor: unicorn`, plus its image entry. +- `chart/`: add `pgbouncer.ini` ConfigMap template gated by a unicorn-only + values flag (e.g. `postgresql.poolerFipsConfig: true` in + `values/unicorn-values.yaml`); never rendered for other flavors. +- `docs/configuration.md`: document FIPS-flavor pooler behavior (mesh mTLS, + scram-sha-256). +- `renovate.json` / scan / lint: wire the new image + TS module into automation. +- Names: derived Secret `pgbouncer-fips-userlist`, ConfigMap + `pgbouncer-config`, capability `pgbouncer-fips-pooler`, namespace + `postgres`. + +## Risks / prerequisites + +1. **FIPS Pepr controller image** must be available (reuse uds-core's). If not, + the lift and image-sourcing change — confirm before implementation. +2. Adds a TypeScript/Node toolchain to a currently pure YAML/Helm/Zarf repo — a + real maintenance consideration; mirrors uds-core's structure and is the + standard UDS way to ship admission logic. +3. Password duplicated into a second in-namespace Secret (`pgbouncer-fips-userlist`), + RBAC-protected like the source. + +## Reference + +Upstream `pooler/pgbouncer.ini.tmpl` and `pooler/entrypoint.sh` +(zalando/postgres-operator) are the source of truth for the rendered config; +this design reproduces them with `auth_type = scram-sha-256` and client TLS +disabled (mesh mTLS), and replaces the `envsubst`/`exec` entrypoint with a +chart-rendered ConfigMap + Pepr mutation. diff --git a/manifests/pepr-module-pgbouncer.yaml b/manifests/pepr-module-pgbouncer.yaml new file mode 100644 index 0000000..fa87938 --- /dev/null +++ b/manifests/pepr-module-pgbouncer.yaml @@ -0,0 +1,360 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pepr-pgbouncer +rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pepr-pgbouncer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pepr-pgbouncer +subjects: + - kind: ServiceAccount + name: pepr-pgbouncer + namespace: pepr-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pepr-pgbouncer + namespace: pepr-system +--- +apiVersion: v1 +data: + value: >- + YjBhYzhiNGZkZGM2ODg5ZjU2MWEyZjkwM2IzNWQwNTZhODNhNjdlOWY3OTRmNjMwMzdiMjRhNzU1MTNmNWMyMA== +kind: Secret +metadata: + name: pepr-pgbouncer-api-path + namespace: pepr-system +type: Opaque +--- +apiVersion: v1 +data: + tls.crt: >- + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDcURDQ0FaQ2dBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBQU1CNFhEVEkyTURZd05EQXdOREUxDQpNbG9YRFRJM01EWXdOREF3TkRFMU1sb3dBRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DDQpnZ0VCQUtzRmhucjRma1FMWWp5Wk9TZzVRWlNKRGgweTUrcytobVY5YUxBd3V3SXdEOG05MmxTZC9DZktWendLDQo4a3ArV2U4Y1Bsd2Fmd0VGZnMxdTRhdHBYSnE3Z3YrSnNTZ3VsTkNLaERxVEtrZFdwdGdiblNESHpFQktDR1BLDQpIVXZqd1QzMDFSZC8wY2ZBZksxQmlnSlNQWTA3bXM0T0d5VERVNWlwaDhuMzExSGM5NG5wWnpzdXQ3VWsyUnQ2DQpBeW9OQzVDMXkwTitBSE9QWmMxNHVYQWs2Q1hYUkt1cFlHSUlWSnFnRHUxenljSWdDbG1YWnQzcldsZWlBelRtDQorQ25wOHdqVzdJVjhyZnIrTU1EMjY3QWlSTkZKelBRbURvNFNwN3FHb1NWQ1NwUmZPOURzK09zL1QxVG9WcUxvDQp3WmlBaFRLZ0s4Mmc2OVcwZVU1YWcyZUhNbk1DQXdFQUFhTXRNQ3N3S1FZRFZSMFJCQ0l3SUlJZWNHVndjaTF3DQpaMkp2ZFc1alpYSXVjR1Z3Y2kxemVYTjBaVzB1YzNaak1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQS9GcmNrDQpYY29TWHJhaW4vZGNJZiswdmtzeXMybFdNOVdsd3pBY1IyYWw2eDdaeGlBbFRsK01jK1JwcFFYMzh2ODFwWUFUDQpxaGRSN251VVdabnQvaTI5K2JuM2FyWHgrY3ZsbnoyS1VmMTROOGwzakpxS1Y3UGFPa1ZnNEhJTDdBbkdjV2V5DQpTT3h3TlNvbEVFeHJzb1NuclZUTWdBdlNYRk8xVE9zZUI1MUY0WWpLVmsxWnlxRm9NdjczTnRHR2EvK1FiNk1TDQpGMXJwd0hQWFV0dXlHSFhmYlBLWDFpUzBNbER5MTFYWFRoWXZPa3BzOWptdHNNbzZsMmlyV0t4NHVDd0lGOEZxDQpPTVYvdnlRZDNhVVpTOUJYb0xCWjBsZ2VQTEx6RVRmalJ0cmp2ejhTN1B5VzZtN0ZqNVhaM05nY20rdTJiTXgyDQpRY0RyZGpYT0Ztb2ZPTm1PDQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo= + tls.key: >- + LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ0KTUlJRXBBSUJBQUtDQVFFQXF3V0dldmgrUkF0aVBKazVLRGxCbElrT0hUTG42ejZHWlgxb3NEQzdBakFQeWIzYQ0KVkozOEo4cFhQQXJ5U241Wjd4dytYQnAvQVFWK3pXN2hxMmxjbXJ1Qy80bXhLQzZVMElxRU9wTXFSMWFtMkJ1ZA0KSU1mTVFFb0lZOG9kUytQQlBmVFZGMy9SeDhCOHJVR0tBbEk5alR1YXpnNGJKTU5UbUttSHlmZlhVZHozaWVsbg0KT3k2M3RTVFpHM29ES2cwTGtMWExRMzRBYzQ5bHpYaTVjQ1RvSmRkRXE2bGdZZ2hVbXFBTzdYUEp3aUFLV1pkbQ0KM2V0YVY2SUROT2I0S2VuekNOYnNoWHl0K3Y0d3dQYnJzQ0pFMFVuTTlDWU9qaEtudW9haEpVSktsRjg3ME96NA0KNno5UFZPaFdvdWpCbUlDRk1xQXJ6YURyMWJSNVRscURaNGN5Y3dJREFRQUJBb0lCQUFVN0Y0aG1WbEpWZU0wNg0Kc0lWYTd2Y1FsQlp2aXFsbTBheUQvL0kzbzFpblNLeFdlcm1RMVhnUUY4ZjEyOEJNaWdxbXRmK1NMZVZGbWtIRg0KVFBDMXVjZmZ5VnR3aGpNZzdadE5TVXNUV2oweFdNd09XQ2w3QXZQS2IrUkJkOURzNStteHRkelFvNFYxRFRzdA0KWUgrK3JUUkhLTzU1ZnZvS1lXR3ZlY0JETE5wTGw1Ukw0NVpxUUE1cHRvVWF4eE9uNEdrQTJBZWtUeGxOaDNKUw0KYXNoLy9QRk5XMVRSSW1HZHZER3hTWVhzcFhkSWEyTm9UV2Q5WTV4Q1BDR2xQNWNONnBkUjU4YzZ2blBodjhHUQ0KY2ZpaGdZclhKZXNGUExKTlJRNDY1S1BDYkFZQXlCOFAxd0pMMXdhOGRrY0RaOUpxcFJMUXMrdnYxVldRZWRVSg0KeUxWWThVa0NnWUVBMjFBZjlJem0va1pJYlJPRDFOQlhNYUQvZ3o3QmI3UWhiVDBRSSs4UHZHVFZHTytSd3kxZw0Kb2lEQ2ExWFdob3l2SG1rdlJJL0dMK0E3cmlSamJjYmVtdWY2RjgrRzdsbHBQdTZ2OCt4R0o1SElMWDJxbVdxdg0KSjJOTlFwMDY1eW9zdWtqb1hZN0UxUDhLblJndUhnKzRlWDRhUlpwUHMybmY3cWhva1JCVnk2a0NnWUVBeDZGZA0KckY0NW5hSjhoTFB6Mit1Z3hUTEs1eFlnUnp3ZjZCdXlVeHF2dGVibW9iZ1MzUWV2Y3JGYis2L2JxZ2JHMmJMQw0KMVlNOGRlejZudVhQTGlQRENsSTVXSjduclVuUlJXN2tIUngrekV4QTF1NjBNcmtDSTM1ZjVDbkU0TFhrVkhmKw0KdVJuVTY4eGlpMUFtUWZ3TDNNYWZlYkRUaER0UzNOUmFrMTZVdnJzQ2dZRUEwUVhXenYrVUVQanZnblk5Q1pIZg0KNkw4bmgvRkI3N0xnd1BxWDdZZWxtY3NJaHhHZC9VVzhlZ2w3QTAzMmZwcUxOUkxQS0N0WG1yMitZOFR1dHV2NQ0Kc2U0eW9JcjhjU0xxZWo2SG1KV3liM2cwTDVjOEI2aDBjN2ZqSlFBeDZheDZvTGxvTGZNcWlrN2gwTVFCQUVtLw0KYXB2VGNrOFdjMHNQVUtsVnNCeS9pTEVDZ1lCMlFTcWlQcmJXb0RndXpBSzYxZHZJdFF2bzAveU85aGpZZi8raw0KcHZ4TFB0cUVGZXhtcm5USjlqSk01Nkd5R0kyV3pBUUtRdEYvOGIrTWZRbTdoVWUyUjNyYytsUzNIREV4ZGp6Kw0KMmJCckNRaW55WU5KUUxyNWw1VHFMYXdJaVBjVzZuWWo1Qjl6QndHaEVQdDR2dnV2N3FEdGowZmMzdDk1SFBvQw0KcmxaaW5RS0JnUUM5WEtOdk1qVkZTUVREVGdtOHJkWVZyMC93U0MwNnhGTFNscmFCdENQcnlRMUdIVmkxd2RmNg0KMWpZRUFIMXlPTFZGMEIreDNsNlFwZWpvWVY4Wnlldzk3c0w4eituVjB3dTV3UUl6NWFIMDBTeW1wbkx5c28xWg0Kb0VuOC92eWx2VGNmZUwrMzdOZFBvcktXRDhENURWUW9RcHdPTjdtUDV6cEY0MW42OGh6cmJBPT0NCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tDQo= +kind: Secret +metadata: + name: pepr-pgbouncer-tls + namespace: pepr-system +type: kubernetes.io/tls +--- +apiVersion: v1 +data: + module-e0519630f08b84a64d74fb755b0034c2d22ba9cbbfe54c303fe5b2bd4c21bbef.js.gz: >- + H4sIAAAAAAAAE71XbW/bNhD+3l+hcEEiATTtNFsXyFC8ttmAYs0SpOsKLEhhSqJt1hLJkpRdT9F/35GyHDkI2mEYlgS2RB6Pd88995IV1cE8uUo/scySnM24YNdaKqbtZryCPZOEArMoOZ/DNxK0ZAjXK1pULGY4k2LG55WmacHig1ET+SN5otnnimsWIsWURu1qkdTudOzXBmqeykpkTCO8YtpwKWI0IiNygrDdKJAqZV4VcFfOTKa5sl7i9fY+ZgK7YEHOjdWyYMYEO30B2CTAF5APlIRNHcyk9uJ/0oKKXMKysXPQMXBuUivBhiXbrKXOTXzbmozR8szAp5IFzzYDJuaAi3t3tnemIcOySnO7QXe4lTBxLWQO1p8nz503I9RgdySuq4rn4PqD11L8rLXUMeJzITVoW7N0IeXyd14yWdn4ZISzylhZvqUpK5xiAM8omrG49mZAsFYoRqhpMC3WdGPeeEU9QfDmDjbzkhsPcP01uQavqc0W3xLiIiuqnOW/8MIvgeOruIaNNkpgJ1qe5gPDbKXAOngO4ICxEIacFcyywEMItgdHR0F/O9OM9rcHg+WpGVA9D44HsJBW858M00CWeHQMm2vKrVdRpRDtIgAeFIBbYCy1lYHLVCE3JRM2GAgvNDAbuKcEfjFjY7Ti7jvQlUA4rXiRt8QM/DOEDRQwkTORcRdVH0R0Qp47glYi5xmP0ccfPWGd7OpiT9xRuAUkRj+QM3IKLOftvR9PQckLOCTBFc1zJ45SDQgP2BdFhYsUclfBL+hufO7IJzOqSgRbB5K8poqmvAAihl2KdTwbtCnwX6QRQbhPBtRlEbprIlx/WDARl01SYZU8bOHMvfjTaj7YRppApAEpy2lhSCf6uSA04zn5y+UoySXCPOm5UUHoCzATjWew4K2a+bpUA6cCm5hQJ+eaaIg6mBcO0XCOjxE6jjACxwEvDYTUYooOaxuKqEGBf2Lw9GzamHCGkXbx0++7i6JxGUpCyTsG5tqIvDGvPUHzK/1e5e4hhEXxWwdJqCLygduFWwiziNwwQDCDLAmp2YgsEMm5t5Ul4B61dDKpmzGfhQeMOOcctPf38KKoMa4URbUkb+WcrKkW4fSwzprA57GYB538sJMdB2bJlYK9aedp0+LyqprNAPGZlmX4cBFGKTXsxfcoIla+sxoOhqiyszMUYf3oTHfHV86MqUvGcIQl+fXMRADbkot8h9xLpQpgZsksdY63NSXmD2yKFZZrwfQNg3shhRy9aqr4H11jWEHSOZUxanW2TIwF6XQS75Ursb01eHUNylEbCBgfnOC0kNnyyl114WqR031w0kCNNN6fC28d6rhG7BeL4llosY4a4HgbDy5mMpzqLrp5cFjzJnBgBS5I02jbBGnSr/abPpnbrtmj8goo2ZFjQoxi2YRAqQIuW9a+t0wBgrzUmm4IN/4bwuMcpNB5tInu7/uvpICWZBdJkoyilhJjRlayqAD0ZPc0mbgS3r0RI4G8PpMcoHCWeq3dtqrMYltiKFZaupmB5XFtZKXbqLWuXVK1jfIGQ9kr3Q502F5dAhg5woraxePFxnWZ2vg476iyp2QvPlsde2tOBfxF4zYH+qjcju7GduvPJdxqTbL/6gHZX3oalUcye9CUbu3aGzZkNhv2iAA1JL8SxcZPS3BRJssShpLkFg0ro4cpF33pR8eH+1DdQeFaYURdfl37KnvtWviudF3seuA/L19+2gi9Tp5Rx06wIk8HD+2gaykRuayg17LQVTZgMLmha0f+HavX32Z1S8x/TezJwUl8EO6ROXoqWoDTGmZXxnLzSkoL2U7V/4bS1xpBV6sm3tYxOzpyoB0dhU9X1L6pT1dV1q+qUNcAZJhGtqDHPWkqhLTecjd/PPCqmyyH6Q6oGLoPlEZGhFyHUTNt3A+uYarO2qF/rzLuzimojUq7qQby0rWt7TTem8wOawYF05HGDTI5uYbLL/1wHRb4trqLxs+Gw++CtrxAUXEd7v3N22T/PwiSfTKkpOrZ35rdzkvLDAAA +kind: Secret +metadata: + name: pepr-pgbouncer-module + namespace: pepr-system +type: Opaque +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pepr-pgbouncer-store + namespace: pepr-system +rules: + - apiGroups: + - pepr.dev + resourceNames: + - '' + resources: + - peprstores + verbs: + - create + - get + - patch + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pepr-pgbouncer-store + namespace: pepr-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pepr-pgbouncer-store +subjects: + - kind: ServiceAccount + name: pepr-pgbouncer-store + namespace: pepr-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + pepr.dev/description: >- + Configures the distroless pgbouncer connection pooler for the Zalando postgres-operator + labels: + app: pepr-pgbouncer-watcher + pepr.dev/controller: watcher + pepr.dev/uuid: pgbouncer + name: pepr-pgbouncer-watcher + namespace: pepr-system +spec: + replicas: 1 + selector: + matchLabels: + app: pepr-pgbouncer-watcher + pepr.dev/controller: watcher + strategy: + type: Recreate + template: + metadata: + annotations: + buildTimestamp: '1780533712429' + labels: + app: pepr-pgbouncer-watcher + pepr.dev/controller: watcher + spec: + containers: + - args: + - /app/node_modules/pepr/dist/controller.js + - e0519630f08b84a64d74fb755b0034c2d22ba9cbbfe54c303fe5b2bd4c21bbef + env: + - name: PEPR_WATCH_MODE + value: 'true' + - name: PEPR_PRETTY_LOG + value: 'false' + - name: LOG_LEVEL + value: info + image: ghcr.io/defenseunicorns/pepr/private/controller:v1.2.1 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: 3000 + scheme: HTTPS + initialDelaySeconds: 10 + name: watcher + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /healthz + port: 3000 + scheme: HTTPS + initialDelaySeconds: 10 + resources: + limits: + memory: 512Mi + cpu: 500m + requests: + memory: 256Mi + cpu: 200m + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: + - mountPath: /etc/certs + name: tls-certs + readOnly: true + - mountPath: /app/load + name: module + readOnly: true + securityContext: + fsGroup: 1000 + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + serviceAccountName: pepr-pgbouncer + terminationGracePeriodSeconds: 5 + volumes: + - name: tls-certs + secret: + secretName: pepr-pgbouncer-tls + - name: module + secret: + secretName: pepr-pgbouncer-module +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + pepr.dev/description: >- + Configures the distroless pgbouncer connection pooler for the Zalando postgres-operator + labels: + app: pepr-pgbouncer + pepr.dev/controller: admission + pepr.dev/uuid: pgbouncer + name: pepr-pgbouncer + namespace: pepr-system +spec: + replicas: 2 + selector: + matchLabels: + app: pepr-pgbouncer + pepr.dev/controller: admission + template: + metadata: + annotations: + buildTimestamp: '1780533712429' + labels: + app: pepr-pgbouncer + pepr.dev/controller: admission + spec: + containers: + - args: + - /app/node_modules/pepr/dist/controller.js + - e0519630f08b84a64d74fb755b0034c2d22ba9cbbfe54c303fe5b2bd4c21bbef + env: + - name: PEPR_WATCH_MODE + value: 'false' + - name: PEPR_PRETTY_LOG + value: 'false' + - name: LOG_LEVEL + value: info + image: ghcr.io/defenseunicorns/pepr/private/controller:v1.2.1 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: 3000 + scheme: HTTPS + initialDelaySeconds: 10 + name: server + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /healthz + port: 3000 + scheme: HTTPS + initialDelaySeconds: 10 + resources: + limits: + memory: 512Mi + cpu: 500m + requests: + memory: 256Mi + cpu: 200m + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: + - mountPath: /etc/certs + name: tls-certs + readOnly: true + - mountPath: /app/api-path + name: api-path + readOnly: true + - mountPath: /app/load + name: module + readOnly: true + priorityClassName: system-node-critical + securityContext: + fsGroup: 1000 + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + serviceAccountName: pepr-pgbouncer + terminationGracePeriodSeconds: 5 + volumes: + - name: tls-certs + secret: + secretName: pepr-pgbouncer-tls + - name: api-path + secret: + secretName: pepr-pgbouncer-api-path + - name: module + secret: + secretName: pepr-pgbouncer-module +--- +apiVersion: v1 +kind: Service +metadata: + labels: + pepr.dev/controller: admission + name: pepr-pgbouncer + namespace: pepr-system +spec: + ports: + - port: 443 + targetPort: 3000 + selector: + app: pepr-pgbouncer + pepr.dev/controller: admission +--- +apiVersion: v1 +kind: Service +metadata: + labels: + pepr.dev/controller: watcher + name: pepr-pgbouncer-watcher + namespace: pepr-system +spec: + ports: + - port: 443 + targetPort: 3000 + selector: + app: pepr-pgbouncer-watcher + pepr.dev/controller: watcher +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: pepr-pgbouncer +webhooks: + - admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + caBundle: >- + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDdERDQ0FaeWdBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBY01Sb3dHQVlEVlFRREV4RlFaWEJ5DQpJRVZ3YUdWdFpYSmhiQ0JEUVRBZUZ3MHlOakEyTURRd01EUXhOVEphRncweU56QTJNRFF3TURReE5USmFNQUF3DQpnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDM1R4cC9IeTd3Wm5kaisxOGFQc3VGDQpoMlFkOE9EaFRycjNJd25zOU41SFczYVdRdTVGK2cwVTM3cjdEVi9ZR2VuNW9ZMzY2TG1XV1ZMNy9sOWdTaFJZDQpZMkIwdHgvZzBma2JhemVXZGZBT3Z2T2pHdUJIL3Npc0VTQ3RhV3NXalFadFhXREhaamZIbmgzY1FqbUxmRmhzDQpiNlRKdWdvbEZkREcrc3FvOTZYQTZnVW42aUNXMWZyTTBhREdxT1MvWnV1aDQ2Q0g3bnNHby9lMGRKazZFeFB0DQpMSEpDZkx3UUp6MklrcGIzNyt4dW9oMnJPODZEeDVsdGhhYTA0TXFmRGlEd2tYNTE3dHRRd2F2QTFKdGJ3aVMwDQpiOUNSMzAyOEVIRUFYNE1LYitWd0hsMHZiWERCckNONkdySnRYNmVydWZlT2I0UVUxWkNvdzJ0c0hnL2x5YU0vDQpBZ01CQUFHakhUQWJNQXdHQTFVZEV3UUZNQU1CQWY4d0N3WURWUjBQQkFRREFnTDBNQTBHQ1NxR1NJYjNEUUVCDQpDd1VBQTRJQkFRQjlEOUlFVGpaWm9kWUd4Vmg0QXZ5MFJ0cG9BdWF0ZEhiZVFZVmV0MUV3ZGh5ajVTbkVjd1pzDQpncFFtZWJOZmF5Z2ZtUm44S3hxSmttWWJqdnlPSER6N0YrbnlHcCtETUJkMEEwdXZnOGRhaElUbFEyZE1tSVRHDQp6NkZMV1BBeGFvU1liN3htUUtmU1ZBalVKZU5jK1RqTnR5dzU1eFNRcEdkVjdBK3J5aEUxZXJPNGRRSlh1UWZyDQpGcDhNbGJ4aVZGSWlTQ3ZCVHRPUDRWNWJQRklkdGtBNVNoSXZrME9nY0JyVFlJVVlCUjNDalgzRlpLWGUwUDBqDQoyZHV6TGh6T1hoQ2ZlOXlCSW1DeTQwUGd6eTNITWVXTHlKSURFZktyT0VyNE1zcWxCdEZWT0NIbHpRSlN0UU51DQpKQ0lMNjY3S05wUE5qNEQ0NHEzdHJQNStOcGZtUWkrSg0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ0K + service: + name: pepr-pgbouncer + namespace: pepr-system + path: >- + /mutate/b0ac8b4fddc6889f561a2f903b35d056a83a67e9f794f63037b24a75513f5c20 + failurePolicy: Ignore + matchPolicy: Equivalent + name: pepr-pgbouncer.pepr.dev + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - kube-system + - pepr-system + rules: + - apiGroups: + - apps + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - deployments + sideEffects: None + timeoutSeconds: 10 diff --git a/oscal-component.yaml b/oscal-component.yaml deleted file mode 100644 index c731c1b..0000000 --- a/oscal-component.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -component-definition: - uuid: d2e86504-87ba-4249-9a45-548749930038 - metadata: - title: UDS Package Postgres Operator - last-modified: "2024-10-15T19:57:17Z" - version: "20241015" - oscal-version: 1.1.2 - parties: - - uuid: f3cf70f8-ba44-4e55-9ea3-389ef24847d3 - type: organization - name: Defense Unicorns - links: - - href: https://defenseunicorns.com - rel: website - components: - - uuid: 78cd17e2-9f06-48a4-a543-0f9734e6f1fb - type: software - title: Postgres Operator - description: | - The Postgres operator manages PostgreSQL database clusters on Kubernetes (K8s) using the Zalando Postgres Operator - purpose: Provides other applications a PostgreSQL database for storing relational data. - responsible-roles: - - role-id: provider - party-uuids: - - f3cf70f8-ba44-4e55-9ea3-389ef24847d3 - control-implementations: - - uuid: d2afb4c4-2cd8-5305-a6cc-d1bc7b388d0c - source: https://raw.githubusercontent.com/GSA/fedramp-automation/93ca0e20ff5e54fc04140613476fba80f08e3c7d/dist/content/rev5/baselines/json/FedRAMP_rev5_HIGH-baseline-resolved-profile_catalog.json - description: Controls implemented by Postgres Operator for inheritance by applications that adheres to FedRAMP High Baseline and DoD IL 6. - implemented-requirements: - - uuid: b75234f3-93ca-40eb-90d3-11654ef35db6 - control-id: cm-3.6 - description: >- - Postgres Operator utilizes the underlying Istio for FIPS encryption in transit and leverages a properly configured Kubernetes storage class for encryption at rest. - - uuid: 1e651b14-30aa-4697-941e-4dc7553b4ab4 - control-id: sc-13 - description: >- - Postgres Operator utilizes the underlying Istio for FIPS encryption in transit and leverages a properly configured Kubernetes storage class for encryption at rest. - back-matter: - resources: - - uuid: cd4382c0-6df1-4ace-8681-29c497060c69 - title: UDS Package Postgres Operator - rlinks: - - href: https://github.com/defenseunicorns/uds-package-postgres-operator diff --git a/release-please-config.json b/release-please-config.json deleted file mode 100644 index 034a4be..0000000 --- a/release-please-config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "packages": { - ".": { - "changelog-path": "CHANGELOG.md", - "changelog-sections": [ - { "type": "feat", "section": "Features", "hidden": false }, - { "type": "fix", "section": "Bug Fixes", "hidden": false }, - { "type": "chore", "section": "Miscellaneous", "hidden": false } - ], - "release-type": "simple", - "bump-minor-pre-major": true, - "bump-patch-for-minor-pre-major": true, - "draft": false, - "versioning": "prerelease", - "prerelease-type": "uds", - "extra-files": [ - "bundle/uds-bundle.yaml", - "tasks.yaml", - "zarf.yaml" - ] - } - }, - "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" - } \ No newline at end of file diff --git a/releaser.yaml b/releaser.yaml new file mode 100644 index 0000000..3a1d35f --- /dev/null +++ b/releaser.yaml @@ -0,0 +1,13 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +flavors: + - name: upstream + # renovate-uds: datasource=docker depName=ghcr.io/zalando/postgres-operator extractVersion=^v?(?\d+\.\d+\.\d+)$ + version: 1.15.1-uds.4 + - name: registry1 + # renovate-uds: datasource=docker depName=registry1.dso.mil/ironbank/opensource/zalando/postgres-operator extractVersion=^v?(?\d+\.\d+\.\d+)$ + version: 1.15.0-uds.18 + - name: unicorn + # renovate-uds: datasource=docker depName=quay.io/rfcurated/zalando/postgres-operator extractVersion=^v?(?\d+\.\d+\.\d+)$ + version: 1.15.1-uds.0 diff --git a/renovate.json b/renovate.json index 41594f5..e30b2b9 100644 --- a/renovate.json +++ b/renovate.json @@ -1,31 +1,64 @@ { - "enabled": true, - "forkProcessing": "enabled", - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "github>defenseunicorns/uds-common//config/renovate.json5", - ":semanticCommits", - ":semanticCommitTypeAll(chore)" - ], - "packageRules": [ - { - "groupName": "Postgres Support Dependencies", - "labels": ["support-deps"], - "commitMessageTopic": "support-deps", - "packagePatterns": ["*"] - }, - { - "groupName": "Postgres Package Dependencies", - "labels": ["package-deps"], - "commitMessageTopic": "package-deps", - "matchDatasources": ["docker", "helm", "git-tags"] - }, - { - "groupName": "Postgres Package Dependencies", - "labels": ["package-deps"], - "commitMessageTopic": "package-deps", - "matchPackageNames": ["zalando/postgres-operator", "registry.opensource.zalan.do/acid/logical-backup", "registry.opensource.zalan.do/acid/postgres-operator"], - "allowedVersions": "/v.+/" - } - ] - } + "enabled": true, + "forkProcessing": "enabled", + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "github>defenseunicorns/uds-common//config/renovate.json5", + ":semanticCommits", + ":semanticCommitTypeAll(chore)" + ], + "packageRules": [ + { + "matchDatasources": ["docker"], + "matchPackagePatterns": ["^quay\\.io/rfcurated/"], + "versioning": "regex:^(?\\d+)\\.(?\\d+)(\\.(?\\d+))?-.*fips.*rfcurated$" + }, + { + "matchPackageNames": ["quay.io/rfcurated/prometheuscommunity/postgres-exporter"], + "versioning": "regex:^(?\\d+)\\.(?\\d+)(\\.(?\\d+))?-jammy-scratch-bnt-fips-rfcurated$" + }, + { + "matchPackageNames": ["quay.io/rfcurated/zalando/spilo-17"], + "versioning": "regex:^(?\\d+)\\.(?\\d+)-p(?\\d+)-jammy-fips-rfcurated$" + }, + { + "matchPackageNames": ["ghcr.io/zalando/spilo-17"], + "versioning": "regex:^(?\\d+)\\.(?\\d+)-p(?\\d+)$" + }, + { + "groupName": "Postgres Support Dependencies", + "labels": [ + "support-deps" + ], + "commitMessageTopic": "support-deps", + "matchPackageNames": [ + "*" + ] + }, + { + "groupName": "Postgres Package Dependencies", + "labels": [ + "package-deps" + ], + "commitMessageTopic": "package-deps", + "matchDatasources": [ + "docker", + "helm", + "git-tags" + ] + }, + { + "groupName": "Postgres Package Dependencies", + "labels": [ + "package-deps" + ], + "commitMessageTopic": "package-deps", + "matchPackageNames": [ + "zalando/postgres-operator", + "registry.opensource.zalan.do/acid/logical-backup", + "registry.opensource.zalan.do/acid/postgres-operator" + ], + "allowedVersions": "/v.+/" + } + ] +} diff --git a/src/namespace/gitlab-ns.yaml b/src/namespace/gitlab-ns.yaml deleted file mode 100644 index e6102c8..0000000 --- a/src/namespace/gitlab-ns.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -kind: Namespace -apiVersion: v1 -metadata: - name: gitlab - # This label is only needed for testing! - # In a real deployment this namespace would be controlled by a UDS Package / the UDS Operator - labels: - istio-injection: enabled diff --git a/src/namespace/mattermost-ns.yaml b/src/namespace/mattermost-ns.yaml deleted file mode 100644 index bed9f8c..0000000 --- a/src/namespace/mattermost-ns.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -kind: Namespace -apiVersion: v1 -metadata: - name: mattermost - # This label is only needed for testing! - # In a real deployment this namespace would be controlled by a UDS Package / the UDS Operator - labels: - istio-injection: enabled diff --git a/src/namespace/sonarqube-ns.yaml b/src/namespace/sonarqube-ns.yaml deleted file mode 100644 index d815b8b..0000000 --- a/src/namespace/sonarqube-ns.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -kind: Namespace -apiVersion: v1 -metadata: - name: sonarqube - # This label is only needed for testing! - # In a real deployment this namespace would be controlled by a UDS Package / the UDS Operator - labels: - istio-injection: enabled diff --git a/src/namespace/zarf.yaml b/src/namespace/zarf.yaml deleted file mode 100644 index 056de56..0000000 --- a/src/namespace/zarf.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -kind: ZarfPackageConfig -metadata: - name: dev-namespaces - description: "create namespaces for cross-ns secret functionality" - version: 0.1.0 - -components: - - name: deploy-namespace-for-cross-ns-secrets-test - required: true - manifests: - - name: dev-namespaces - files: - - gitlab-ns.yaml - - mattermost-ns.yaml - - sonarqube-ns.yaml diff --git a/src/pepr/.gitignore b/src/pepr/.gitignore new file mode 100644 index 0000000..b7b72a6 --- /dev/null +++ b/src/pepr/.gitignore @@ -0,0 +1,4 @@ +# Ignore node_modules and Pepr build artifacts +node_modules +dist +insecure* diff --git a/src/pepr/.prettierrc b/src/pepr/.prettierrc new file mode 100644 index 0000000..1294bab --- /dev/null +++ b/src/pepr/.prettierrc @@ -0,0 +1,14 @@ +{ + "arrowParens": "avoid", + "bracketSameLine": false, + "bracketSpacing": true, + "embeddedLanguageFormatting": "auto", + "insertPragma": false, + "printWidth": 100, + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "tabWidth": 2, + "useTabs": false, + "vueIndentScriptAndStyle": false +} \ No newline at end of file diff --git a/src/pepr/README.md b/src/pepr/README.md new file mode 100644 index 0000000..df1ae8b --- /dev/null +++ b/src/pepr/README.md @@ -0,0 +1,21 @@ +# Pepr Module + +This is a Pepr Module. [Pepr](https://github.com/defenseunicorns/pepr) is a type-safe Kubernetes middleware system. + +The `capabilities` directory contains all the capabilities for this module. By default, +a capability is a single typescript file in the format of `capability-name.ts` that is +imported in the root `pepr.ts` file as `import { HelloPepr } from "./capabilities/hello-pepr";`. +Because this is typescript, you can organize this however you choose, e.g. creating a sub-folder +per-capability or common logic in shared files or folders. + +Example Structure: + +```text +Module Root +├── package.json +├── pepr.ts +└── capabilities + ├── example-one.ts + ├── example-three.ts + └── example-two.ts +``` diff --git a/src/pepr/capabilities/pgbouncer-pooler.test.ts b/src/pepr/capabilities/pgbouncer-pooler.test.ts new file mode 100644 index 0000000..957dbdc --- /dev/null +++ b/src/pepr/capabilities/pgbouncer-pooler.test.ts @@ -0,0 +1,82 @@ +import { describe, it, expect } from "vitest"; +import { a } from "pepr"; +import { renderUserlist, applyPoolerPatch, needsBootstrap } from "./pgbouncer-pooler"; + +describe("renderUserlist", () => { + it("formats a pgbouncer auth_file line from username/password", () => { + expect(renderUserlist("pooler", "s3cr3t")).toBe('"pooler" "s3cr3t"\n'); + }); + + it("escapes embedded double quotes in the password", () => { + expect(renderUserlist("pooler", 'pa"ss')).toBe('"pooler" "pa""ss"\n'); + }); +}); + +function poolerDeployment(): a.Deployment { + return { + spec: { + template: { + spec: { + volumes: [], + containers: [{ name: "connection-pooler", image: "cgr.dev/x/pgbouncer:v1", volumeMounts: [] }], + }, + }, + }, + } as unknown as a.Deployment; +} + +describe("applyPoolerPatch", () => { + it("sets the pgbouncer command on containers[0]", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + expect(d.spec!.template.spec!.containers[0].command).toEqual([ + "/usr/bin/pgbouncer", + "/etc/pgbouncer/pgbouncer.ini", + ]); + }); + + it("adds a projected /etc/pgbouncer volume + mount", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + const vol = d.spec!.template.spec!.volumes!.find(v => v.name === "pgbouncer"); + expect(vol!.projected!.sources).toHaveLength(2); + const mount = d.spec!.template.spec!.containers[0].volumeMounts!.find( + m => m.name === "pgbouncer", + ); + expect(mount!.mountPath).toBe("/etc/pgbouncer"); + expect(mount!.readOnly).toBe(true); + }); + + it("is idempotent (no duplicate volume/mount on second apply)", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + applyPoolerPatch(d); + expect(d.spec!.template.spec!.volumes!.filter(v => v.name === "pgbouncer")).toHaveLength(1); + expect( + d.spec!.template.spec!.containers[0].volumeMounts!.filter(m => m.name === "pgbouncer"), + ).toHaveLength(1); + }); +}); + +describe("needsBootstrap", () => { + it("returns false for a Deployment already carrying the pgbouncer volume", () => { + const d = poolerDeployment(); + applyPoolerPatch(d); + expect(needsBootstrap(d)).toBe(false); + }); + + it("returns true for a fresh, unmutated pooler Deployment", () => { + const d = poolerDeployment(); + expect(needsBootstrap(d)).toBe(true); + }); + + it("returns false for a Deployment with no containers / empty spec", () => { + const empty = {} as unknown as a.Deployment; + expect(needsBootstrap(empty)).toBe(false); + + const noContainers = { + spec: { template: { spec: { volumes: [], containers: [] } } }, + } as unknown as a.Deployment; + expect(needsBootstrap(noContainers)).toBe(false); + }); +}); diff --git a/src/pepr/capabilities/pgbouncer-pooler.ts b/src/pepr/capabilities/pgbouncer-pooler.ts new file mode 100644 index 0000000..4445d2c --- /dev/null +++ b/src/pepr/capabilities/pgbouncer-pooler.ts @@ -0,0 +1,151 @@ +import { Capability, a, K8s, kind, Log } from "pepr"; + +export const Pgbouncer = new Capability({ + name: "pgbouncer-pooler", + description: "Configures the distroless pgbouncer connection pooler.", + namespaces: ["postgres"], +}); + +const { When } = Pgbouncer; + +// Exported for reuse by the Mutator task. +export const NS = "postgres"; +export const SOURCE_SECRET = "pooler.pg-cluster.credentials.postgresql.acid.zalan.do"; +export const DERIVED_SECRET = "pgbouncer-userlist"; + +// pgbouncer auth_file format: `"user" "password"` with "" escaping inside quotes. +export function renderUserlist(username: string, password: string): string { + const esc = (s: string) => s.replace(/"/g, '""'); + return `"${esc(username)}" "${esc(password)}"\n`; +} + +// Reconcile the operator's pooler credential Secret into a derived userlist Secret. +When(a.Secret) + .IsCreatedOrUpdated() + .InNamespace(NS) + .WithName(SOURCE_SECRET) + .Reconcile(async secret => { + const data = secret.data ?? {}; + if (!data.username || !data.password) { + Log.warn(`${SOURCE_SECRET} missing username/password; skipping`); + return; + } + const username = Buffer.from(data.username, "base64").toString("utf8"); + const password = Buffer.from(data.password, "base64").toString("utf8"); + + await K8s(kind.Secret).Apply({ + metadata: { + name: DERIVED_SECRET, + namespace: NS, + ownerReferences: [ + { + apiVersion: "v1", + kind: "Secret", + name: secret.metadata!.name!, + uid: secret.metadata!.uid!, + controller: false, + blockOwnerDeletion: false, + }, + ], + }, + stringData: { "userlist.txt": renderUserlist(username, password) }, + }); + Log.info(`reconciled ${DERIVED_SECRET} from ${SOURCE_SECRET}`); + }); + +const VOLUME = "pgbouncer"; +const CONFIG_MAP = "pgbouncer-config"; + +// Pure, idempotent mutation of a pooler Deployment object. +export function applyPoolerPatch(d: a.Deployment): void { + const podSpec = d?.spec?.template?.spec; + if (!podSpec || !Array.isArray(podSpec.containers) || podSpec.containers.length === 0) { + return; + } + podSpec.volumes = podSpec.volumes ?? []; + if (!podSpec.volumes.some(v => v.name === VOLUME)) { + podSpec.volumes.push({ + name: VOLUME, + projected: { + sources: [ + { + configMap: { + name: CONFIG_MAP, + items: [{ key: "pgbouncer.ini", path: "pgbouncer.ini" }], + }, + }, + { + secret: { + name: DERIVED_SECRET, + items: [{ key: "userlist.txt", path: "userlist.txt" }], + }, + }, + ], + }, + }); + } + + const c = podSpec.containers[0]; // connection-pooler is containers[0] + c.volumeMounts = c.volumeMounts ?? []; + if (!c.volumeMounts.some(m => m.name === VOLUME)) { + c.volumeMounts.push({ name: VOLUME, mountPath: "/etc/pgbouncer", readOnly: true }); + } + c.command = ["/usr/bin/pgbouncer", "/etc/pgbouncer/pgbouncer.ini"]; +} + +// Mutate every pooler Deployment in the postgres namespace (unicorn-only deploy). +When(a.Deployment) + .IsCreatedOrUpdated() + .InNamespace(NS) + .WithLabel("application", "db-connection-pooler") + .Mutate(request => { + applyPoolerPatch(request.Raw); + }); + +// Bootstrap support: the Mutate webhook above only fires on Deployment CREATE/UPDATE. +// When this module is deployed onto an already-running cluster, the operator's pooler +// Deployment already exists and is not mutated until the operator's next write to it. +// The Reconcile handler below processes PRE-EXISTING resources on module startup; for any +// pooler Deployment that has not yet been mutated, it "touches" the pod template so an +// UPDATE fires and the Mutate webhook enriches it. needsBootstrap acts as the loop guard. + +// True when a pooler Deployment has not yet been mutated (no pgbouncer volume). +export function needsBootstrap(d: a.Deployment): boolean { + const podSpec = d?.spec?.template?.spec; + if (!podSpec || !Array.isArray(podSpec.containers) || podSpec.containers.length === 0) { + return false; + } + const volumes = podSpec.volumes ?? []; + return !volumes.some(v => v.name === VOLUME); +} + +// Touch pre-existing pooler Deployments so the Mutate webhook enriches them on startup. +When(a.Deployment) + .IsCreatedOrUpdated() + .InNamespace(NS) + .WithLabel("application", "db-connection-pooler") + .Reconcile(async deploy => { + const name = deploy.metadata?.name; + if (!name) { + return; + } + // Loop guard: once the Mutate webhook has added the pgbouncer volume, stop touching. + if (!needsBootstrap(deploy)) { + return; + } + // Server-side apply of a partial object: we only own the single bootstrap annotation, + // so this merges into the existing pod-template annotations (creating the map if absent) + // without clobbering other annotations or fighting the operator over fields we don't set. + await K8s(kind.Deployment).Apply( + { + metadata: { name, namespace: NS }, + spec: { + template: { + metadata: { annotations: { "pgbouncer.pepr.dev/bootstrap": `${Date.now()}` } }, + }, + }, + }, + { force: true }, + ); + Log.info(`bootstrapped pre-existing pooler deployment ${name}`); + }); diff --git a/src/pepr/eslint.config.mjs b/src/pepr/eslint.config.mjs new file mode 100644 index 0000000..4035e23 --- /dev/null +++ b/src/pepr/eslint.config.mjs @@ -0,0 +1,45 @@ +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; +import globals from "globals"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default [ + { + ignores: ["**/node_modules", "**/dist", "**/*.test.ts"], + }, + ...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"), + { + plugins: { + "@typescript-eslint": typescriptEslint, + }, + + languageOptions: { + parser: tsParser, + parserOptions: { + projectService: { + allowDefaultProject: ["eslint.config.mjs"], + }, + tsconfigRootDir: __dirname, + sourceType: "module", + }, + globals: { + ...globals.node, + }, + }, + + rules: { + "@typescript-eslint/no-floating-promises": "error", + }, + }, +]; diff --git a/src/pepr/package-lock.json b/src/pepr/package-lock.json new file mode 100644 index 0000000..13ad80b --- /dev/null +++ b/src/pepr/package-lock.json @@ -0,0 +1,6274 @@ +{ + "name": "pepr-pgbouncer-config", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pepr-pgbouncer-config", + "version": "0.0.1", + "dependencies": { + "pepr": "1.2.1", + "undici": "^7.0.1" + }, + "devDependencies": { + "typescript": "5.8.3", + "vitest": "^3.2.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@glideapps/ts-necessities": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", + "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@kubernetes/client-node": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-1.4.0.tgz", + "integrity": "sha512-Zge3YvF7DJi264dU1b3wb/GmzR99JhUpqTvp+VGHfwZT+g7EOOYNScDJNZwXy9cszyIGPIs0VHr+kk8e95qqrA==", + "license": "Apache-2.0", + "dependencies": { + "@types/js-yaml": "^4.0.1", + "@types/node": "^24.0.0", + "@types/node-fetch": "^2.6.13", + "@types/stream-buffers": "^3.0.3", + "form-data": "^4.0.0", + "hpagent": "^1.2.0", + "isomorphic-ws": "^5.0.0", + "js-yaml": "^4.1.0", + "jsonpath-plus": "^10.3.0", + "node-fetch": "^2.7.0", + "openid-client": "^6.1.3", + "rfc4648": "^1.3.0", + "socks-proxy-agent": "^8.0.4", + "stream-buffers": "^3.0.2", + "tar-fs": "^3.0.9", + "ws": "^8.18.2" + } + }, + "node_modules/@kubernetes/client-node/node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@kubernetes/client-node/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.0.tgz", + "integrity": "sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.0.tgz", + "integrity": "sha512-Bp3JpGP00Vu3f238ivRrjf7z3xSzVPXqCmaJYA9t2c+c8vKYvOzmXF7LkkeUalTEGd6cZcSWe+PFIP3Vy48fRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.0.tgz", + "integrity": "sha512-zaYIpr670mUmmZ1tVzUFplbQbG7h3Gugx3L5FoqhsC2m/YnLlR1a7zVLmXNPy+iY1tFPEbNG+HHBXZGyId0G5w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.0.tgz", + "integrity": "sha512-+P49fvkv2dSoeevUW+lgZ/I2JHSsJCK1Lyjj7Cu6E4UHG4tS9XIefzIjo5qhgELjAclnen1rLzK2PMKJdo+Dyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.0.tgz", + "integrity": "sha512-l3FAAOyKJXH2ea6KNFN+MMgC/rnE94YGLXs2ehYqDcCoHt1DpvgWX75BhUJxN38XojP7Ul+4H8PRn7EdyqSDrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.0.tgz", + "integrity": "sha512-VokPN3TSctKj65cyCNPaUh4vMFA8awxOot/0sp+4J7ZlNRKQEhXhawqPwajoi8H5ZFt61i0ugZJuTKXBjGJ17Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.0.tgz", + "integrity": "sha512-DxH0P3wxm+Yzs/p3zrk9dw1rURu8p0Nv5+MRK/L7OtnLNg5rLZraSBFZ8iUXOd9f2BlhJyEpIZUH/emjq4UJ4g==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.0.tgz", + "integrity": "sha512-T6ZvMNe84kAz6TBWHC7hGAoEtzP1LWYw/AqayGWEF6uISt3Abk/st06LqRD9THd7Xz3NxzurUpzAuEAUbZf+nw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.0.tgz", + "integrity": "sha512-q/4hzvQkDs8b4jIBab1pnLiiM0ayTZsN2amBFPDzuyZxjEd4wDwx0UJFYM3cOZzSf5Kw8fnWSprJzIBMkcR44Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.0.tgz", + "integrity": "sha512-vvYWX3akdEAY6km+9wAqFDnk6pQsbJKVnj7xawcvs/+fdlYBGp+U+Qq/lLfpIxYIZvZLHMAKD9HLdacSx/r3dw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.0.tgz", + "integrity": "sha512-DePa5cqOxDP/Zp0VOXpeWaGew5iIv5DXp9NYbzkX5PFQyWVX9184WCTh3hvr/7lhXo8ZVlbFLkz8+o/q1dU6gA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.0.tgz", + "integrity": "sha512-LV8aWMB8UChglMCEzs7RkN0GsH29RJaLLqwm9fCIjlqwxQTiWAqNcc7wjBkH31hV0PU/yVxGYvrYsgfea2qw6g==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.0.tgz", + "integrity": "sha512-QoNSnwQtaeNu5grdBbsL0tt1uyl5EnS8DA8Mr3nluMXbhdQNyhN+G4tBax7VCdxLKj8YJ0/4OO9Ho84jMnJtKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.0.tgz", + "integrity": "sha512-/zZp5MKapIIApE8trN8qLGNSiRN9TUoaUZ1cmVu4XnVdd5LQLOXTtyi+vtfUbNnT3iyjzpPqYeKXmvJ+gJGYWw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.0.tgz", + "integrity": "sha512-RbrzcD3aJ1k3UbtMRRBNwojdVVyXjuVAFTfn/xPa6EEl6GE9Sm/akPgFTb9aAC9pMKGJ6CtWxaGrqWcabH+ySg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.0.tgz", + "integrity": "sha512-ZF+onDsBso8PJf1XaG9lB+O9RnBpKGnY6OrzC4CSHrtC1jb6jWLTKK4bRqdoCXHd22gyr2hiYmEAm8Wns/BOCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.0.tgz", + "integrity": "sha512-Atk0aSIk5Zx2Wuh9dgRQgLP0Koc8hOeYpbWryMXyk8G8/HmPkwPPkMqIIDhrXHHYqfUzSJA/I7IWSBv8xSmRBA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.0.tgz", + "integrity": "sha512-0uMOcf3eZ5K+K4cYHkdxShFMPlPXCOdfDFEFn9dNYAEEd2cVvmOfH7zFgRVoDgmtQ1m9k5q7qfrHzyMAubKYUA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.0.tgz", + "integrity": "sha512-mvFtE4A/t/7hRJ7X8Ozmu8FsIkAUat2nzl12pgU337BRmq87AQUJztwHz2Zv5/tjo9/C95E66CK03SI/ToEDJw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.0.tgz", + "integrity": "sha512-z9b9+aTxvt8n2rNltMPvyaUfB8NJ+CVyOrGK/MdIKHx7B+lXmZpm/XbRsU7Rpf3fRqJ2uS6mBJiJveCtq8LHDg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.0.tgz", + "integrity": "sha512-jXaXFqKMehsOc+g8R6oo33RRC6w07G9jDBxAE5eAKX7mOcCbZloYIPNhfG9Wl+P9O9IWHFO4OJgPi1Ml2qkt7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.0.tgz", + "integrity": "sha512-OXNWVFocS2IA4+QplhTZZ2a+8hPZR7T8KuozsNmJKK8y7cp83StHvGksfHzPG3wczWTczyWHVQuqeiTUbjiyBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.0.tgz", + "integrity": "sha512-AlAbNtBO637LxSldqV43z0FfXoGfl2TW1DgAg/bs7aQswFbDewz2SJm3BUhiGfbOVtW571xbc9p+REdxhyN/Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.0.tgz", + "integrity": "sha512-QRSrQXyJ1M4tjNXdR0/G/IgV6lzfQQJYBjlWIEYkY2Xs86DRl/iEpQ4blMDjJxSl7n19eDKKXMg0AmuBVYy8pQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.0.tgz", + "integrity": "sha512-tkuFxhvKO/HlGd0VsINF6vHSYH8AF8W0TcNxKDK6JZmrehngFj78pToc8iemtnvwilDjs2G/qSzYFhe9U8q+fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@types/prompts": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz", + "integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "kleur": "^3.0.3" + } + }, + "node_modules/@types/ramda": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.31.1.tgz", + "integrity": "sha512-Vt6sFXnuRpzaEj+yeutA0q3bcAsK7wdPuASIzR9LXqL4gJPyFw8im9qchlbp4ltuf3kDEIRmPJTD/Fkg60dn7g==", + "license": "MIT", + "dependencies": { + "types-ramda": "^0.31.0" + } + }, + "node_modules/@types/stream-buffers": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.8.tgz", + "integrity": "sha512-J+7VaHKNvlNPJPEJXX/fKa9DZtR/xPMwuIbe+yNOwp1YB+ApUOBv2aUpEoBJEi8nJgbgs1x8e73ttg0r1rSUdw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.4.tgz", + "integrity": "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==", + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/type-utils": "8.59.4", + "@typescript-eslint/utils": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.4", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.4.tgz", + "integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz", + "integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.59.4", + "@typescript-eslint/types": "^8.59.4", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.4.tgz", + "integrity": "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz", + "integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.4.tgz", + "integrity": "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/utils": "8.59.4", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz", + "integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz", + "integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.59.4", + "@typescript-eslint/tsconfig-utils": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.4.tgz", + "integrity": "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz", + "integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.4", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.6", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", + "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz", + "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz", + "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browser-or-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", + "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "license": "Apache-2.0" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fast-copy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", + "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "license": "ISC" + }, + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", + "license": "MIT" + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-pointer": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", + "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "license": "MIT", + "dependencies": { + "foreach": "^2.0.4" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "license": "MIT" + }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/kubernetes-fluent-client": { + "version": "3.11.7", + "resolved": "https://registry.npmjs.org/kubernetes-fluent-client/-/kubernetes-fluent-client-3.11.7.tgz", + "integrity": "sha512-2ynNXX2BZIX4WnmNIm55U9QSI5vSED/rTt67M1Uuprfze5UsN67Z0p3WdyLL8DmIN5zHnE1f4MCkv70wfYcuMA==", + "license": "Apache-2.0", + "dependencies": { + "@kubernetes/client-node": "1.4.0", + "http-status-codes": "2.3.0", + "js-yaml": "4.1.1", + "node-fetch": "2.7.0", + "quicktype-core": "23.2.6", + "tsx": "4.21.0", + "undici": "7.24.6", + "yargs": "18.0.0" + }, + "bin": { + "kubernetes-fluent-client": "dist/cli.js" + }, + "engines": { + "node": ">=20.6.0" + } + }, + "node_modules/kubernetes-fluent-client/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/kubernetes-fluent-client/node_modules/undici": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.6.tgz", + "integrity": "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "peer": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/oauth4webapi": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", + "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openid-client": { + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.4.tgz", + "integrity": "sha512-QSw0BA08piujetEwfZsHoTrDpMEha7GDZDicQqVwX4u0ChCjefvjDB++TZ8BTg76UpwhzIQgdvvfgfl3HpCSAw==", + "license": "MIT", + "dependencies": { + "jose": "^6.2.2", + "oauth4webapi": "^3.8.5" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/pepr": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pepr/-/pepr-1.2.1.tgz", + "integrity": "sha512-kBFEhVDsw/0a58NX/26rNt8/bfFNzqKkReNwtg/pD2FX4bMm2qUxJJWf1TslQgIpeGIiCrDhAdLTCHUNh4o2vw==", + "license": "Apache-2.0", + "dependencies": { + "@types/ramda": "0.31.1", + "@typescript-eslint/eslint-plugin": "8.59.4", + "@typescript-eslint/parser": "8.59.4", + "commander": "14.0.3", + "eslint": "9.39.4", + "express": "5.2.1", + "fast-json-patch": "3.1.1", + "http-status-codes": "^2.3.0", + "json-pointer": "^0.6.2", + "kubernetes-fluent-client": "3.11.7", + "pino": "10.3.1", + "pino-pretty": "13.1.3", + "prom-client": "15.1.3", + "quicktype-core": "^23.2.6", + "ramda": "0.32.0" + }, + "bin": { + "pepr": "dist/cli.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@types/prompts": "^2.4.9", + "esbuild": "^0.28.0", + "node-forge": "^1.4.0", + "prettier": "^3.6.2", + "prompts": "^2.4.2", + "typescript": "^5.8.3", + "uuid": "^13.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/prom-client": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz", + "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.4.0", + "tdigest": "^0.1.1" + }, + "engines": { + "node": "^16 || ^18 || >=20" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/quicktype-core": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-23.2.6.tgz", + "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.2.3", + "browser-or-node": "^3.0.0", + "collection-utils": "^1.0.1", + "cross-fetch": "^4.0.0", + "is-url": "^1.2.4", + "js-base64": "^3.7.7", + "lodash": "^4.17.21", + "pako": "^1.0.6", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.4.1" + } + }, + "node_modules/ramda": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.32.0.tgz", + "integrity": "sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rfc4648": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.4.tgz", + "integrity": "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.0.tgz", + "integrity": "sha512-T9mWdbWfQtp0B5lv/HX+wrhYsmXRlcWnXXmJbXqKJhlRaoS6KMhq0gpyzW4UJfclcxrEdLnTgjT2NjruLONu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.61.0", + "@rollup/rollup-android-arm64": "4.61.0", + "@rollup/rollup-darwin-arm64": "4.61.0", + "@rollup/rollup-darwin-x64": "4.61.0", + "@rollup/rollup-freebsd-arm64": "4.61.0", + "@rollup/rollup-freebsd-x64": "4.61.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.0", + "@rollup/rollup-linux-arm-musleabihf": "4.61.0", + "@rollup/rollup-linux-arm64-gnu": "4.61.0", + "@rollup/rollup-linux-arm64-musl": "4.61.0", + "@rollup/rollup-linux-loong64-gnu": "4.61.0", + "@rollup/rollup-linux-loong64-musl": "4.61.0", + "@rollup/rollup-linux-ppc64-gnu": "4.61.0", + "@rollup/rollup-linux-ppc64-musl": "4.61.0", + "@rollup/rollup-linux-riscv64-gnu": "4.61.0", + "@rollup/rollup-linux-riscv64-musl": "4.61.0", + "@rollup/rollup-linux-s390x-gnu": "4.61.0", + "@rollup/rollup-linux-x64-gnu": "4.61.0", + "@rollup/rollup-linux-x64-musl": "4.61.0", + "@rollup/rollup-openbsd-x64": "4.61.0", + "@rollup/rollup-openharmony-arm64": "4.61.0", + "@rollup/rollup-win32-arm64-msvc": "4.61.0", + "@rollup/rollup-win32-ia32-msvc": "4.61.0", + "@rollup/rollup-win32-x64-gnu": "4.61.0", + "@rollup/rollup-win32-x64-msvc": "4.61.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT", + "peer": true + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-buffers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.3.tgz", + "integrity": "sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==", + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/streamx": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.26.0.tgz", + "integrity": "sha512-VvNG1K72Po/xwJzxZFnZ++Tbrv4lwSptsbkFuzXCJAYZvCK5nnxsvXU6ajqkv7chyiI1Y0YXq2Jh8Iy8Y7NF/A==", + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "license": "MIT", + "dependencies": { + "bintrees": "1.0.2" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/thread-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz", + "integrity": "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==", + "license": "MIT", + "dependencies": { + "real-require": "^1.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/thread-stream/node_modules/real-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-1.0.0.tgz", + "integrity": "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==", + "license": "MIT" + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "license": "Apache-2.0" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/types-ramda": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/types-ramda/-/types-ramda-0.31.0.tgz", + "integrity": "sha512-vaoC35CRC3xvL8Z6HkshDbi6KWM1ezK0LHN0YyxXWUn9HKzBNg/T3xSGlJZjCYspnOD3jE7bcizsp0bUXZDxnQ==", + "license": "MIT", + "dependencies": { + "ts-toolbelt": "^9.6.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.0.tgz", + "integrity": "sha512-+t2Z/GwkZQDtu00813aP66ygViGtPHKhhoFZpQKpKrE+9jIgES+Zw+mFNaDWOVRKiuJjuqKHzD3B1sfGg8+ZOQ==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.2.tgz", + "integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/src/pepr/package.json b/src/pepr/package.json new file mode 100644 index 0000000..ec9c846 --- /dev/null +++ b/src/pepr/package.json @@ -0,0 +1,57 @@ +{ + "name": "pepr-pgbouncer", + "version": "0.0.1", + "type": "module", + "description": "Configures the distroless pgbouncer connection pooler for the Zalando postgres-operator", + "keywords": [ + "pepr", + "k8s", + "policy-engine", + "pepr-module", + "security" + ], + "engines": { + "node": ">=20.0.0" + }, + "pepr": { + "uuid": "pgbouncer", + "onError": "ignore", + "webhookTimeout": 10, + "customLabels": { + "namespace": { + "pepr.dev": "" + } + }, + "alwaysIgnore": { + "namespaces": [] + }, + "admission": { + "alwaysIgnore": { + "namespaces": [] + } + }, + "watch": { + "alwaysIgnore": { + "namespaces": [] + } + }, + "includedFiles": [], + "env": {} + }, + "scripts": { + "k3d-setup": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0' --wait && kubectl rollout status deployment -n kube-system", + "test": "vitest run", + "build": "pepr build" + }, + "dependencies": { + "pepr": "1.2.1", + "undici": "^7.0.1" + }, + "devDependencies": { + "typescript": "5.8.3", + "vitest": "^3.2.6" + }, + "overrides": { + "brace-expansion": "1.1.11" + } +} diff --git a/src/pepr/pepr.ts b/src/pepr/pepr.ts new file mode 100644 index 0000000..74a586d --- /dev/null +++ b/src/pepr/pepr.ts @@ -0,0 +1,5 @@ +import { PeprModule } from "pepr"; +import cfg from "./package.json"; +import { Pgbouncer } from "./capabilities/pgbouncer-pooler"; + +new PeprModule(cfg, [Pgbouncer]); diff --git a/src/pepr/tsconfig.json b/src/pepr/tsconfig.json new file mode 100644 index 0000000..1a6d0d9 --- /dev/null +++ b/src/pepr/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "esModuleInterop": true, + "lib": [ + "ES2022" + ], + "module": "es2022", + "moduleResolution": "bundler", + "outDir": "dist", + "resolveJsonModule": true, + "rootDir": ".", + "strict": false, + "target": "ES2022", + "useUnknownInCatchVariables": false + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules", + "dist", + "**/*.test.ts" + ] +} \ No newline at end of file diff --git a/tasks.yaml b/tasks.yaml index 6951f11..4386df4 100644 --- a/tasks.yaml +++ b/tasks.yaml @@ -2,18 +2,16 @@ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial includes: - - dependencies: ./tasks/dependencies.yaml - test: ./tasks/test.yaml - - create: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/create.yaml - - publish: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/publish.yaml - - lint: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/lint.yaml - - pull: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/pull.yaml - - deploy: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/deploy.yaml - - setup: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/setup.yaml - - actions: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/actions.yaml - - badge: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/badge.yaml - - upgrade: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/upgrade.yaml - - compliance: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.2/tasks/compliance.yaml + - create: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/create.yaml + - publish: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/publish.yaml + - lint: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/lint.yaml + - pull: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/pull.yaml + - deploy: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/deploy.yaml + - setup: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/setup.yaml + - actions: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/actions.yaml + - badge: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/badge.yaml + - upgrade: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.24.8/tasks/upgrade.yaml tasks: - name: default @@ -30,13 +28,30 @@ tasks: with: options: "--skip-sbom" + - name: build-pepr + description: | + Build the pgbouncer Pepr module manifest into src/pepr/dist (gitignored). + For local iteration only — `zarf package create --flavor unicorn` runs this + automatically via the unicorn component's onCreate action. Requires Node.js 20+ and yq. + actions: + - description: "Build the pgbouncer Pepr module" + dir: src/pepr + cmd: | + npm ci --no-audit --no-fund + npx pepr build --custom-image ghcr.io/defenseunicorns/pepr/private/controller:v1.2.1 + # Strip the shared pepr-system Namespace (owned by uds-core) so package removal + # never cascade-deletes it. See zarf.yaml onCreate for the rationale. + yq ea -i 'select(.kind != "Namespace")' dist/pepr-module-pgbouncer.yaml + # Copy the built manifest to the repo-root manifests/ dir so it can be committed + # (cmd runs in src/pepr, so the root is two levels up). + mkdir -p ../../manifests + cp dist/pepr-module-pgbouncer.yaml ../../manifests/pepr-module-pgbouncer.yaml + - name: create-deploy-test-bundle description: Test and validate cluster is deployed with Postgres Operator actions: - - task: dependencies:create - task: create:test-bundle - task: deploy:test-bundle - - task: setup:create-doug-user - task: test:all - name: dev @@ -54,22 +69,15 @@ tasks: - task: create-dev-package - task: setup:k3d-test-cluster - task: create-deploy-test-bundle - - task: compliance:validate - name: test-upgrade description: Test an upgrade from the latest released package to the current branch actions: - task: upgrade:create-latest-tag-bundle - with: - dep_commands: ./uds run dependencies:create - task: setup:k3d-test-cluster - task: deploy:test-bundle - - task: setup:create-doug-user - - task: compliance:validate - task: create-dev-package - task: create-deploy-test-bundle - - task: compliance:validate - - task: compliance:evaluate - name: publish-release description: Build and publish the packages @@ -80,7 +88,3 @@ tasks: - task: create-deploy-test-bundle - description: Publish the package task: publish:package - with: - # x-release-please-start-version - version: "1.13.0-uds.2" - # x-release-please-end diff --git a/tasks/dependencies.yaml b/tasks/dependencies.yaml deleted file mode 100644 index a75bc52..0000000 --- a/tasks/dependencies.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -tasks: - - name: create - description: Create the namespace dependency package - actions: - - cmd: uds zarf package create src/namespace --confirm --no-progress --architecture="${UDS_ARCH}" --skip-sbom diff --git a/tests/postgres/bad-password-test.yaml b/tests/postgres/bad-password-test.yaml new file mode 100644 index 0000000..6897842 --- /dev/null +++ b/tests/postgres/bad-password-test.yaml @@ -0,0 +1,40 @@ +# Copyright 2025 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +apiVersion: batch/v1 +kind: Job +metadata: + name: bad-password-test + namespace: gitlab + labels: + app: gitlab +spec: + template: + spec: + restartPolicy: Never + containers: + - name: bad-password-test + image: docker.io/postgres:18 + command: + - sh + - -c + - | + echo "Testing connection with incorrect password - this should FAIL" + export PGPASSWORD="wrongpassword" + if psql -h $DB_HOST -U $DB_USER -d $DB_NAME -c "SELECT 1" 2>&1; then + echo "ERROR: Connection succeeded with wrong password!" + exit 1 + else + echo "SUCCESS: Connection properly rejected with wrong password" + exit 0 + fi + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: gitlab.gitlab.pg-cluster.credentials.postgresql.acid.zalan.do + key: username + - name: DB_HOST + value: pg-cluster.postgres.svc.cluster.local + - name: DB_NAME + value: gitlabdb diff --git a/tests/postgres/db-seed-cross-namespace.yaml b/tests/postgres/db-seed-cross-namespace.yaml index 619f52c..c147ee9 100644 --- a/tests/postgres/db-seed-cross-namespace.yaml +++ b/tests/postgres/db-seed-cross-namespace.yaml @@ -26,7 +26,7 @@ spec: spec: containers: - name: db-seed - image: docker.io/postgres:13 + image: docker.io/postgres:18 command: - sh - -c diff --git a/tests/postgres/db-seed.yaml b/tests/postgres/db-seed.yaml index a80ef0d..df9e2f7 100644 --- a/tests/postgres/db-seed.yaml +++ b/tests/postgres/db-seed.yaml @@ -26,7 +26,7 @@ spec: spec: containers: - name: db-seed - image: docker.io/postgres:13 + image: docker.io/postgres:18 command: - sh - -c diff --git a/tests/postgres/pooler-connection-test.yaml b/tests/postgres/pooler-connection-test.yaml new file mode 100644 index 0000000..e0d799d --- /dev/null +++ b/tests/postgres/pooler-connection-test.yaml @@ -0,0 +1,103 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +apiVersion: batch/v1 +kind: Job +metadata: + name: pooler-primary-test + namespace: gitlab + labels: + app: gitlab +spec: + template: + spec: + restartPolicy: Never + containers: + - name: pooler-primary-test + image: docker.io/postgres:18 + command: + - sh + - -c + - | + echo "Testing RW path via primary pooler at $DB_HOST" + SEL=$(psql -qtAc "SELECT 1" -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME") + if [ "$SEL" != "1" ]; then + echo "ERROR: SELECT 1 via primary pooler returned '$SEL', expected '1'" + exit 1 + fi + if ! psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" <<'SQL' + DO $probe$ + DECLARE + cnt int; + BEGIN + CREATE TEMP TABLE pooler_rw_probe(val int) ON COMMIT DROP; + INSERT INTO pooler_rw_probe VALUES (1),(2),(3); + SELECT count(*) INTO cnt FROM pooler_rw_probe; + IF cnt <> 3 THEN + RAISE EXCEPTION 'temp-table RW probe returned %, expected 3', cnt; + END IF; + END $probe$; + SQL + then + echo "ERROR: temp-table RW probe via primary pooler failed" + exit 1 + fi + echo "SUCCESS: primary pooler RW path verified" + exit 0 + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: gitlab.gitlab.pg-cluster.credentials.postgresql.acid.zalan.do + key: username + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: gitlab.gitlab.pg-cluster.credentials.postgresql.acid.zalan.do + key: password + - name: DB_HOST + value: pg-cluster-pooler.postgres.svc.cluster.local + - name: DB_NAME + value: gitlabdb +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: pooler-replica-test + namespace: gitlab + labels: + app: gitlab +spec: + template: + spec: + restartPolicy: Never + containers: + - name: pooler-replica-test + image: docker.io/postgres:18 + command: + - sh + - -c + - | + echo "Verifying replica pooler routes to a standby at $DB_HOST" + IN_RECOVERY=$(psql -tAc "SELECT pg_is_in_recovery()" -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME") + if [ "$IN_RECOVERY" != "t" ]; then + echo "ERROR: replica pooler routed to non-standby (pg_is_in_recovery='$IN_RECOVERY', expected 't')" + exit 1 + fi + echo "SUCCESS: replica pooler routed to a standby (pg_is_in_recovery=t)" + exit 0 + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: gitlab.gitlab.pg-cluster.credentials.postgresql.acid.zalan.do + key: username + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: gitlab.gitlab.pg-cluster.credentials.postgresql.acid.zalan.do + key: password + - name: DB_HOST + value: pg-cluster-pooler-repl.postgres.svc.cluster.local + - name: DB_NAME + value: gitlabdb \ No newline at end of file diff --git a/tests/postgres/postgres-minimal.yaml b/tests/postgres/postgres-minimal.yaml index 1df3d31..d503d76 100644 --- a/tests/postgres/postgres-minimal.yaml +++ b/tests/postgres/postgres-minimal.yaml @@ -7,8 +7,8 @@ metadata: name: acid # This label is only needed for testing! # In a real deployment this namespace would be controlled by a UDS Package / the UDS Operator - labels: - istio-injection: enabled + # labels: + # istio-injection: enabled --- apiVersion: acid.zalan.do/v1 kind: postgresql @@ -16,6 +16,21 @@ metadata: name: pg-cluster namespace: acid spec: + patroni: + initdb: + auth-host: scram-sha-256 + auth-local: trust + pg_hba: + - local all all trust + - hostssl all +zalandos 127.0.0.1/32 pam + - host all all 127.0.0.1/32 scram-sha-256 + - hostssl all +zalandos ::1/128 pam + - host all all ::1/128 scram-sha-256 + - local replication standby trust + - hostssl replication standby all scram-sha-256 + - hostnossl all all all reject + - hostssl all +zalandos all pam + - hostssl all all all scram-sha-256 teamId: "myteam" volume: size: 1Gi @@ -25,4 +40,7 @@ spec: databases: mydb: myuser postgresql: + parameters: + log_rotation_age: 2d + password_encryption: scram-sha-256 version: "14" diff --git a/tests/postgres/uds-package-cross-namespace.yaml b/tests/postgres/uds-package-cross-namespace.yaml new file mode 100644 index 0000000..62dfc26 --- /dev/null +++ b/tests/postgres/uds-package-cross-namespace.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + +apiVersion: uds.dev/v1alpha1 +kind: Package +metadata: + name: gitlab + namespace: gitlab +spec: + network: + serviceMesh: + mode: ambient + allow: + - direction: Egress + selector: + job-name: db-seed-job + remoteNamespace: postgres + remoteSelector: + cluster-name: pg-cluster diff --git a/tests/zarf.yaml b/tests/zarf.yaml index 965ea44..fb896f3 100644 --- a/tests/zarf.yaml +++ b/tests/zarf.yaml @@ -14,9 +14,10 @@ components: manifests: - name: db-seed files: + - postgres/uds-package-cross-namespace.yaml - postgres/db-seed-cross-namespace.yaml images: - - docker.io/postgres:13 + - docker.io/postgres:18 actions: onDeploy: before: @@ -35,6 +36,23 @@ components: namespace: gitlab condition: "'{.status.succeeded}'=1" + - name: test-bad-password + required: true + manifests: + - name: bad-password-test + files: + - postgres/bad-password-test.yaml + images: + - docker.io/postgres:18 + actions: + onDeploy: + after: + - wait: + cluster: + kind: Job + name: bad-password-test + namespace: gitlab + condition: "'{.status.succeeded}'=1" - name: deploy-postgres-standalone required: true @@ -53,6 +71,7 @@ components: namespace: acid condition: "'{.status.PostgresClusterStatus}'=Running" maxTotalSeconds: 600 + - name: test-standalone-postgres-deployment required: true manifests: @@ -60,7 +79,7 @@ components: files: - postgres/db-seed.yaml images: - - docker.io/postgres:13 + - docker.io/postgres:18 actions: onDeploy: after: diff --git a/values/registry1-config-values.yaml b/values/registry1-config-values.yaml index 29673af..eb57fe5 100644 --- a/values/registry1-config-values.yaml +++ b/values/registry1-config-values.yaml @@ -2,4 +2,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial metrics: - image: "registry1.dso.mil/ironbank/opensource/prometheus/postgres-exporter:v0.15.0" + image: "registry1.dso.mil/ironbank/opensource/prometheus/postgres-exporter:v0.19.1" + +job: + image: "ghcr.io/zalando/spilo-17:4.0-p3" diff --git a/values/registry1-values.yaml b/values/registry1-values.yaml index 4ad5c26..018ce8f 100644 --- a/values/registry1-values.yaml +++ b/values/registry1-values.yaml @@ -4,11 +4,11 @@ image: registry: registry1.dso.mil repository: ironbank/opensource/zalando/postgres-operator - tag: v1.13.0 + tag: v1.15.0 configConnectionPooler: - connection_pooler_image: "registry1.dso.mil/ironbank/opensource/zalando/pgbouncer:1.21.0" + connection_pooler_image: "registry1.dso.mil/ironbank/opensource/zalando/pgbouncer:1.25.1" configLogicalBackup: - logical_backup_docker_image: "registry1.dso.mil/ironbank/opensource/zalando/logical-backup:v1.8.2" + logical_backup_docker_image: "registry1.dso.mil/ironbank/opensource/zalando/logical-backup:v1.15.1" # Note there is not a spilo image in registry1 configGeneral: - docker_image: "ghcr.io/zalando/spilo-15:3.2-p1" + docker_image: "ghcr.io/zalando/spilo-17:4.0-p3" diff --git a/values/unicorn-config-values.yaml b/values/unicorn-config-values.yaml index 9b2303a..897ad41 100644 --- a/values/unicorn-config-values.yaml +++ b/values/unicorn-config-values.yaml @@ -2,4 +2,13 @@ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial metrics: - image: "cgr.dev/du-uds-defenseunicorns/prometheus-postgres-exporter-fips:0.15.0" + image: "cgr.dev/defenseunicorns.com/prometheus-postgres-exporter-fips:v0.19.1" + +job: + image: "cgr.dev/defenseunicorns.com/spilo-17:v4.1.2" + +# chainguard pgbouncer has no entrypoint to build pgbouncer.ini; render the +# static config ConfigMap (mounted by the pepr module) on this flavor only. +postgresql: + poolerConfig: + enabled: true diff --git a/values/unicorn-values.yaml b/values/unicorn-values.yaml index ecc2d85..339764c 100644 --- a/values/unicorn-values.yaml +++ b/values/unicorn-values.yaml @@ -3,11 +3,11 @@ image: registry: cgr.dev - repository: du-uds-defenseunicorns/postgres-operator-fips - tag: "1.13.0" + repository: defenseunicorns.com/postgres-operator-fips + tag: "v1.15.1" configConnectionPooler: - connection_pooler_image: "cgr.dev/du-uds-defenseunicorns/pgbouncer-fips:1.22.1" + connection_pooler_image: "cgr.dev/defenseunicorns.com/pgbouncer-fips:v1.25.2" configLogicalBackup: - logical_backup_docker_image: "ghcr.io/zalando/postgres-operator/logical-backup:v1.13.0" + logical_backup_docker_image: "quay.io/rfcurated/zalando/postgres-operator/logical-backup:1.15-jammy-scratch-fips-rfcurated" configGeneral: - docker_image: "ghcr.io/zalando/spilo-15:3.2-p1" + docker_image: "cgr.dev/defenseunicorns.com/spilo-17:v4.1.2" diff --git a/values/upstream-config-values.yaml b/values/upstream-config-values.yaml index 36cfd3b..ed7a6b0 100644 --- a/values/upstream-config-values.yaml +++ b/values/upstream-config-values.yaml @@ -2,4 +2,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial metrics: - image: "quay.io/prometheuscommunity/postgres-exporter:v0.15.0" + image: "quay.io/prometheuscommunity/postgres-exporter:v0.19.1" + +job: + image: "ghcr.io/zalando/spilo-17:4.0-p3" diff --git a/values/upstream-values.yaml b/values/upstream-values.yaml index 07fd344..53f206a 100644 --- a/values/upstream-values.yaml +++ b/values/upstream-values.yaml @@ -4,10 +4,10 @@ image: registry: ghcr.io repository: zalando/postgres-operator - tag: v1.13.0 + tag: v1.15.1 configConnectionPooler: - connection_pooler_image: "docker.io/bitnami/pgbouncer:1.23.1" + connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-32" configLogicalBackup: - logical_backup_docker_image: "ghcr.io/zalando/postgres-operator/logical-backup:v1.13.0" + logical_backup_docker_image: "ghcr.io/zalando/postgres-operator/logical-backup:v1.15.1" configGeneral: - docker_image: "ghcr.io/zalando/spilo-15:3.2-p1" + docker_image: "ghcr.io/zalando/spilo-17:4.0-p3" diff --git a/version.txt b/version.txt deleted file mode 100644 index 1ece499..0000000 --- a/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.13.0-uds.2 diff --git a/zarf.yaml b/zarf.yaml index b5e1adc..b7c58ca 100644 --- a/zarf.yaml +++ b/zarf.yaml @@ -4,11 +4,15 @@ kind: ZarfPackageConfig metadata: name: postgres-operator - description: "A deployment of zalando postgres operator" + description: "PostgreSQL is a powerful, open source object-relational database system that uses and extends the SQL language combined with many features that safely store and scale the most complicated data workloads. PostgreSQL comes with many features aimed to help developers build applications, administrators to protect data integrity and build fault-tolerant environments, and help you manage your data no matter how big or small the dataset. In addition to being free and open source, PostgreSQL is highly extensible. For example, you can define your own data types, build out custom functions, even write code from different programming languages without recompiling your database!" url: https://github.com/zalando/postgres-operator - # x-release-please-start-version - version: "1.13.0-uds.2" - # x-release-please-end + version: "dev" + annotations: + dev.uds.title: Postgres Operator + dev.uds.tagline: The World''s Most Advanced Open Source Relational Database + dev.uds.categories: Databases, IT Management, Software Dev + dev.uds.keywords: Open Source Database, Object-Relational Database, SQL, Data Integrity, Fault-Tolerant, Data Management, Extensibility, Custom Data Types, Custom Functions, Scalability, Free and Open Source + dev.uds.icon: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBmaWxsPSJub25lIj48c3R5bGU+PCFbQ0RBVEFbLkd7c3Ryb2tlLWxpbmVjYXA6cm91bmR9Lkh7c3Ryb2tlLXdpZHRoOjEuMzF9Lkl7c3Ryb2tlLWxpbmVqb2luOnJvdW5kfV1dPjwvc3R5bGU+PGcgY2xpcC1wYXRoPSJ1cmwoI0EpIj48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMSIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm11bHRpcGx5IiBkPSJNMTIgMTJoNTZ2NTZIMTJ6Ii8+PHBhdGggZD0iTTUzLjU3NyA1Mi44ODZjLjM1Ny0yLjk5NS4yNTItMy40MzYgMi40OC0yLjk1M2wuNTY4LjA1M2MxLjcxMy4wNzQgMy45NjItLjI3MyA1LjI4Ni0uODkzIDIuODM3LTEuMzE0IDQuNTI5LTMuNTIgMS43MjMtMi45NDItNi4zODkgMS4zMTQtNi44MzEtLjg0MS02LjgzMS0uODQxIDYuNzQ2LTEwLjAwNCA5LjU2My0yMi43MDkgNy4xMzUtMjUuODE5LTYuNjQxLTguNDgtMTguMTI3LTQuNDc3LTE4LjMyNy00LjM3MmwtLjA2My4wMTFjLTEuMjYxLS4yNjMtMi42OC0uNDItNC4yNjYtLjQ0MS0yLjg5LS4wNTMtNS4wODYuNzU3LTYuNzQ2IDIuMDE4IDAgMC0yMC41MDItOC40NDktMTkuNTQ2IDEwLjYyNC4yIDQuMDU2IDUuODExIDMwLjY5NSAxMi41MDUgMjIuNjQ2IDIuNDQ4LTIuOTQyIDQuODEzLTUuNDMzIDQuODEzLTUuNDMzIDEuMTc3Ljc3OCAyLjU3NSAxLjE3NyA0LjA1NiAxLjAzbC4xMTYtLjA5NWMtLjAzMi4zNjgtLjAyMS43MjUuMDQyIDEuMTQ1LTEuNzEzIDEuOTIzLTEuMjA4IDIuMjctNC42NTUgMi45NzQtMy40ODkuNzE1LTEuNDQgMS45OTctLjEwNSAyLjMzMyAxLjYxOC40MSA1LjM3Ljk3NyA3LjkxMy0yLjU2NGwtLjEwNS40MWMuNjcyLjUzNi42MyAzLjg4OC43MjUgNi4yODRzLjI1MiA0LjYyNC43NDYgNS45MzdjLjQ4MyAxLjMxNCAxLjA2MSA0LjcwOCA1LjU5IDMuNzMxIDMuNzk0LS44MiA2LjY4My0xLjk4NiA2Ljk0Ni0xMi44NDF6IiBmaWxsPSIjMDAwIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy45MyIvPjxwYXRoIGQ9Ik02My42MzQgNDYuMTVjLTYuMzg5IDEuMzE0LTYuODMxLS44NDEtNi44MzEtLjg0MSA2Ljc0Ni0xMC4wMDQgOS41NjMtMjIuNzE5IDcuMTM1LTI1LjgxOS02LjY0MS04LjQ4LTE4LjEyNy00LjQ2Ni0xOC4zMjctNC4zNzJsLS4wNjMuMDExYy0xLjI2MS0uMjYzLTIuNjgtLjQyLTQuMjY2LS40NDEtMi44OS0uMDUyLTUuMDg2Ljc1Ny02Ljc0NiAyLjAxOCAwIDAtMjAuNTAyLTguNDQ5LTE5LjU0NiAxMC42MjQuMiA0LjA1NiA1LjgxMSAzMC42OTUgMTIuNTA1IDIyLjY0NiAyLjQ0OC0yLjk0MiA0LjgxMy01LjQzMyA0LjgxMy01LjQzMyAxLjE3Ny43NzggMi41NzUgMS4xNzcgNC4wNTYgMS4wM2wuMTE2LS4wOTVjLS4wMzIuMzY4LS4wMjEuNzI1LjA0MiAxLjE0NS0xLjcxMyAxLjkyMy0xLjIwOCAyLjI3LTQuNjU1IDIuOTc0LTMuNDg5LjcxNS0xLjQ0IDEuOTk3LS4xMDUgMi4zMzMgMS42MTguNDEgNS4zNy45NzcgNy45MTMtMi41NjRsLS4xMDUuNDFjLjY3Mi41MzYgMS4xNDUgMy41MiAxLjA3MiA2LjIyMS0uMDg0IDIuNzAxLS4xMzcgNC41NS4zOTkgNnMxLjA2MSA0LjcwOCA1LjU5IDMuNzNjMy43ODMtLjgwOSA1Ljc0OC0yLjkxMSA2LjAyMS02LjQyMS4xODktMi40OS42My0yLjEyMy42NjItNC4zNWwuMzQ3LTEuMDUxYy40MS0zLjM4NC4wNjMtNC40NjYgMi4zOTYtMy45NjJsLjU2OC4wNTNjMS43MTMuMDczIDMuOTYyLS4yNzMgNS4yODYtLjg5MyAyLjg0OC0xLjMzNCA0LjUyOS0zLjUzMSAxLjcyMy0yLjk1M3oiIGZpbGw9IiMzMzY3OTEiLz48ZyBzdHJva2U9IiNmZmYiPjxnIGNsYXNzPSJHIEgiPjxwYXRoIGQ9Ik0zOS45NDggNDguMDg0Yy0uMTc5IDYuMjg0LjA0MiAxMi42MjEuNjYyIDE0LjE2NS42MiAxLjUzNCAxLjkzNCA0LjUyOSA2LjQ2MyAzLjU2MiAzLjc4My0uODA5IDUuMTYtMi4zODUgNS43NTktNS44NTMuNDQxLTIuNTU0IDEuMjkzLTkuNjM2IDEuMzk4LTExLjA4Nk0zNC41MTUgMTYuNTU4UzE0LjAwMiA4LjE3MyAxNC45NTkgMjcuMjQ2Yy4yIDQuMDU2IDUuODExIDMwLjY5NSAxMi41MDUgMjIuNjQ2IDIuNDQ4LTIuOTQyIDQuNjU1LTUuMjU0IDQuNjU1LTUuMjU0bTEzLjQ4Mi0yOS42MDJjLS43MTUuMjIxIDExLjQxMi00LjQzNCAxOC4yOTUgNC4zNzIgMi40MzggMy4xMTEtLjM4OSAxNS44MTUtNy4xMzUgMjUuODE5IiBjbGFzcz0iSSIvPjxwYXRoIGQ9Ik01Ni43NjEgNDUuMjI2cy40NDEgMi4xNjUgNi44MzEuODQxYzIuNzk1LS41NzggMS4xMTQgMS42MTgtMS43MjMgMi45NDItMi4zMzMgMS4wODItNy41NTYgMS4zNTYtNy42NC0uMTM3LS4yMjEtMy44NDYgMi43NTMtMi42OCAyLjUzMy0zLjY0N3ptMCAwYy0uMTg5LS44NzItMS41MjQtMS43MjMtMi4zOTYtMy44NTctLjc2Ny0xLjg2LTEwLjUxOS0xNi4xMDkgMi43MDEtMTMuOTk3LjQ4My0uMTA1LTMuNDQ3LTEyLjU3OS0xNS44MTUtMTIuNzc4UzI5LjI5MiAyOS43OTkgMjkuMjkyIDI5Ljc5OSIgc3Ryb2tlLWxpbmVqb2luPSJiZXZlbCIvPjwvZz48ZyBjbGFzcz0iSCBJIj48cGF0aCBkPSJNMzYuNDggNDYuNTQ5Yy0xLjcyMyAxLjkyMy0xLjIxOSAyLjI1OS00LjY2NiAyLjk3NC0zLjQ4OS43MTUtMS40NCAxLjk5Ny0uMTA1IDIuMzMzIDEuNjE4LjQxIDUuMzcuOTc3IDcuOTEzLTIuNTY0Ljc2Ny0xLjA4MiAwLTIuODA2LTEuMDYxLTMuMjQ3LS41MTUtLjIyMS0xLjE5OC0uNDgzLTIuMDgxLjUwNHoiLz48cGF0aCBkPSJNMzYuMzc1IDQ2LjUwN2MtLjE3OS0xLjEzNS4zNjgtMi40OC45NTYtNC4wNTYuODgzLTIuMzY0IDIuOTExLTQuNzI5IDEuMjgyLTEyLjIzMi0xLjIwOS01LjU5MS05LjMyMS0xLjE2Ni05LjMzMS0uNDEgMCAuNzU3LjM2OCAzLjg0Ni0uMTM3IDcuNDQtLjY1MSA0LjY4NyAyLjk4NCA4LjY0OCA3LjE3NyA4LjI0OSIgY2xhc3M9IkciLz48L2c+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTM0LjQ0MSAyOS43MDRjLS4wMzIuMjYzLjQ3My45NDYgMS4xMzUgMS4wNHMxLjIzLS40NTIgMS4yNzEtLjcwNGMuMDMyLS4yNjMtLjQ3My0uNTQ3LTEuMTM1LS42NDFzLTEuMjQuMDQyLTEuMjcyLjMwNXoiIHN0cm9rZS13aWR0aD0iLjQzNyIvPjxwYXRoIGQ9Ik01NC42OTEgMjkuMTY4Yy4wMzIuMjYzLS40NzMuOTQ2LTEuMTM1IDEuMDRzLTEuMjMtLjQ1Mi0xLjI3MS0uNzA0Yy0uMDMyLS4yNjMuNDczLS41NDYgMS4xNDUtLjY0MS42NTItLjA4NCAxLjIxOS4wNTMgMS4yNjEuMzA1eiIgc3Ryb2tlLXdpZHRoPSIuMjE4Ii8+PC9nPjwvZz48L2c+PC9zdmc+ components: # CRD lifecycle is managed outside of the main chart to support upgrades @@ -17,10 +21,10 @@ components: manifests: - name: crds files: - - https://github.com/zalando/postgres-operator/raw/v1.13.0/charts/postgres-operator/crds/operatorconfigurations.yaml - - https://github.com/zalando/postgres-operator/raw/v1.13.0/charts/postgres-operator/crds/postgresqls.yaml - - https://github.com/zalando/postgres-operator/raw/v1.13.0/charts/postgres-operator/crds/postgresteams.yaml - + - https://github.com/zalando/postgres-operator/raw/v1.15.1/charts/postgres-operator/crds/operatorconfigurations.yaml + - https://github.com/zalando/postgres-operator/raw/v1.15.1/charts/postgres-operator/crds/postgresqls.yaml + - https://github.com/zalando/postgres-operator/raw/v1.15.1/charts/postgres-operator/crds/postgresteams.yaml + serverSideApply: "false" - name: postgres-operator required: true only: @@ -38,13 +42,13 @@ components: - ./values/registry1-config-values.yaml images: # Iron Bank - - registry1.dso.mil/ironbank/opensource/zalando/postgres-operator:v1.13.0 - - registry1.dso.mil/ironbank/opensource/zalando/logical-backup:v1.8.2 - - registry1.dso.mil/ironbank/opensource/zalando/pgbouncer:1.21.0 + - registry1.dso.mil/ironbank/opensource/zalando/postgres-operator:v1.15.0 + - registry1.dso.mil/ironbank/opensource/zalando/logical-backup:v1.15.1 + - registry1.dso.mil/ironbank/opensource/zalando/pgbouncer:1.25.1 # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA - - ghcr.io/zalando/spilo-15:3.2-p1 + - ghcr.io/zalando/spilo-17:4.0-p3 # Container image that provides the postgres-exporter sidecar to create a metrics endpoint - - registry1.dso.mil/ironbank/opensource/prometheus/postgres-exporter:v0.15.0 + - registry1.dso.mil/ironbank/opensource/prometheus/postgres-exporter:v0.19.1 - name: postgres-operator required: true @@ -60,13 +64,13 @@ components: valuesFiles: - ./values/upstream-config-values.yaml images: - - ghcr.io/zalando/postgres-operator:v1.13.0 - - ghcr.io/zalando/postgres-operator/logical-backup:v1.13.0 - - docker.io/bitnami/pgbouncer:1.23.1 + - ghcr.io/zalando/postgres-operator:v1.15.1 + - ghcr.io/zalando/postgres-operator/logical-backup:v1.15.1 + - registry.opensource.zalan.do/acid/pgbouncer:master-32 # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA - - ghcr.io/zalando/spilo-15:3.2-p1 + - ghcr.io/zalando/spilo-17:4.0-p3 # Container image that provides the postgres-exporter sidecar to create a metrics endpoint - - quay.io/prometheuscommunity/postgres-exporter:v0.15.0 + - quay.io/prometheuscommunity/postgres-exporter:v0.19.1 - name: postgres-operator required: true @@ -81,11 +85,19 @@ components: - name: uds-postgres-config valuesFiles: - ./values/unicorn-config-values.yaml + manifests: + # Pepr module that configures the chainguard pgbouncer connection pooler + - name: pepr-pgbouncer + namespace: pepr-system + files: + - ./manifests/pepr-module-pgbouncer.yaml images: - - cgr.dev/du-uds-defenseunicorns/postgres-operator-fips:1.13.0 - - ghcr.io/zalando/postgres-operator/logical-backup:v1.13.0 - - cgr.dev/du-uds-defenseunicorns/pgbouncer-fips:1.22.1 + - cgr.dev/defenseunicorns.com/postgres-operator-fips:v1.15.1 + - quay.io/rfcurated/zalando/postgres-operator/logical-backup:1.15-jammy-scratch-fips-rfcurated + - cgr.dev/defenseunicorns.com/pgbouncer-fips:v1.25.2 # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA - - ghcr.io/zalando/spilo-15:3.2-p1 + - cgr.dev/defenseunicorns.com/spilo-17:v4.1.2 # Container image that provides the postgres-exporter sidecar to create a metrics endpoint - - cgr.dev/du-uds-defenseunicorns/prometheus-postgres-exporter-fips:0.15.0 + - cgr.dev/defenseunicorns.com/prometheus-postgres-exporter-fips:v0.19.1 + # Pepr controller for the pgbouncer pooler config module + - ghcr.io/defenseunicorns/pepr/private/controller:v1.2.1 From a6986470e3cbd7d62573fa85d11c77e73e3b06f7 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 13:54:17 -0400 Subject: [PATCH 05/12] feat(pepr): enhance pgbouncer module documentation and update build tasks --- src/pepr/README.md | 64 ++++++++++++++++++++++++++------------ tasks.yaml | 10 ++---- values/unicorn-values.yaml | 2 +- zarf.yaml | 2 +- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/pepr/README.md b/src/pepr/README.md index df1ae8b..c6da416 100644 --- a/src/pepr/README.md +++ b/src/pepr/README.md @@ -1,21 +1,45 @@ -# Pepr Module - -This is a Pepr Module. [Pepr](https://github.com/defenseunicorns/pepr) is a type-safe Kubernetes middleware system. - -The `capabilities` directory contains all the capabilities for this module. By default, -a capability is a single typescript file in the format of `capability-name.ts` that is -imported in the root `pepr.ts` file as `import { HelloPepr } from "./capabilities/hello-pepr";`. -Because this is typescript, you can organize this however you choose, e.g. creating a sub-folder -per-capability or common logic in shared files or folders. - -Example Structure: - -```text -Module Root -├── package.json -├── pepr.ts -└── capabilities - ├── example-one.ts - ├── example-three.ts - └── example-two.ts +# pepr-pgbouncer + +A [Pepr](https://github.com/defenseunicorns/pepr) module that makes the Zalando postgres-operator's connection pooler work when the pooler image is a **distroless** PgBouncer (the `unicorn` flavor of this package). + +## Why this exists + +The Zalando operator launches the connection-pooler container with **only an image and environment variables — no `command`/`args`** — and relies on the image's entrypoint to render `/etc/pgbouncer/pgbouncer.ini` (and `userlist.txt`) from those env vars and then exec PgBouncer. + +The `unicorn` flavor uses Chainguard's distroless `pgbouncer-fips` image, which is the bare `/usr/bin/pgbouncer` binary — no entrypoint script, no template, no shell. This module adds the missing pieces (config, auth file, and the launch command). + +> [!NOTE] +> Currently Only the `unicorn` flavor ships this module. +> The `registry1` flavor needs a similar patch. + +## What it does + +The module has one capability, `pgbouncer-pooler` (namespace `postgres`), with three handlers in `capabilities/pgbouncer-pooler.ts`: + +1. **Reconciler — derive the PgBouncer auth file** (`Watch`/`Reconcile` on the pooler credential `Secret`). When the operator creates `pooler.pg-cluster.credentials.postgresql.acid.zalan.do`, this reads the `username`/`password` and writes a derived Secret **`pgbouncer-userlist`** whose `userlist.txt` key holds the PgBouncer `auth_file` line `"pooler" ""`. The derived Secret is owner-referenced to the source Secret so it is garbage-collected with the cluster. (The distroless image can't transform the raw password into the auth-file format at runtime, so we do it here.) + +2. **Mutator — wire up the pooler container** (`Mutate` admission on pooler `Deployment`s, selected by label `application: db-connection-pooler`). Idempotently, on `containers[0]` (the `connection-pooler` container): + 1. mounts a projected volume at `/etc/pgbouncer` combining the **`pgbouncer-config`** ConfigMap's `pgbouncer.ini` (shipped by the `uds-postgres-config` Helm chart) and the **`pgbouncer-userlist`** Secret's `userlist.txt` + 2. sets `command: ["/usr/bin/pgbouncer", "/etc/pgbouncer/pgbouncer.ini"]`. +3. Because admission mutation re-applies on every operator write, the configuration is restored automatically and there is no reconcile-drift window. `failurePolicy` is `Ignore` so a webhook outage can never block the operator from managing the cluster. +4. **Bootstrap — fix pre-existing pooler Deployments** (`Reconcile` on pooler `Deployment`s). A `Mutate` webhook only fires on create/update, so a pooler Deployment that already existed before this module was installed would never be mutated until the operator next wrote it. On module startup the reconciler finds any pooler Deployment **missing** the `pgbouncer` volume (`needsBootstrap`) and touches a pod-template annotation, which triggers an update that the Mutator then enriches. A guard skips Deployments that are already configured, so it runs at most once per Deployment. + +## How it fits with the rest of the package + +- The static `pgbouncer.ini` lives in the `uds-postgres-config` chart (`chart/templates/pgbouncer-config.yaml`, ConfigMap `pgbouncer-config`, rendered only when `postgresql.poolerConfig.enabled` is true). It uses `auth_type = scram-sha-256` with `auth_query`/`auth_user = pooler`, `server_tls_sslmode = require` for PgBouncer→Postgres, and no client TLS (app→PgBouncer encryption is provided by the Istio service mesh). +- The built module manifest is committed at `manifests/pepr-module-pgbouncer.yaml` and referenced by the `unicorn` component in `zarf.yaml`. The shared `pepr-system` namespace is stripped from that manifest so removing this package never deletes the namespace shared with `pepr-uds-core`. + +See `docs/configuration.md` ("Connection Pooler") for the full design, encryption/auth details, tunables, and the known replica-pooler limitation. + +## Build & test + +```bash +# Build the module manifest into dist/ and copy it to the repo-root manifests/ +# (also run automatically during `zarf package create --flavor unicorn`): +uds run build-pepr + +# Unit tests: +cd src/pepr && npx vitest run ``` + +Building requires Node.js 20+ on the host (`uds run build-pepr` uses `uds zarf tools yq` for the namespace strip, and the deployed controller image is pinned in `zarf.yaml` via `--custom-image`; keep that in sync if it changes. diff --git a/tasks.yaml b/tasks.yaml index 4386df4..2ff1a83 100644 --- a/tasks.yaml +++ b/tasks.yaml @@ -30,20 +30,14 @@ tasks: - name: build-pepr description: | - Build the pgbouncer Pepr module manifest into src/pepr/dist (gitignored). - For local iteration only — `zarf package create --flavor unicorn` runs this - automatically via the unicorn component's onCreate action. Requires Node.js 20+ and yq. + Build the pgbouncer Pepr module manifest and copy it to the repo-root /manifests directory. actions: - description: "Build the pgbouncer Pepr module" dir: src/pepr cmd: | npm ci --no-audit --no-fund npx pepr build --custom-image ghcr.io/defenseunicorns/pepr/private/controller:v1.2.1 - # Strip the shared pepr-system Namespace (owned by uds-core) so package removal - # never cascade-deletes it. See zarf.yaml onCreate for the rationale. - yq ea -i 'select(.kind != "Namespace")' dist/pepr-module-pgbouncer.yaml - # Copy the built manifest to the repo-root manifests/ dir so it can be committed - # (cmd runs in src/pepr, so the root is two levels up). + uds zarf tools yq ea -i 'select(.kind != "Namespace")' dist/pepr-module-pgbouncer.yaml mkdir -p ../../manifests cp dist/pepr-module-pgbouncer.yaml ../../manifests/pepr-module-pgbouncer.yaml diff --git a/values/unicorn-values.yaml b/values/unicorn-values.yaml index 339764c..f3398a8 100644 --- a/values/unicorn-values.yaml +++ b/values/unicorn-values.yaml @@ -8,6 +8,6 @@ image: configConnectionPooler: connection_pooler_image: "cgr.dev/defenseunicorns.com/pgbouncer-fips:v1.25.2" configLogicalBackup: - logical_backup_docker_image: "quay.io/rfcurated/zalando/postgres-operator/logical-backup:1.15-jammy-scratch-fips-rfcurated" + logical_backup_docker_image: "registry1.dso.mil/ironbank/opensource/zalando/logical-backup:v1.15.1" configGeneral: docker_image: "cgr.dev/defenseunicorns.com/spilo-17:v4.1.2" diff --git a/zarf.yaml b/zarf.yaml index fce3d3a..a2d8eb4 100644 --- a/zarf.yaml +++ b/zarf.yaml @@ -93,7 +93,7 @@ components: - ./manifests/pepr-module-pgbouncer.yaml images: - cgr.dev/defenseunicorns.com/postgres-operator-fips:v1.15.1 - - quay.io/rfcurated/zalando/postgres-operator/logical-backup:1.15-jammy-scratch-fips-rfcurated + - registry1.dso.mil/ironbank/opensource/zalando/logical-backup:v1.15.1 - cgr.dev/defenseunicorns.com/pgbouncer-fips:v1.25.2 # Docker image that provides PostgreSQL and Patroni bundled together for PostgreSQL HA - cgr.dev/defenseunicorns.com/spilo-17:v4.1.2 From 93e759ff4b78b92daa9cc829317ab0e4daa868bf Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 13:58:30 -0400 Subject: [PATCH 06/12] feat: remove unused configuration files and add copyright headers --- .serena/.gitignore | 2 - .serena/project.yml | 132 ------------------ .yamllint | 1 - .../capabilities/pgbouncer-pooler.test.ts | 3 + src/pepr/capabilities/pgbouncer-pooler.ts | 3 + src/pepr/eslint.config.mjs | 3 + src/pepr/pepr.ts | 3 + tests/postgres/pooler-connection-test.yaml | 2 +- 8 files changed, 13 insertions(+), 136 deletions(-) delete mode 100644 .serena/.gitignore delete mode 100644 .serena/project.yml diff --git a/.serena/.gitignore b/.serena/.gitignore deleted file mode 100644 index 2e510af..0000000 --- a/.serena/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/cache -/project.local.yml diff --git a/.serena/project.yml b/.serena/project.yml deleted file mode 100644 index 5ba3331..0000000 --- a/.serena/project.yml +++ /dev/null @@ -1,132 +0,0 @@ -# the name by which the project can be referenced within Serena -project_name: "postgres-operator" - - -# list of languages for which language servers are started; choose from: -# al angular ansible bash clojure -# cpp cpp_ccls crystal csharp csharp_omnisharp -# dart elixir elm erlang fortran -# fsharp go groovy haskell haxe -# hlsl html java json julia -# kotlin lean4 lua luau markdown -# matlab msl nix ocaml pascal -# perl php php_phpactor powershell python -# python_jedi python_ty r rego ruby -# ruby_solargraph rust scala scss solidity -# svelte swift systemverilog terraform toml -# typescript typescript_vts vue yaml zig -# (This list may be outdated. For the current list, see values of Language enum here: -# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py -# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) -# Note: -# - For C, use cpp -# - For JavaScript, use typescript -# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) -# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) -# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) -# - For Free Pascal/Lazarus, use pascal -# Special requirements: -# Some languages require additional setup/installations. -# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers -# When using multiple languages, the first language server that supports a given file will be used for that file. -# The first language is the default language and the respective language server will be used as a fallback. -# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. -languages: [] - -# the encoding used by text files in the project -# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings -encoding: "utf-8" - -# line ending convention to use when writing source files. -# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) -# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. -line_ending: - -# The language backend to use for this project. -# If not set, the global setting from serena_config.yml is used. -# Valid values: LSP, JetBrains -# Note: the backend is fixed at startup. If a project with a different backend -# is activated post-init, an error will be returned. -language_backend: - -# whether to use project's .gitignore files to ignore files -ignore_all_files_in_gitignore: true - -# advanced configuration option allowing to configure language server-specific options. -# Maps the language key to the options. -# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. -# No documentation on options means no options are available. -ls_specific_settings: {} - -# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). -# Paths can be absolute or relative to the project root. -# Each folder is registered as an LSP workspace folder, enabling language servers to discover -# symbols and references across package boundaries. -# Currently supported for: TypeScript. -# Example: -# additional_workspace_folders: -# - ../sibling-package -# - ../shared-lib -additional_workspace_folders: [] - -# list of additional paths to ignore in this project. -# Same syntax as gitignore, so you can use * and **. -# Note: global ignored_paths from serena_config.yml are also applied additively. -ignored_paths: [] - -# whether the project is in read-only mode -# If set to true, all editing tools will be disabled and attempts to use them will result in an error -# Added on 2025-04-18 -read_only: false - -# list of tool names to exclude. -# This extends the existing exclusions (e.g. from the global configuration) -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -excluded_tools: [] - -# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). -# This extends the existing inclusions (e.g. from the global configuration). -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -included_optional_tools: [] - -# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. -# This cannot be combined with non-empty excluded_tools or included_optional_tools. -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -fixed_tools: [] - -# list of mode names that are to be activated by default, overriding the setting in the global configuration. -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. -# Otherwise, this overrides the setting from the global configuration (serena_config.yml). -# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply -# for this project. -# This setting can, in turn, be overridden by CLI parameters (--mode). -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -default_modes: - -# list of mode names to be activated additionally for this project, e.g. ["query-projects"] -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -added_modes: - -# initial prompt for the project. It will always be given to the LLM upon activating the project -# (contrary to the memories, which are loaded on demand). -initial_prompt: "" - -# time budget (seconds) per tool call for the retrieval of additional symbol information -# such as docstrings or parameter information. -# This overrides the corresponding setting in the global configuration; see the documentation there. -# If null or missing, use the setting from the global configuration. -symbol_info_budget: - -# list of regex patterns which, when matched, mark a memory entry as read‑only. -# Extends the list from the global configuration, merging the two lists. -read_only_memory_patterns: [] - -# list of regex patterns for memories to completely ignore. -# Matching memories will not appear in list_memories or activate_project output -# and cannot be accessed via read_memory or write_memory. -# To access ignored memory files, use the read_file tool on the raw file path. -# Extends the list from the global configuration, merging the two lists. -# Example: ["_archive/.*", "_episodes/.*"] -ignored_memory_patterns: [] diff --git a/.yamllint b/.yamllint index 0b01b80..6df21b3 100644 --- a/.yamllint +++ b/.yamllint @@ -6,7 +6,6 @@ yaml-files: ignore: - '**/chart/templates**' - rules: anchors: enable braces: enable diff --git a/src/pepr/capabilities/pgbouncer-pooler.test.ts b/src/pepr/capabilities/pgbouncer-pooler.test.ts index 957dbdc..cc91a1d 100644 --- a/src/pepr/capabilities/pgbouncer-pooler.test.ts +++ b/src/pepr/capabilities/pgbouncer-pooler.test.ts @@ -1,3 +1,6 @@ +// Copyright 2024 Defense Unicorns +// SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + import { describe, it, expect } from "vitest"; import { a } from "pepr"; import { renderUserlist, applyPoolerPatch, needsBootstrap } from "./pgbouncer-pooler"; diff --git a/src/pepr/capabilities/pgbouncer-pooler.ts b/src/pepr/capabilities/pgbouncer-pooler.ts index 4445d2c..d661fc0 100644 --- a/src/pepr/capabilities/pgbouncer-pooler.ts +++ b/src/pepr/capabilities/pgbouncer-pooler.ts @@ -1,3 +1,6 @@ +// Copyright 2024 Defense Unicorns +// SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + import { Capability, a, K8s, kind, Log } from "pepr"; export const Pgbouncer = new Capability({ diff --git a/src/pepr/eslint.config.mjs b/src/pepr/eslint.config.mjs index 4035e23..39f7381 100644 --- a/src/pepr/eslint.config.mjs +++ b/src/pepr/eslint.config.mjs @@ -1,3 +1,6 @@ +// Copyright 2024 Defense Unicorns +// SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + import typescriptEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; import path from "node:path"; diff --git a/src/pepr/pepr.ts b/src/pepr/pepr.ts index 74a586d..d422043 100644 --- a/src/pepr/pepr.ts +++ b/src/pepr/pepr.ts @@ -1,3 +1,6 @@ +// Copyright 2024 Defense Unicorns +// SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + import { PeprModule } from "pepr"; import cfg from "./package.json"; import { Pgbouncer } from "./capabilities/pgbouncer-pooler"; diff --git a/tests/postgres/pooler-connection-test.yaml b/tests/postgres/pooler-connection-test.yaml index e0d799d..af80213 100644 --- a/tests/postgres/pooler-connection-test.yaml +++ b/tests/postgres/pooler-connection-test.yaml @@ -100,4 +100,4 @@ spec: - name: DB_HOST value: pg-cluster-pooler-repl.postgres.svc.cluster.local - name: DB_NAME - value: gitlabdb \ No newline at end of file + value: gitlabdb From 5fb70c96b0b84ec88eb1c7c478ae361361c3b938 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 13:59:24 -0400 Subject: [PATCH 07/12] docs(pepr): properly documented Pepr module --- bundle/uds-config.yaml | 2 ++ manifests/pepr-module-pgbouncer.yaml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/bundle/uds-config.yaml b/bundle/uds-config.yaml index e69de29..2067cc5 100644 --- a/bundle/uds-config.yaml +++ b/bundle/uds-config.yaml @@ -0,0 +1,2 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial diff --git a/manifests/pepr-module-pgbouncer.yaml b/manifests/pepr-module-pgbouncer.yaml index fa87938..39ba122 100644 --- a/manifests/pepr-module-pgbouncer.yaml +++ b/manifests/pepr-module-pgbouncer.yaml @@ -1,3 +1,6 @@ +# Copyright 2024 Defense Unicorns +# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: From 92eeb9d64ee79bb4572515a46cf70822df6cbfae Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 16:24:43 -0400 Subject: [PATCH 08/12] feat(pg-bouncer): implement FIPS connection pooler via Pepr module - Add support for enabling connection pooling in the PostgreSQL Helm chart. - Introduce a new Pepr module to mutate pooler deployments and reconcile userlist secrets. - Update Helm templates to include a static pgbouncer.ini ConfigMap for FIPS compliance. - Modify Zarf configuration to deploy the new Pepr module only for the unicorn flavor. - Remove outdated design and implementation plans from documentation. - Add tests for the new functionality, ensuring proper deployment and configuration of the pooler. --- ...2-configure-distroless-pooler-with-pepr.md | 31 + bundle/uds-bundle.yaml | 5 + chart/templates/pgbouncer-config.yaml | 4 +- chart/templates/uds-package-postgres.yaml | 3 - chart/values.yaml | 3 +- common/zarf.yaml | 4 +- .../2026-06-03-pgbouncer-fips-pooler-pepr.md | 625 ------------------ ...06-03-pgbouncer-fips-pooler-pepr-design.md | 191 ------ 8 files changed, 40 insertions(+), 826 deletions(-) create mode 100644 adr/0002-configure-distroless-pooler-with-pepr.md delete mode 100644 docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md delete mode 100644 docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md diff --git a/adr/0002-configure-distroless-pooler-with-pepr.md b/adr/0002-configure-distroless-pooler-with-pepr.md new file mode 100644 index 0000000..f893eea --- /dev/null +++ b/adr/0002-configure-distroless-pooler-with-pepr.md @@ -0,0 +1,31 @@ +# 2. Configure the distroless connection pooler with a Pepr module + +Date: 2026-06-04 + +## Status + +Proposed + +## Context + +The Zalando postgres-operator launches the connection-pooler container with only an image and environment variables — no `command`/`args` — and relies on the image's entrypoint to render `pgbouncer.ini` (and the `userlist.txt` auth file) from those env vars and then exec PgBouncer. + +The `unicorn` flavor uses a distroless PgBouncer image (`pgbouncer-fips`) that is the bare binary with no entrypoint script, template, or shell. Launched argument-less it prints usage and exits, so the pooler crash-loops. The operator does not let us set the pooler container's command, volumes, or config, and it reconciles the pooler Deployment, so any manual patch is eventually reverted. + +We need a way to supply PgBouncer's config, auth file, and launch command that (a) works with a distroless image, (b) survives operator reconciliation, and (c) is coupled to this package's lifecycle. A one-shot `kubectl`/Job patch was rejected (the operator reverts it on its next write). + +## Decision + +We ship a [Pepr](https://github.com/defenseunicorns/pepr) module (`src/pepr`, capability `pgbouncer-pooler`), bundled as a manifest in the `unicorn` component, that: + +1. reconciles the operator's pooler credential Secret into a derived `pgbouncer-userlist` Secret (the PgBouncer `auth_file`), +2. mutates each pooler Deployment to mount that Secret plus a chart-shipped `pgbouncer-config` ConfigMap at `/etc/pgbouncer` and to set the PgBouncer launch command, and +3. bootstraps pre-existing pooler Deployments on startup so the mutation also applies when the module is installed onto a running cluster. + +The static `pgbouncer.ini` is rendered by the `uds-postgres-config` chart. Only the `unicorn` flavor ships the module; `registry1`/`upstream` use self-configuring PgBouncer images and need none of it. + +## Consequences + +The distroless FIPS pooler now starts and proxies correctly, and because admission mutation re-applies on every operator write there is no reconcile-drift window (`failurePolicy: Ignore` keeps a webhook outage from blocking the operator). + +This adds a TypeScript/Node module and a long-lived Pepr controller (admission webhook) to a previously YAML-only package — new build tooling (Node.js, `pepr build`) and an additional component to maintain. The built manifest is committed at `manifests/pepr-module-pgbouncer.yaml`; its shared `pepr-system` Namespace is stripped so package removal does not affect `pepr-uds-core`. The replica pooler is not yet supported (the rendered config targets the primary), and `registry1` would need a similar approach if it ever moves to a distroless pooler image. diff --git a/bundle/uds-bundle.yaml b/bundle/uds-bundle.yaml index ccb256b..b558247 100644 --- a/bundle/uds-bundle.yaml +++ b/bundle/uds-bundle.yaml @@ -51,3 +51,8 @@ packages: remoteSelector: cluster-name: pg-cluster description: "Egress to a non-default pg cluster" + values: + - path: enableConnectionPooler + value: true + - path: enableReplicaConnectionPooler + value: true diff --git a/chart/templates/pgbouncer-config.yaml b/chart/templates/pgbouncer-config.yaml index 33e5270..01e961b 100644 --- a/chart/templates/pgbouncer-config.yaml +++ b/chart/templates/pgbouncer-config.yaml @@ -1,9 +1,7 @@ # Copyright 2024 Defense Unicorns # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial -{{- /* poolerConfig has no defaults in values.yaml; gate is nil-safe and each value - falls back to a sensible default below, overridable via postgresql.poolerConfig.* */}} -{{- if and .Values.postgresql.enabled (dig "poolerConfig" "enabled" false .Values.postgresql) }} +{{- if and .Values.postgresql.enabled (or .Values.postgresql.enableConnectionPooler .Values.postgresql.enableReplicaConnectionPooler) }} {{- $p := .Values.postgresql.poolerConfig | default dict }} apiVersion: v1 kind: ConfigMap diff --git a/chart/templates/uds-package-postgres.yaml b/chart/templates/uds-package-postgres.yaml index 76bf802..3ffd243 100644 --- a/chart/templates/uds-package-postgres.yaml +++ b/chart/templates/uds-package-postgres.yaml @@ -51,9 +51,6 @@ spec: cluster-name: pg-cluster remoteGenerated: KubeAPI - {{- /* Pooler (pgbouncer) traffic. Zalando labels pooler pods with - `application=db-connection-pooler`. IntraNamespace rules above - already cover pooler <-> spilo traffic within this namespace. */}} {{- if or (.Values.postgresql.enableConnectionPooler | default false) (.Values.postgresql.enableReplicaConnectionPooler | default false) }} {{- if kindIs "slice" .Values.postgresql.ingress -}} {{- range .Values.postgresql.ingress }} diff --git a/chart/values.yaml b/chart/values.yaml index 7525cd6..09606c2 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -19,9 +19,8 @@ postgresql: # Connection pooler options # Ref: https://opensource.zalando.com/postgres-operator/docs/user.html#connection-pooler - enableConnectionPooler: true + enableConnectionPooler: false enableReplicaConnectionPooler: false - connectionPooler: {} # Example values for postgresql # diff --git a/common/zarf.yaml b/common/zarf.yaml index b454be0..df7fc68 100644 --- a/common/zarf.yaml +++ b/common/zarf.yaml @@ -41,7 +41,7 @@ components: maxTotalSeconds: 300 cmd: | if ./zarf tools kubectl get packages.uds.dev postgres -n postgres; then - ./zarf tools wait-for packages.uds.dev postgres -n postgres '{.status.phase}'=Ready + ./zarf tools wait-for resource packages.uds.dev postgres -n postgres '{.status.phase}'=Ready fi - description: Postgres Operator to be Healthy maxTotalSeconds: 90 @@ -55,5 +55,5 @@ components: maxTotalSeconds: 300 cmd: | if ./zarf tools kubectl get postgresql pg-cluster -n postgres; then - ./zarf tools wait-for postgresql pg-cluster -n postgres '{.status.PostgresClusterStatus}'=Running + ./zarf tools wait-for resource postgresql pg-cluster -n postgres '{.status.PostgresClusterStatus}'=Running fi diff --git a/docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md b/docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md deleted file mode 100644 index 90665fa..0000000 --- a/docs/superpowers/plans/2026-06-03-pgbouncer-fips-pooler-pepr.md +++ /dev/null @@ -1,625 +0,0 @@ -# FIPS Connection Pooler via Pepr Module — Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Make the Zalando connection pooler work on the `unicorn` flavor's distroless `pgbouncer-fips` image by shipping a Pepr module that supplies pgbouncer's config + auth and sets its launch command. - -**Architecture:** The Helm chart ships a static `pgbouncer.ini` ConfigMap (unicorn-gated). A flavor-gated Pepr module (1) reconciles the operator's pooler credential Secret into a derived `userlist.txt` Secret, and (2) mutates each operator-created pooler Deployment to mount both via a projected volume at `/etc/pgbouncer` and set `command: ["/usr/bin/pgbouncer","/etc/pgbouncer/pgbouncer.ini"]`. Admission mutation re-applies on every operator write, so there is no reconcile-drift window. - -**Tech Stack:** Pepr (TypeScript admission/reconcile framework), Helm, Zarf, the Zalando postgres-operator, pgbouncer. - -**Source of truth:** Design spec at `docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md`. Upstream reference: `zalando/postgres-operator` `pooler/pgbouncer.ini.tmpl` + `pooler/entrypoint.sh`. - -**Note on commits:** Commit steps below are written per the skill's TDD cadence for execution time. The current session has been instructed not to commit — honor that; the executor commits per repo/user preference. - ---- - -## Pre-flight facts (do not re-derive) - -- Pooler container is `containers[0]`, name `connection-pooler`; pods labeled `application: db-connection-pooler`. Deployments: `pg-cluster-pooler`, `pg-cluster-pooler-repl`. Namespace `postgres`. -- Pooler user/schema = `pooler`/`pooler`; source Secret `pooler.pg-cluster.credentials.postgresql.acid.zalan.do` (keys `username`, `password`, base64). -- Cluster is `scram-sha-256`; pg_hba rejects non-SSL, so `server_tls_sslmode = require`. -- Distroless binary path: `/usr/bin/pgbouncer`. We omit `logfile`/`pidfile` (log to stderr, run in foreground) so the container needs no writable dirs; config mounts are read-only. -- Operator installs `pooler.user_lookup(...)` in each DB regardless of image, so `auth_query` works. - ---- - -## File structure - -- Create `src/pepr/package.json` — module manifest + Pepr dep + scripts. -- Create `src/pepr/pepr.ts` — module entrypoint registering the capability. -- Create `src/pepr/capabilities/pgbouncer-fips-pooler.ts` — Reconciler + Mutator. -- Create `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts` — unit tests. -- Create `chart/templates/pgbouncer-config.yaml` — `pgbouncer.ini` ConfigMap (unicorn-gated). -- Modify `chart/values.yaml` — add `postgresql.poolerFipsConfig` defaults block. -- Modify `values/unicorn-values.yaml` — enable `postgresql.poolerFipsConfig`. -- Modify `zarf.yaml` — add Pepr component + image, gated `only.flavor: unicorn`. -- Modify `docs/configuration.md` — document FIPS-flavor pooler behavior. -- Modify `renovate.json` — track the Pepr controller image. -- Modify `tests/postgres/` + `tasks/test.yaml` — e2e regression for unicorn pooler. - ---- - -## Task 0: Confirm FIPS Pepr controller image (prerequisite gate) - -**Files:** none (investigation; record result in the spec's Risks section). - -- [ ] **Step 1: Identify the Pepr image uds-core ships** - -Run: -```bash -# Inspect a running uds-core install or its package definition for the pepr image -kubectl -n pepr-system get deploy -o jsonpath='{.items[*].spec.template.spec.containers[*].image}' 2>/dev/null; echo -# and/or check the pepr controller image tag uds-core pins -``` -Expected: a `ghcr.io/defenseunicorns/pepr/controller:vX.Y.Z` (or registry1/cgr FIPS variant) reference. - -- [ ] **Step 2: Decide image source** - -If a FIPS/registry1 Pepr controller image is available, record its reference for use in `zarf.yaml` (Task 5). If NOT available, STOP and revisit the design with the user — the lift/image-sourcing changes. Do not proceed past this gate without a usable image. - -**GATE RESULT (2026-06-03):** PASSED. uds-core runs `ghcr.io/defenseunicorns/pepr/controller:v1.2.0` in the live `k3d-uds` cluster (`pepr-system/pepr-uds-core`). Use that image for dev/test; the unicorn-flavor FIPS variant (cgr/registry1 Pepr controller) is a `zarf.yaml` packaging detail to finalize in Task 5, non-blocking for build/test. **Pepr is v1.x — pin the npm `pepr` dep to `1.2.0`, not `0.x`.** The live `pg-cluster-pooler` is in CrashLoopBackOff, so the fix is verifiable end-to-end here. - ---- - -## Task 1: Scaffold the Pepr module - -**Files:** -- Create: `src/pepr/package.json` -- Create: `src/pepr/pepr.ts` - -- [ ] **Step 1: Create `src/pepr/package.json`** - -```json -{ - "name": "pepr-pgbouncer-fips", - "version": "0.0.1", - "description": "Configures the distroless pgbouncer-fips connection pooler for the Zalando postgres-operator", - "keywords": ["pepr", "k8s", "policy-engine"], - "pepr": { - "uuid": "pgbouncer-fips", - "onError": "ignore", - "webhookTimeout": 10, - "alwaysIgnore": { "namespaces": [] }, - "includedFiles": [] - }, - "scripts": { - "test": "vitest run", - "build": "pepr build" - }, - "dependencies": { - "pepr": "1.2.0" - }, - "devDependencies": { - "vitest": "^1.6.0" - } -} -``` - -Note: Prefer scaffolding with `npx pepr@1.2.0 init` (non-interactive flags: `--name pepr-pgbouncer-fips --uuid pgbouncer-fips --errorBehavior ignore --skip-post-init --yes` — adjust flags to the 1.2.0 CLI) so the generated `package.json`/`pepr.ts` match the v1.2.0 format exactly; then reconcile with the fields shown above. `onError: ignore` maps to `failurePolicy: Ignore` per the design. Pin `pepr` to `1.2.0` to match the controller image from Task 0. - -- [ ] **Step 2: Create `src/pepr/pepr.ts`** - -```typescript -import { PeprModule } from "pepr"; -// eslint-disable-next-line @typescript-eslint/no-var-requires -import cfg from "./package.json"; -import { PgbouncerFips } from "./capabilities/pgbouncer-fips-pooler"; - -new PeprModule(cfg, [PgbouncerFips]); -``` - -- [ ] **Step 3: Install deps and verify Pepr CLI works** - -Run: -```bash -cd src/pepr && npm install && npx pepr --version -``` -Expected: prints the Pepr version (matches Task 0 image). - -- [ ] **Step 4: Commit** - -```bash -git add src/pepr/package.json src/pepr/pepr.ts src/pepr/package-lock.json -git commit -m "feat(pepr): scaffold pgbouncer-fips module" -``` - ---- - -## Task 2: Ship the static `pgbouncer.ini` ConfigMap (chart) - -**Files:** -- Create: `chart/templates/pgbouncer-config.yaml` -- Modify: `chart/values.yaml` -- Modify: `values/unicorn-values.yaml` - -- [ ] **Step 1: Add values defaults to `chart/values.yaml`** - -Under the `postgresql:` block, add: - -```yaml - # FIPS pooler config: rendered only when true (set by the unicorn flavor). - # The distroless pgbouncer-fips image has no entrypoint to build pgbouncer.ini, - # so we ship it here and the pepr module mounts it. - poolerFipsConfig: - enabled: false - listenPort: 5432 - poolMode: transaction - defaultPoolSize: 20 - reservePoolSize: 10 - maxClientConn: 10000 - maxDBConnections: 60 -``` - -- [ ] **Step 2: Enable it in `values/unicorn-values.yaml`** - -Under `postgresql:` add: - -```yaml - poolerFipsConfig: - enabled: true -``` - -- [ ] **Step 3: Create `chart/templates/pgbouncer-config.yaml`** - -```yaml -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -{{- if and .Values.postgresql.enabled .Values.postgresql.poolerFipsConfig.enabled }} -{{- $p := .Values.postgresql.poolerFipsConfig }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: pgbouncer-config - namespace: postgres -data: - pgbouncer.ini: | - [databases] - * = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler - postgres = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler - - [pgbouncer] - pool_mode = {{ $p.poolMode }} - listen_port = {{ $p.listenPort }} - listen_addr = * - admin_users = pooler - auth_dbname = postgres - auth_file = /etc/pgbouncer/userlist.txt - auth_query = SELECT * FROM pooler.user_lookup($1) - auth_type = scram-sha-256 - server_tls_sslmode = require - log_connections = 0 - log_disconnections = 0 - max_prepared_statements = 200 - default_pool_size = {{ $p.defaultPoolSize }} - reserve_pool_size = {{ $p.reservePoolSize }} - max_client_conn = {{ $p.maxClientConn }} - max_db_connections = {{ $p.maxDBConnections }} - idle_transaction_timeout = 600 - server_login_retry = 5 - ignore_startup_parameters = extra_float_digits,options -{{- end }} -``` - -Notes vs upstream template: `auth_type` is `scram-sha-256` (cluster uses scram, not md5); client TLS lines and `server_tls_ca_file` removed (mesh mTLS for clients; `require` needs no CA); `logfile`/`pidfile` removed (stderr + foreground, no writable dirs); `min_pool_size` left out (upstream comments it out). - -- [ ] **Step 4: Render-test ConfigMap presence (unicorn) and absence (upstream)** - -Run: -```bash -helm template chart -f chart/values.yaml -f values/unicorn-values.yaml \ - --set postgresql.enabled=true --set postgresql.volume.size=10Gi \ - --set metrics.image=foo --set metrics.tag=bar \ - --show-only templates/pgbouncer-config.yaml 2>&1 | grep -c "auth_type = scram-sha-256" -``` -Expected: `1`. - -Run: -```bash -helm template chart -f chart/values.yaml -f values/upstream-values.yaml \ - --set postgresql.enabled=true --set postgresql.volume.size=10Gi \ - --set metrics.image=foo --set metrics.tag=bar \ - --show-only templates/pgbouncer-config.yaml 2>&1 | grep -c "kind: ConfigMap" || true -``` -Expected: `0` (template renders empty for non-unicorn). - -- [ ] **Step 5: Commit** - -```bash -git add chart/templates/pgbouncer-config.yaml chart/values.yaml values/unicorn-values.yaml -git commit -m "feat(chart): add unicorn-gated pgbouncer.ini ConfigMap for FIPS pooler" -``` - ---- - -## Task 3: Pepr Reconciler — derived `userlist.txt` Secret - -**Files:** -- Create: `src/pepr/capabilities/pgbouncer-fips-pooler.ts` (Reconciler portion) -- Create: `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts` - -- [ ] **Step 1: Write the failing unit test for userlist rendering** - -`src/pepr/capabilities/pgbouncer-fips-pooler.test.ts`: - -```typescript -import { describe, it, expect } from "vitest"; -import { renderUserlist } from "./pgbouncer-fips-pooler"; - -describe("renderUserlist", () => { - it("formats a pgbouncer auth_file line from username/password", () => { - expect(renderUserlist("pooler", "s3cr3t")).toBe('"pooler" "s3cr3t"\n'); - }); - - it("escapes embedded double quotes in the password", () => { - expect(renderUserlist("pooler", 'pa"ss')).toBe('"pooler" "pa""ss"\n'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` -Expected: FAIL — `renderUserlist` is not exported / not defined. - -- [ ] **Step 3: Create the capability file with the Reconciler + `renderUserlist`** - -`src/pepr/capabilities/pgbouncer-fips-pooler.ts`: - -```typescript -import { Capability, a, K8s, kind, Log } from "pepr"; - -export const PgbouncerFips = new Capability({ - name: "pgbouncer-fips-pooler", - description: "Configures the distroless pgbouncer-fips connection pooler.", - namespaces: ["postgres"], -}); - -const { When } = PgbouncerFips; - -const SOURCE_SECRET = "pooler.pg-cluster.credentials.postgresql.acid.zalan.do"; -const DERIVED_SECRET = "pgbouncer-fips-userlist"; -const NS = "postgres"; - -// pgbouncer auth_file format: `"user" "password"` with "" escaping inside quotes. -export function renderUserlist(username: string, password: string): string { - const esc = (s: string) => s.replace(/"/g, '""'); - return `"${esc(username)}" "${esc(password)}"\n`; -} - -// Reconcile the operator's pooler credential Secret into a derived userlist Secret. -When(a.Secret) - .IsCreatedOrUpdated() - .InNamespace(NS) - .WithName(SOURCE_SECRET) - // Reconcile (not Watch): ordered, idempotent queue — the operator pattern for - // creating/owning derived resources. - .Reconcile(async secret => { - const data = secret.data ?? {}; - if (!data.username || !data.password) { - Log.warn(`${SOURCE_SECRET} missing username/password; skipping`); - return; - } - const username = Buffer.from(data.username, "base64").toString("utf8"); - const password = Buffer.from(data.password, "base64").toString("utf8"); - - await K8s(kind.Secret).Apply({ - metadata: { - name: DERIVED_SECRET, - namespace: NS, - ownerReferences: [ - { - apiVersion: "v1", - kind: "Secret", - name: secret.metadata!.name!, - uid: secret.metadata!.uid!, - controller: false, - blockOwnerDeletion: false, - }, - ], - }, - stringData: { "userlist.txt": renderUserlist(username, password) }, - }); - Log.info(`reconciled ${DERIVED_SECRET} from ${SOURCE_SECRET}`); - }); -``` - -- [ ] **Step 4: Run test to verify it passes** - -Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` -Expected: PASS (both `renderUserlist` cases). - -- [ ] **Step 5: Commit** - -```bash -git add src/pepr/capabilities/pgbouncer-fips-pooler.ts src/pepr/capabilities/pgbouncer-fips-pooler.test.ts -git commit -m "feat(pepr): reconcile pooler secret into pgbouncer userlist secret" -``` - ---- - -## Task 4: Pepr Mutator — inject config + command into the pooler Deployment - -**Files:** -- Modify: `src/pepr/capabilities/pgbouncer-fips-pooler.ts` (add Mutator + helper) -- Modify: `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts` (add mutation tests) - -- [ ] **Step 1: Write failing tests for the mutation helper** - -Append to `src/pepr/capabilities/pgbouncer-fips-pooler.test.ts`: - -```typescript -import { applyPoolerPatch } from "./pgbouncer-fips-pooler"; - -function poolerDeployment(): any { - return { - spec: { - template: { - spec: { - volumes: [], - containers: [{ name: "connection-pooler", image: "cgr.dev/x/pgbouncer-fips:v1", volumeMounts: [] }], - }, - }, - }, - }; -} - -describe("applyPoolerPatch", () => { - it("sets the pgbouncer command on containers[0]", () => { - const d = poolerDeployment(); - applyPoolerPatch(d); - expect(d.spec.template.spec.containers[0].command).toEqual([ - "/usr/bin/pgbouncer", - "/etc/pgbouncer/pgbouncer.ini", - ]); - }); - - it("adds a projected /etc/pgbouncer volume + mount", () => { - const d = poolerDeployment(); - applyPoolerPatch(d); - const vol = d.spec.template.spec.volumes.find((v: any) => v.name === "pgbouncer-fips"); - expect(vol.projected.sources).toHaveLength(2); - const mount = d.spec.template.spec.containers[0].volumeMounts.find( - (m: any) => m.name === "pgbouncer-fips", - ); - expect(mount.mountPath).toBe("/etc/pgbouncer"); - expect(mount.readOnly).toBe(true); - }); - - it("is idempotent (no duplicate volume/mount on second apply)", () => { - const d = poolerDeployment(); - applyPoolerPatch(d); - applyPoolerPatch(d); - expect(d.spec.template.spec.volumes.filter((v: any) => v.name === "pgbouncer-fips")).toHaveLength(1); - expect( - d.spec.template.spec.containers[0].volumeMounts.filter((m: any) => m.name === "pgbouncer-fips"), - ).toHaveLength(1); - }); -}); -``` - -- [ ] **Step 2: Run tests to verify they fail** - -Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` -Expected: FAIL — `applyPoolerPatch` not exported. - -- [ ] **Step 3: Add `applyPoolerPatch` + the Mutator to the capability file** - -Append to `src/pepr/capabilities/pgbouncer-fips-pooler.ts`: - -```typescript -const VOLUME = "pgbouncer-fips"; -const CONFIG_MAP = "pgbouncer-config"; - -// Pure, idempotent mutation of a pooler Deployment object. -export function applyPoolerPatch(d: any): void { - const podSpec = d?.spec?.template?.spec; - if (!podSpec || !Array.isArray(podSpec.containers) || podSpec.containers.length === 0) { - return; - } - podSpec.volumes = podSpec.volumes ?? []; - if (!podSpec.volumes.some((v: any) => v.name === VOLUME)) { - podSpec.volumes.push({ - name: VOLUME, - projected: { - sources: [ - { configMap: { name: CONFIG_MAP, items: [{ key: "pgbouncer.ini", path: "pgbouncer.ini" }] } }, - { secret: { name: DERIVED_SECRET, items: [{ key: "userlist.txt", path: "userlist.txt" }] } }, - ], - }, - }); - } - - const c = podSpec.containers[0]; // connection-pooler is containers[0] - c.volumeMounts = c.volumeMounts ?? []; - if (!c.volumeMounts.some((m: any) => m.name === VOLUME)) { - c.volumeMounts.push({ name: VOLUME, mountPath: "/etc/pgbouncer", readOnly: true }); - } - c.command = ["/usr/bin/pgbouncer", "/etc/pgbouncer/pgbouncer.ini"]; -} - -// Mutate every pooler Deployment in the postgres namespace (unicorn-only deploy). -When(a.Deployment) - .IsCreatedOrUpdated() - .InNamespace(NS) - .WithLabel("application", "db-connection-pooler") - .Mutate(request => { - applyPoolerPatch(request.Raw); - }); -``` - -- [ ] **Step 4: Run tests to verify they pass** - -Run: `cd src/pepr && npx vitest run capabilities/pgbouncer-fips-pooler.test.ts` -Expected: PASS (all 5 tests: 2 userlist + 3 mutation). - -- [ ] **Step 5: Commit** - -```bash -git add src/pepr/capabilities/pgbouncer-fips-pooler.ts src/pepr/capabilities/pgbouncer-fips-pooler.test.ts -git commit -m "feat(pepr): mutate pooler deployment to mount config and set pgbouncer command" -``` - ---- - -## Task 5: Build the module and wire it into Zarf (unicorn-gated) - -**Files:** -- Modify: `zarf.yaml` - -- [ ] **Step 1: Build the Pepr module** - -Run: -```bash -cd src/pepr && npx pepr build -``` -Expected: produces `src/pepr/dist/` containing `pepr-module-pgbouncer-fips.yaml` (manifests) and prints the controller image used. - -- [ ] **Step 2: Add a flavor-gated component to `zarf.yaml`** - -Add a component (place near the existing config component). Use the manifests produced by `pepr build` and the controller image confirmed in Task 0: - -```yaml - - name: pgbouncer-fips-pooler - description: "Pepr module configuring the distroless pgbouncer-fips pooler" - required: false - only: - flavor: unicorn - manifests: - - name: pepr-pgbouncer-fips - namespace: pepr-pgbouncer-fips - files: - - src/pepr/dist/pepr-module-pgbouncer-fips.yaml - images: - - "" -``` - -Replace `` with the exact reference recorded in Task 0. If `pepr build` emits a different manifest filename, use that exact path. - -- [ ] **Step 3: Validate the package builds for unicorn and excludes the component elsewhere** - -Run: -```bash -zarf dev inspect manifests . --flavor unicorn 2>&1 | grep -c "pepr-module-pgbouncer-fips" || true -``` -Expected: `>= 1` for unicorn. - -Run: -```bash -zarf dev inspect manifests . --flavor upstream 2>&1 | grep -c "pepr-pgbouncer-fips" || true -``` -Expected: `0`. - -(If `zarf dev inspect manifests` cannot resolve the component, fall back to `zarf package create . --flavor unicorn --confirm -o /tmp` and inspect the built package's `zarf.yaml`.) - -- [ ] **Step 4: Commit** - -```bash -git add zarf.yaml src/pepr/dist -git commit -m "feat(zarf): deploy pgbouncer-fips pepr module on unicorn flavor" -``` - ---- - -## Task 6: e2e regression test (unicorn pooler runs and proxies) - -**Files:** -- Modify: `tests/postgres/postgres-minimal.yaml` or add `tests/postgres/pooler-fips-test.yaml` -- Modify: `tasks/test.yaml` - -- [ ] **Step 1: Add an e2e assertion that the pooler pod runs (not usage-exit)** - -Add a test task in `tasks/test.yaml` (match existing task style). The assertion: after deploying the unicorn flavor with pooling enabled, the pooler pods become Ready. - -```yaml - - name: validate-fips-pooler - description: "pgbouncer-fips pooler pods start and accept connections" - actions: - - cmd: | - kubectl -n postgres rollout status deployment/pg-cluster-pooler --timeout=180s - - description: "Pooler proxies a query (auth via auth_query)" - cmd: | - kubectl -n postgres run pooler-smoke-$RANDOM --rm -i --restart=Never \ - --image=$(yq '.postgresql.connection_pooler_image' values/unicorn-values.yaml) \ - --command -- /usr/bin/pgbouncer --version -``` - -Note: the second action only proves the binary runs; the authoritative check is the existing through-pooler psql connectivity test in `tests/postgres/`. Wire `validate-fips-pooler` to run after the existing pooler routing test in the unicorn test flow. - -- [ ] **Step 2: Extend/confirm the existing pooler connectivity test targets the pooler service** - -Confirm `tests/postgres/` pooler routing test connects via the pooler Service (`pg-cluster-pooler.postgres.svc`) and runs a `SELECT`. If it currently only runs for non-unicorn, add a unicorn invocation in `tasks/test.yaml`. - -- [ ] **Step 3: Run the unicorn e2e flow locally (if a cluster is available)** - -Run: -```bash -uds run test: # match the actual task name in tasks/test.yaml -``` -Expected: pooler rollout succeeds; through-pooler `SELECT` returns rows (no usage-exit, no auth failure). - -- [ ] **Step 4: Commit** - -```bash -git add tasks/test.yaml tests/postgres -git commit -m "test: verify pgbouncer-fips pooler runs and proxies on unicorn" -``` - ---- - -## Task 7: Docs + automation wiring - -**Files:** -- Modify: `docs/configuration.md` -- Modify: `renovate.json` - -- [ ] **Step 1: Document the FIPS pooler behavior** - -In `docs/configuration.md`, in the connection pooler section, add a subsection: on the `unicorn` (FIPS) flavor the pooler image is distroless and is configured by the bundled Pepr module (`pgbouncer-fips-pooler`); client→pooler encryption is provided by the service mesh (mTLS), pooler→postgres uses `server_tls_sslmode=require`, and auth uses `scram-sha-256` via `auth_query`. Note that pool sizes are set via `postgresql.poolerFipsConfig.*` rather than the operator's dynamic sizing. - -- [ ] **Step 2: Track the Pepr controller image in renovate** - -In `renovate.json`, add a rule (matching existing patterns) so the Pepr controller image reference in `zarf.yaml` is updated by renovate. If the repo pins images via a custom manager/regex, mirror that for the new image. - -- [ ] **Step 3: Lint** - -Run: -```bash -uds run lint # or the repo's lint task; match tasks.yaml -``` -Expected: passes. - -- [ ] **Step 4: Commit** - -```bash -git add docs/configuration.md renovate.json -git commit -m "docs: document FIPS pooler; chore: track pepr image in renovate" -``` - ---- - -## Self-Review - -**Spec coverage:** -- Image-compatibility root cause → Tasks 2–5 (config + mutation + command). -- Module scope (unicorn-only, mutate all poolers) → Task 5 `only.flavor: unicorn`; Mutator has no image gate (Task 4). -- Client TLS via mesh / server `require` → Task 2 ConfigMap. -- Pepr-derived userlist Secret → Task 3. -- `failurePolicy: Ignore` → Task 1 `onError: ignore`. -- Static `pgbouncer.ini` in chart, unicorn-gated → Task 2. -- Data-flow/ordering (by-name refs, kubelet volume-wait) → Task 4 (refs by name) + Task 6 (cold-deploy). -- Idempotency → Task 4 Step 1 test. -- Testing (unit + e2e + flavor gating) → Tasks 3, 4, 6; gating assertions Task 2 Step 4 / Task 5 Step 3. -- Packaging/layout/docs/renovate → Tasks 1, 5, 7. -- FIPS Pepr image risk → Task 0 gate. - -**Placeholder scan:** One intentional placeholder — `` (resolved by Task 0) and the test/lint task names which must match `tasks/test.yaml`/`tasks.yaml`. All code steps contain real code. - -**Type consistency:** `DERIVED_SECRET`, `CONFIG_MAP`, `VOLUME`, `renderUserlist`, `applyPoolerPatch`, `PgbouncerFips` are used consistently across Tasks 3–4 and tests. Container index 0 / name `connection-pooler` consistent with pre-flight facts. - -## Open items the executor must resolve against the live repo -- Exact `pepr` package version + matching controller image (Task 0/1/5). -- Exact `pepr build` output filename (Task 5 Step 2). -- Actual task names in `tasks/test.yaml` / `tasks.yaml` for lint + e2e (Tasks 6, 7). -- Confirm `tests/postgres/` pooler routing test's connection target (Task 6 Step 2). diff --git a/docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md b/docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md deleted file mode 100644 index a126d68..0000000 --- a/docs/superpowers/specs/2026-06-03-pgbouncer-fips-pooler-pepr-design.md +++ /dev/null @@ -1,191 +0,0 @@ -# Design: FIPS Connection Pooler via Pepr Module - -- **Date:** 2026-06-03 -- **Status:** Approved (design); pending implementation plan -- **Scope:** `unicorn` flavor only - -## Problem - -On the `unicorn` flavor, `connection_pooler_image` is set to Chainguard's -**distroless** `cgr.dev/defenseunicorns.com/pgbouncer-fips`. The Zalando -postgres-operator launches the pooler container with **only an image + env vars -and no `command`/`args`** (confirmed in `pkg/cluster/connection_pooler.go`, -v1.15.1). It depends on the image's ENTRYPOINT to render -`/etc/pgbouncer/pgbouncer.ini` (+ `userlist.txt`) from those env vars via -`envsubst` and then `exec pgbouncer `. - -The canonical Zalando image (`registry.opensource.zalan.do/acid/pgbouncer`) and -the Iron Bank rebuild (`registry1.dso.mil/.../zalando/pgbouncer`) carry that -entrypoint script + template. Chainguard's distroless image is the bare -`/usr/bin/pgbouncer` binary — no entrypoint script, no template, no shell — so -the operator's argument-less launch yields `pgbouncer` with no `CONFIG_FILE`, -which prints usage and exits. - -This is an **image-compatibility** problem, not a chart/values bug. - -## Why not the simpler options - -- **One-shot Job/Zarf patch (rejected).** The operator's - `syncConnectionPoolerWorker` regenerates the entire pod spec and `Update()`s - the Deployment whenever a *tracked* field drifts (image, resources, replicas, - `PGUSER`/`PGSCHEMA`, owner refs). It does not track - `command`/`initContainers`/`volumes`, so a patch survives steady-state 5-min - resyncs but is **silently wiped** on the next operator-driven update (image - bump, CR edit, operator restart perceiving drift). Latent breakage; also races - the operator on first create. Wrong for a shipped feature. -- **Swap to an operator-compatible FIPS image (rejected).** Would be cleanest if - such an image existed, but it requires the Zalando entrypoint glue that the - distroless FIPS image deliberately omits. The requirement is to use the - distroless Chainguard FIPS image. - -## Chosen approach - -A standalone **Pepr module**, deployed only for the `unicorn` flavor, that: - -1. **Mutates** the operator-created pooler Deployment on every create/update to - mount a config ConfigMap + a derived auth Secret and set the pgbouncer - `command`. Because admission mutation re-applies on every operator write, - there is no drift window. -2. **Reconciles** the operator's pooler credential Secret into a derived - `userlist.txt` Secret (the distroless image cannot transform the raw password - into pgbouncer's `auth_file` format at runtime). - -No new images beyond the Pepr controller, which **reuses the FIPS Pepr image -uds-core already runs** (prerequisite — see Risks). - -## Key environment facts (verified) - -- Cluster uses **`scram-sha-256`** (`chart/templates/postgres-minimal.yaml`: - `password_encryption: scram-sha-256`, pg_hba). The rendered config MUST use - `auth_type = scram-sha-256` (not the upstream template's `md5`). -- pg_hba contains `hostnossl all all all reject` → **pgbouncer→postgres must use - SSL** (`server_tls_sslmode = require`; `require` encrypts without needing a CA). -- Pooler container is `containers[0]`, name **`connection-pooler`** - (`k8sres.go`), runs as uid 100 / gid 101. -- Pooler Deployments: `pg-cluster-pooler` (primary), `pg-cluster-pooler-repl` - (replica); pods labeled `application: db-connection-pooler`. -- Pooler user/schema default **`pooler`/`pooler`**; credential Secret - `pooler.pg-cluster.credentials.postgresql.acid.zalan.do` (keys `username`, - `password`). -- Operator sets on `containers[0]`: `PGHOST`, `PGPORT`, `PGUSER`, `PGSCHEMA`, - `PGPASSWORD`, `CONNECTION_POOLER_{PORT,MODE,DEFAULT_SIZE,MIN_SIZE,RESERVE_SIZE,MAX_CLIENT_CONN,MAX_DB_CONN}`. -- Operator installs the `pooler.user_lookup` SECURITY DEFINER function in each - database regardless of pooler image, so `auth_query` works. - -## Decisions - -| Topic | Decision | -|---|---| -| Module scope | Deployed for `unicorn` flavor only; mutates **all** pooler Deployments unconditionally (no runtime image gate). | -| Client TLS (app→pgbouncer) | Disabled in pgbouncer; rely on Istio mesh mTLS for encryption-in-transit. | -| Server TLS (pgbouncer→postgres) | `server_tls_sslmode = require` (mandatory; non-SSL rejected by pg_hba). | -| `userlist.txt` | Pepr-derived Secret; no init container, no extra image. | -| `failurePolicy` | `Ignore` (a webhook outage must not block the operator). | -| Static `pgbouncer.ini` | Shipped by the Helm chart (gated by a unicorn-only values flag). | - -## Architecture & components - -New Pepr module in `src/pepr/`, built with `pepr build`, deployed as a -flavor-gated Zarf component (`only.flavor: unicorn`). One capability, -`pgbouncer-fips-pooler`, with two parts: - -- **Reconciler** — `When(a.Secret).IsCreatedOrUpdated().InNamespace("postgres")` - filtered to `pooler.pg-cluster.credentials.postgresql.acid.zalan.do`. Writes a - derived Secret `pgbouncer-fips-userlist` with key `userlist.txt` = - `"pooler" ""`, owner-referenced to the source Secret for GC. -- **Mutator** — - `When(a.Deployment).IsCreatedOrUpdated().InNamespace("postgres")` filtered to - `application: db-connection-pooler` (covers `-pooler` and `-pooler-repl`). - Idempotently mounts the `pgbouncer-config` ConfigMap and the - `pgbouncer-fips-userlist` Secret into `containers[0]`, and sets - `command: ["/usr/bin/pgbouncer", "/etc/pgbouncer/pgbouncer.ini"]`. - -The static `pgbouncer.ini` ConfigMap (`pgbouncer-config`) is rendered by -the Helm chart from chart values: `pool_mode`, pool sizes, `auth_type = -scram-sha-256`, `auth_query = SELECT * FROM pooler.user_lookup($1)`, -`auth_user = pooler`, `auth_file = /etc/pgbouncer/userlist.txt`, -`server_tls_sslmode = require`, client TLS disabled, plus -`ignore_startup_parameters = extra_float_digits,options`. - -## Data flow & ordering - -1. Operator creates the pooler Secret → Reconciler writes - `pgbouncer-fips-userlist`. -2. Operator creates/updates the pooler Deployment → Mutator injects - volumes/mounts + command. Mutation references ConfigMap/Secret **by name** - only (does not read contents), so it succeeds regardless of ordering. -3. If the pod starts before the derived Secret exists, the kubelet holds it in - `ContainerCreating` until the Secret volume resolves — no crash-loop. -4. Every later operator reconcile re-triggers the Mutator → injected fields are - restored; drift is impossible. -5. Password rotation: operator updates source Secret → Reconciler rewrites - derived Secret. Baseline is pod restart to pick up; live `RELOAD` is a - possible follow-up. - -Idempotency: the Mutator checks for its own volume/mount/command before adding, -so repeated mutations are no-ops and there is no operator↔webhook hot-loop. - -## Error handling & edge cases - -- Derived Secret missing/slow → kubelet volume-wait; self-heals on next Secret - event (Reconciler is idempotent, single writer). -- Reconciler can't read source Secret (RBAC/timing) → logged + retried; nothing - acts on stale data (Mutator references by name). -- Replica pooler → same labels, covered automatically; one derived - Secret/ConfigMap serves both. -- Missing `user_lookup` → pgbouncer auth fails clearly in its log (surfaced). -- Wrong flavor/image → module not shipped outside unicorn, so it can't touch - Zalando-image poolers. -- Webhook down → `failurePolicy: Ignore`; a pooler created during the outage - runs unconfigured until the next operator write re-triggers the recovered - mutation. - -## Testing - -- **Pepr unit tests** — Mutator produces expected volumes/mounts/command and is - a no-op when already mutated; Reconciler renders correct `userlist.txt` from a - fake source Secret. No cluster required. -- **e2e (unicorn)** — extend existing `tests/postgres/` pooler tests: deploy - unicorn flavor with `enableConnectionPooler: true`, assert pooler pods reach - `Running` (not usage-exit), then run the existing through-pooler psql - connectivity check. Regression guard for the original bug. -- **Ordering** — cold-deploy e2e implicitly covers pod-before-Secret via the - kubelet volume-wait path. -- **Flavor gating** — assert the Pepr component is absent from `registry1` / - `upstream` builds. -- CI: module builds in the existing pipeline; `pepr build` output (image + - manifests) wired into `zarf.yaml`; matches current lint/test/scan workflows. - -## Packaging & repo layout - -- `src/pepr/` (new): `package.json`, `pepr.ts`, - `capabilities/pgbouncer-fips-pooler.ts`. -- Pepr controller image: reuse uds-core's FIPS image (prerequisite to confirm). -- `zarf.yaml`: Pepr component gated `only.flavor: unicorn`, plus its image entry. -- `chart/`: add `pgbouncer.ini` ConfigMap template gated by a unicorn-only - values flag (e.g. `postgresql.poolerFipsConfig: true` in - `values/unicorn-values.yaml`); never rendered for other flavors. -- `docs/configuration.md`: document FIPS-flavor pooler behavior (mesh mTLS, - scram-sha-256). -- `renovate.json` / scan / lint: wire the new image + TS module into automation. -- Names: derived Secret `pgbouncer-fips-userlist`, ConfigMap - `pgbouncer-config`, capability `pgbouncer-fips-pooler`, namespace - `postgres`. - -## Risks / prerequisites - -1. **FIPS Pepr controller image** must be available (reuse uds-core's). If not, - the lift and image-sourcing change — confirm before implementation. -2. Adds a TypeScript/Node toolchain to a currently pure YAML/Helm/Zarf repo — a - real maintenance consideration; mirrors uds-core's structure and is the - standard UDS way to ship admission logic. -3. Password duplicated into a second in-namespace Secret (`pgbouncer-fips-userlist`), - RBAC-protected like the source. - -## Reference - -Upstream `pooler/pgbouncer.ini.tmpl` and `pooler/entrypoint.sh` -(zalando/postgres-operator) are the source of truth for the rendered config; -this design reproduces them with `auth_type = scram-sha-256` and client TLS -disabled (mesh mTLS), and replaces the `envsubst`/`exec` entrypoint with a -chart-rendered ConfigMap + Pepr mutation. From cc8535bcba4d72aa6f123ce3840be4c43ae16b16 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 16:25:48 -0400 Subject: [PATCH 09/12] feat(releaser): update datasource for unicorn flavor to FIPS compliant version --- releaser.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/releaser.yaml b/releaser.yaml index 3a1d35f..734a41a 100644 --- a/releaser.yaml +++ b/releaser.yaml @@ -9,5 +9,5 @@ flavors: # renovate-uds: datasource=docker depName=registry1.dso.mil/ironbank/opensource/zalando/postgres-operator extractVersion=^v?(?\d+\.\d+\.\d+)$ version: 1.15.0-uds.18 - name: unicorn - # renovate-uds: datasource=docker depName=quay.io/rfcurated/zalando/postgres-operator extractVersion=^v?(?\d+\.\d+\.\d+)$ + # renovate-uds: datasource=docker depName=cgr.dev/defenseunicorns.com/postgres-operator-fips extractVersion=^v?(?\d+\.\d+\.\d+)$ version: 1.15.1-uds.0 From 3351d0182bb6d6e7f3420afd16a1150fa14f81a4 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 16:56:30 -0400 Subject: [PATCH 10/12] feat(pg-bouncer): enhance connection pooler configuration and refactor related code --- chart/templates/pgbouncer-config.yaml | 15 ++++++++------- chart/values.yaml | 19 +++++++++++++++++++ src/pepr/capabilities/pgbouncer-pooler.ts | 6 +++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/chart/templates/pgbouncer-config.yaml b/chart/templates/pgbouncer-config.yaml index 01e961b..db84946 100644 --- a/chart/templates/pgbouncer-config.yaml +++ b/chart/templates/pgbouncer-config.yaml @@ -2,21 +2,21 @@ # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial {{- if and .Values.postgresql.enabled (or .Values.postgresql.enableConnectionPooler .Values.postgresql.enableReplicaConnectionPooler) }} -{{- $p := .Values.postgresql.poolerConfig | default dict }} apiVersion: v1 kind: ConfigMap metadata: name: pgbouncer-config namespace: postgres data: +{{- with .Values.postgresql.configConnectionPooler -}} pgbouncer.ini: | [databases] * = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler postgres = host=pg-cluster.postgres.svc.cluster.local port=5432 auth_user=pooler [pgbouncer] - pool_mode = {{ $p.poolMode | default "transaction" }} - listen_port = {{ $p.listenPort | default 5432 }} + pool_mode = {{ .connection_pooler_mode | default "transaction" }} + listen_port = {{ .connection_pooler_listen_port | default 5432 }} listen_addr = * admin_users = pooler auth_dbname = postgres @@ -27,11 +27,12 @@ data: log_connections = 0 log_disconnections = 0 max_prepared_statements = 200 - default_pool_size = {{ $p.defaultPoolSize | default 20 }} - reserve_pool_size = {{ $p.reservePoolSize | default 10 }} - max_client_conn = {{ $p.maxClientConn | default 10000 }} - max_db_connections = {{ $p.maxDBConnections | default 60 }} + default_pool_size = {{ .connection_pooler_default_pool_size | default 20 }} + reserve_pool_size = {{ .connection_pooler_reserve_pool_size | default 10 }} + max_client_conn = {{ .connection_pooler_max_client_conn | default 10000 }} + max_db_connections = {{ .connection_pooler_max_db_connections | default 60 }} idle_transaction_timeout = 600 server_login_retry = 5 ignore_startup_parameters = extra_float_digits,options +{{- end -}} {{- end }} diff --git a/chart/values.yaml b/chart/values.yaml index 09606c2..a2ecb5f 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -21,6 +21,25 @@ postgresql: # Ref: https://opensource.zalando.com/postgres-operator/docs/user.html#connection-pooler enableConnectionPooler: false enableReplicaConnectionPooler: false + # Connection pooler configuration. Ref: https://opensource.zalando.com/postgres-operator/docs/reference/operator_parameters.html#connection-pooler-configuration + configConnectionPooler: + # db schema to install lookup function into + connection_pooler_schema: "pooler" + # db user for pooler to use + connection_pooler_user: "pooler" + # docker image + connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-32" + # max db connections the pooler should hold + connection_pooler_max_db_connections: 60 + # default pooling mode + connection_pooler_mode: "transaction" + # number of pooler instances + connection_pooler_number_of_instances: 2 + # default resources + connection_pooler_default_cpu_request: 500m + connection_pooler_default_memory_request: 100Mi + connection_pooler_default_cpu_limit: "1" + connection_pooler_default_memory_limit: 100Mi # Example values for postgresql # diff --git a/src/pepr/capabilities/pgbouncer-pooler.ts b/src/pepr/capabilities/pgbouncer-pooler.ts index d661fc0..d6b7bab 100644 --- a/src/pepr/capabilities/pgbouncer-pooler.ts +++ b/src/pepr/capabilities/pgbouncer-pooler.ts @@ -12,9 +12,9 @@ export const Pgbouncer = new Capability({ const { When } = Pgbouncer; // Exported for reuse by the Mutator task. -export const NS = "postgres"; -export const SOURCE_SECRET = "pooler.pg-cluster.credentials.postgresql.acid.zalan.do"; -export const DERIVED_SECRET = "pgbouncer-userlist"; +const NS = "postgres"; +const SOURCE_SECRET = "pooler.pg-cluster.credentials.postgresql.acid.zalan.do"; +const DERIVED_SECRET = "pgbouncer-userlist"; // pgbouncer auth_file format: `"user" "password"` with "" escaping inside quotes. export function renderUserlist(username: string, password: string): string { From e7f80fdecca7ba83810da8cc37128dea22790de7 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 16:56:56 -0400 Subject: [PATCH 11/12] feat(pepr): update secrets and build timestamps for pgbouncer configuration --- manifests/pepr-module-pgbouncer.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/manifests/pepr-module-pgbouncer.yaml b/manifests/pepr-module-pgbouncer.yaml index 39ba122..73f9e02 100644 --- a/manifests/pepr-module-pgbouncer.yaml +++ b/manifests/pepr-module-pgbouncer.yaml @@ -41,7 +41,7 @@ metadata: apiVersion: v1 data: value: >- - YjBhYzhiNGZkZGM2ODg5ZjU2MWEyZjkwM2IzNWQwNTZhODNhNjdlOWY3OTRmNjMwMzdiMjRhNzU1MTNmNWMyMA== + OGY0Zjk4YzA5MWFhOTA4ZTRiNGZiMDhiNzY0NjcyZWE4ZGM0NmMzNmJmMmM5N2QyYWQwY2U5ODlmMjcwNTQ4Yg== kind: Secret metadata: name: pepr-pgbouncer-api-path @@ -51,9 +51,9 @@ type: Opaque apiVersion: v1 data: tls.crt: >- - LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDcURDQ0FaQ2dBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBQU1CNFhEVEkyTURZd05EQXdOREUxDQpNbG9YRFRJM01EWXdOREF3TkRFMU1sb3dBRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DDQpnZ0VCQUtzRmhucjRma1FMWWp5Wk9TZzVRWlNKRGgweTUrcytobVY5YUxBd3V3SXdEOG05MmxTZC9DZktWendLDQo4a3ArV2U4Y1Bsd2Fmd0VGZnMxdTRhdHBYSnE3Z3YrSnNTZ3VsTkNLaERxVEtrZFdwdGdiblNESHpFQktDR1BLDQpIVXZqd1QzMDFSZC8wY2ZBZksxQmlnSlNQWTA3bXM0T0d5VERVNWlwaDhuMzExSGM5NG5wWnpzdXQ3VWsyUnQ2DQpBeW9OQzVDMXkwTitBSE9QWmMxNHVYQWs2Q1hYUkt1cFlHSUlWSnFnRHUxenljSWdDbG1YWnQzcldsZWlBelRtDQorQ25wOHdqVzdJVjhyZnIrTU1EMjY3QWlSTkZKelBRbURvNFNwN3FHb1NWQ1NwUmZPOURzK09zL1QxVG9WcUxvDQp3WmlBaFRLZ0s4Mmc2OVcwZVU1YWcyZUhNbk1DQXdFQUFhTXRNQ3N3S1FZRFZSMFJCQ0l3SUlJZWNHVndjaTF3DQpaMkp2ZFc1alpYSXVjR1Z3Y2kxemVYTjBaVzB1YzNaak1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQS9GcmNrDQpYY29TWHJhaW4vZGNJZiswdmtzeXMybFdNOVdsd3pBY1IyYWw2eDdaeGlBbFRsK01jK1JwcFFYMzh2ODFwWUFUDQpxaGRSN251VVdabnQvaTI5K2JuM2FyWHgrY3ZsbnoyS1VmMTROOGwzakpxS1Y3UGFPa1ZnNEhJTDdBbkdjV2V5DQpTT3h3TlNvbEVFeHJzb1NuclZUTWdBdlNYRk8xVE9zZUI1MUY0WWpLVmsxWnlxRm9NdjczTnRHR2EvK1FiNk1TDQpGMXJwd0hQWFV0dXlHSFhmYlBLWDFpUzBNbER5MTFYWFRoWXZPa3BzOWptdHNNbzZsMmlyV0t4NHVDd0lGOEZxDQpPTVYvdnlRZDNhVVpTOUJYb0xCWjBsZ2VQTEx6RVRmalJ0cmp2ejhTN1B5VzZtN0ZqNVhaM05nY20rdTJiTXgyDQpRY0RyZGpYT0Ztb2ZPTm1PDQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo= + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDcURDQ0FaQ2dBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBQU1CNFhEVEkyTURZd05ESXdOVFl4DQpNbG9YRFRJM01EWXdOREl3TlRZeE1sb3dBRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DDQpnZ0VCQUpRZTFtbW9xZFdEZnpnUlU3T1NkUC95Qm4xcjFKQ1A4akx5RXlWWlZSbGU4Q3M3b0o4S2E0MGFxbDA2DQp3ZTdrTy9qR2c1M1N6NUMva0NjZDluU2I3bTRaa2RGMkpSNWR2eWY5R3hvNzdxajB6MGR2S2p1bGRtK3VPcHZHDQoveHM5ZGxUTVNxb1JQWTR0QnpObzFkN1YxNVBMTVF3bXFZZm5RZjRHNkh5Ukd6bFl2ZWtqdWhDb2VjbDZmQWhBDQo0cVB4bGxJdnpDK0JQbnNCb1NnNGZRdzV6TXFZTStzT2srSVBDWVZkOStkcFNWV1JBcDhobTdCY1c1N0NxdDVUDQpJTVgyTEFISWxCK1BMcnppY2xpMGdCREhhcDQ5SmJsNTFhUE9pQUZDSUFPb1paZWtzQUg4VEQ5cEd1VlBJNGgxDQpoejB4NWFPQWhqRjRUNGdTOHUveFc0dGExaUVDQXdFQUFhTXRNQ3N3S1FZRFZSMFJCQ0l3SUlJZWNHVndjaTF3DQpaMkp2ZFc1alpYSXVjR1Z3Y2kxemVYTjBaVzB1YzNaak1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQjVPcG5FDQpzZXpEK2wwNjVTSzZjOTlKL1RTSW1iTnZMaVJ1YkUxM20zbmw4YlUxZSt6djFpb0M0VWZhOG5KZzZsNllKeEg5DQpxb05UOUdYTDMzZnVtSzhrdmM3VkNJVEs3WG5NSkttaHdRZ3EyT3B3YXR3RW1XVDJscG9TT2MrVjFtS2xZVjR1DQpCTEovQVZnczRyVm1ybFR1aTE1TmRPano5clZ0WGlWRGw2eVpaUVlEVW9hUk10YXNHckFhZEpUdE1OQ3NRTmpvDQpIVEZua210ZWZPeS9wSUU3VForc1dFeE41ZjJ1SENnOFljRjd1ZXlkYTc1LzRkL0ZpU3UyY29vcW1xS2RkaG9nDQozMUJqbGF3V2dxUVFqSW02SmY3RFJrdGtCd1krckFjMmM0a2h3N1FyVlRRVGpPcVp1M2o4TlNHWHRVLzhhYllzDQovWTFTZDRrUlMrY04xQUllDQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo= tls.key: >- - LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ0KTUlJRXBBSUJBQUtDQVFFQXF3V0dldmgrUkF0aVBKazVLRGxCbElrT0hUTG42ejZHWlgxb3NEQzdBakFQeWIzYQ0KVkozOEo4cFhQQXJ5U241Wjd4dytYQnAvQVFWK3pXN2hxMmxjbXJ1Qy80bXhLQzZVMElxRU9wTXFSMWFtMkJ1ZA0KSU1mTVFFb0lZOG9kUytQQlBmVFZGMy9SeDhCOHJVR0tBbEk5alR1YXpnNGJKTU5UbUttSHlmZlhVZHozaWVsbg0KT3k2M3RTVFpHM29ES2cwTGtMWExRMzRBYzQ5bHpYaTVjQ1RvSmRkRXE2bGdZZ2hVbXFBTzdYUEp3aUFLV1pkbQ0KM2V0YVY2SUROT2I0S2VuekNOYnNoWHl0K3Y0d3dQYnJzQ0pFMFVuTTlDWU9qaEtudW9haEpVSktsRjg3ME96NA0KNno5UFZPaFdvdWpCbUlDRk1xQXJ6YURyMWJSNVRscURaNGN5Y3dJREFRQUJBb0lCQUFVN0Y0aG1WbEpWZU0wNg0Kc0lWYTd2Y1FsQlp2aXFsbTBheUQvL0kzbzFpblNLeFdlcm1RMVhnUUY4ZjEyOEJNaWdxbXRmK1NMZVZGbWtIRg0KVFBDMXVjZmZ5VnR3aGpNZzdadE5TVXNUV2oweFdNd09XQ2w3QXZQS2IrUkJkOURzNStteHRkelFvNFYxRFRzdA0KWUgrK3JUUkhLTzU1ZnZvS1lXR3ZlY0JETE5wTGw1Ukw0NVpxUUE1cHRvVWF4eE9uNEdrQTJBZWtUeGxOaDNKUw0KYXNoLy9QRk5XMVRSSW1HZHZER3hTWVhzcFhkSWEyTm9UV2Q5WTV4Q1BDR2xQNWNONnBkUjU4YzZ2blBodjhHUQ0KY2ZpaGdZclhKZXNGUExKTlJRNDY1S1BDYkFZQXlCOFAxd0pMMXdhOGRrY0RaOUpxcFJMUXMrdnYxVldRZWRVSg0KeUxWWThVa0NnWUVBMjFBZjlJem0va1pJYlJPRDFOQlhNYUQvZ3o3QmI3UWhiVDBRSSs4UHZHVFZHTytSd3kxZw0Kb2lEQ2ExWFdob3l2SG1rdlJJL0dMK0E3cmlSamJjYmVtdWY2RjgrRzdsbHBQdTZ2OCt4R0o1SElMWDJxbVdxdg0KSjJOTlFwMDY1eW9zdWtqb1hZN0UxUDhLblJndUhnKzRlWDRhUlpwUHMybmY3cWhva1JCVnk2a0NnWUVBeDZGZA0KckY0NW5hSjhoTFB6Mit1Z3hUTEs1eFlnUnp3ZjZCdXlVeHF2dGVibW9iZ1MzUWV2Y3JGYis2L2JxZ2JHMmJMQw0KMVlNOGRlejZudVhQTGlQRENsSTVXSjduclVuUlJXN2tIUngrekV4QTF1NjBNcmtDSTM1ZjVDbkU0TFhrVkhmKw0KdVJuVTY4eGlpMUFtUWZ3TDNNYWZlYkRUaER0UzNOUmFrMTZVdnJzQ2dZRUEwUVhXenYrVUVQanZnblk5Q1pIZg0KNkw4bmgvRkI3N0xnd1BxWDdZZWxtY3NJaHhHZC9VVzhlZ2w3QTAzMmZwcUxOUkxQS0N0WG1yMitZOFR1dHV2NQ0Kc2U0eW9JcjhjU0xxZWo2SG1KV3liM2cwTDVjOEI2aDBjN2ZqSlFBeDZheDZvTGxvTGZNcWlrN2gwTVFCQUVtLw0KYXB2VGNrOFdjMHNQVUtsVnNCeS9pTEVDZ1lCMlFTcWlQcmJXb0RndXpBSzYxZHZJdFF2bzAveU85aGpZZi8raw0KcHZ4TFB0cUVGZXhtcm5USjlqSk01Nkd5R0kyV3pBUUtRdEYvOGIrTWZRbTdoVWUyUjNyYytsUzNIREV4ZGp6Kw0KMmJCckNRaW55WU5KUUxyNWw1VHFMYXdJaVBjVzZuWWo1Qjl6QndHaEVQdDR2dnV2N3FEdGowZmMzdDk1SFBvQw0KcmxaaW5RS0JnUUM5WEtOdk1qVkZTUVREVGdtOHJkWVZyMC93U0MwNnhGTFNscmFCdENQcnlRMUdIVmkxd2RmNg0KMWpZRUFIMXlPTFZGMEIreDNsNlFwZWpvWVY4Wnlldzk3c0w4eituVjB3dTV3UUl6NWFIMDBTeW1wbkx5c28xWg0Kb0VuOC92eWx2VGNmZUwrMzdOZFBvcktXRDhENURWUW9RcHdPTjdtUDV6cEY0MW42OGh6cmJBPT0NCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tDQo= + LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ0KTUlJRW9nSUJBQUtDQVFFQWxCN1dhYWlwMVlOL09CRlRzNUowLy9JR2ZXdlVrSS95TXZJVEpWbFZHVjd3S3p1Zw0KbndwcmpScXFYVHJCN3VRNytNYURuZExQa0wrUUp4MzJkSnZ1YmhtUjBYWWxIbDIvSi8wYkdqdnVxUFRQUjI4cQ0KTzZWMmI2NDZtOGIvR3oxMlZNeEtxaEU5amkwSE0yalYzdFhYazhzeERDYXBoK2RCL2dib2ZKRWJPVmk5NlNPNg0KRUtoNXlYcDhDRURpby9HV1VpL01MNEUrZXdHaEtEaDlERG5NeXBnejZ3NlQ0ZzhKaFYzMzUybEpWWkVDbnlHYg0Kc0Z4Ym5zS3EzbE1neGZZc0FjaVVINDh1dk9KeVdMU0FFTWRxbmowbHVYblZvODZJQVVJZ0E2aGxsNlN3QWZ4TQ0KUDJrYTVVOGppSFdIUFRIbG80Q0dNWGhQaUJMeTcvRmJpMXJXSVFJREFRQUJBb0lCQUFUVFNGcmkwcjJRN2hrTw0KZjNLUEo5NmFyTmx6Sk5hY3llQWRBTUNydTFqN1BjbTZ4STNKMGgwanJEOGpSZVFaYlZhNmFObEFYK0N3VE9ycA0KVC9rV2gxcnczRTQ5a2hIK0xkY0lxTlJlOVhSdG5UOFBnUW0yWnpoV0xiU2JjLzRZTDMydHRoVDZRTTRiNjJzaQ0KVkMxUlBCZWxlL0NRWmQ5MmlqRFRXc21NRkozMm1IQnRTMHJDc2F6dFE0L2ZiSUJjR2pYNGRJSmR2WlBUTFd2TQ0KdWtlKzZwY1orTWtuRXF0NndqUy9MSHpUeXBPWEFVQko4eUhMZk9vUDg5RXlEV2d0OFdMTWpsODFvRk10ZHo5Sg0KMTlUQjJnbGFlTlJPZzFmazk3Y1lYVjFmU2lPbFZldGRUUnZqeTlENHEwajBWWTlnYnFHWjdtaXU5VlhoU09sQg0KS1AxSTJWRUNnWUVBeHg1MC84M0lLM1dYN0NaUTVnemNYTTVHUnhGWXdROFhzd0V6OVJNS3RKTzJSRFc5aHBOWA0KaENOQnlqc3l2ZlArLy9QMGlqajMvQkxkT3dSTnVMV05NdjBKYW1LT0VueVZBeXZoUmxCTnEybzNNeHBPaEcxeQ0KZktnTklxQTh1VEsySlJGZkR3MFdnUUU1UHpldExFN0VJUFN2TlJXUEJOWDdJVS8zcDdIMGRCMENnWUVBdm03ZA0KdzdvdlJaNjJ2TlMvM0FCb2ZidTFiRkdSYWlzeG10SDhmT0tlTlJ3VGVLQlpsaXljc3lCNXpCR2UwSVY0K0JUbw0KeW9Nd1A3U1Blb0Z0RGFCKzJRalVteFB2eDU3dkJGNDNOby96bUxCT0hBUVcydStUMlByemR6Nm1teUt2dzVKWA0KWlpVRVZtbGM5eStkUDBTRnY2U080ek45SWs1L0ZVNnJuVURtQXRVQ2dZQUY2K3owMG96YVpnUGZuUUFZNTFjQw0KVjR3VmZ2bVJ2RDRyTDZUNDY5a01wN3ZxNldJNmgxVTU4OFo0R2l5WEk1TjR6eXQ5bE5ZakkvaDZVZFZ4NGN4Uw0KTU40LzBMQ0M4anVJUFp6VWQzem4xUi9SSUQ0bmlBMjRrVkxhcmNOQWlyYUtBYXMvQ2xlWi9JeFVTZmFYYzd3Mw0KY3E5bk43M3FHZWIvQlo3SzJPcjVMUUtCZ0MvR3JNaUFHNEFCODZLb1ZZSWljQlNyVlRiWnQvdkUzbXNUSjU5Rg0KVTUvTGJXOGorNVhibDJ5eFJ4MVZobHlXUCtVdGljSFU2L1B2bnRlRFJSTFlJenJjSmtySjA2eG5TVnYxTHpEMw0KS0l3MEgwU1VHZy9QYjI1T2QycUJRMWRFZW9nOFhNVFZnQU1WNkFiejRTV1FVV1hsS1J3RFBPK3dkZDJvb1JHUQ0KeUtRSkFvR0FEYjFQcWQwNi9JUVNrVjZPUHE5K3I4bWxYODd5cy9hc3ZXTlZzMlVxc1o5VFg1Q09XOUh2Q2NReg0KTk1DMEhpaXN0c3d0SmZLMCtxajM2bVhKNVRwZ1h4OUdDaWRIdVk3M1ZLNU91azZ6b2E1dzRqQVQwK09BTllVbg0KUTljM3FTcUFaV2QzKzg3R3RyYWN5eUVZK2tIRi91VElnQWJyckhyYUwyQVZOSFFnczZjPQ0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0NCg== kind: Secret metadata: name: pepr-pgbouncer-tls @@ -125,7 +125,7 @@ spec: template: metadata: annotations: - buildTimestamp: '1780533712429' + buildTimestamp: '1780606572134' labels: app: pepr-pgbouncer-watcher pepr.dev/controller: watcher @@ -216,7 +216,7 @@ spec: template: metadata: annotations: - buildTimestamp: '1780533712429' + buildTimestamp: '1780606572134' labels: app: pepr-pgbouncer pepr.dev/controller: admission @@ -333,12 +333,12 @@ webhooks: - v1beta1 clientConfig: caBundle: >- - LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDdERDQ0FaeWdBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBY01Sb3dHQVlEVlFRREV4RlFaWEJ5DQpJRVZ3YUdWdFpYSmhiQ0JEUVRBZUZ3MHlOakEyTURRd01EUXhOVEphRncweU56QTJNRFF3TURReE5USmFNQUF3DQpnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDM1R4cC9IeTd3Wm5kaisxOGFQc3VGDQpoMlFkOE9EaFRycjNJd25zOU41SFczYVdRdTVGK2cwVTM3cjdEVi9ZR2VuNW9ZMzY2TG1XV1ZMNy9sOWdTaFJZDQpZMkIwdHgvZzBma2JhemVXZGZBT3Z2T2pHdUJIL3Npc0VTQ3RhV3NXalFadFhXREhaamZIbmgzY1FqbUxmRmhzDQpiNlRKdWdvbEZkREcrc3FvOTZYQTZnVW42aUNXMWZyTTBhREdxT1MvWnV1aDQ2Q0g3bnNHby9lMGRKazZFeFB0DQpMSEpDZkx3UUp6MklrcGIzNyt4dW9oMnJPODZEeDVsdGhhYTA0TXFmRGlEd2tYNTE3dHRRd2F2QTFKdGJ3aVMwDQpiOUNSMzAyOEVIRUFYNE1LYitWd0hsMHZiWERCckNONkdySnRYNmVydWZlT2I0UVUxWkNvdzJ0c0hnL2x5YU0vDQpBZ01CQUFHakhUQWJNQXdHQTFVZEV3UUZNQU1CQWY4d0N3WURWUjBQQkFRREFnTDBNQTBHQ1NxR1NJYjNEUUVCDQpDd1VBQTRJQkFRQjlEOUlFVGpaWm9kWUd4Vmg0QXZ5MFJ0cG9BdWF0ZEhiZVFZVmV0MUV3ZGh5ajVTbkVjd1pzDQpncFFtZWJOZmF5Z2ZtUm44S3hxSmttWWJqdnlPSER6N0YrbnlHcCtETUJkMEEwdXZnOGRhaElUbFEyZE1tSVRHDQp6NkZMV1BBeGFvU1liN3htUUtmU1ZBalVKZU5jK1RqTnR5dzU1eFNRcEdkVjdBK3J5aEUxZXJPNGRRSlh1UWZyDQpGcDhNbGJ4aVZGSWlTQ3ZCVHRPUDRWNWJQRklkdGtBNVNoSXZrME9nY0JyVFlJVVlCUjNDalgzRlpLWGUwUDBqDQoyZHV6TGh6T1hoQ2ZlOXlCSW1DeTQwUGd6eTNITWVXTHlKSURFZktyT0VyNE1zcWxCdEZWT0NIbHpRSlN0UU51DQpKQ0lMNjY3S05wUE5qNEQ0NHEzdHJQNStOcGZtUWkrSg0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ0K + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDdERDQ0FaeWdBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBY01Sb3dHQVlEVlFRREV4RlFaWEJ5DQpJRVZ3YUdWdFpYSmhiQ0JEUVRBZUZ3MHlOakEyTURReU1EVTJNVEphRncweU56QTJNRFF5TURVMk1USmFNQUF3DQpnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDamJ3akdmTWx1OHg5SHZjd293WERQDQptRWNLUFBObzNaejlXVlZKRVdpSEMwZVRLcGM0S2diS1Z2V2M2Tk1DbjQxZHR6NUE2b0RVTTJCMFBiV1N6THlKDQo5bm8zM0FUWVJ6VlpGbHE3OHNxeTNUeVhZbzhJSGwxZmNDdnArTGN6OERrWUF0K3Urcjhlbzd4NU9aa00zdkQwDQpFMXhTYVNCaGMrT0VOK3luaFd5VkVFMTJXVHBURHByZ1IxZFE2RURSWmlvL0dxc0tRcE5YeFluMy9yTlVVL2pnDQpZa0NjbGN5Nm03NGlHTU5lcTRxT3JxZllEdmo0UHBBNUFaN09uWndTa3gzZUdNZTRGVjJSOWhESG9GTDE4eGVVDQpMUkhuTExMU0d1YjMxcEszQVdjQnlLUExGaGk4ay9QQyt2WDZBL0NMRGlnUmJwMS90UHNWdDdMejlxT3Z4MGVMDQpBZ01CQUFHakhUQWJNQXdHQTFVZEV3UUZNQU1CQWY4d0N3WURWUjBQQkFRREFnTDBNQTBHQ1NxR1NJYjNEUUVCDQpDd1VBQTRJQkFRQjNUbjN6QjJxSmlvQWRBdnFUV2piSDIwTnRDeE5qTnQxT2g3UFBmSGVLMmxGZ2hrZm80RjZIDQp4YjZOSG5Venl2UndIbjkrMFVzSll5UEt0bVl1UkxrTWVwT3JzM3NtcEVoa1ZEVkcyaGlyWnptd2pHeExNLzBZDQpkdFpKYXRMNEtFZ1g2ZE9sb1hRQWV6b0ZuejRQb25zQVQ0NU1kTXlWUURlZGt4Qy9FSUc1S0dkSXljSlh4dGdpDQorZ3lUSkVMMEZyTXpic2pyL3pONCsxSkFGVzZwOUxDQ09kYzgzT2lJbW9NK25vSFltSXlNZTFJUG9oWXNHZFlMDQowTjhyc29Ka3ZuYU5MQ2J3Ui9Xbmg4dmFtWk1ubXVXUDZLbmpBME1xLzJZZnBmMm1RcDNtM2Rlb1hIUXVXSGhvDQpNejkwYTQ2N3lndHZiMTlIc2JDSTZTZHl5eUFhTkZkVQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ0K service: name: pepr-pgbouncer namespace: pepr-system path: >- - /mutate/b0ac8b4fddc6889f561a2f903b35d056a83a67e9f794f63037b24a75513f5c20 + /mutate/8f4f98c091aa908e4b4fb08b764672ea8dc46c36bf2c97d2ad0ce989f270548b failurePolicy: Ignore matchPolicy: Equivalent name: pepr-pgbouncer.pepr.dev From f128b9b37335cdfd30542acfec1636f5b60d5075 Mon Sep 17 00:00:00 2001 From: Mitch Murphy Date: Thu, 4 Jun 2026 17:00:37 -0400 Subject: [PATCH 12/12] feat(pepr): add license header to generated pgbouncer manifest --- manifests/pepr-module-pgbouncer.yaml | 15 +++++++-------- tasks.yaml | 5 +++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/manifests/pepr-module-pgbouncer.yaml b/manifests/pepr-module-pgbouncer.yaml index 73f9e02..5d44302 100644 --- a/manifests/pepr-module-pgbouncer.yaml +++ b/manifests/pepr-module-pgbouncer.yaml @@ -1,6 +1,5 @@ # Copyright 2024 Defense Unicorns # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -41,7 +40,7 @@ metadata: apiVersion: v1 data: value: >- - OGY0Zjk4YzA5MWFhOTA4ZTRiNGZiMDhiNzY0NjcyZWE4ZGM0NmMzNmJmMmM5N2QyYWQwY2U5ODlmMjcwNTQ4Yg== + Y2FiMTU5ZTVjNTg3NjkwNWVjNmY0NWMwMjY5ODIyNTRiZTI4Mzg0MWM3Mzk3NDkyYjEzZjgwZDUxZDJmNGQyYw== kind: Secret metadata: name: pepr-pgbouncer-api-path @@ -51,9 +50,9 @@ type: Opaque apiVersion: v1 data: tls.crt: >- - LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDcURDQ0FaQ2dBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBQU1CNFhEVEkyTURZd05ESXdOVFl4DQpNbG9YRFRJM01EWXdOREl3TlRZeE1sb3dBRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DDQpnZ0VCQUpRZTFtbW9xZFdEZnpnUlU3T1NkUC95Qm4xcjFKQ1A4akx5RXlWWlZSbGU4Q3M3b0o4S2E0MGFxbDA2DQp3ZTdrTy9qR2c1M1N6NUMva0NjZDluU2I3bTRaa2RGMkpSNWR2eWY5R3hvNzdxajB6MGR2S2p1bGRtK3VPcHZHDQoveHM5ZGxUTVNxb1JQWTR0QnpObzFkN1YxNVBMTVF3bXFZZm5RZjRHNkh5Ukd6bFl2ZWtqdWhDb2VjbDZmQWhBDQo0cVB4bGxJdnpDK0JQbnNCb1NnNGZRdzV6TXFZTStzT2srSVBDWVZkOStkcFNWV1JBcDhobTdCY1c1N0NxdDVUDQpJTVgyTEFISWxCK1BMcnppY2xpMGdCREhhcDQ5SmJsNTFhUE9pQUZDSUFPb1paZWtzQUg4VEQ5cEd1VlBJNGgxDQpoejB4NWFPQWhqRjRUNGdTOHUveFc0dGExaUVDQXdFQUFhTXRNQ3N3S1FZRFZSMFJCQ0l3SUlJZWNHVndjaTF3DQpaMkp2ZFc1alpYSXVjR1Z3Y2kxemVYTjBaVzB1YzNaak1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQjVPcG5FDQpzZXpEK2wwNjVTSzZjOTlKL1RTSW1iTnZMaVJ1YkUxM20zbmw4YlUxZSt6djFpb0M0VWZhOG5KZzZsNllKeEg5DQpxb05UOUdYTDMzZnVtSzhrdmM3VkNJVEs3WG5NSkttaHdRZ3EyT3B3YXR3RW1XVDJscG9TT2MrVjFtS2xZVjR1DQpCTEovQVZnczRyVm1ybFR1aTE1TmRPano5clZ0WGlWRGw2eVpaUVlEVW9hUk10YXNHckFhZEpUdE1OQ3NRTmpvDQpIVEZua210ZWZPeS9wSUU3VForc1dFeE41ZjJ1SENnOFljRjd1ZXlkYTc1LzRkL0ZpU3UyY29vcW1xS2RkaG9nDQozMUJqbGF3V2dxUVFqSW02SmY3RFJrdGtCd1krckFjMmM0a2h3N1FyVlRRVGpPcVp1M2o4TlNHWHRVLzhhYllzDQovWTFTZDRrUlMrY04xQUllDQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo= + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDcURDQ0FaQ2dBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBQU1CNFhEVEkyTURZd05ESXdOVGsxDQpORm9YRFRJM01EWXdOREl3TlRrMU5Gb3dBRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DDQpnZ0VCQUttWjlDZlVscGdMQTZydlJTYmdsV3pGSmJCWHJJYmtqUkRPMm8zTjhSVGtwUjRuOFoxZjNNUHB1Z2oxDQpsRGRvS2JNU2kyZll0aVRmdjJ4STU0eW5YUVNVUFNlK0ZJQkk3R2x3OGJwemVDb1RkdkZ5UndMRGc4d3gva3F4DQpnRHRtbGI0Y0ZRNGs3bGpHSTFEaHA3cHRwcVJaM3hUM3BmelNMd1NCcC9xNXdqaHMzTlJ6Ukw1Vy8ybGllN3lDDQpHWGlscjU3alNKcXlIWjJQbUN2S3lpdmRGNURhSU1ITzlFYkNKak1penBjSDV1Qmx4R2lXbzljTXRyVFpqS0g4DQp2Mlk3d0xac2tXM2dGQ1VUbEw4aG9TUU9jVUpJUkVHdXlTaHo2VVJveWhtM3lxMnpacVFxRTZsbTU5WWFwcDVpDQp1dXFKMm1NSzl6RFN0eGcvTXRkRStKUEpneThDQXdFQUFhTXRNQ3N3S1FZRFZSMFJCQ0l3SUlJZWNHVndjaTF3DQpaMkp2ZFc1alpYSXVjR1Z3Y2kxemVYTjBaVzB1YzNaak1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRRHVncHpuDQpoQTNvczZvNDlpZVN4eGthejNyNzU5L2Y5cldMWWpDRzVMNDQ2czBmMG45TEQwSWVmRHROQmxSTS8xY2ZMSDlXDQo4VUpKUWxFZjl4VlN0TzRIYXl0ZVNUZTEwd3ZRcCs4eWJ6Q1FKWjBvWDhsT0ZDa0d2NnlKaG5nZ0lxRlZuckY3DQpFTXpVN1E4ZCsydFZOWU0yMFVqQW5mSWxScHI3b2Z4cHdIWWtaRk1PblN1NDI4blRabHdMMmtUTGRTNGVuWWUvDQpZRlc5UXFOaUxSUkE1MDVOVjRFUVJmUlk5WnJ1a0lmQWNnRkVGamF0VGloMnkyeTZDVXBqejhCcFdMWGxRTThCDQo5RXFTQlNRM1ptUmszeWFCcVExeXk3cStIb3hEcHNTTXIzdHRqMTBzN3NjS28vNG5DRjR5NHM0RnN2YnBsKzIxDQpVck91anpUTVFxS3ZvNUw0DQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo= tls.key: >- - LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ0KTUlJRW9nSUJBQUtDQVFFQWxCN1dhYWlwMVlOL09CRlRzNUowLy9JR2ZXdlVrSS95TXZJVEpWbFZHVjd3S3p1Zw0KbndwcmpScXFYVHJCN3VRNytNYURuZExQa0wrUUp4MzJkSnZ1YmhtUjBYWWxIbDIvSi8wYkdqdnVxUFRQUjI4cQ0KTzZWMmI2NDZtOGIvR3oxMlZNeEtxaEU5amkwSE0yalYzdFhYazhzeERDYXBoK2RCL2dib2ZKRWJPVmk5NlNPNg0KRUtoNXlYcDhDRURpby9HV1VpL01MNEUrZXdHaEtEaDlERG5NeXBnejZ3NlQ0ZzhKaFYzMzUybEpWWkVDbnlHYg0Kc0Z4Ym5zS3EzbE1neGZZc0FjaVVINDh1dk9KeVdMU0FFTWRxbmowbHVYblZvODZJQVVJZ0E2aGxsNlN3QWZ4TQ0KUDJrYTVVOGppSFdIUFRIbG80Q0dNWGhQaUJMeTcvRmJpMXJXSVFJREFRQUJBb0lCQUFUVFNGcmkwcjJRN2hrTw0KZjNLUEo5NmFyTmx6Sk5hY3llQWRBTUNydTFqN1BjbTZ4STNKMGgwanJEOGpSZVFaYlZhNmFObEFYK0N3VE9ycA0KVC9rV2gxcnczRTQ5a2hIK0xkY0lxTlJlOVhSdG5UOFBnUW0yWnpoV0xiU2JjLzRZTDMydHRoVDZRTTRiNjJzaQ0KVkMxUlBCZWxlL0NRWmQ5MmlqRFRXc21NRkozMm1IQnRTMHJDc2F6dFE0L2ZiSUJjR2pYNGRJSmR2WlBUTFd2TQ0KdWtlKzZwY1orTWtuRXF0NndqUy9MSHpUeXBPWEFVQko4eUhMZk9vUDg5RXlEV2d0OFdMTWpsODFvRk10ZHo5Sg0KMTlUQjJnbGFlTlJPZzFmazk3Y1lYVjFmU2lPbFZldGRUUnZqeTlENHEwajBWWTlnYnFHWjdtaXU5VlhoU09sQg0KS1AxSTJWRUNnWUVBeHg1MC84M0lLM1dYN0NaUTVnemNYTTVHUnhGWXdROFhzd0V6OVJNS3RKTzJSRFc5aHBOWA0KaENOQnlqc3l2ZlArLy9QMGlqajMvQkxkT3dSTnVMV05NdjBKYW1LT0VueVZBeXZoUmxCTnEybzNNeHBPaEcxeQ0KZktnTklxQTh1VEsySlJGZkR3MFdnUUU1UHpldExFN0VJUFN2TlJXUEJOWDdJVS8zcDdIMGRCMENnWUVBdm03ZA0KdzdvdlJaNjJ2TlMvM0FCb2ZidTFiRkdSYWlzeG10SDhmT0tlTlJ3VGVLQlpsaXljc3lCNXpCR2UwSVY0K0JUbw0KeW9Nd1A3U1Blb0Z0RGFCKzJRalVteFB2eDU3dkJGNDNOby96bUxCT0hBUVcydStUMlByemR6Nm1teUt2dzVKWA0KWlpVRVZtbGM5eStkUDBTRnY2U080ek45SWs1L0ZVNnJuVURtQXRVQ2dZQUY2K3owMG96YVpnUGZuUUFZNTFjQw0KVjR3VmZ2bVJ2RDRyTDZUNDY5a01wN3ZxNldJNmgxVTU4OFo0R2l5WEk1TjR6eXQ5bE5ZakkvaDZVZFZ4NGN4Uw0KTU40LzBMQ0M4anVJUFp6VWQzem4xUi9SSUQ0bmlBMjRrVkxhcmNOQWlyYUtBYXMvQ2xlWi9JeFVTZmFYYzd3Mw0KY3E5bk43M3FHZWIvQlo3SzJPcjVMUUtCZ0MvR3JNaUFHNEFCODZLb1ZZSWljQlNyVlRiWnQvdkUzbXNUSjU5Rg0KVTUvTGJXOGorNVhibDJ5eFJ4MVZobHlXUCtVdGljSFU2L1B2bnRlRFJSTFlJenJjSmtySjA2eG5TVnYxTHpEMw0KS0l3MEgwU1VHZy9QYjI1T2QycUJRMWRFZW9nOFhNVFZnQU1WNkFiejRTV1FVV1hsS1J3RFBPK3dkZDJvb1JHUQ0KeUtRSkFvR0FEYjFQcWQwNi9JUVNrVjZPUHE5K3I4bWxYODd5cy9hc3ZXTlZzMlVxc1o5VFg1Q09XOUh2Q2NReg0KTk1DMEhpaXN0c3d0SmZLMCtxajM2bVhKNVRwZ1h4OUdDaWRIdVk3M1ZLNU91azZ6b2E1dzRqQVQwK09BTllVbg0KUTljM3FTcUFaV2QzKzg3R3RyYWN5eUVZK2tIRi91VElnQWJyckhyYUwyQVZOSFFnczZjPQ0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0NCg== + LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ0KTUlJRW93SUJBQUtDQVFFQXFabjBKOVNXbUFzRHF1OUZKdUNWYk1VbHNGZXNodVNORU03YWpjM3hGT1NsSGlmeA0KblYvY3crbTZDUFdVTjJncHN4S0xaOWkySk4rL2JFam5qS2RkQkpROUo3NFVnRWpzYVhEeHVuTjRLaE4yOFhKSA0KQXNPRHpESCtTckdBTzJhVnZod1ZEaVR1V01ZalVPR251bTJtcEZuZkZQZWwvTkl2QklHbitybkNPR3pjMUhORQ0KdmxiL2FXSjd2SUlaZUtXdm51TkltcklkblkrWUs4cktLOTBYa05vZ3djNzBSc0ltTXlMT2x3Zm00R1hFYUphag0KMXd5MnRObU1vZnkvWmp2QXRteVJiZUFVSlJPVXZ5R2hKQTV4UWtoRVFhN0pLSFBwUkdqS0diZktyYk5tcENvVA0KcVdibjFocW1ubUs2Nm9uYVl3cjNNTkszR0Q4eTEwVDRrOG1ETHdJREFRQUJBb0lCQURWRklsOTZVZHlxcFBuRg0KRW9MT0NwRHg4VThNa3FlQjFOOEJJYnRsZ29IdCtRRGFTZlVFdlpvWmFQSFVkTHZjYnpDTU5CWW5ocnBaUHM0Nw0KcmVMTFZKZVNHZzFJRWpkaThFS0VFNkRkRU5LaWIzc1J5a1VQZE8rbmlqZ2F2V3lxNFlDbllHT2piT3VjUEU1MA0KdWhKL3kxWVcxazlISTY4ZnMxM21mWVR1WUpjSTgyWnBYRDdMSVZmMGQ1RFRVMnVWVDhzczNSd2NrRWxpVG9qYg0KMW9UL1luSkpxN0FPaUJWdEpxNTQ5RHhzU0c3cngrU2pjUnN0UXZQM0lLSDJ6ZEtiYzU1M3pMYUxxTUprL1pJRA0KQ2pmSi81OS85a1FuM3EzVkU2cGYrYUVpMkpsYld3T0VWWmJOc3dZVThmZnVOK2lJOEVJZXF2OEVnTkNEV1dJbQ0KbFc3anF3RUNnWUVBMlZ3UVJLTWE5TWc5dTBJaU5ldjVDUU5OTncxOTY2ck5DbnU4dDlsMkZTY2tqMkNDVThxTg0KZU5VV1NlUEZWd25uT0tQaUYvMDYvMHo3MjVQd3pRYmwzM3BGY2hZcDUrSStKVnJkOVhmSWQxVnBnbFN0a0g0eQ0KSVF3Z295Z1FWS2pWcXZpQWJqTjM0TDZuSlpQMXdCTjZYWUlOUHFpQithTEowQTVYZWVadEVDOENnWUVBeDhCdg0KUVRLRWJUemRKZkd5eE9hWnBLRnBLQnNGbHlhN0tzdm01M2xNZ2dKOEI5RVFWVEhqWnkrNk1TdjJidkRRUi84WA0KTldQNmVDZ29wdE1kN1NzM2Uyc0NMV3cyLzg1VTBSeWNIYzRpcHIvc1phaGFkamt6QzNvdWE3M1UxVE1XVFdRZg0KbEt0dEI5cGJhRnNSY1ZONlFoSnJ5ZndmM2RaUDhtdTBMSHdDL1FFQ2dZQThtYzV2VklwUGRRVEJFTTg0K1hHVg0KY2JZMWd5MTRaMGFEaGJ3NEJnbEdISU8wOWROZ1NUam9WNEMvV1NITUFwYlUwOXhWaytTL0NWZXZBTEJDZVluZA0KcE5sMzFYWVprSnFERDdLU25iTG1rb200TEtPM2hYZTBmdzBhY0RFZGFYVXBGZCs0MmVDeWFIVnhwSzcvdm01Lw0KWTZNTnRTMkh6RHM0SnNkODFTSFRRUUtCZ1FDNHpIQmhHZkpuK1hJRFE2dUcvR3hTWWI0ZWkzbE5rRmlDVEdmUA0KNkdsK3NmdTdZNUEvc1VyWDBORHA0dWszVS9UdFZyTkxBcmJiYVJQSzJ2QUoxZnliWXJGK0FtcVRtSGpoaVIxcA0KZWFhWExHSHczcUxxVXhyRldJRVB6bXpUM1ZLWndMSnk0WEdhWFVwSnJrN2gwRUFBVm5pQVFvL2N0UVA3bStieA0KYkwxN0FRS0JnRjFOL0NUeHVEZlJrZWEvdEs1TG41M3hpY1lkL2hiWVRjRWpxMmlnMjV3eklxSlRpNFpGVGJuTw0KMmo4RVJIRGdTbVovbjJaeHdUQmpkN2I4QlNaWDF4SXo3RXd1NU42WWo5OUNMU0UwRzdZVW5RWWpOUkFnZTRTVQ0KeWVacVVodjBXWjB6MGM1bjlpRVArLzA0MFBnZk5sMS96SXZ0SzFpNmhHMlh0NFlrWjcxaA0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0NCg== kind: Secret metadata: name: pepr-pgbouncer-tls @@ -125,7 +124,7 @@ spec: template: metadata: annotations: - buildTimestamp: '1780606572134' + buildTimestamp: '1780606793952' labels: app: pepr-pgbouncer-watcher pepr.dev/controller: watcher @@ -216,7 +215,7 @@ spec: template: metadata: annotations: - buildTimestamp: '1780606572134' + buildTimestamp: '1780606793952' labels: app: pepr-pgbouncer pepr.dev/controller: admission @@ -333,12 +332,12 @@ webhooks: - v1beta1 clientConfig: caBundle: >- - LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDdERDQ0FaeWdBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBY01Sb3dHQVlEVlFRREV4RlFaWEJ5DQpJRVZ3YUdWdFpYSmhiQ0JEUVRBZUZ3MHlOakEyTURReU1EVTJNVEphRncweU56QTJNRFF5TURVMk1USmFNQUF3DQpnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDamJ3akdmTWx1OHg5SHZjd293WERQDQptRWNLUFBObzNaejlXVlZKRVdpSEMwZVRLcGM0S2diS1Z2V2M2Tk1DbjQxZHR6NUE2b0RVTTJCMFBiV1N6THlKDQo5bm8zM0FUWVJ6VlpGbHE3OHNxeTNUeVhZbzhJSGwxZmNDdnArTGN6OERrWUF0K3Urcjhlbzd4NU9aa00zdkQwDQpFMXhTYVNCaGMrT0VOK3luaFd5VkVFMTJXVHBURHByZ1IxZFE2RURSWmlvL0dxc0tRcE5YeFluMy9yTlVVL2pnDQpZa0NjbGN5Nm03NGlHTU5lcTRxT3JxZllEdmo0UHBBNUFaN09uWndTa3gzZUdNZTRGVjJSOWhESG9GTDE4eGVVDQpMUkhuTExMU0d1YjMxcEszQVdjQnlLUExGaGk4ay9QQyt2WDZBL0NMRGlnUmJwMS90UHNWdDdMejlxT3Z4MGVMDQpBZ01CQUFHakhUQWJNQXdHQTFVZEV3UUZNQU1CQWY4d0N3WURWUjBQQkFRREFnTDBNQTBHQ1NxR1NJYjNEUUVCDQpDd1VBQTRJQkFRQjNUbjN6QjJxSmlvQWRBdnFUV2piSDIwTnRDeE5qTnQxT2g3UFBmSGVLMmxGZ2hrZm80RjZIDQp4YjZOSG5Venl2UndIbjkrMFVzSll5UEt0bVl1UkxrTWVwT3JzM3NtcEVoa1ZEVkcyaGlyWnptd2pHeExNLzBZDQpkdFpKYXRMNEtFZ1g2ZE9sb1hRQWV6b0ZuejRQb25zQVQ0NU1kTXlWUURlZGt4Qy9FSUc1S0dkSXljSlh4dGdpDQorZ3lUSkVMMEZyTXpic2pyL3pONCsxSkFGVzZwOUxDQ09kYzgzT2lJbW9NK25vSFltSXlNZTFJUG9oWXNHZFlMDQowTjhyc29Ka3ZuYU5MQ2J3Ui9Xbmg4dmFtWk1ubXVXUDZLbmpBME1xLzJZZnBmMm1RcDNtM2Rlb1hIUXVXSGhvDQpNejkwYTQ2N3lndHZiMTlIc2JDSTZTZHl5eUFhTkZkVQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ0K + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlDdERDQ0FaeWdBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBY01Sb3dHQVlEVlFRREV4RlFaWEJ5DQpJRVZ3YUdWdFpYSmhiQ0JEUVRBZUZ3MHlOakEyTURReU1EVTVOVE5hRncweU56QTJNRFF5TURVNU5UTmFNQUF3DQpnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEdnVPZ3FVaW90b3ZlMXRWWjl0R1p4DQo4TnBqUGs3QXVSWmhZTDJOQ1Z1bW9jbU9zY0syQXMwOHhOZkQzWmYxMURDaCtmaXRMMEo2MkUzTEkvOFBQOG02DQp5anRVSkt0TVV1Y3p4ZkVyKzNacjZxYWZHV1AwcjFXeTNCZkt3eDd2cFVKM1E5d2xyaXdpWS83Q0ZIMzJ5eWxUDQo5Z3VwRWhKdkY4clRTSHBxRktLcG52V0x3YlViSTdmYld4dVdOSktaYXVEbGlUU0hjTHpJbUtVN1g3aGJxcEVMDQp2SW1OaGQ4UXIzd1J4Z3p0TzhlNmpNZE9KYk94Qi9iTHJHS2VYSS9yL1laQTJXUXdQYmtaR0o1NVIvREkxZTJCDQpINUVhWWdTMEpPVk9GclFPQmlTaGo1TFNPcjlTYkxGblFScFJNRThHQlJVRTg2N3FBcllxcyt2VjdOZlMwODV0DQpBZ01CQUFHakhUQWJNQXdHQTFVZEV3UUZNQU1CQWY4d0N3WURWUjBQQkFRREFnTDBNQTBHQ1NxR1NJYjNEUUVCDQpDd1VBQTRJQkFRQkduMHgvaTczaWRlYlBaKzhsQ282bGdNUXdyelJGUXRPdGs1eVZKYUJRdHU5RjAwNk1sSmRxDQpCby9KdHZiNkpmaWxxVGFxZ1dMTDNCalFGT1hyczRvenRmMk1ic2ZpWm1CbUQwZmFTMTVtN0hHWWlxY0M2VjdaDQpNdkdhSGNDQmZCQjBsT0Z2aFFkSXVtUXpBZVEyZWJERHVjUisyYXh4RWI4Q1NhRzI2UUtzYVNjQnZVNjhXTmQwDQp6SDcvYkVEU3E2aXJucjVOc05YT05DaDBvR2Rwb3k3VHdtR3puc09aSFpuT2dlb3A2K0dRV1RkZjNvNmU4bXd3DQpJNExuMmNObGxSSEFpek5YR1F5Y0hPTkZDb0F3M0JmNkp3Zms4VXc4VVRwcXYxRnhpUHN2aVdpZnNLTllzOE9aDQpZR1YxcVBZTjcyQ1NSalFXdUhWOUl5SjVMeXkxQWlLcQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ0K service: name: pepr-pgbouncer namespace: pepr-system path: >- - /mutate/8f4f98c091aa908e4b4fb08b764672ea8dc46c36bf2c97d2ad0ce989f270548b + /mutate/cab159e5c5876905ec6f45c026982254be283841c7397492b13f80d51d2f4d2c failurePolicy: Ignore matchPolicy: Equivalent name: pepr-pgbouncer.pepr.dev diff --git a/tasks.yaml b/tasks.yaml index 2ff1a83..290441b 100644 --- a/tasks.yaml +++ b/tasks.yaml @@ -40,6 +40,11 @@ tasks: uds zarf tools yq ea -i 'select(.kind != "Namespace")' dist/pepr-module-pgbouncer.yaml mkdir -p ../../manifests cp dist/pepr-module-pgbouncer.yaml ../../manifests/pepr-module-pgbouncer.yaml + # add license header to the generated manifest + # 1 - get license header from ./zarf.yaml (first 2 lines) + _license_header=$(head -n 2 ../../zarf.yaml) + # 2 - prepend license header to the generated manifest + echo "$_license_header" | cat - ../../manifests/pepr-module-pgbouncer.yaml > temp && mv temp ../../manifests/pepr-module-pgbouncer.yaml - name: create-deploy-test-bundle description: Test and validate cluster is deployed with Postgres Operator