From bed328b4b9ff7fcc4a69fe51419e2eea658a58bb Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Mon, 4 Dec 2023 19:06:29 +0100 Subject: [PATCH] chore: adjust chart and values Refs: CPLP-3362 --- .../{dependencies.yaml => dependencies.yml} | 0 .github/workflows/lint-pull-request.yml | 61 +++++ ...rt-test.yaml => policy-hub-chart-test.yml} | 2 +- .github/workflows/release-tag.yml | 76 ++++++ .github/workflows/release_candidate.yml | 25 -- .../workflows/release_release_candidate.yml | 28 -- .github/workflows/trivy-dev.yml | 1 + .github/workflows/trivy.yml | 1 + DEPENDENCIES | 1 + charts/policy-hub/Chart.yaml | 1 - charts/policy-hub/README.md | 107 ++++---- charts/policy-hub/templates/_helpers.tpl | 29 ++ ...init.yaml => configmap-postgres-init.yaml} | 8 - ...t-backend-hub.yaml => deployment-hub.yaml} | 48 ++-- charts/policy-hub/templates/ingress.yaml | 80 ++++++ ...ns.yaml => job-policy-hub-migrations.yaml} | 22 +- ...gres-init.yaml => secret-external-db.yaml} | 15 +- .../templates/secret-postgres-init.yaml | 26 ++ charts/policy-hub/templates/service-hub.yaml | 30 +++ charts/policy-hub/values.yaml | 249 +++++++++--------- .../argocd-app-templates/appsetup-stable.yaml | 58 ++-- consortia/environments/values-beta.yaml | 82 +++--- consortia/environments/values-dev.yaml | 59 +++-- consortia/environments/values-int.yaml | 63 ++--- consortia/environments/values-pen.yaml | 59 +++-- consortia/environments/values-rc.yaml | 60 +++-- consortia/environments/values-upgrade.yaml | 12 +- src/PolicyHub.sln | 7 + .../PolicyHub.DbAccess/HubRepositories.cs | 16 -- .../PolicyHub.DbAccess/IHubRepositories.cs | 4 - .../PolicyHub.Entities/PolicyHubContext.cs | 21 +- src/database/PolicyHub.Migrations/Program.cs | 2 +- .../Seeder/BatchInsertSeeder.cs | 10 +- .../Seeder/BatchUpdateSeeder.cs | 9 +- .../KeycloakClaimsTransformation.cs | 2 +- .../BusinessLogic/PolicyHubBusinessLogic.cs | 8 +- .../Extensions/CorsExtensions.cs | 67 ----- .../HealthCheck/HealthCheckExtensions.cs | 81 ------ .../HealthCheck/HealthCheckSettings.cs | 30 --- .../JwtBearerConfigurationHealthCheck.cs | 66 ----- .../Setup/TestDbFixture.cs | 4 +- .../PolicyHub.Entities.Tests.csproj | 52 ++++ .../PolicyKindExtensionsTests.cs | 51 ++++ .../PolicyHub.Entities.Tests/Usings.cs | 23 ++ .../KeycloakClaimsTransformationTests.cs | 92 +++++++ .../PolicyHubBusinessLogicTests.cs | 97 ++++++- .../Controllers/PolicyHubControllerTests.cs | 59 ++++- .../JsonGenerationExtensionsTests.cs | 52 ++++ .../Setup/IntegrationTestFactory.cs | 8 +- 49 files changed, 1166 insertions(+), 798 deletions(-) rename .github/workflows/{dependencies.yaml => dependencies.yml} (100%) create mode 100644 .github/workflows/lint-pull-request.yml rename .github/workflows/{policy-hub-chart-test.yaml => policy-hub-chart-test.yml} (95%) create mode 100644 .github/workflows/release-tag.yml rename charts/policy-hub/templates/{configmap-backend-postgres-init.yaml => configmap-postgres-init.yaml} (79%) rename charts/policy-hub/templates/{deployment-backend-hub.yaml => deployment-hub.yaml} (68%) create mode 100644 charts/policy-hub/templates/ingress.yaml rename charts/policy-hub/templates/{job-backend-policy-hub-migrations.yaml => job-policy-hub-migrations.yaml} (68%) rename charts/policy-hub/templates/{secret-backend-postgres-init.yaml => secret-external-db.yaml} (57%) create mode 100644 charts/policy-hub/templates/secret-postgres-init.yaml create mode 100644 charts/policy-hub/templates/service-hub.yaml delete mode 100644 src/hub/PolicyHub.Service/Extensions/CorsExtensions.cs delete mode 100644 src/hub/PolicyHub.Service/HealthCheck/HealthCheckExtensions.cs delete mode 100644 src/hub/PolicyHub.Service/HealthCheck/HealthCheckSettings.cs delete mode 100644 src/hub/PolicyHub.Service/HealthCheck/JwtBearerConfigurationHealthCheck.cs create mode 100644 tests/database/PolicyHub.Entities.Tests/PolicyHub.Entities.Tests.csproj create mode 100644 tests/database/PolicyHub.Entities.Tests/PolicyKindExtensionsTests.cs create mode 100644 tests/database/PolicyHub.Entities.Tests/Usings.cs create mode 100644 tests/hub/PolicyHub.Service.Tests/Authentication/KeycloakClaimsTransformationTests.cs create mode 100644 tests/hub/PolicyHub.Service.Tests/Extensions/JsonGenerationExtensionsTests.cs diff --git a/.github/workflows/dependencies.yaml b/.github/workflows/dependencies.yml similarity index 100% rename from .github/workflows/dependencies.yaml rename to .github/workflows/dependencies.yml diff --git a/.github/workflows/lint-pull-request.yml b/.github/workflows/lint-pull-request.yml new file mode 100644 index 0000000..7849e6d --- /dev/null +++ b/.github/workflows/lint-pull-request.yml @@ -0,0 +1,61 @@ +############################################################### +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +############################################################### + +name: "Lint PullRequest" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + id: lint_pr_title + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: marocchino/sticky-pull-request-comment@v2 + # When the previous steps fail, the workflow would stop. By adding this + # condition you can continue the execution with the populated error message. + if: always() && (steps.lint_pr_title.outputs.error_message != null) + with: + header: pr-title-lint-error + message: | + Hey there and thank you for opening this pull request! 👋🏼 + + We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. + + Details: + + ``` + ${{ steps.lint_pr_title.outputs.error_message }} + ``` + + # Delete a previous comment when the issue has been resolved + - if: ${{ steps.lint_pr_title.outputs.error_message == null }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: pr-title-lint-error + delete: true \ No newline at end of file diff --git a/.github/workflows/policy-hub-chart-test.yaml b/.github/workflows/policy-hub-chart-test.yml similarity index 95% rename from .github/workflows/policy-hub-chart-test.yaml rename to .github/workflows/policy-hub-chart-test.yml index 18b38cc..80a7b9b 100644 --- a/.github/workflows/policy-hub-chart-test.yaml +++ b/.github/workflows/policy-hub-chart-test.yml @@ -103,7 +103,7 @@ jobs: run: ct lint --validate-maintainers=false --target-branch ${{ github.event.repository.default_branch }} - name: Run service chart-testing (install) - run: ct install --charts charts/policy-hub --config charts/chart-testing-config.yaml --helm-extra-set-args "--set=backend.policyhub.image=kind-registry:5000/policy-hub-service:testing --set=backend.policyhubmigrations.image=kind-registry:5000/policy-hub-migrations:testing" + run: ct install --charts charts/policy-hub --config charts/chart-testing-config.yaml --helm-extra-set-args "--set=policyhub.image=kind-registry:5000/policy-hub-service:testing --set=policyhubmigrations.image=kind-registry:5000/policy-hub-migrations:testing" if: github.event_name != 'pull_request' || steps.list-changed.outputs.changed == 'true' # currently the update is commented out, at the moment we're working for the initial version, after that the update will be enabled diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml new file mode 100644 index 0000000..5ce1817 --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,76 @@ + +############################################################### +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +############################################################### + +name: Release tag and changelog + +on: + pull_request: + types: + - closed + branches: + - 'release/v*.*.*' + + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + + # Run the workflow only if the PR was merged, if it was rejected or closed we don't want to create the tags + release-rc: + if: github.event.pull_request.merged == true && startsWith(github.ref_name, 'refs/heads/release/v*-RC') + runs-on: ubuntu-latest + steps: + - uses: google-github-actions/release-please-action@v3 + id: release + with: + release-type: simple + changelog-types: '[{"type":"feat","section":"Change","hidden":false},{"type":"fix","section":"Bugfix","hidden":false},{"type":"chore","section":"Technical Support","hidden":false}]' + pull-request-header: 'New release was created' + prerelease: true + + # Run the workflow only if the PR was merged, if it was rejected or closed we don't want to create the tags + release: + if: github.event.pull_request.merged == true && !startsWith(github.ref_name, 'refs/heads/release/v*-RC') + runs-on: ubuntu-latest + steps: + - uses: google-github-actions/release-please-action@v3 + id: release + with: + release-type: simple + changelog-types: '[{"type":"feat","section":"Change","hidden":false},{"type":"fix","section":"Bugfix","hidden":false},{"type":"chore","section":"Technical Support","hidden":false}]' + pull-request-header: 'New release was created' + - uses: actions/checkout@v2 + - name: tag major and minor versions + if: ${{ steps.release.outputs.release_created }} + run: | + git config user.name eclipse-tractusx-bot + git config user.email tractusx-bot@eclipse.org + git remote add gh-token "https://${{ secrets.GITHUB_TOKEN }}@github.com/${{github.event.repository.name}}.git" + git tag -d v${{ steps.release.outputs.major }} || true + git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true + git push origin :v${{ steps.release.outputs.major }} || true + git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true + git tag -a v${{ steps.release.outputs.major }} -m "Version v${{ steps.release.outputs.major }}: Catena-X Policy Hub" + git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} -m "Version v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}: Catena-X Policy Hub" + git push origin v${{ steps.release.outputs.major }} + git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} \ No newline at end of file diff --git a/.github/workflows/release_candidate.yml b/.github/workflows/release_candidate.yml index aee0a5e..051da24 100644 --- a/.github/workflows/release_candidate.yml +++ b/.github/workflows/release_candidate.yml @@ -134,28 +134,3 @@ jobs: password: ${{ secrets.DOCKER_HUB_TOKEN }} repository: ${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME_MIGRATIONS }} readme-filepath: "./docker/notice-policy-hub-migrations.md" - - # auth-and-dispatch: - # needs: [ policy-hub-service-release, policy-hub-migrations-release ] - # runs-on: ubuntu-latest - - # steps: - # - name: Get token - # id: get_workflow_token - # uses: peter-murray/workflow-application-token-action@v2 - # with: - # application_id: ${{ secrets.ORG_PORTAL_DISPATCH_APPID }} - # application_private_key: ${{ secrets.ORG_PORTAL_DISPATCH_KEY }} - - # - name: Trigger workflow - # id: call_action - # env: - # TOKEN: ${{ steps.get_workflow_token.outputs.token }} - # run: | - # curl -v \ - # --request POST \ - # --url https://api.github.com/repos/eclipse-tractusx/portal-cd/actions/workflows/portal-backend-release-image-update.yml/dispatches \ - # --header "authorization: Bearer $TOKEN" \ - # --header "Accept: application/vnd.github.v3+json" \ - # --data '{"ref":"release-candidate", "inputs": { "new-image":"${{ github.sha }}" }}' \ - # --fail diff --git a/.github/workflows/release_release_candidate.yml b/.github/workflows/release_release_candidate.yml index f7ca8f6..69ae9ae 100644 --- a/.github/workflows/release_release_candidate.yml +++ b/.github/workflows/release_release_candidate.yml @@ -134,31 +134,3 @@ jobs: password: ${{ secrets.DOCKER_HUB_TOKEN }} repository: ${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME_MIGRATIONS }} readme-filepath: "./docker/notice-policy-hub-migrations.md" - - # auth-and-dispatch: - # needs: [ policy-hub-service-release, policy-hub-migrations-release ] - # runs-on: ubuntu-latest - - # steps: - # - name: Set env - # run: echo "RELEASE_VERSION=${{ github.ref_name }}" >> $GITHUB_ENV - - # - name: Get token - # id: get_workflow_token - # uses: peter-murray/workflow-application-token-action@v2 - # with: - # application_id: ${{ secrets.ORG_PORTAL_DISPATCH_APPID }} - # application_private_key: ${{ secrets.ORG_PORTAL_DISPATCH_KEY }} - - # - name: Trigger workflow - # id: call_action - # env: - # TOKEN: ${{ steps.get_workflow_token.outputs.token }} - # run: | - # curl -v \ - # --request POST \ - # --url https://api.github.com/repos/eclipse-tractusx/portal-cd/actions/workflows/portal-backend-release-image-update.yml/dispatches \ - # --header "authorization: Bearer $TOKEN" \ - # --header "Accept: application/vnd.github.v3+json" \ - # --data '{"ref":"release-candidate", "inputs": { "new-image":"${{ github.ref_name }}" }}' \ - # --fail diff --git a/.github/workflows/trivy-dev.yml b/.github/workflows/trivy-dev.yml index 05fd11e..e6be35d 100644 --- a/.github/workflows/trivy-dev.yml +++ b/.github/workflows/trivy-dev.yml @@ -126,6 +126,7 @@ jobs: format: "sarif" output: "trivy-results9.sarif" vuln-type: "os,library" + skip-dirs: "docs/" - name: Upload Trivy scan results to GitHub Security tab if: always() diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 9ccfb40..0219a5f 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -61,6 +61,7 @@ jobs: format: "sarif" output: "trivy-results1.sarif" vuln-type: "os,library" + skip-dirs: "docs/" timeout: "3600s" - name: Upload Trivy scan results to GitHub Security tab diff --git a/DEPENDENCIES b/DEPENDENCIES index 192b4d7..aa9dbca 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -9,6 +9,7 @@ nuget/nuget/-/FluentAssertions/6.11.0, Apache-2.0 AND MIT, approved, #10061 nuget/nuget/-/Flurl.Signed/3.0.6, MIT, approved, #3501 nuget/nuget/-/Humanizer.Core/2.14.1, MIT, approved, #10060 nuget/nuget/-/Mono.TextTemplating/2.2.1, MIT, approved, clearlydefined +nuget/nuget/-/Newtonsoft.Json/13.0.1, MIT AND BSD-3-Clause, approved, #3266 nuget/nuget/-/Newtonsoft.Json/13.0.3, MIT AND BSD-3-Clause, approved, #3266 nuget/nuget/-/Npgsql.EntityFrameworkCore.PostgreSQL/7.0.11, PostgreSQL AND MIT AND Apache-2.0, approved, #10081 nuget/nuget/-/Npgsql/7.0.6, PostgreSQL, approved, #10062 diff --git a/charts/policy-hub/Chart.yaml b/charts/policy-hub/Chart.yaml index 6b0fcae..3fd5d99 100644 --- a/charts/policy-hub/Chart.yaml +++ b/charts/policy-hub/Chart.yaml @@ -27,6 +27,5 @@ home: https://github.com/eclipse-tractusx/policy-hub dependencies: - condition: postgresql.enabled name: postgresql - alias: postgrespolicyhub repository: https://charts.bitnami.com/bitnami version: 12.12.x diff --git a/charts/policy-hub/README.md b/charts/policy-hub/README.md index d16443b..fa056a8 100644 --- a/charts/policy-hub/README.md +++ b/charts/policy-hub/README.md @@ -45,51 +45,38 @@ dependencies: | Key | Type | Default | Description | |-----|------|---------|-------------| | affinity.podAntiAffinity | object | `{"preferredDuringSchedulingIgnoredDuringExecution":[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]}` | Following Catena-X Helm Best Practices, [reference](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity). | -| backend.dbConnection.schema | string | `"hub"` | | -| backend.dbConnection.sslMode | string | `"Disable"` | | -| backend.dotnetEnvironment | string | `"Production"` | | -| backend.healthChecks.liveness.path | string | `"/healthz"` | | -| backend.healthChecks.readyness.path | string | `"/ready"` | | -| backend.healthChecks.startup.path | string | `"/health/startup"` | | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-origin" | string | `"https://*.example.org"` | Provide CORS allowed origin. | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/enable-cors" | string | `"true"` | | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/proxy-body-size" | string | `"8m"` | | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/use-regex" | string | `"true"` | | -| backend.ingress.className | string | `"nginx"` | | -| backend.ingress.enabled | bool | `false` | Policy Hub ingress parameters, enable ingress record generation for policy-hub. | -| backend.ingress.hosts[0] | object | `{"host":"policy-hub.example.org","paths":[{"backend":{"port":8080,"service":"policy-hub-service"},"path":"/api/hub","pathType":"Prefix"}]}` | Provide default path for the ingress record. | -| backend.ingress.name | string | `"policy-hub"` | | -| backend.ingress.tls[0] | object | `{"hosts":[""],"secretName":""}` | Provide tls secret. | -| backend.ingress.tls[0].hosts | list | `[""]` | Provide host for tls secret. | -| backend.keycloak.central.authRealm | string | `"CX-Central"` | | -| backend.keycloak.central.jwtBearerOptions.metadataPath | string | `"/auth/realms/CX-Central/.well-known/openid-configuration"` | | -| backend.keycloak.central.jwtBearerOptions.refreshInterval | string | `"00:00:30"` | | -| backend.keycloak.central.jwtBearerOptions.requireHttpsMetadata | string | `"true"` | | -| backend.keycloak.central.jwtBearerOptions.tokenValidationParameters.validAudience | string | `"ClXX-CX-Policy-Hub"` | | -| backend.keycloak.central.jwtBearerOptions.tokenValidationParameters.validIssuerPath | string | `"/auth/realms/CX-Central"` | | -| backend.keycloak.central.tokenPath | string | `"/auth/realms/CX-Central/protocol/openid-connect/token"` | | -| backend.keycloak.central.useAuthTrail | bool | `true` | Flag if the api should be used with an leading /auth path | -| backend.policyhub.healthChecks.startup.tags[0].name | string | `"HEALTHCHECKS__0__TAGS__1"` | | -| backend.policyhub.healthChecks.startup.tags[0].value | string | `"policyhubdb"` | | -| backend.policyhub.image | string | `"tractusx/policy-hub-service:0.1.0"` | | -| backend.policyhub.keycloakClientId | string | `"ClXX-CX-Policy-Hub"` | | -| backend.policyhub.logging.businessLogic | string | `"Information"` | | -| backend.policyhub.logging.default | string | `"Information"` | | -| backend.policyhub.name | string | `"policy-hub-service"` | | -| backend.policyhub.resources | object | `{"requests":{"cpu":"15m","memory":"300M"}}` | We recommend not to specify default resource limits and to leave this as a conscious choice for the user. If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. | -| backend.policyhubmigrations.image | string | `"tractusx/policy-hub-migrations:0.1.0"` | | -| backend.policyhubmigrations.logging.default | string | `"Information"` | | -| backend.policyhubmigrations.name | string | `"policy-hub-migrations"` | | -| backend.policyhubmigrations.resources | object | `{"requests":{"cpu":"15m","memory":"105M"}}` | We recommend not to specify default resource limits and to leave this as a conscious choice for the user. If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. | -| backend.policyhubmigrations.seeding.testDataEnvironments | string | `""` | | -| backend.policyhubmigrations.seeding.testDataPaths | string | `"Seeder/Data"` | | | centralidpAddress | string | `"https://centralidp.example.org"` | Provide centralidp base address (CX IAM), without trailing '/auth'. | -| externalDatabase.database | string | `"postgres"` | Database name | -| externalDatabase.host | string | `"policy-hub-postgresql-external-db"` | External PostgreSQL configuration IMPORTANT: init scripts (01-init-db-user.sh and 02-init-db.sql) available in templates/configmap-backend-postgres-init.yaml need to be executed beforehand. Database host | -| externalDatabase.policyHubPassword | string | `""` | Password for the non-root username 'hub'. Secret-key 'policy-hub-password'. | -| externalDatabase.policyHubUser | string | `"hub"` | Non-root username for hub. | -| externalDatabase.port | int | `5432` | Database port number | -| externalDatabase.secret | string | `"secret-postgres-external-db"` | Secret containing the passwords non-root username hub. | +| dbConnection.schema | string | `"hub"` | | +| dbConnection.sslMode | string | `"Disable"` | | +| dotnetEnvironment | string | `"Production"` | | +| externalDatabase.database | string | `"policy-hub"` | Database name. | +| externalDatabase.existingSecret | string | `"policy-hub-external-db"` | Secret containing the password non-root username, (default 'hub'). | +| externalDatabase.existingSecretPasswordKey | string | `"password"` | Name of an existing secret key containing the database credentials. | +| externalDatabase.host | string | `"policy-hub-postgresql-external-db"` | External PostgreSQL configuration IMPORTANT: non-root db user needs needs to be created beforehand on external database. Database host ('-primary' is added as postfix). | +| externalDatabase.password | string | `""` | Password for the non-root username (default 'hub'). Secret-key 'password'. | +| externalDatabase.port | int | `5432` | Database port number. | +| externalDatabase.user | string | `"hub"` | Non-root username for policy-hub. | +| healthChecks.liveness.path | string | `"/healthz"` | | +| healthChecks.readyness.path | string | `"/ready"` | | +| healthChecks.startup.path | string | `"/health/startup"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-origin" | string | `"https://*.example.org"` | Provide CORS allowed origin. | +| ingress.annotations."nginx.ingress.kubernetes.io/enable-cors" | string | `"true"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/proxy-body-size" | string | `"8m"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/use-regex" | string | `"true"` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `false` | Policy Hub ingress parameters, enable ingress record generation for policy-hub. | +| ingress.hosts[0] | object | `{"host":"policy-hub.example.org","paths":[{"backend":{"port":8080,"service":"policy-hub-service"},"path":"/api/hub","pathType":"Prefix"}]}` | Provide default path for the ingress record. | +| ingress.name | string | `"policy-hub"` | | +| ingress.tls[0] | object | `{"hosts":[""],"secretName":""}` | Provide tls secret. | +| ingress.tls[0].hosts | list | `[""]` | Provide host for tls secret. | +| keycloak.central.authRealm | string | `"CX-Central"` | | +| keycloak.central.jwtBearerOptions.metadataPath | string | `"/auth/realms/CX-Central/.well-known/openid-configuration"` | | +| keycloak.central.jwtBearerOptions.refreshInterval | string | `"00:00:30"` | | +| keycloak.central.jwtBearerOptions.requireHttpsMetadata | string | `"true"` | | +| keycloak.central.jwtBearerOptions.tokenValidationParameters.validAudience | string | `"ClXX-CX-Policy-Hub"` | | +| keycloak.central.jwtBearerOptions.tokenValidationParameters.validIssuerPath | string | `"/auth/realms/CX-Central"` | | +| keycloak.central.tokenPath | string | `"/auth/realms/CX-Central/protocol/openid-connect/token"` | | +| keycloak.central.useAuthTrail | bool | `true` | Flag if the api should be used with an leading /auth path | | livenessProbe.failureThreshold | int | `3` | | | livenessProbe.initialDelaySeconds | int | `10` | | | livenessProbe.periodSeconds | int | `10` | | @@ -97,23 +84,30 @@ dependencies: | livenessProbe.timeoutSeconds | int | `10` | | | name | string | `"policy-hub"` | | | nodeSelector | object | `{}` | Node labels for pod assignment | +| policyhub.healthChecks.startup.tags[0].name | string | `"HEALTHCHECKS__0__TAGS__1"` | | +| policyhub.healthChecks.startup.tags[0].value | string | `"policyhubdb"` | | +| policyhub.image | string | `"tractusx/policy-hub-service:0.1.0"` | | +| policyhub.keycloakClientId | string | `"ClXX-CX-Policy-Hub"` | | +| policyhub.logging.businessLogic | string | `"Information"` | | +| policyhub.logging.default | string | `"Information"` | | +| policyhub.name | string | `"policy-hub-service"` | | +| policyhub.resources | object | `{"requests":{"cpu":"15m","memory":"300M"}}` | We recommend not to specify default resource limits and to leave this as a conscious choice for the user. If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. | +| policyhubmigrations.image | string | `"tractusx/policy-hub-migrations:0.1.0"` | | +| policyhubmigrations.logging.default | string | `"Information"` | | +| policyhubmigrations.name | string | `"policy-hub-migrations"` | | +| policyhubmigrations.resources | object | `{"requests":{"cpu":"15m","memory":"105M"}}` | We recommend not to specify default resource limits and to leave this as a conscious choice for the user. If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. | +| policyhubmigrations.seeding.testDataEnvironments | string | `""` | | +| policyhubmigrations.seeding.testDataPaths | string | `"Seeder/Data"` | | | portContainer | int | `8080` | | | portService | int | `8080` | | | postgresql.architecture | string | `"replication"` | | | postgresql.audit.logLinePrefix | string | `"%m %u %d "` | | | postgresql.audit.pgAuditLog | string | `"write, ddl"` | | -| postgresql.auth.database | string | `"postgres"` | Database name | -| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the passwords for root usernames postgres and non-root usernames repl_user and hub. | -| postgresql.auth.password | string | `""` | Password for the root username 'postgres'. Secret-key 'postgres-password'. | -| postgresql.auth.policyHubPassword | string | `""` | Password for the non-root username 'hub'. Secret-key 'policy-hub-password'. | -| postgresql.auth.policyHubUser | string | `"hub"` | Non-root username for hub. | -| postgresql.auth.port | int | `5432` | Database port number | -| postgresql.enabled | bool | `true` | PostgreSQL chart configuration Switch to enable or disable the PostgreSQL helm chart | -| postgresql.fullnameOverride | string | `"policy-hub-postgresql"` | FullnameOverride to 'policy-hub-postgresql'. | +| postgresql.auth.database | string | `"policy-hub"` | Database name. | +| postgresql.auth.existingSecret | string | `"policy-hub-postgres"` | Secret containing the passwords for root usernames postgres and non-root username hub. | +| postgresql.auth.username | string | `"hub"` | Non-root username. | +| postgresql.enabled | bool | `true` | PostgreSQL chart configuration; default configurations: host: "policy-hub-postgresql-primary", port: 5432; Switch to enable or disable the PostgreSQL helm chart. | | postgresql.primary.extendedConfiguration | string | `""` | Extended PostgreSQL Primary configuration (increase of max_connections recommended - default is 100) | -| postgresql.primary.extraEnvVars[0].name | string | `"POLICY_HUB_PASSWORD"` | | -| postgresql.primary.extraEnvVars[0].valueFrom.secretKeyRef.key | string | `"policy-hub-password"` | | -| postgresql.primary.extraEnvVars[0].valueFrom.secretKeyRef.name | string | `"{{ .Values.auth.existingSecret }}"` | | | postgresql.primary.initdb.scriptsConfigMap | string | `"configmap-postgres-init"` | | | postgresql.readReplicas.extendedConfiguration | string | `""` | Extended PostgreSQL read only replicas configuration (increase of max_connections recommended - default is 100) | | readinessProbe.failureThreshold | int | `3` | | @@ -122,6 +116,9 @@ dependencies: | readinessProbe.successThreshold | int | `1` | | | readinessProbe.timeoutSeconds | int | `1` | | | replicaCount | int | `3` | | +| secrets.postgresql.auth.existingSecret.password | string | `""` | Password for the non-root username 'hub'. Secret-key 'password'. | +| secrets.postgresql.auth.existingSecret.postgrespassword | string | `""` | Password for the root username 'postgres'. Secret-key 'postgres-password'. | +| secrets.postgresql.auth.existingSecret.replicationPassword | string | `""` | Password for the non-root username 'repl_user'. Secret-key 'replication-password'. | | startupProbe | object | `{"failureThreshold":30,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Following Catena-X Helm Best Practices, [reference](https://github.com/helm/charts/blob/master/stable/nginx-ingress/values.yaml#L210). | | tolerations | list | `[]` | Tolerations for pod assignment | | updateStrategy.rollingUpdate.maxSurge | int | `1` | | diff --git a/charts/policy-hub/templates/_helpers.tpl b/charts/policy-hub/templates/_helpers.tpl index 7ba5edc..0453858 100644 --- a/charts/policy-hub/templates/_helpers.tpl +++ b/charts/policy-hub/templates/_helpers.tpl @@ -60,3 +60,32 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* +Determine database hostname for subchart +*/}} + +{{- define "postgresql.primary.fullname" -}} +{{- if eq .Values.postgresql.architecture "replication" }} +{{- printf "%s-primary" (include "chart-name-postgresql-dependency" .) | trunc 63 | trimSuffix "-" -}} +{{- else -}} + {{- include "chart-name-postgresql-dependency" . -}} +{{- end -}} +{{- end -}} + +{{- define "postgresql.readReplica.fullname" -}} +{{- printf "%s-read" (include "chart-name-postgresql-dependency" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "chart-name-postgresql-dependency" -}} +{{- if .Values.postgresql.fullnameOverride -}} +{{- .Values.postgresql.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default "postgresql" .Values.postgresql.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/policy-hub/templates/configmap-backend-postgres-init.yaml b/charts/policy-hub/templates/configmap-postgres-init.yaml similarity index 79% rename from charts/policy-hub/templates/configmap-backend-postgres-init.yaml rename to charts/policy-hub/templates/configmap-postgres-init.yaml index 8ede273..c218c7f 100644 --- a/charts/policy-hub/templates/configmap-backend-postgres-init.yaml +++ b/charts/policy-hub/templates/configmap-postgres-init.yaml @@ -24,14 +24,6 @@ metadata: name: {{ .Values.postgresql.primary.initdb.scriptsConfigMap }} namespace: {{ .Release.Namespace }} data: - 01-init-db-user.sh: | - postgresql_create_hub_user() { - local -r escaped_password="${POLICY_HUB_PASSWORD//\'/\'\'}" - info "Creating user hub" - export PGPASSWORD="$POSTGRES_PASSWORD" - echo "CREATE USER hub WITH PASSWORD '${escaped_password}';" | psql -U postgres - } - postgresql_create_hub_user 02-init-db.sql: | CREATE SCHEMA hub; ALTER SCHEMA hub OWNER TO hub; diff --git a/charts/policy-hub/templates/deployment-backend-hub.yaml b/charts/policy-hub/templates/deployment-hub.yaml similarity index 68% rename from charts/policy-hub/templates/deployment-backend-hub.yaml rename to charts/policy-hub/templates/deployment-hub.yaml index e60f1d6..565e70c 100644 --- a/charts/policy-hub/templates/deployment-backend-hub.yaml +++ b/charts/policy-hub/templates/deployment-hub.yaml @@ -20,32 +20,32 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Values.backend.policyhub.name }} + name: "{{ .Release.Name }}-{{ .Values.policyhub.name }}" spec: replicas: {{ .Values.replicaCount }} strategy: {{- toYaml .Values.updateStrategy | nindent 4 }} selector: matchLabels: - app: {{ .Values.backend.policyhub.name }} + app: {{ .Values.policyhub.name }} template: metadata: labels: - app: {{ .Values.backend.policyhub.name }} + app: {{ .Values.policyhub.name }} spec: containers: - - name: {{ .Values.backend.policyhub.name }} + - name: {{ .Values.policyhub.name }} securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL runAsNonRoot: true - image: "{{ .Values.backend.policyhub.image }}" + image: "{{ .Values.policyhub.image }}" imagePullPolicy: "Always" env: - name: DOTNET_ENVIRONMENT - value: "{{ .Values.backend.dotnetEnvironment }}" + value: "{{ .Values.dotnetEnvironment }}" {{- if .Values.postgresql.enabled }} - name: "POLICY_HUB_PASSWORD" valueFrom: @@ -53,7 +53,7 @@ spec: name: "{{ .Values.postgresql.auth.existingSecret }}" key: "policy-hub-password" - name: "CONNECTIONSTRINGS__POLICYHUBDB" - value: "Server={{ .Values.postgresql.fullnameOverride }}-primary;Database={{ .Values.postgresql.auth.database }};Port={{ .Values.postgresql.auth.port }};User Id={{ .Values.postgresql.auth.policyHubUser }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.backend.dbConnection.sslMode }};" + value: "Server={{ template "postgresql.primary.fullname" . }};Database={{ .Values.postgresql.auth.database }};Port={{ .Values.postgresql.auth.port }};User Id={{ .Values.postgresql.auth.username }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.dbConnection.sslMode }};" {{- end }} {{- if not .Values.postgresql.enabled }} - name: "POLICY_HUB_PASSWORD" @@ -62,38 +62,38 @@ spec: name: "{{ .Values.externalDatabase.secret }}" key: "policy-hub-password" - name: "CONNECTIONSTRINGS__POLICYHUBDB" - value: "Server={{ .Values.externalDatabase.host }};Database={{ .Values.externalDatabase.database }};Port={{ .Values.externalDatabase.port }};User Id={{ .Values.externalDatabase.policyHubUser }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.backend.dbConnection.sslMode }};" + value: "Server={{ .Values.externalDatabase.host }};Database={{ .Values.externalDatabase.database }};Port={{ .Values.externalDatabase.port }};User Id={{ .Values.externalDatabase.username }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.dbConnection.sslMode }};" {{- end }} - name: "HEALTHCHECKS__0__PATH" - value: "{{ .Values.backend.healthChecks.startup.path}}" - {{- if .Values.backend.policyhub.healthChecks.startup.tags }} - {{- toYaml .Values.backend.policyhub.healthChecks.startup.tags | nindent 8 }} + value: "{{ .Values.healthChecks.startup.path}}" + {{- if .Values.policyhub.healthChecks.startup.tags }} + {{- toYaml .Values.policyhub.healthChecks.startup.tags | nindent 8 }} {{- end }} - name: "HEALTHCHECKS__1__PATH" - value: "{{ .Values.backend.healthChecks.readyness.path}}" + value: "{{ .Values.healthChecks.readyness.path}}" - name: "HEALTHCHECKS__2__PATH" - value: "{{ .Values.backend.healthChecks.liveness.path}}" + value: "{{ .Values.healthChecks.liveness.path}}" - name: "JWTBEAREROPTIONS__METADATAADDRESS" - value: "{{ .Values.centralidpAddress }}{{ .Values.backend.keycloak.central.jwtBearerOptions.metadataPath }}" + value: "{{ .Values.centralidpAddress }}{{ .Values.keycloak.central.jwtBearerOptions.metadataPath }}" - name: "JWTBEAREROPTIONS__REQUIREHTTPSMETADATA" - value: "{{ .Values.backend.keycloak.central.jwtBearerOptions.requireHttpsMetadata }}" + value: "{{ .Values.keycloak.central.jwtBearerOptions.requireHttpsMetadata }}" - name: "JWTBEAREROPTIONS__TOKENVALIDATIONPARAMETERS__VALIDAUDIENCE" - value: "{{ .Values.backend.keycloak.central.jwtBearerOptions.tokenValidationParameters.validAudience }}" + value: "{{ .Values.keycloak.central.jwtBearerOptions.tokenValidationParameters.validAudience }}" - name: "JWTBEAREROPTIONS__TOKENVALIDATIONPARAMETERS__VALIDISSUER" - value: "{{ .Values.centralidpAddress }}{{ .Values.backend.keycloak.central.jwtBearerOptions.tokenValidationParameters.validIssuerPath }}" + value: "{{ .Values.centralidpAddress }}{{ .Values.keycloak.central.jwtBearerOptions.tokenValidationParameters.validIssuerPath }}" - name: "JWTBEAREROPTIONS__REFRESHINTERVAL" - value: "{{ .Values.backend.keycloak.central.jwtBearerOptions.refreshInterval }}" + value: "{{ .Values.keycloak.central.jwtBearerOptions.refreshInterval }}" - name: "SERILOG__MINIMUMLEVEL__Default" - value: "{{ .Values.backend.policyhub.logging.default }}" + value: "{{ .Values.policyhub.logging.default }}" - name: "SERILOG__MINIMUMLEVEL__OVERRIDE__Org.Eclipse.TractusX.PolicyHub.Service" - value: "{{ .Values.backend.policyhub.logging.businessLogic }}" + value: "{{ .Values.policyhub.logging.businessLogic }}" ports: - name: http containerPort: {{ .Values.portContainer }} protocol: TCP startupProbe: httpGet: - path: {{ .Values.backend.healthChecks.startup.path }} + path: {{ .Values.healthChecks.startup.path }} port: {{ .Values.portContainer }} scheme: HTTP initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} @@ -103,7 +103,7 @@ spec: failureThreshold: {{ .Values.startupProbe.failureThreshold }} livenessProbe: httpGet: - path: {{ .Values.backend.healthChecks.liveness.path }} + path: {{ .Values.healthChecks.liveness.path }} port: {{ .Values.portContainer }} scheme: HTTP initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} @@ -113,7 +113,7 @@ spec: failureThreshold: {{ .Values.livenessProbe.failureThreshold }} readinessProbe: httpGet: - path: {{ .Values.backend.healthChecks.readyness.path }} + path: {{ .Values.healthChecks.readyness.path }} port: {{ .Values.portContainer }} scheme: HTTP initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} @@ -122,7 +122,7 @@ spec: successThreshold: {{ .Values.readinessProbe.successThreshold }} failureThreshold: {{ .Values.readinessProbe.failureThreshold }} resources: - {{- toYaml .Values.backend.policyhub.resources | nindent 10 }} + {{- toYaml .Values.policyhub.resources | nindent 10 }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/policy-hub/templates/ingress.yaml b/charts/policy-hub/templates/ingress.yaml new file mode 100644 index 0000000..f999995 --- /dev/null +++ b/charts/policy-hub/templates/ingress.yaml @@ -0,0 +1,80 @@ +{{- /* +* Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* This program and the accompanying materials are made available under the +* terms of the Apache License, Version 2.0 which is available at +* https://www.apache.org/licenses/LICENSE-2.0. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +* +* SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if .Values.ingress.enabled -}} +{{- $fullName := .Values.ingress.name -}} +{{- $svcPort := .Values.portService -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ .service }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ .service }} + servicePort: {{ .port }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/policy-hub/templates/job-backend-policy-hub-migrations.yaml b/charts/policy-hub/templates/job-policy-hub-migrations.yaml similarity index 68% rename from charts/policy-hub/templates/job-backend-policy-hub-migrations.yaml rename to charts/policy-hub/templates/job-policy-hub-migrations.yaml index 9c46b5c..708563c 100644 --- a/charts/policy-hub/templates/job-backend-policy-hub-migrations.yaml +++ b/charts/policy-hub/templates/job-policy-hub-migrations.yaml @@ -20,7 +20,7 @@ apiVersion: batch/v1 kind: Job metadata: - name: {{ .Values.backend.policyhubmigrations.name }} + name: {{ .Values.policyhubmigrations.name }} annotations: "batch.kubernetes.io/job-tracking": "true" "helm.sh/hook": post-install,post-upgrade @@ -28,22 +28,22 @@ metadata: spec: template: metadata: - name: {{ .Values.backend.policyhubmigrations.name }} + name: {{ .Values.policyhubmigrations.name }} spec: restartPolicy: Never containers: - - name: {{ .Values.backend.policyhubmigrations.name }} + - name: {{ .Values.policyhubmigrations.name }} securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL runAsNonRoot: true - image: "{{ .Values.backend.policyhubmigrations.image }}" + image: "{{ .Values.policyhubmigrations.image }}" imagePullPolicy: "Always" env: - name: DOTNET_ENVIRONMENT - value: "{{ .Values.backend.dotnetEnvironment }}" + value: "{{ .Values.dotnetEnvironment }}" {{- if .Values.postgresql.enabled }} - name: "POLICY_HUB_PASSWORD" valueFrom: @@ -51,7 +51,7 @@ spec: name: "{{ .Values.postgresql.auth.existingSecret }}" key: "policy-hub-password" - name: "CONNECTIONSTRINGS__POLICYHUBDB" - value: "Server={{ .Values.postgresql.fullnameOverride }}-primary;Database={{ .Values.postgresql.auth.database }};Port={{ .Values.postgresql.auth.port }};User Id={{ .Values.postgresql.auth.policyHubUser }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.backend.dbConnection.sslMode }};" + value: "Server={{ template "postgresql.primary.fullname" . }};Database={{ .Values.postgresql.auth.database }};Port={{ .Values.postgresql.auth.port }};User Id={{ .Values.postgresql.auth.username }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.dbConnection.sslMode }};" {{- end }} {{- if not .Values.postgresql.enabled }} - name: "POLICY_HUB_PASSWORD" @@ -60,17 +60,17 @@ spec: name: "{{ .Values.externalDatabase.secret }}" key: "policy-hub-password" - name: "CONNECTIONSTRINGS__POLICYHUBDB" - value: "Server={{ .Values.externalDatabase.host }};Database={{ .Values.externalDatabase.database }};Port={{ .Values.externalDatabase.port }};User Id={{ .Values.externalDatabase.policyHubUser }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.backend.dbConnection.sslMode }};" + value: "Server={{ .Values.externalDatabase.host }};Database={{ .Values.externalDatabase.database }};Port={{ .Values.externalDatabase.port }};User Id={{ .Values.externalDatabase.username }};Password=$(POLICY_HUB_PASSWORD);Ssl Mode={{ .Values.dbConnection.sslMode }};" {{- end }} - name: "SEEDING__TESTDATAENVIRONMENTS__0" - value: "{{ .Values.backend.policyhubmigrations.seeding.testDataEnvironments }}" + value: "{{ .Values.policyhubmigrations.seeding.testDataEnvironments }}" - name: "SEEDING__DATAPATHS__0" - value: "{{ .Values.backend.policyhubmigrations.seeding.testDataPaths }}" + value: "{{ .Values.policyhubmigrations.seeding.testDataPaths }}" - name: "SERILOG__MINIMUMLEVEL__Default" - value: "{{ .Values.backend.policyhubmigrations.logging.default }}" + value: "{{ .Values.policyhubmigrations.logging.default }}" ports: - name: http containerPort: {{ .Values.portContainer }} protocol: TCP resources: - {{- toYaml .Values.backend.policyhubmigrations.resources | nindent 10 }} + {{- toYaml .Values.policyhubmigrations.resources | nindent 10 }} diff --git a/charts/policy-hub/templates/secret-backend-postgres-init.yaml b/charts/policy-hub/templates/secret-external-db.yaml similarity index 57% rename from charts/policy-hub/templates/secret-backend-postgres-init.yaml rename to charts/policy-hub/templates/secret-external-db.yaml index e08bd49..78c60e5 100644 --- a/charts/policy-hub/templates/secret-backend-postgres-init.yaml +++ b/charts/policy-hub/templates/secret-external-db.yaml @@ -17,28 +17,23 @@ * SPDX-License-Identifier: Apache-2.0 */}} -{{- if .Values.postgresql.enabled -}} +{{- if not .Values.postgresql.enabled -}} apiVersion: v1 kind: Secret metadata: - name: {{ .Values.postgresql.auth.existingSecret }} + name: {{ .Values.externalDatabase.existingSecret }} namespace: {{ .Release.Namespace }} type: Opaque # use lookup function to check if secret exists -{{- $secret := (lookup "v1" "Secret" .Release.Namespace .Values.postgresql.auth.existingSecret) }} +{{- $secret := (lookup "v1" "Secret" .Release.Namespace .Values.externalDatabase.existingSecret) }} {{ if $secret -}} data: # if secret exists, use value provided from values file (to cover update scenario) or existing value from secret # use data map instead of stringData to prevent base64 encoding of already base64-encoded existing value from secret - # use index function for secret keys with hyphen otherwise '$secret.data.secretKey' works too - postgres-password: {{ ( .Values.postgresql.auth.password | b64enc ) | default ( index $secret.data "postgres-password" ) | quote }} - replication-password: {{ ( .Values.postgresql.auth.replicationPassword | b64enc ) | default ( index $secret.data "replication-password" ) | quote }} - policy-hub-password: {{ ( .Values.postgresql.auth.policyHubPassword | b64enc ) | default ( index $secret.data "policy-hub-password" ) | quote }} + password: {{ ( .Values.externalDatabase.password | b64enc ) | default $secret.data.password | quote }} {{ else -}} stringData: # if secret doesn't exist, use provided value from values file or generate a random one - postgres-password: {{ .Values.postgresql.auth.password | default ( randAlphaNum 32 ) | quote }} - replication-password: {{ .Values.postgresql.auth.replicationPassword | default ( randAlphaNum 32 ) | quote }} - policy-hub-password: {{ .Values.postgresql.auth.policyHubPassword | default ( randAlphaNum 32 ) | quote }} + password: {{ .Values.externalDatabase.password | default ( randAlphaNum 32 ) | quote }} {{ end }} {{- end -}} diff --git a/charts/policy-hub/templates/secret-postgres-init.yaml b/charts/policy-hub/templates/secret-postgres-init.yaml new file mode 100644 index 0000000..6ea68ed --- /dev/null +++ b/charts/policy-hub/templates/secret-postgres-init.yaml @@ -0,0 +1,26 @@ + +{{- if .Values.postgresql.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.postgresql.auth.existingSecret }} + namespace: {{ .Release.Namespace }} +type: Opaque +# use lookup function to check if secret exists +{{- $secret := (lookup "v1" "Secret" .Release.Namespace .Values.postgresql.auth.existingSecret) }} +{{ if $secret -}} +data: + # if secret exists, use value provided from values file (to cover update scenario) or existing value from secret + # use data map instead of stringData to prevent base64 encoding of already base64-encoded existing value from secret + # use index function for secret keys with hyphen otherwise '$secret.data.secretKey' works too + postgres-password: {{ ( .Values.secrets.postgresql.auth.existingSecret.postgrespassword | b64enc ) | default ( index $secret.data "postgres-password" ) | quote }} + password: {{ ( .Values.secrets.postgresql.auth.existingSecret.password | b64enc ) | default $secret.data.password | quote }} + replication-password: {{ ( .Values.secrets.postgresql.auth.existingSecret.replicationPassword | b64enc ) | default ( index $secret.data "replication-password" ) | quote}} +{{ else -}} +stringData: + # if secret doesn't exist, use provided value from values file or generate a random one + postgres-password: {{ .Values.secrets.postgresql.auth.existingSecret.postgrespassword | default ( randAlphaNum 32 ) | quote }} + password: {{ .Values.secrets.postgresql.auth.existingSecret.password | default ( randAlphaNum 32 ) | quote }} + replication-password: {{ .Values.secrets.postgresql.auth.existingSecret.replicationPassword | default ( randAlphaNum 32 ) | quote }} +{{ end }} +{{- end -}} diff --git a/charts/policy-hub/templates/service-hub.yaml b/charts/policy-hub/templates/service-hub.yaml new file mode 100644 index 0000000..c7009ab --- /dev/null +++ b/charts/policy-hub/templates/service-hub.yaml @@ -0,0 +1,30 @@ +############################################################### +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +############################################################### + +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.policyhub.name }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.portService }} + targetPort: {{ .Values.portContainer }} + selector: + app: {{ .Values.policyhub.name }} diff --git a/charts/policy-hub/values.yaml b/charts/policy-hub/values.yaml index 2e46c9c..6106bb5 100644 --- a/charts/policy-hub/values.yaml +++ b/charts/policy-hub/values.yaml @@ -22,117 +22,112 @@ name: "policy-hub" # -- Provide centralidp base address (CX IAM), without trailing '/auth'. centralidpAddress: "https://centralidp.example.org" -backend: - ingress: - # -- Policy Hub ingress parameters, - # enable ingress record generation for policy-hub. - enabled: false - name: "policy-hub" - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - # -- Provide CORS allowed origin. - nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.example.org" - tls: - # -- Provide tls secret. - - secretName: "" - # -- Provide host for tls secret. - hosts: - - "" - hosts: - # -- Provide default path for the ingress record. - - host: "policy-hub.example.org" - paths: - - path: "/api/hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 - dotnetEnvironment: "Production" - dbConnection: - schema: "hub" - sslMode: "Disable" - keycloak: - central: - authRealm: "CX-Central" - jwtBearerOptions: - requireHttpsMetadata: "true" - metadataPath: "/auth/realms/CX-Central/.well-known/openid-configuration" - tokenValidationParameters: - validIssuerPath: "/auth/realms/CX-Central" - validAudience: "ClXX-CX-Policy-Hub" - refreshInterval: "00:00:30" - tokenPath: "/auth/realms/CX-Central/protocol/openid-connect/token" - # -- Flag if the api should be used with an leading /auth path - useAuthTrail: true +ingress: + # -- Policy Hub ingress parameters, + # enable ingress record generation for policy-hub. + enabled: false + name: "policy-hub" + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + # -- Provide CORS allowed origin. + nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.example.org" + tls: + # -- Provide tls secret. + - secretName: "" + # -- Provide host for tls secret. + hosts: + - "" + hosts: + # -- Provide default path for the ingress record. + - host: "policy-hub.example.org" + paths: + - path: "/api/hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 +dotnetEnvironment: "Production" +dbConnection: + schema: "hub" + sslMode: "Disable" +keycloak: + central: + authRealm: "CX-Central" + jwtBearerOptions: + requireHttpsMetadata: "true" + metadataPath: "/auth/realms/CX-Central/.well-known/openid-configuration" + tokenValidationParameters: + validIssuerPath: "/auth/realms/CX-Central" + validAudience: "ClXX-CX-Policy-Hub" + refreshInterval: "00:00:30" + tokenPath: "/auth/realms/CX-Central/protocol/openid-connect/token" + # -- Flag if the api should be used with an leading /auth path + useAuthTrail: true +healthChecks: + startup: + path: "/health/startup" + liveness: + path: "/healthz" + readyness: + path: "/ready" +policyhub: + name: "policy-hub-service" + image: "tractusx/policy-hub-service:0.1.0" + # -- We recommend not to specify default resource limits and to leave this as a conscious choice for the user. + # If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. + resources: + requests: + cpu: 15m + memory: 300M + # limits: + # cpu: 45m + # memory: 400M + logging: + businessLogic: "Information" + default: "Information" + keycloakClientId: "ClXX-CX-Policy-Hub" healthChecks: startup: - path: "/health/startup" - liveness: - path: "/healthz" - readyness: - path: "/ready" - policyhub: - name: "policy-hub-service" - image: "tractusx/policy-hub-service:0.1.0" - # -- We recommend not to specify default resource limits and to leave this as a conscious choice for the user. - # If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. - resources: - requests: - cpu: 15m - memory: 300M - # limits: - # cpu: 45m - # memory: 400M - logging: - businessLogic: "Information" - default: "Information" - keycloakClientId: "ClXX-CX-Policy-Hub" - healthChecks: - startup: - tags: - - name: "HEALTHCHECKS__0__TAGS__1" - value: "policyhubdb" - policyhubmigrations: - name: "policy-hub-migrations" - image: "tractusx/policy-hub-migrations:0.1.0" - # -- We recommend not to specify default resource limits and to leave this as a conscious choice for the user. - # If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. - resources: - requests: - cpu: 15m - memory: 105M - # limits: - # cpu: 45m - # memory: 105M - seeding: - testDataEnvironments: "" - testDataPaths: "Seeder/Data" - logging: - default: "Information" + tags: + - name: "HEALTHCHECKS__0__TAGS__1" + value: "policyhubdb" + +policyhubmigrations: + name: "policy-hub-migrations" + image: "tractusx/policy-hub-migrations:0.1.0" + # -- We recommend not to specify default resource limits and to leave this as a conscious choice for the user. + # If you do want to specify resource limits, uncomment the following lines and adjust them as necessary. + resources: + requests: + cpu: 15m + memory: 105M + # limits: + # cpu: 45m + # memory: 105M + seeding: + testDataEnvironments: "" + testDataPaths: "Seeder/Data" + logging: + default: "Information" postgresql: -# -- PostgreSQL chart configuration - # Switch to enable or disable the PostgreSQL helm chart + # -- PostgreSQL chart configuration; + # default configurations: + # host: "policy-hub-postgresql-primary", + # port: 5432; + # Switch to enable or disable the PostgreSQL helm chart. enabled: true - # -- FullnameOverride to 'policy-hub-postgresql'. - fullnameOverride: "policy-hub-postgresql" auth: - # -- Database name - database: "postgres" - # -- Database port number - port: 5432 - # -- Secret containing the passwords for root usernames postgres and non-root usernames repl_user and hub. - existingSecret: "secret-postgres-init" - # -- Password for the root username 'postgres'. Secret-key 'postgres-password'. - password: "" - # -- Non-root username for hub. - policyHubUser: "hub" - # -- Password for the non-root username 'hub'. Secret-key 'policy-hub-password'. - policyHubPassword: "" - architecture: "replication" + # -- Non-root username. + username: hub + # -- Database name. + database: policy-hub + # -- Secret containing the passwords for root usernames postgres and non-root username hub. + existingSecret: "policy-hub-postgres" + architecture: replication audit: pgAuditLog: "write, ddl" logLinePrefix: "%m %u %d " @@ -141,32 +136,38 @@ postgresql: extendedConfiguration: "" initdb: scriptsConfigMap: "configmap-postgres-init" - extraEnvVars: - - name: "POLICY_HUB_PASSWORD" - valueFrom: - secretKeyRef: - name: "{{ .Values.auth.existingSecret }}" - key: "policy-hub-password" readReplicas: # -- Extended PostgreSQL read only replicas configuration (increase of max_connections recommended - default is 100) extendedConfiguration: "" externalDatabase: -# -- External PostgreSQL configuration -# IMPORTANT: init scripts (01-init-db-user.sh and 02-init-db.sql) available -# in templates/configmap-backend-postgres-init.yaml need to be executed beforehand. - # Database host + # -- External PostgreSQL configuration + # IMPORTANT: non-root db user needs needs to be created beforehand on external database. + # Database host ('-primary' is added as postfix). host: "policy-hub-postgresql-external-db" - # -- Database name - database: "postgres" - # -- Database port number + # -- Database port number. port: 5432 - # -- Secret containing the passwords non-root username hub. - secret: "secret-postgres-external-db" - # -- Non-root username for hub. - policyHubUser: "hub" - # -- Password for the non-root username 'hub'. Secret-key 'policy-hub-password'. - policyHubPassword: "" + # -- Non-root username for policy-hub. + user: "hub" + # -- Database name. + database: "policy-hub" + # -- Password for the non-root username (default 'hub'). Secret-key 'password'. + password: "" + # -- Secret containing the password non-root username, (default 'hub'). + existingSecret: "policy-hub-external-db" + # -- Name of an existing secret key containing the database credentials. + existingSecretPasswordKey: "password" + +secrets: + postgresql: + auth: + existingSecret: + # -- Password for the root username 'postgres'. Secret-key 'postgres-password'. + postgrespassword: "" + # -- Password for the non-root username 'hub'. Secret-key 'password'. + password: "" + # -- Password for the non-root username 'repl_user'. Secret-key 'replication-password'. + replicationPassword: "" portContainer: 8080 diff --git a/consortia/argocd-app-templates/appsetup-stable.yaml b/consortia/argocd-app-templates/appsetup-stable.yaml index 32c7261..59a3ce4 100644 --- a/consortia/argocd-app-templates/appsetup-stable.yaml +++ b/consortia/argocd-app-templates/appsetup-stable.yaml @@ -35,41 +35,43 @@ spec: - name: HELM_VALUES value: | policyHubBackendAddress: "https://policy-hub.stable.demo.catena-x.net" - backend: - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.stable.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub.stable.demo.catena-x.net" - hosts: - - host: "policy-hub.stable.demo.catena-x.net" - paths: - - path: "/api/policy-hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 - policyhubmigrations: - logging: - default: "Debug" + ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.stable.demo.catena-x.net" + tls: + - secretName: "tls-secret" + hosts: + - "policy-hub.stable.demo.catena-x.net" + hosts: + - host: "policy-hub.stable.demo.catena-x.net" + paths: + - path: "/api/policy-hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 + policyhubmigrations: + logging: + default: "Debug" postgresql: - auth: - password: "" - replicationPassword: "" - policy-hubPassword: "" primary: extendedConfiguration: | max_connections = 200 readReplicas: extendedConfiguration: | max_connections = 200 + secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" chart: policy-hub sources: [] project: project-policy-hub diff --git a/consortia/environments/values-beta.yaml b/consortia/environments/values-beta.yaml index cc1afe5..3665422 100644 --- a/consortia/environments/values-beta.yaml +++ b/consortia/environments/values-beta.yaml @@ -20,63 +20,43 @@ policyHubBackendAddress: "https://policy-hub.beta.demo.catena-x.net" centralidpAddress: "https://centralidp.beta.demo.catena-x.net" -frontend: +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.beta.demo.catena-x.net" + tls: + - secretName: "tls-secret" + hosts: + - "policy-hub.beta.demo.catena-x.net" + hosts: + - host: "policy-hub.beta.demo.catena-x.net" + paths: + - path: "/api/policy-hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/rewrite-target: "/$1" - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.beta.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub.beta.demo.catena-x.net" - hosts: - - host: "policy-hub.beta.demo.catena-x.net" - paths: - - path: "/(.*)" - pathType: "Prefix" - backend: - service: "policy-hub" - port: 8080 - -backend: - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.beta.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub.beta.demo.catena-x.net" - hosts: - - host: "policy-hub.beta.demo.catena-x.net" - paths: - - path: "/api/policy-hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 - - policyhubmigrations: - logging: - default: "Debug" +policyhubmigrations: + logging: + default: "Debug" postgresql: - auth: - password: "" - replicationPassword: "" - policyHubPassword: "" primary: extendedConfiguration: | max_connections = 200 readReplicas: extendedConfiguration: | max_connections = 200 + +secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" diff --git a/consortia/environments/values-dev.yaml b/consortia/environments/values-dev.yaml index 8479e5b..7ee4d9b 100644 --- a/consortia/environments/values-dev.yaml +++ b/consortia/environments/values-dev.yaml @@ -20,40 +20,43 @@ policyHubAddress: "https://policy-hub.dev.demo.catena-x.net" centralidpAddress: "https://centralidp.dev.demo.catena-x.net" -backend: - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.dev.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub.dev.demo.catena-x.net" - hosts: - - host: "policy-hub.dev.demo.catena-x.net" - paths: - - path: "/api/policy-hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.dev.demo.catena-x.net" + tls: + - secretName: "tls-secret" + hosts: + - "policy-hub.dev.demo.catena-x.net" + hosts: + - host: "policy-hub.dev.demo.catena-x.net" + paths: + - path: "/api/policy-hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 - policyhubmigrations: - logging: - default: "Debug" +policyhubmigrations: + logging: + default: "Debug" postgresql: - auth: - password: "" - replicationPassword: "" - policyHubPassword: "" primary: extendedConfiguration: | max_connections = 200 readReplicas: extendedConfiguration: | max_connections = 200 + +secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" diff --git a/consortia/environments/values-int.yaml b/consortia/environments/values-int.yaml index fc4bc8b..fed0a9d 100644 --- a/consortia/environments/values-int.yaml +++ b/consortia/environments/values-int.yaml @@ -20,42 +20,45 @@ policyHubAddress: "https://policy-hub.int.demo.catena-x.net" centralidpAddress: "https://centralidp.int.demo.catena-x.net" -backend: - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.int.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub.int.demo.catena-x.net" - hosts: - - host: "policy-hub.int.demo.catena-x.net" - paths: - - path: "/api/policy-hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.int.demo.catena-x.net" + tls: + - secretName: "tls-secret" + hosts: + - "policy-hub.int.demo.catena-x.net" + hosts: + - host: "policy-hub.int.demo.catena-x.net" + paths: + - path: "/api/policy-hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 - policyhubmigrations: - logging: - default: "Debug" - seeding: - testDataEnvironments: "consortia" +policyhubmigrations: + logging: + default: "Debug" + seeding: + testDataEnvironments: "consortia" postgresql: - auth: - password: "" - replicationPassword: "" - policyHubPassword: "" primary: extendedConfiguration: | max_connections = 200 readReplicas: extendedConfiguration: | max_connections = 200 + +secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" diff --git a/consortia/environments/values-pen.yaml b/consortia/environments/values-pen.yaml index 1c07a94..dc84654 100644 --- a/consortia/environments/values-pen.yaml +++ b/consortia/environments/values-pen.yaml @@ -20,40 +20,43 @@ policyHubAddress: "https://policy-hub-pen.dev.demo.catena-x.net" centralidpAddress: "https://centralidp-pen.dev.demo.catena-x.net" -backend: - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.dev.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub-backend-pen.dev.demo.catena-x.net" - hosts: - - host: "policy-hub-backend-pen.dev.demo.catena-x.net" - paths: - - path: "/api/policy-hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.dev.demo.catena-x.net" + tls: + - secretName: "tls-secret" + hosts: + - "policy-hub-backend-pen.dev.demo.catena-x.net" + hosts: + - host: "policy-hub-backend-pen.dev.demo.catena-x.net" + paths: + - path: "/api/policy-hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 - policyhubmigrations: - logging: - default: "Debug" +policyhubmigrations: + logging: + default: "Debug" postgresql: - auth: - password: "" - replicationPassword: "" - policyHubPassword: "" primary: extendedConfiguration: | max_connections = 200 readReplicas: extendedConfiguration: | max_connections = 200 + +secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" diff --git a/consortia/environments/values-rc.yaml b/consortia/environments/values-rc.yaml index 2f92194..fa0b499 100644 --- a/consortia/environments/values-rc.yaml +++ b/consortia/environments/values-rc.yaml @@ -20,41 +20,43 @@ policyHubAddress: "https://policy-hub-rc.dev.demo.catena-x.net" centralidpAddress: "https://centralidp-rc.dev.demo.catena-x.net" -backend: - ingress: - enabled: true - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/proxy-body-size: "8m" - nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.dev.demo.catena-x.net" - tls: - - secretName: "tls-secret" - hosts: - - "policy-hub-backend-rc.dev.demo.catena-x.net" - hosts: - - host: "policy-hub-backend-rc.dev.demo.catena-x.net" - paths: - - path: "/api/policy-hub" - pathType: "Prefix" - backend: - service: "policy-hub-service" - port: 8080 +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "8m" + nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000, https://*.dev.demo.catena-x.net" + tls: + - secretName: "tls-secret" + hosts: + - "policy-hub-backend-rc.dev.demo.catena-x.net" + hosts: + - host: "policy-hub-backend-rc.dev.demo.catena-x.net" + paths: + - path: "/api/policy-hub" + pathType: "Prefix" + backend: + service: "policy-hub-service" + port: 8080 - policyhubmigrations: - logging: - default: "Debug" +policyhubmigrations: + logging: + default: "Debug" postgresql: - fullnameOverride: "policy-hub-backend-rc-postgresql" - auth: - password: "" - replicationPassword: "" - policyHubPassword: "" primary: extendedConfiguration: | max_connections = 200 readReplicas: extendedConfiguration: | max_connections = 200 + +secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" diff --git a/consortia/environments/values-upgrade.yaml b/consortia/environments/values-upgrade.yaml index 8efce1b..8c84149 100644 --- a/consortia/environments/values-upgrade.yaml +++ b/consortia/environments/values-upgrade.yaml @@ -19,8 +19,10 @@ replicaCount: 0 -postgresql: - auth: - password: "" - replicationPassword: "" - policyHubPassword: "" +secrets: + postgresql: + auth: + existingSecret: + postgrespassword: "" + password: "" + replicationPassword: "" diff --git a/src/PolicyHub.sln b/src/PolicyHub.sln index 4788d2c..6c0fe51 100644 --- a/src/PolicyHub.sln +++ b/src/PolicyHub.sln @@ -18,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolicyHub.DbAccess.Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolicyHub.Service.Tests", "..\tests\hub\PolicyHub.Service.Tests\PolicyHub.Service.Tests.csproj", "{A337EA35-B303-4F1B-9A83-5205E2CBA69D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolicyHub.Entities.Tests", "..\tests\database\PolicyHub.Entities.Tests\PolicyHub.Entities.Tests.csproj", "{1F4F15B3-C3D6-4030-9822-62D72B6DA1C9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -48,6 +50,10 @@ Global {A337EA35-B303-4F1B-9A83-5205E2CBA69D}.Debug|Any CPU.Build.0 = Debug|Any CPU {A337EA35-B303-4F1B-9A83-5205E2CBA69D}.Release|Any CPU.ActiveCfg = Release|Any CPU {A337EA35-B303-4F1B-9A83-5205E2CBA69D}.Release|Any CPU.Build.0 = Release|Any CPU + {1F4F15B3-C3D6-4030-9822-62D72B6DA1C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F4F15B3-C3D6-4030-9822-62D72B6DA1C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F4F15B3-C3D6-4030-9822-62D72B6DA1C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F4F15B3-C3D6-4030-9822-62D72B6DA1C9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {92B16AED-3229-4C46-8498-11D33E5C7F69} = {D30D713C-43E8-488F-BFBB-FD610E77ACA3} @@ -56,5 +62,6 @@ Global {F5BED39D-6419-49AD-A5E0-FAB88723285C} = {6EB9F0CF-3A57-42AA-BF74-AADCF8815F90} {F1551715-BECA-45B2-A71B-CAB60F2D35FE} = {9C9DA872-893E-48BA-9DD5-025D477F6EC3} {A337EA35-B303-4F1B-9A83-5205E2CBA69D} = {9C9DA872-893E-48BA-9DD5-025D477F6EC3} + {1F4F15B3-C3D6-4030-9822-62D72B6DA1C9} = {9C9DA872-893E-48BA-9DD5-025D477F6EC3} EndGlobalSection EndGlobal diff --git a/src/database/PolicyHub.DbAccess/HubRepositories.cs b/src/database/PolicyHub.DbAccess/HubRepositories.cs index 647eae5..5c74d96 100644 --- a/src/database/PolicyHub.DbAccess/HubRepositories.cs +++ b/src/database/PolicyHub.DbAccess/HubRepositories.cs @@ -17,10 +17,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Microsoft.EntityFrameworkCore; using Org.Eclipse.TractusX.PolicyHub.DbAccess.Repositories; using Org.Eclipse.TractusX.PolicyHub.Entities; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Library; using System.Collections.Immutable; namespace Org.Eclipse.TractusX.PolicyHub.DbAccess; @@ -49,18 +47,4 @@ public RepositoryType GetInstance() return (RepositoryType)(repository ?? throw new ArgumentException($"unexpected type {typeof(RepositoryType).Name}", nameof(RepositoryType))); } - - public Task SaveAsync() - { - try - { - return _dbContext.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException e) - { - throw new ConflictException("while processing a concurrent update was saved to the database (reason could also be data to be deleted is no longer existing)", e); - } - } - - public void Clear() => _dbContext.ChangeTracker.Clear(); } diff --git a/src/database/PolicyHub.DbAccess/IHubRepositories.cs b/src/database/PolicyHub.DbAccess/IHubRepositories.cs index d09728a..360c798 100644 --- a/src/database/PolicyHub.DbAccess/IHubRepositories.cs +++ b/src/database/PolicyHub.DbAccess/IHubRepositories.cs @@ -22,8 +22,4 @@ namespace Org.Eclipse.TractusX.PolicyHub.DbAccess; public interface IHubRepositories { public T GetInstance(); - - public Task SaveAsync(); - - void Clear(); } diff --git a/src/database/PolicyHub.Entities/PolicyHubContext.cs b/src/database/PolicyHub.Entities/PolicyHubContext.cs index 7e1f291..2da36e1 100644 --- a/src/database/PolicyHub.Entities/PolicyHubContext.cs +++ b/src/database/PolicyHub.Entities/PolicyHubContext.cs @@ -25,6 +25,10 @@ namespace Org.Eclipse.TractusX.PolicyHub.Entities; public class PolicyHubContext : DbContext { + public PolicyHubContext() + { + } + public PolicyHubContext(DbContextOptions options) : base(options) { @@ -94,23 +98,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) x.HasKey(e => new { e.PolicyId, e.UseCaseId }); }); - entity.HasMany(p => p.UseCases) - .WithMany(pt => pt.Policies) - .UsingEntity(p => p - .HasOne(x => x.UseCase) - .WithMany() - .HasForeignKey(x => x.UseCaseId) - .OnDelete(DeleteBehavior.ClientSetNull), - p => p - .HasOne(x => x.Policy) - .WithMany() - .HasForeignKey(x => x.PolicyId) - .OnDelete(DeleteBehavior.ClientSetNull), - x => - { - x.HasKey(e => new { e.PolicyId, e.UseCaseId }); - }); - entity.HasOne(p => p.AttributeKey) .WithMany(pt => pt.Policies) .HasForeignKey(p => p.AttributeKeyId) diff --git a/src/database/PolicyHub.Migrations/Program.cs b/src/database/PolicyHub.Migrations/Program.cs index 200b672..a90acc9 100644 --- a/src/database/PolicyHub.Migrations/Program.cs +++ b/src/database/PolicyHub.Migrations/Program.cs @@ -38,7 +38,7 @@ .AddDbContext(o => o.UseNpgsql(hostContext.Configuration.GetConnectionString("PolicyHubDb"), x => x.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name) - .MigrationsHistoryTable("__efmigrations_history_hub"))) + .MigrationsHistoryTable("__efmigrations_history_hub", "public"))) .AddDatabaseInitializer(hostContext.Configuration.GetSection("Seeding")); }) .AddLogging() diff --git a/src/database/PolicyHub.Migrations/Seeder/BatchInsertSeeder.cs b/src/database/PolicyHub.Migrations/Seeder/BatchInsertSeeder.cs index 4d8b968..ba580a2 100644 --- a/src/database/PolicyHub.Migrations/Seeder/BatchInsertSeeder.cs +++ b/src/database/PolicyHub.Migrations/Seeder/BatchInsertSeeder.cs @@ -70,21 +70,21 @@ public async Task ExecuteAsync(CancellationToken cancellationToken) private async Task SeedTable(string fileName, Func keySelector, CancellationToken cancellationToken) where T : class { - _logger.LogInformation("Start seeding {Filename}", fileName); + _logger.LogDebug("Start seeding {Filename}", fileName); var additionalEnvironments = _settings.TestDataEnvironments ?? Enumerable.Empty(); var data = await SeederHelper.GetSeedData(_logger, fileName, _settings.DataPaths, cancellationToken, additionalEnvironments.ToArray()).ConfigureAwait(false); - _logger.LogInformation("Found {ElementCount} data", data.Count); + _logger.LogDebug("Found {ElementCount} data", data.Count); if (data.Any()) { var typeName = typeof(T).Name; - _logger.LogInformation("Started to Seed {TableName}", typeName); + _logger.LogDebug("Started to Seed {TableName}", typeName); data = data.GroupJoin(_context.Set(), keySelector, keySelector, (d, dbEntry) => new { d, dbEntry }) .SelectMany(t => t.dbEntry.DefaultIfEmpty(), (t, x) => new { t, x }) .Where(t => t.x == null) .Select(t => t.t.d).ToList(); - _logger.LogInformation("Seeding {DataCount} {TableName}", data.Count, typeName); + _logger.LogDebug("Seeding {DataCount} {TableName}", data.Count, typeName); await _context.Set().AddRangeAsync(data, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Seeded {TableName}", typeName); + _logger.LogDebug("Seeded {TableName}", typeName); } } } diff --git a/src/database/PolicyHub.Migrations/Seeder/BatchUpdateSeeder.cs b/src/database/PolicyHub.Migrations/Seeder/BatchUpdateSeeder.cs index d3b4ab7..ff172d4 100644 --- a/src/database/PolicyHub.Migrations/Seeder/BatchUpdateSeeder.cs +++ b/src/database/PolicyHub.Migrations/Seeder/BatchUpdateSeeder.cs @@ -65,10 +65,10 @@ await SeedTable( private async Task SeedTable(string fileName, Func keySelector, Func<(T dataEntity, T dbEntity), bool> whereClause, Action updateEntries, CancellationToken cancellationToken) where T : class { - _logger.LogInformation("Start seeding {Filename}", fileName); + _logger.LogDebug("Start seeding {Filename}", fileName); var additionalEnvironments = _settings.TestDataEnvironments ?? Enumerable.Empty(); var data = await SeederHelper.GetSeedData(_logger, fileName, _settings.DataPaths, cancellationToken, additionalEnvironments.ToArray()).ConfigureAwait(false); - _logger.LogInformation("Found {ElementCount} data", data.Count); + _logger.LogDebug("Found {ElementCount} data", data.Count); if (data.Any()) { var typeName = typeof(T).Name; @@ -78,12 +78,13 @@ private async Task SeedTable(string fileName, Func keySelector, Fu .ToList(); if (entriesForUpdate.Any()) { - _logger.LogInformation("Started to Update {EntryCount} entries of {TableName}", entriesForUpdate.Count, typeName); + _logger.LogDebug("Started to Update {EntryCount} entries of {TableName}", entriesForUpdate.Count, typeName); foreach (var entry in entriesForUpdate) { updateEntries.Invoke(entry.DbEntry, entry.DataEntry); } - _logger.LogInformation("Updated {TableName}", typeName); + + _logger.LogDebug("Updated {TableName}", typeName); } } } diff --git a/src/hub/PolicyHub.Service/Authentication/KeycloakClaimsTransformation.cs b/src/hub/PolicyHub.Service/Authentication/KeycloakClaimsTransformation.cs index 8e20755..c81c94a 100644 --- a/src/hub/PolicyHub.Service/Authentication/KeycloakClaimsTransformation.cs +++ b/src/hub/PolicyHub.Service/Authentication/KeycloakClaimsTransformation.cs @@ -28,7 +28,7 @@ namespace Org.Eclipse.TractusX.PolicyHub.Service.Authentication; public class KeycloakClaimsTransformation : IClaimsTransformation { private readonly JwtBearerOptions _options; - private const string ResourceAccess = "resource_access"; + public const string ResourceAccess = "resource_access"; public KeycloakClaimsTransformation(IOptions options) { diff --git a/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs b/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs index e07e3e1..c888798 100644 --- a/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs +++ b/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs @@ -86,7 +86,7 @@ private static object GetRegexValue((AttributeKeyId? Key, IEnumerable Va throw new UnexpectedConditionException("There should only be one regex pattern defined"); } - if (!Regex.IsMatch(value, attributes.Values.Single())) + if (!Regex.IsMatch(value, attributes.Values.Single(), RegexOptions.Compiled, TimeSpan.FromSeconds(1))) { throw new ControllerArgumentException($"The provided value {value} does not match the regex pattern {attributes.Values.Single()}", nameof(value)); } @@ -118,13 +118,13 @@ public async Task GetPolicyContentAsync(PolicyContentRequest req var multipleDefinedKey = keyCounts.Where(x => x.Value != 1); if (multipleDefinedKey.Any()) { - throw new ControllerArgumentException($"Keys {multipleDefinedKey.Select(x => x.Key)} have been defined multiple times"); + throw new ControllerArgumentException($"Keys {string.Join(",", multipleDefinedKey.Select(x => x.Key).Distinct())} have been defined multiple times"); } var policies = await _hubRepositories.GetInstance().GetPolicyForOperandContent(requestData.PolicyType, requestData.Constraints.Select(x => x.Key)).ToListAsync().ConfigureAwait(false); if (policies.Count != requestData.Constraints.Count()) { - throw new NotFoundException($"Policy for type {requestData.PolicyType} and technicalKeys {requestData.Constraints.Select(x => x.Key).Except(policies.Select(x => x.TechnicalKey))} does not exists"); + throw new NotFoundException($"Policy for type {requestData.PolicyType} and technicalKeys {string.Join(",", requestData.Constraints.Select(x => x.Key).Except(policies.Select(x => x.TechnicalKey)))} does not exists"); } var constraints = new List(); @@ -172,5 +172,5 @@ public async Task GetPolicyContentAsync(PolicyContentRequest req return new PolicyResponse(content, additionalAttributes); } - private static object[] GetContext() => new object[] { "https://www.w3.org/ns/odrl.jsonld", new { cx = "https://w3id.org/catenax/v0.0.1/ns/" } }; + private static IEnumerable GetContext() => new object[] { "https://www.w3.org/ns/odrl.jsonld", new { cx = "https://w3id.org/catenax/v0.0.1/ns/" } }; } diff --git a/src/hub/PolicyHub.Service/Extensions/CorsExtensions.cs b/src/hub/PolicyHub.Service/Extensions/CorsExtensions.cs deleted file mode 100644 index 1122357..0000000 --- a/src/hub/PolicyHub.Service/Extensions/CorsExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -using Microsoft.AspNetCore.Cors.Infrastructure; - -namespace Org.Eclipse.TractusX.PolicyHub.Service.Extensions; - -/// -/// Configuration for CORS -/// -public class CorsConfiguration -{ - /// The Cors configuration - public CorsModel Cors { get; init; } = null!; -} - -/// -/// Model for the Cors Configuration -/// -public class CorsModel -{ - /// The allowed origins - public string[] AllowedOrigins { get; init; } = null!; -} - -/// -/// Provides Extension methods for cors -/// -public static class CorsExtensions -{ - public const string AllowSpecificOrigins = "_catenaXAllowSpecificOrigins"; - - /// - /// Setup for the cors configuration - /// - /// Cors options - /// configuration to access the allowed domains - public static void SetupCors(this CorsOptions corsOption, IConfigurationRoot configuration) - { - var corsConfig = configuration.Get(); - if (corsConfig?.Cors?.AllowedOrigins?.Any() ?? false) - { - corsOption.AddPolicy(AllowSpecificOrigins, policy => - { - policy.WithOrigins(corsConfig.Cors.AllowedOrigins) - .AllowAnyHeader() - .AllowAnyMethod(); - }); - } - } -} diff --git a/src/hub/PolicyHub.Service/HealthCheck/HealthCheckExtensions.cs b/src/hub/PolicyHub.Service/HealthCheck/HealthCheckExtensions.cs deleted file mode 100644 index e2682b5..0000000 --- a/src/hub/PolicyHub.Service/HealthCheck/HealthCheckExtensions.cs +++ /dev/null @@ -1,81 +0,0 @@ -// /******************************************************************************** -// * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation -// * -// * See the NOTICE file(s) distributed with this work for additional -// * information regarding copyright ownership. -// * -// * This program and the accompanying materials are made available under the -// * terms of the Apache License, Version 2.0 which is available at -// * https://www.apache.org/licenses/LICENSE-2.0. -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// * License for the specific language governing permissions and limitations -// * under the License. -// * -// * SPDX-License-Identifier: Apache-2.0 -// ********************************************************************************/ -// -// using Microsoft.Extensions.Diagnostics.HealthChecks; -// using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -// using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq; -// using System.Net.Mime; -// using System.Text.Json; -// using System.Text.Json.Serialization; -// -// namespace Org.Eclipse.TractusX.PolicyHub.Service.HealthCheck; -// -// public static class HealthCheckExtensions -// { -// private static readonly JsonSerializerOptions SerializerOptions = new() -// { -// WriteIndented = false, -// PropertyNamingPolicy = JsonNamingPolicy.CamelCase, -// DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull -// }; -// -// private static Task WriteResponse( -// HttpContext context, -// HealthReport report) -// { -// context.Response.ContentType = MediaTypeNames.Application.Json; -// return context.Response.WriteAsync(JsonSerializer.Serialize( -// new -// { -// Status = report.Status.ToString(), -// Duration = report.TotalDuration, -// Info = report.Entries -// .Select(e => new -// { -// Key = e.Key, -// Description = e.Value.Description, -// Duration = e.Value.Duration, -// Status = Enum.GetName(e.Value.Status), -// Error = e.Value.Exception?.Message, -// Data = e.Value.Data -// }) -// }, -// SerializerOptions)); -// } -// -// public static void MapDefaultHealthChecks(this WebApplication app, IEnumerable? settings) -// { -// if (settings == null) -// return; -// -// if (settings.DuplicatesBy(x => x.Path).Any()) -// { -// throw new ConfigurationException($"HealthChecks mapping {string.Join(", ", settings.Select(x => x.Path))} contains ambiguous pathes"); -// } -// -// foreach (var configured in settings) -// { -// app.MapHealthChecks(configured.Path, new() -// { -// Predicate = registration => configured.Tags != null && configured.Tags.Intersect(registration.Tags).Any(), -// ResponseWriter = WriteResponse -// }); -// } -// } -// } diff --git a/src/hub/PolicyHub.Service/HealthCheck/HealthCheckSettings.cs b/src/hub/PolicyHub.Service/HealthCheck/HealthCheckSettings.cs deleted file mode 100644 index 3e65fb5..0000000 --- a/src/hub/PolicyHub.Service/HealthCheck/HealthCheckSettings.cs +++ /dev/null @@ -1,30 +0,0 @@ -// /******************************************************************************** -// * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation -// * -// * See the NOTICE file(s) distributed with this work for additional -// * information regarding copyright ownership. -// * -// * This program and the accompanying materials are made available under the -// * terms of the Apache License, Version 2.0 which is available at -// * https://www.apache.org/licenses/LICENSE-2.0. -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// * License for the specific language governing permissions and limitations -// * under the License. -// * -// * SPDX-License-Identifier: Apache-2.0 -// ********************************************************************************/ -// -// using System.ComponentModel.DataAnnotations; -// -// namespace Org.Eclipse.TractusX.PolicyHub.Service.HealthCheck; -// -// public class HealthCheckSettings -// { -// [Required(AllowEmptyStrings = false)] -// public string Path { get; set; } = null!; -// -// public IEnumerable? Tags { get; set; } -// } diff --git a/src/hub/PolicyHub.Service/HealthCheck/JwtBearerConfigurationHealthCheck.cs b/src/hub/PolicyHub.Service/HealthCheck/JwtBearerConfigurationHealthCheck.cs deleted file mode 100644 index 13c13e4..0000000 --- a/src/hub/PolicyHub.Service/HealthCheck/JwtBearerConfigurationHealthCheck.cs +++ /dev/null @@ -1,66 +0,0 @@ -// /******************************************************************************** -// * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation -// * -// * See the NOTICE file(s) distributed with this work for additional -// * information regarding copyright ownership. -// * -// * This program and the accompanying materials are made available under the -// * terms of the Apache License, Version 2.0 which is available at -// * https://www.apache.org/licenses/LICENSE-2.0. -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// * License for the specific language governing permissions and limitations -// * under the License. -// * -// * SPDX-License-Identifier: Apache-2.0 -// ********************************************************************************/ -// -// using Microsoft.AspNetCore.Authentication.JwtBearer; -// using Microsoft.Extensions.Diagnostics.HealthChecks; -// using Microsoft.Extensions.Options; -// using Microsoft.IdentityModel.Protocols; -// using Microsoft.IdentityModel.Protocols.OpenIdConnect; -// -// namespace Org.Eclipse.TractusX.PolicyHub.Service.HealthCheck; -// -// public class JwtBearerConfigurationHealthCheck : IHealthCheck -// { -// private readonly IConfigurationManager _configurationManager; -// -// public JwtBearerConfigurationHealthCheck(IOptions jwtOptions) -// { -// var options = jwtOptions.Value; -// if (!options.RequireHttpsMetadata) -// { -// options.BackchannelHttpHandler = new HttpClientHandler -// { -// ServerCertificateCustomValidationCallback = (_, _, _, _) => true -// }; -// } -// -// _configurationManager = options.BackchannelHttpHandler == null -// ? new ConfigurationManager( -// options.MetadataAddress, -// new OpenIdConnectConfigurationRetriever()) -// : new ConfigurationManager( -// options.MetadataAddress, -// new OpenIdConnectConfigurationRetriever(), -// new HttpClient(options.BackchannelHttpHandler)); -// } -// -// public async Task CheckHealthAsync( -// HealthCheckContext context, CancellationToken cancellationToken = default) -// { -// try -// { -// await _configurationManager.GetConfigurationAsync(cancellationToken).ConfigureAwait(false); -// return HealthCheckResult.Healthy(); -// } -// catch (Exception e) -// { -// return HealthCheckResult.Unhealthy(exception: e); -// } -// } -// } diff --git a/tests/database/PolicyHub.DbAccess.Tests/Setup/TestDbFixture.cs b/tests/database/PolicyHub.DbAccess.Tests/Setup/TestDbFixture.cs index 0d9bdb0..250dab3 100644 --- a/tests/database/PolicyHub.DbAccess.Tests/Setup/TestDbFixture.cs +++ b/tests/database/PolicyHub.DbAccess.Tests/Setup/TestDbFixture.cs @@ -53,7 +53,7 @@ public async Task GetPolicyHubDbContext() optionsBuilder.UseNpgsql( _container.GetConnectionString(), x => x.MigrationsAssembly(typeof(BatchInsertSeeder).Assembly.GetName().Name) - .MigrationsHistoryTable("__efmigrations_history_hub") + .MigrationsHistoryTable("__efmigrations_history_hub", "public") ); var context = new PolicyHubContext(optionsBuilder.Options); await context.Database.EnsureCreatedAsync().ConfigureAwait(false); @@ -74,7 +74,7 @@ await _container.StartAsync() optionsBuilder.UseNpgsql( _container.GetConnectionString(), x => x.MigrationsAssembly(typeof(BatchInsertSeeder).Assembly.GetName().Name) - .MigrationsHistoryTable("__efmigrations_history_hub") + .MigrationsHistoryTable("__efmigrations_history_hub", "public") ); var context = new PolicyHubContext(optionsBuilder.Options); await context.Database.MigrateAsync(); diff --git a/tests/database/PolicyHub.Entities.Tests/PolicyHub.Entities.Tests.csproj b/tests/database/PolicyHub.Entities.Tests/PolicyHub.Entities.Tests.csproj new file mode 100644 index 0000000..be39110 --- /dev/null +++ b/tests/database/PolicyHub.Entities.Tests/PolicyHub.Entities.Tests.csproj @@ -0,0 +1,52 @@ + + + + + Org.Eclipse.TractusX.PolicyHub.Entities.Tests + Org.Eclipse.TractusX.PolicyHub.Entities.Tests + net7.0 + enable + enable + false + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + diff --git a/tests/database/PolicyHub.Entities.Tests/PolicyKindExtensionsTests.cs b/tests/database/PolicyHub.Entities.Tests/PolicyKindExtensionsTests.cs new file mode 100644 index 0000000..5439a3e --- /dev/null +++ b/tests/database/PolicyHub.Entities.Tests/PolicyKindExtensionsTests.cs @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; +using Org.Eclipse.TractusX.PolicyHub.Entities.Extensions; + +namespace Org.Eclipse.TractusX.PolicyHub.Entities.Tests; + +public class PolicyKindExtensionsTests +{ + [Theory] + [InlineData(PolicyKindId.BusinessPartnerNumber, true)] + [InlineData(PolicyKindId.Membership, true)] + [InlineData(PolicyKindId.Framework, true)] + [InlineData(PolicyKindId.Purpose, false)] + [InlineData(PolicyKindId.Dismantler, true)] + public void IsTechnicalEnforced_WithValidData_ReturnsExpected(PolicyKindId policyKindId, bool expectedResult) + { + // Act + var result = policyKindId.IsTechnicalEnforced(); + + // Assert + result.Should().Be(expectedResult); + } + + [Fact] + public void IsTechnicalEnforced_WithInvalidData_ThrowsArgumentOutOfRangeException() + { + // Act + var ex = Assert.Throws(() => ((PolicyKindId)0).IsTechnicalEnforced()); + + // Assert + ex.Message.Should().Be("PolicyKindId 0 is not supported (Parameter 'policyKindId')\nActual value was 0."); + } +} diff --git a/tests/database/PolicyHub.Entities.Tests/Usings.cs b/tests/database/PolicyHub.Entities.Tests/Usings.cs new file mode 100644 index 0000000..5f8f40c --- /dev/null +++ b/tests/database/PolicyHub.Entities.Tests/Usings.cs @@ -0,0 +1,23 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +global using AutoFixture; +global using AutoFixture.AutoFakeItEasy; +global using FluentAssertions; +global using Xunit; diff --git a/tests/hub/PolicyHub.Service.Tests/Authentication/KeycloakClaimsTransformationTests.cs b/tests/hub/PolicyHub.Service.Tests/Authentication/KeycloakClaimsTransformationTests.cs new file mode 100644 index 0000000..9c5bb63 --- /dev/null +++ b/tests/hub/PolicyHub.Service.Tests/Authentication/KeycloakClaimsTransformationTests.cs @@ -0,0 +1,92 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using Org.Eclipse.TractusX.PolicyHub.Service.Authentication; +using System.Security.Claims; +using System.Text.Json; + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Tests.Authentication; + +public class KeycloakClaimsTransformationTests +{ + private readonly KeycloakClaimsTransformation _sut; + + public KeycloakClaimsTransformationTests() + { + var options = Options.Create(new JwtBearerOptions + { + TokenValidationParameters = new TokenValidationParameters + { + ValidAudience = "validAudience" + } + }); + _sut = new KeycloakClaimsTransformation(options); + } + + [Fact] + public async Task TransformAsync_WithoutRoles_ReturnsExpected() + { + // Arrange + var identity = new ClaimsIdentity(Enumerable.Repeat(new Claim(ClaimTypes.Email, "test@mail.com"), 1)); + var principal = new ClaimsPrincipal(identity); + + // Act + var result = await _sut.TransformAsync(principal).ConfigureAwait(false); + + // Assert + result.Claims.Should().ContainSingle() + .And.Satisfy(x => x.Type == ClaimTypes.Email && x.Value == "test@mail.com"); + } + + [Fact] + public async Task TransformAsync_WithRoles_ReturnsExpected() + { + // Arrange + var json = JsonSerializer.Serialize(new { validAudience = new { roles = Enumerable.Repeat("testRole", 1) } }); + var identity = new ClaimsIdentity(Enumerable.Repeat(new Claim(KeycloakClaimsTransformation.ResourceAccess, json, "JSON"), 1)); + var principal = new ClaimsPrincipal(identity); + + // Act + var result = await _sut.TransformAsync(principal).ConfigureAwait(false); + + // Assert + result.Claims.Should().HaveCount(2).And.Satisfy( + x => x.Type == KeycloakClaimsTransformation.ResourceAccess && x.Value == json, + x => x.Type == ClaimTypes.Role && x.Value == "testRole"); + } + + [Fact] + public async Task TransformAsync_WithIntRole_ReturnsExpected() + { + // Arrange + var json = JsonSerializer.Serialize(new { validAudience = new { roles = Enumerable.Repeat(1, 1) } }); + var identity = new ClaimsIdentity(Enumerable.Repeat(new Claim(KeycloakClaimsTransformation.ResourceAccess, json, "JSON"), 1)); + var principal = new ClaimsPrincipal(identity); + + // Act + var result = await _sut.TransformAsync(principal).ConfigureAwait(false); + + // Assert + result.Claims.Should().ContainSingle() + .And.Satisfy(x => x.Type == KeycloakClaimsTransformation.ResourceAccess && x.Value == json); + } +} diff --git a/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs b/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs index 6877145..8d03945 100644 --- a/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs +++ b/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs @@ -22,6 +22,7 @@ using Org.Eclipse.TractusX.PolicyHub.DbAccess.Repositories; using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; using Org.Eclipse.TractusX.PolicyHub.Service.BusinessLogic; +using Org.Eclipse.TractusX.PolicyHub.Service.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Library; namespace Org.Eclipse.TractusX.PolicyHub.Service.Tests.BusinessLogic; @@ -108,10 +109,10 @@ public async Task GetPolicyTypes_WithUseCaseFilter_ReturnsExpected() #endregion - #region GetPolicyContentAsync + #region GetPolicyContentWithFiltersAsync [Fact] - public async Task GetPolicyContentAsync_WithNotExistingInDatabase_ThrowsNotFoundException() + public async Task GetPolicyContentWithFiltersAsync_WithNotExistingInDatabase_ThrowsNotFoundException() { // Arrange const PolicyTypeId policyTypeId = PolicyTypeId.Access; @@ -126,6 +127,98 @@ public async Task GetPolicyContentAsync_WithNotExistingInDatabase_ThrowsNotFound ex.Message.Should().Be($"Policy for type {policyTypeId} and technicalKey membership does not exists"); } + [Fact] + public async Task GetPolicyContentWithFiltersAsync_AttributeAndRightOperandNull_ThrowsUnexpectedConditionException() + { + // Arrange + const PolicyTypeId policyTypeId = PolicyTypeId.Access; + A.CallTo(() => _policyRepository.GetPolicyContentAsync(null, policyTypeId, "membership")) + .Returns(new ValueTuple), string?>(true, "test", (null, Enumerable.Empty()), null!)); + async Task Act() => await _sut.GetPolicyContentWithFiltersAsync(null, policyTypeId, "membership", OperatorId.Equals, null); + + // Act + var ex = await Assert.ThrowsAsync(Act); + + // Assert + ex.Message.Should().Be("There must be one configured rightOperand value"); + } + + [Fact] + public async Task GetPolicyContentWithFiltersAsync_WithDynamicValue_ThrowsUnexpectedConditionException() + { + // Arrange + const PolicyTypeId policyTypeId = PolicyTypeId.Access; + A.CallTo(() => _policyRepository.GetPolicyContentAsync(null, policyTypeId, "membership")) + .Returns(new ValueTuple), string?>(true, "test", (AttributeKeyId.DynamicValue, Enumerable.Empty()), "test:{0}")); + + // Act + var result = await _sut.GetPolicyContentWithFiltersAsync(null, policyTypeId, "membership", OperatorId.Equals, "abc"); + + // Assert + result.Content.Permission.Constraint.RightOperandValue.Should().Be("abc"); + } + + [Fact] + public async Task GetPolicyContentWithFiltersAsync_WithMultipleRegexValues_ThrowsUnexpectedConditionException() + { + // Arrange + const PolicyTypeId policyTypeId = PolicyTypeId.Access; + A.CallTo(() => _policyRepository.GetPolicyContentAsync(null, policyTypeId, "membership")) + .Returns(new ValueTuple), string?>(true, "test", (AttributeKeyId.Regex, new[] { "test1", "test2" }), null)); + async Task Act() => await _sut.GetPolicyContentWithFiltersAsync(null, policyTypeId, "membership", OperatorId.Equals, "test"); + + // Act + var ex = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + + // Assert + ex.Message.Should().Be("There should only be one regex pattern defined"); + } + + #endregion + + #region GetPolicyContentAsync + + [Fact] + public async Task GetPolicyContentAsync_WithUnmatchingPoliciesAndConstraints_ThrowsNotFoundException() + { + // Arrange + var data = new PolicyContentRequest(PolicyTypeId.Access, ConstraintOperandId.Or, + new[] + { + new Constraints("test", OperatorId.In, null), + new Constraints("abc", OperatorId.Equals, null) + }); + A.CallTo(() => _policyRepository.GetPolicyForOperandContent(data.PolicyType, A>._)) + .Returns(Enumerable.Repeat(new ValueTuple>, string?>("test", "active", default, null), 1).ToAsyncEnumerable()); + async Task Act() => await _sut.GetPolicyContentAsync(data); + + // Act + var ex = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + + // Assert + ex.Message.Should().Be($"Policy for type {data.PolicyType} and technicalKeys abc does not exists"); + } + + [Fact] + public async Task GetPolicyContentAsync_WithAttributeAndRightOperandNull_ThrowsUnexpectedConditionException() + { + // Arrange + var data = new PolicyContentRequest(PolicyTypeId.Access, ConstraintOperandId.Or, + new[] + { + new Constraints("test", OperatorId.In, null), + }); + A.CallTo(() => _policyRepository.GetPolicyForOperandContent(data.PolicyType, A>._)) + .Returns(Enumerable.Repeat(new ValueTuple>, string?>("test", "active", (null, Enumerable.Empty()), null), 1).ToAsyncEnumerable()); + async Task Act() => await _sut.GetPolicyContentAsync(data); + + // Act + var ex = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + + // Assert + ex.Message.Should().Be("There must be one configured rightOperand value"); + } + #endregion #region Setup diff --git a/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs b/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs index 5f08075..614f4e7 100644 --- a/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs +++ b/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs @@ -2,6 +2,7 @@ using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; using Org.Eclipse.TractusX.PolicyHub.Service.Models; using Org.Eclipse.TractusX.PolicyHub.Service.Tests.Setup; +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Library; using System.Net; using System.Net.Http.Json; using System.Text.Json; @@ -103,17 +104,31 @@ public async Task GetPolicyTypes_WithUseCaseFilter_ReturnsExpected() #region Policy Content [Fact] - public async Task GetPolicyContent_UsageMembershipEquals_ReturnsExpected() + public async Task GetPolicyContent_WithRegexWithIncorrectValue_ReturnsExpected() { // Act - var response = await _client.GetAsync($"{BaseUrl}/policy-content?type={PolicyTypeId.Usage}&credential=Membership&operatorId={OperatorId.Equals}").ConfigureAwait(false); + var response = await _client.GetAsync($"{BaseUrl}/policy-content?type={PolicyTypeId.Access}&credential=BusinessPartnerNumber&operatorId={OperatorId.Equals}&value=notmatching").ConfigureAwait(false); // Assert response.Should().NotBeNull(); - response.StatusCode.Should().Be(HttpStatusCode.OK); - (await response.Content.ReadAsStringAsync().ConfigureAwait(false)) - .Should() - .Be("{\"content\":{\"@context\":[\"https://www.w3.org/ns/odrl.jsonld\",{\"cx\":\"https://w3id.org/catenax/v0.0.1/ns/\"}],\"@type\":\"Offer\",\"@id\":\"....\",\"permission\":{\"action\":\"use\",\"constraint\":{\"leftOperand\":\"Membership\",\"operator\":\"eq\",\"rightOperand\":\"active\"}}}}"); + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + var error = await response.Content.ReadFromJsonAsync(Options).ConfigureAwait(false); + error!.Errors.Should().ContainSingle().And.Satisfy( + x => x.Value.Single() == @"The provided value notmatching does not match the regex pattern ^BPNL[\w|\d]{12}$ (Parameter 'value')"); + } + + [Fact] + public async Task GetPolicyContent_WithRegexWithoutValue_ReturnsExpected() + { + // Act + var response = await _client.GetAsync($"{BaseUrl}/policy-content?type={PolicyTypeId.Access}&credential=BusinessPartnerNumber&operatorId={OperatorId.Equals}").ConfigureAwait(false); + + // Assert + response.Should().NotBeNull(); + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + var error = await response.Content.ReadFromJsonAsync(Options).ConfigureAwait(false); + error!.Errors.Should().ContainSingle().And.Satisfy( + x => x.Value.Single() == "you must provide a value for the regex (Parameter 'value')"); } [Fact] @@ -174,10 +189,10 @@ public async Task GetPolicyContent_TraceabilityUsagePurposeEquals_ReturnsExpecte #endregion - #region Policy Content with Constraints + #region Policy Content with Filters [Fact] - public async Task GetPolicyContent_TwoEqualsConstraintsAndOperand_ReturnsExpected() + public async Task GetPolicyContentWithFiltersAsync_TwoEqualsConstraintsAndOperand_ReturnsExpected() { // Arrange var data = new PolicyContentRequest( @@ -201,7 +216,7 @@ public async Task GetPolicyContent_TwoEqualsConstraintsAndOperand_ReturnsExpecte } [Fact] - public async Task GetPolicyContent_MultipleConstraintsEqualsAndOperand_ReturnsExpected() + public async Task GetPolicyContentWithFiltersAsync_MultipleConstraintsEqualsAndOperand_ReturnsExpected() { // Arrange var data = new PolicyContentRequest( @@ -226,7 +241,7 @@ public async Task GetPolicyContent_MultipleConstraintsEqualsAndOperand_ReturnsEx } [Fact] - public async Task GetPolicyContent_MultipleConstraintsEqualsOrOperand_ReturnsExpected() + public async Task GetPolicyContentWithFiltersAsync_MultipleConstraintsEqualsOrOperand_ReturnsExpected() { // Arrange var data = new PolicyContentRequest( @@ -249,6 +264,30 @@ public async Task GetPolicyContent_MultipleConstraintsEqualsOrOperand_ReturnsExp .Be("{\"content\":{\"@context\":[\"https://www.w3.org/ns/odrl.jsonld\",{\"cx\":\"https://w3id.org/catenax/v0.0.1/ns/\"}],\"@type\":\"Offer\",\"@id\":\"....\",\"permission\":{\"action\":\"use\",\"constraint\":{\"odrl:or\":[{\"leftOperand\":\"FrameworkAgreement.traceability\",\"operator\":\"eq\",\"rightOperand\":\"@FrameworkAgreement.traceability-Version\"},{\"leftOperand\":\"Dismantler.activityType\",\"operator\":\"in\",\"rightOperand\":[\"Audi\",\"BMW\",\"VW\"]}]}}},\"attributes\":[{\"key\":\"@FrameworkAgreement.traceability-Version\",\"possibleValues\":[\"active:1.0\",\"active:1.1\",\"active:1.2\"]}]}"); } + [Fact] + public async Task GetPolicyContentWithFiltersAsync_WithSameConstraintKeys_ReturnsError() + { + // Arrange + var data = new PolicyContentRequest( + PolicyTypeId.Usage, + ConstraintOperandId.Or, + new[] + { + new Constraints("FrameworkAgreement.traceability", OperatorId.Equals, null), + new Constraints("FrameworkAgreement.traceability", OperatorId.Equals, null), + }); + + // Act + var response = await _client.PostAsJsonAsync($"{BaseUrl}/policy-content", data, Options).ConfigureAwait(false); + + // Assert + response.Should().NotBeNull(); + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + var error = await response.Content.ReadFromJsonAsync(Options).ConfigureAwait(false); + error!.Errors.Should().ContainSingle().And.Satisfy( + x => x.Value.Single() == "Keys FrameworkAgreement.traceability have been defined multiple times"); + } + #endregion #region Swagger diff --git a/tests/hub/PolicyHub.Service.Tests/Extensions/JsonGenerationExtensionsTests.cs b/tests/hub/PolicyHub.Service.Tests/Extensions/JsonGenerationExtensionsTests.cs new file mode 100644 index 0000000..9230f34 --- /dev/null +++ b/tests/hub/PolicyHub.Service.Tests/Extensions/JsonGenerationExtensionsTests.cs @@ -0,0 +1,52 @@ +using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; +using Org.Eclipse.TractusX.PolicyHub.Service.Extensions; + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Tests.Extensions; + +public class JsonGenerationExtensionsTests +{ + [Theory] + [InlineData(PolicyTypeId.Access, "access")] + [InlineData(PolicyTypeId.Usage, "use")] + [InlineData(PolicyTypeId.Purpose, "use")] + public void TypeToJsonString_WithValidData_ReturnsExpected(PolicyTypeId policyTypeId, string result) + { + // Act + var jsonString = policyTypeId.TypeToJsonString(); + + // Assert + jsonString.Should().Be(result); + } + + [Fact] + public void TypeToJsonString_WithInvalidData_ThrowsArgumentOutOfRangeException() + { + // Act + var ex = Assert.Throws(() => ((PolicyTypeId)0).TypeToJsonString()); + + // Assert + ex.Message.Should().Be("0 is not a valid value (Parameter 'type')\nActual value was 0."); + } + + [Theory] + [InlineData(OperatorId.Equals, "eq")] + [InlineData(OperatorId.In, "in")] + public void OperatorToJsonString_WithValidData_ReturnsExpected(OperatorId operatorId, string result) + { + // Act + var jsonString = operatorId.OperatorToJsonString(); + + // Assert + jsonString.Should().Be(result); + } + + [Fact] + public void OperatorToJsonString_WithInvalidData_ThrowsArgumentOutOfRangeException() + { + // Act + var ex = Assert.Throws(() => ((OperatorId)0).OperatorToJsonString()); + + // Assert + ex.Message.Should().Be("0 is not a valid value (Parameter 'type')\nActual value was 0."); + } +} diff --git a/tests/hub/PolicyHub.Service.Tests/Setup/IntegrationTestFactory.cs b/tests/hub/PolicyHub.Service.Tests/Setup/IntegrationTestFactory.cs index bb70853..a53a817 100644 --- a/tests/hub/PolicyHub.Service.Tests/Setup/IntegrationTestFactory.cs +++ b/tests/hub/PolicyHub.Service.Tests/Setup/IntegrationTestFactory.cs @@ -72,7 +72,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) { options.UseNpgsql(Container.GetConnectionString(), x => x.MigrationsAssembly(typeof(BatchInsertSeeder).Assembly.GetName().Name) - .MigrationsHistoryTable("__efmigrations_history_hub")); + .MigrationsHistoryTable("__efmigrations_history_hub", "public")); }); services.AddSingleton(); }); @@ -89,7 +89,7 @@ protected override IHost CreateHost(IHostBuilder builder) optionsBuilder.UseNpgsql( Container.GetConnectionString(), x => x.MigrationsAssembly(typeof(BatchInsertSeeder).Assembly.GetName().Name) - .MigrationsHistoryTable("__efmigrations_history_hub") + .MigrationsHistoryTable("__efmigrations_history_hub", "public") ); var context = new PolicyHubContext(optionsBuilder.Options); context.Database.Migrate(); @@ -103,6 +103,10 @@ protected override IHost CreateHost(IHostBuilder builder) LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger(), seederOptions); insertSeeder.ExecuteAsync(CancellationToken.None).GetAwaiter().GetResult(); + var updateSeeder = new BatchUpdateSeeder(context, + LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger(), + seederOptions); + updateSeeder.ExecuteAsync(CancellationToken.None).GetAwaiter().GetResult(); return host; }