From 1af5a8f89783579f082a6ab2e2c36f50a5c73c63 Mon Sep 17 00:00:00 2001 From: Micah Nagel Date: Fri, 18 Oct 2024 10:12:00 -0600 Subject: [PATCH] chore: add e2e playwright tests for grafana (#844) ## Description Adds e2e testing structure and specific e2e test for Grafana using playwright. This test: - Validates existence and successful connection to datasources (Loki and Prometheus) - Validates two custom dashboards exist and dropdowns populate for ns selection (resources and loki quicksearch) - Validates SSO login success ## Related Issue Fixes https://github.com/defenseunicorns/uds-core/issues/764 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Other (security config, docs update, etc) ## Checklist before merging - [x] Test, docs, adr added or updated as needed - [x] [Contributor Guide](https://github.com/defenseunicorns/uds-template-capability/blob/main/CONTRIBUTING.md) followed --- .codespellrc | 4 +- .eslintrc.json | 29 +++-- .github/actions/save-logs/action.yaml | 8 ++ .github/test-infra/azure/aks/variables.tf | 2 +- .github/workflows/test.yaml | 2 +- .gitignore | 7 +- CONTRIBUTING.md | 98 +++++++++++++---- e2e/playwright/auth.setup.ts | 32 ++++++ e2e/playwright/grafana.test.ts | 54 ++++++++++ e2e/playwright/package-lock.json | 102 ++++++++++++++++++ e2e/playwright/package.json | 8 ++ e2e/playwright/playwright.config.ts | 45 ++++++++ e2e/playwright/tsconfig.json | 10 ++ e2e/playwright/uds.config.ts | 7 ++ packages/monitoring/tasks.yaml | 1 + pepr.ts | 4 + src/grafana/tasks.yaml | 20 ++++ src/keycloak/chart/templates/statefulset.yaml | 2 +- src/loki/values/values.yaml | 9 +- src/pepr/logger.ts | 1 + src/pepr/patches/index.ts | 42 ++++++++ tasks/deploy.yaml | 2 +- tasks/test.yaml | 32 +++++- tasks/utils.yaml | 35 ++++++ tsconfig.json | 12 ++- 25 files changed, 526 insertions(+), 42 deletions(-) create mode 100644 e2e/playwright/auth.setup.ts create mode 100644 e2e/playwright/grafana.test.ts create mode 100644 e2e/playwright/package-lock.json create mode 100644 e2e/playwright/package.json create mode 100644 e2e/playwright/playwright.config.ts create mode 100644 e2e/playwright/tsconfig.json create mode 100644 e2e/playwright/uds.config.ts create mode 100644 src/pepr/patches/index.ts diff --git a/.codespellrc b/.codespellrc index 50ac37787..f3d25b3c9 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,5 +1,5 @@ # Lint Codespell configurations [codespell] skip = .codespellrc,.git,node_modules,build,dist,*.zst,CHANGELOG.md -ignore-words-list = NotIn,AKS,LICENS -enable-colors = \ No newline at end of file +ignore-words-list = NotIn,AKS,LICENS,aks +enable-colors = diff --git a/.eslintrc.json b/.eslintrc.json index dcbc9ca6c..63521754f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,21 +3,38 @@ "browser": false, "es2021": true }, - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], "parser": "@typescript-eslint/parser", "parserOptions": { - "project": ["./tsconfig.json"], + "project": [ + "./tsconfig.json" + ], "ecmaVersion": 2022 }, - "plugins": ["@typescript-eslint"], - "ignorePatterns": ["node_modules", "dist", "jest.*.js"], + "plugins": [ + "@typescript-eslint" + ], + "ignorePatterns": [ + "node_modules", + "dist", + "jest.*.js", + "e2e/" + ], "root": true, "rules": { - "@typescript-eslint/no-floating-promises": ["error"] + "@typescript-eslint/no-floating-promises": [ + "error" + ] }, "overrides": [ { - "files": [ "src/pepr/operator/crd/generated/**/*.ts", "src/pepr/operator/crd/generated/*.ts" ], + "files": [ + "src/pepr/operator/crd/generated/**/*.ts", + "src/pepr/operator/crd/generated/*.ts" + ], "rules": { "@typescript-eslint/no-explicit-any": "off" } diff --git a/.github/actions/save-logs/action.yaml b/.github/actions/save-logs/action.yaml index 01aa42225..146d7db48 100644 --- a/.github/actions/save-logs/action.yaml +++ b/.github/actions/save-logs/action.yaml @@ -37,6 +37,12 @@ runs: sudo chown $USER /tmp/uds-*.log || echo "" shell: bash + - name: Move Playwright Artifacts + run: | + sudo mkdir -p /tmp/playwright + sudo mv e2e/playwright/.playwright/* /tmp/playwright || true + shell: bash + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: debug-log${{ inputs.suffix }} @@ -47,3 +53,5 @@ runs: /tmp/debug-*.log /tmp/uds-containerd-logs /tmp/k3d-uds-*.log + /tmp/playwright/output + /tmp/playwright/reports diff --git a/.github/test-infra/azure/aks/variables.tf b/.github/test-infra/azure/aks/variables.tf index 0e1b18b7f..1ba26453a 100644 --- a/.github/test-infra/azure/aks/variables.tf +++ b/.github/test-infra/azure/aks/variables.tf @@ -191,4 +191,4 @@ variable "db_name" { description = "The name to give the database" type = string default = "grafana" -} \ No newline at end of file +} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 284a3139d..edf089363 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -67,7 +67,7 @@ jobs: - name: Test UDS Core Install if: ${{ inputs.package == 'all' && inputs.test_type == 'install' }} - run: uds run test-uds-core --set FLAVOR=${{ inputs.flavor }} --no-progress + run: uds run test:uds-core-e2e --set FLAVOR=${{ inputs.flavor }} --no-progress - name: Compose UDS Core Component Definitions if: ${{ inputs.package == 'all' && inputs.test_type == 'install' }} diff --git a/.gitignore b/.gitignore index 1209c1862..b6b996531 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,12 @@ build/ .DS_Store *.tar.zst zarf-sbom +zarf-sbom/** tmp/ env.ts -node_modules/** +**/node_modules +**/node_modules/** +dist dist/** insecure* .env @@ -19,3 +22,5 @@ extract-terraform.sh cluster-config.yaml **.tfstate **.backup +**/.playwright/** +**/.playwright diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 340dddd87..4ca9d6cb2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,6 @@ # Welcome to UDS Core -Thank you for your interest in Defense Unicorns UDS Core! - -This document describes the process and requirements for contributing to this UDS Core repo. +Thank you for your interest in contributing to Defense Unicorns UDS Core! This document will guide you through the contribution process. ## Table of Contents @@ -20,35 +18,97 @@ Continuous Delivery is core to our development philosophy. Check out [https://mi Specifically: -* We do trunk-based development (main) with short-lived feature branches that originate from the trunk, get merged into the trunk, and are deleted after the merge -* We don't merge code into main that isn't releasable -* We perform automated testing on all changes before they get merged to main -* Continuous integration (CI) pipeline tests are definitive -* We create immutable release artifacts +- We practice trunk-based development (main) with short-lived feature branches that are merged and deleted after the merge. +- We don't merge code into main that isn't releasable. +- All changes are tested automatically before being merged into main. +- Continuous integration (CI) pipeline tests are the source of truth. +- We produce immutable release artifacts. + +### Pre-Commit Checks -Commits: +We use [codespell](https://github.com/codespell-project/codespell) and [yamllint](https://yamllint.readthedocs.io/en/stable/) for pre-commit checks. Please install these before committing, or your commit may fail. -We use [codespell](https://github.com/codespell-project/codespell) and [yamllint](https://yamllint.readthedocs.io/en/stable/) for our precommit checking. It is recommended to have these installed before attempting to commit to the a branch otherwise your commit will not finalize and you will be shown an error. +To install these tools, run: + +```console +uds run lint-check +``` -To install both of these tools you can run `uds run lint-check` to install them or utilize `pip` to install them manually. +Alternatively, you can install them with `pip`: -```bash +```console pip install yamllint codespell ``` ## Definition of Done -We apply these general principles to all User Stories and activities contributing to the UDS. +We apply these principles to all User Stories and contributions: + +- Automated continuous integration (CI) pipeline tests pass +- CI tests are updated to cover new system changes +- Changes are peer-reviewed +- Acceptance criteria is met +- Documentation is updated to reflect changes + +### Testing + +Each individual component of UDS Core contains lightweight validations in its own `src//tasks.yaml` file. These validations focus on the bare minimum functionality, typically covering pod health and endpoint accessibility. + +We also place end-to-end tests under the `e2e` folder. In particular we use [Playwright](https://playwright.dev/) for browser based testing and have authentication setup to login to applications with a shared SSO session. Playwright provides a [test recorder](https://playwright.dev/docs/codegen#generate-tests-with-the-playwright-inspector) which can be beneficial to get a quickstart on new tests. -* Automated continuous integration (CI) pipeline tests pass -* CI pipeline tests have been updated to meet system changes -* Changes are peer reviewed -* Acceptance criteria is met -* Documentation is updated to reflect what changed +In general our testing focuses on the unique configuration and setup provided by UDS Core, rather than exhaustive functionality testing. We take this approach since each of the opensource applications we package and configure also have extensive end-to-end testing in their upstream repositories. ## Getting Started -TBD +This section will help you get set up and ready to contribute to UDS Core. + +### 1. Prerequisites + +Before starting, ensure that you have the following installed: + +- **Git**: [Install Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +- **K3d**: [Install K3d](https://k3d.io/#installation) +- **Node.js** (for building and running Pepr): [Install Node.js](https://nodejs.org/en/download/) +- **UDS CLI** (for running tasks and deploying): [Install UDS](https://uds.defenseunicorns.com/cli/quickstart-and-usage/) + +### 2. Clone the Repository and Make a Branch + +Clone the UDS Core repository to your local machine using Git (note that you may want to [fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) this repository): + +```console +git clone https://github.com/DefenseUnicorns/uds-core.git +cd uds-core +``` + +Then make a branch for your changes: + +```console +git checkout -b my-feature-branch +``` + +### 3. Make Changes and Test Locally + +Make the changes to add the new feature, bug fix, or other change necessary. Keep in mind any documentation or testing changes that are relevant while making code changes. + +When you are ready to test locally you can run the same tests as CI using the below UDS commands: + +```console +# Lightweight validations +uds run test-uds-core + +# Full e2e tests (run in CI) +uds run test:uds-core-e2e +``` + +Each of these tasks will create a local k3d cluster, install UDS Core, and run a series of tests against it, the same tests that are run in CI. + +If you want to run a subset of core for faster iterations against a specific package, you can use the `LAYER` variable with the below task (example for metrics-server): + +```console +uds run test-single-layer --set LAYER=metrics-server +``` + +Note you can also specify the `--set FLAVOR=` flag to test using with either the Iron Bank or Unicorn sourced images instead of the upstream ones. ## Submitting a Pull Request diff --git a/e2e/playwright/auth.setup.ts b/e2e/playwright/auth.setup.ts new file mode 100644 index 000000000..a4f18a21b --- /dev/null +++ b/e2e/playwright/auth.setup.ts @@ -0,0 +1,32 @@ +/** + * Copyright 2024 Defense Unicorns + * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + */ + +import { expect, test as setup } from "@playwright/test"; +import { authFile } from "./playwright.config"; +import { domain } from "./uds.config"; + +const baseURL = `https://sso.${domain}`; + +setup("authenticate", async ({ page, context }) => { + await page.goto(baseURL); + + await page.getByLabel("Username or email").fill("doug"); + await page.getByLabel("Password").fill("unicorn123!@#UN"); + await page.getByRole("button", { name: "Log In" }).click(); + + await page.waitForURL(`${baseURL}/realms/uds/account`); // successful redirect + + // ensure auth cookies were set + const cookies = await context.cookies(); + const keycloakCookie = cookies.find( + (cookie) => cookie.name === "KEYCLOAK_SESSION", + ); + + expect(keycloakCookie).toBeDefined(); + expect(keycloakCookie?.value).not.toBe(""); + expect(keycloakCookie?.domain).toContain("sso."); + + await page.context().storageState({ path: authFile }); +}); diff --git a/e2e/playwright/grafana.test.ts b/e2e/playwright/grafana.test.ts new file mode 100644 index 000000000..302a7d9aa --- /dev/null +++ b/e2e/playwright/grafana.test.ts @@ -0,0 +1,54 @@ +/** + * Copyright 2024 Defense Unicorns + * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + */ + +import { expect, test } from "@playwright/test"; +import { domain, fullCore } from "./uds.config"; + +test.use({ baseURL: `https://grafana.admin.${domain}` }); +test.describe.configure({ mode: 'serial' }); + +test("validate loki datasource", async ({ page }) => { + test.skip(!fullCore, "Loki is only present on full core deploys"); + await test.step("check loki", async () => { + await page.goto(`/connections/datasources`); + await page.getByRole('link', { name: 'Loki' }).click(); + await page.click('text=Save & test'); + // Allow 40 second timeout for datasource validation + await expect(page.locator('[data-testid="data-testid Alert success"]')).toBeVisible({ timeout: 40000 }); + }); +}); + +test("validate prometheus datasource", async ({ page }) => { + await test.step("check prometheus", async () => { + await page.goto(`/connections/datasources`); + await page.getByRole('link', { name: 'Prometheus' }).click(); + await page.click('text=Save & test'); + // Allow 20 second timeout for datasource validation + await expect(page.locator('[data-testid="data-testid Alert success"]')).toBeVisible({ timeout: 20000 }); + }); +}); + +// This dashboard is added by the upstream kube-prometheus-stack +test("validate namespace dashboard", async ({ page }) => { + await test.step("check dashboard", async () => { + await page.goto(`/dashboards`); + await page.click('text="Kubernetes / Compute Resources / Namespace (Pods)"'); + await page.getByTestId('data-testid Dashboard template variables Variable Value DropDown value link text authservice').click(); + await page.getByRole('checkbox', { name: 'grafana' }).click(); + }); +}); + +// This dashboard is deployed "custom" by our uds config chart +test("validate loki dashboard", async ({ page }) => { + test.skip(!fullCore, "Loki is only present on full core deploys"); + await test.step("check dashboard", async () => { + await page.goto(`/dashboards`); + await page.getByPlaceholder('Search for dashboards and folders').fill('Loki'); + await page.click('text="Loki Dashboard quick search"'); + await page.getByTestId('data-testid Dashboard template variables Variable Value DropDown value link text authservice').click(); + await page.getByRole('checkbox', { name: 'grafana' }).click(); + await expect(page.getByTestId('data-testid Panel header Logs Panel').getByTestId('data-testid panel content')).toBeVisible(); + }); +}); diff --git a/e2e/playwright/package-lock.json b/e2e/playwright/package-lock.json new file mode 100644 index 000000000..d85661f43 --- /dev/null +++ b/e2e/playwright/package-lock.json @@ -0,0 +1,102 @@ +{ + "name": "test", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "test", + "devDependencies": { + "@playwright/test": "^1.48.1", + "@types/node": "^22.7.4", + "typescript": "^5.6.2" + } + }, + "node_modules/@playwright/test": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz", + "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==", + "dev": true, + "dependencies": { + "playwright": "1.48.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz", + "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==", + "dev": true, + "dependencies": { + "playwright-core": "1.48.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz", + "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + } + } +} diff --git a/e2e/playwright/package.json b/e2e/playwright/package.json new file mode 100644 index 000000000..f652235aa --- /dev/null +++ b/e2e/playwright/package.json @@ -0,0 +1,8 @@ +{ + "name": "test", + "devDependencies": { + "@playwright/test": "^1.48.1", + "@types/node": "^22.7.4", + "typescript": "^5.6.2" + } +} diff --git a/e2e/playwright/playwright.config.ts b/e2e/playwright/playwright.config.ts new file mode 100644 index 000000000..8230356f6 --- /dev/null +++ b/e2e/playwright/playwright.config.ts @@ -0,0 +1,45 @@ +/** + * Copyright 2024 Defense Unicorns + * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + */ + +import { defineConfig, devices } from "@playwright/test"; + +export const playwrightDir = ".playwright"; +export const authFile = `${playwrightDir}/auth/user.json`; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + fullyParallel: true, + forbidOnly: !!process.env.CI, // fail CI if you accidentally leave `test.only` in source + retries: 1, + workers: 20, // Support up to 20 parallel workers + timeout: 45000, // 45 second timeout for tests + reporter: [ + // Reporter to use. See https://playwright.dev/docs/test-reporters + ['html', { outputFolder: `${playwrightDir}/reports`, open: 'never' }] + ], + + outputDir: `${playwrightDir}/output`, + + use: { + trace: 'retain-on-failure', // save trace for failed tests. See https://playwright.dev/docs/trace-viewer#opening-the-trace + }, + + projects: [ + { name: 'setup', testMatch: /.*\.setup\.ts/ }, // authentication + + ...[ + 'Desktop Chrome', + ].map((p) => ({ + name: devices[p].defaultBrowserType, + dependencies: ['setup'], + use: { + ...devices[p], + storageState: authFile, + }, + })), + ], +}); diff --git a/e2e/playwright/tsconfig.json b/e2e/playwright/tsconfig.json new file mode 100644 index 000000000..ffc74c778 --- /dev/null +++ b/e2e/playwright/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "module": "commonjs", /* Specify what module code is generated. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/e2e/playwright/uds.config.ts b/e2e/playwright/uds.config.ts new file mode 100644 index 000000000..632b8e69d --- /dev/null +++ b/e2e/playwright/uds.config.ts @@ -0,0 +1,7 @@ +/** + * Copyright 2024 Defense Unicorns + * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + */ + +export const domain = process.env.DOMAIN || 'uds.dev'; +export const fullCore = process.env.FULL_CORE === "true"; diff --git a/packages/monitoring/tasks.yaml b/packages/monitoring/tasks.yaml index e7c9b3bee..375c195f0 100644 --- a/packages/monitoring/tasks.yaml +++ b/packages/monitoring/tasks.yaml @@ -10,3 +10,4 @@ tasks: actions: - task: prometheus:validate - task: grafana:validate + - task: grafana:e2e-test diff --git a/pepr.ts b/pepr.ts index b0403818e..18493e612 100644 --- a/pepr.ts +++ b/pepr.ts @@ -14,6 +14,7 @@ import { operator } from "./src/pepr/operator"; import { setupAuthserviceSecret } from "./src/pepr/operator/controllers/keycloak/authservice/config"; import { Policy } from "./src/pepr/operator/crd"; import { registerCRDs } from "./src/pepr/operator/crd/register"; +import { patches } from "./src/pepr/patches"; import { policies, startExemptionWatch } from "./src/pepr/policies"; import { prometheus } from "./src/pepr/prometheus"; @@ -37,6 +38,9 @@ const log = setupLogger(Component.STARTUP); // Prometheus monitoring stack prometheus, + + // Patches for specific components + patches, ]); // Remove legacy policy entries from the pepr store for the 0.5.0 upgrade if ( diff --git a/src/grafana/tasks.yaml b/src/grafana/tasks.yaml index 962abc8a7..a650002c3 100644 --- a/src/grafana/tasks.yaml +++ b/src/grafana/tasks.yaml @@ -1,6 +1,9 @@ # Copyright 2024 Defense Unicorns # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial +includes: + - utils: ../../tasks/utils.yaml + tasks: - name: validate actions: @@ -26,3 +29,20 @@ tasks: echo "ERROR: Grafana is redirecting to $(curl -L -isS https://grafana.admin.uds.dev --output /dev/null -w '%{url_effective}')." exit 1 fi + + - name: e2e-test + actions: + - description: "Setup the Keycloak admin user if needed" + task: utils:keycloak-admin-user + - description: "Setup the Doug User for testing" + # Self-reference this task file to avoid https://github.com/defenseunicorns/maru-runner/issues/144 + cmd: uds run -f tasks/test.yaml common-setup:create-doug-user --set KEYCLOAK_GROUP="/UDS Core/Admin" # Adds the test doug user + - description: E2E Test for Grafana, optionally set FULL_CORE=true to test integrations with Loki + cmd: | + # renovate: datasource=docker depName=mcr.microsoft.com/playwright versioning=docker + docker run --rm --ipc=host -e FULL_CORE="${FULL_CORE}" --net=host --mount type=bind,source="$(pwd)",target=/app mcr.microsoft.com/playwright:v1.48.1-noble sh -c " \ + cd app && \ + npm ci && \ + npx playwright test grafana.test.ts \ + " + dir: e2e/playwright diff --git a/src/keycloak/chart/templates/statefulset.yaml b/src/keycloak/chart/templates/statefulset.yaml index ed23facc4..6f3a9e570 100644 --- a/src/keycloak/chart/templates/statefulset.yaml +++ b/src/keycloak/chart/templates/statefulset.yaml @@ -168,7 +168,7 @@ spec: - name: JAVA_TOOL_OPTIONS value: "-Dcom.redhat.fips=true" {{- end }} - {{- end }} + {{- end }} {{- if .Values.insecureAdminPasswordGeneration.enabled }} - name: KEYCLOAK_ADMIN valueFrom: diff --git a/src/loki/values/values.yaml b/src/loki/values/values.yaml index 243286566..0c9827d51 100644 --- a/src/loki/values/values.yaml +++ b/src/loki/values/values.yaml @@ -12,11 +12,6 @@ fullnameOverride: loki # -- Overrides the chart's cluster label clusterLabelOverride: null -# Prevent startup issues with service existence/resolution -memberlist: - service: - publishNotReadyAddresses: true - chunksCache: enabled: false @@ -166,3 +161,7 @@ write: backend: # Remove default anti-affinity to support single node affinity: null + # Temporary label to trigger mutation for istio service patch + service: + labels: + uds/istio-patch: "true" diff --git a/src/pepr/logger.ts b/src/pepr/logger.ts index b79ca76a5..fd39a81f4 100644 --- a/src/pepr/logger.ts +++ b/src/pepr/logger.ts @@ -22,6 +22,7 @@ export enum Component { POLICIES = "policies", POLICIES_EXEMPTIONS = "policies.exemptions", PROMETHEUS = "prometheus", + PATCHES = "patches", } export function setupLogger(component: Component) { diff --git a/src/pepr/patches/index.ts b/src/pepr/patches/index.ts new file mode 100644 index 000000000..78a99c277 --- /dev/null +++ b/src/pepr/patches/index.ts @@ -0,0 +1,42 @@ +/** + * Copyright 2024 Defense Unicorns + * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial + */ + +import { Capability, a } from "pepr"; +import { Component, setupLogger } from "../logger"; + +export const patches = new Capability({ + name: "patches", + description: "UDS Core Capability for patching miscellaneous things.", +}); + +const { When } = patches; + +// configure subproject logger +const log = setupLogger(Component.PATCHES); + +/** + * Mutate the Loki backend headless support to handle Istio protocol selection properly + * Temporary until fixed upstream in https://github.com/grafana/loki/pull/14507 + */ +When(a.Service) + .IsCreatedOrUpdated() + .InNamespace("loki") + .WithName("loki-backend-headless") + .Mutate(async svc => { + if (svc.Raw.spec === undefined || svc.Raw.spec.ports === undefined) { + return; + } + + log.debug("Patching loki-backend-headless service to add appProtocol"); + + const ports = svc.Raw.spec.ports; + + const grpcPort = ports.find(p => p.name === "grpc"); + + // If found, set appProtocol to "tcp" + if (grpcPort) { + grpcPort.appProtocol = "tcp"; + } + }); diff --git a/tasks/deploy.yaml b/tasks/deploy.yaml index 09325a263..27f13643a 100644 --- a/tasks/deploy.yaml +++ b/tasks/deploy.yaml @@ -18,7 +18,7 @@ tasks: - name: k3d-standard-bundle actions: - description: "Deploy the UDS Core Standard Bundle" - cmd: uds deploy bundles/k3d-standard/uds-bundle-k3d-core-demo-${UDS_ARCH}-${VERSION}.tar.zst --confirm --no-progress + cmd: uds deploy bundles/k3d-standard/uds-bundle-k3d-core-demo-${UDS_ARCH}-${VERSION}.tar.zst --set INSECURE_ADMIN_PASSWORD_GENERATION=true --confirm --no-progress - name: k3d-standard-bundle-ha actions: diff --git a/tasks/test.yaml b/tasks/test.yaml index 22aadbb4a..a8186d90f 100644 --- a/tasks/test.yaml +++ b/tasks/test.yaml @@ -1,13 +1,13 @@ # Copyright 2024 Defense Unicorns # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - includes: - create: ./create.yaml - setup: ./setup.yaml - deploy: ./deploy.yaml + - util: ./utils.yaml + - common-setup: https://raw.githubusercontent.com/defenseunicorns/uds-common/refs/tags/v0.13.1/tasks/setup.yaml - compliance: https://raw.githubusercontent.com/defenseunicorns/uds-common/v1.1.0/tasks/compliance.yaml - - base-layer: ../packages/base/tasks.yaml tasks: - name: base @@ -43,7 +43,7 @@ tasks: done - name: validate-packages - description: "Validated all packages" + description: "Validate all packages" # loop through each src/* package and run the validate.yaml task actions: - cmd: | @@ -52,6 +52,25 @@ tasks: done set +e + - name: e2e-tests + description: "E2E Test all packages" + # Run each e2e test type from the e2e folder + actions: + - description: "Setup the Keycloak admin user if needed" + task: util:keycloak-admin-user + - description: "Setup the Doug User for testing" + # Self-reference this task file to avoid https://github.com/defenseunicorns/maru-runner/issues/144 + cmd: uds run -f tasks/test.yaml common-setup:create-doug-user --set KEYCLOAK_GROUP="/UDS Core/Admin" # Adds the test doug user + - description: "Run Playwright E2E tests for all packages" + dir: e2e/playwright + cmd: | + # renovate: datasource=docker depName=mcr.microsoft.com/playwright versioning=docker + docker run --rm --ipc=host --net=host -e FULL_CORE="true" --mount type=bind,source="$(pwd)",target=/app mcr.microsoft.com/playwright:v1.48.1-noble sh -c " \ + cd app && \ + npm ci && \ + npx playwright test \ + " + - name: uds-core description: "Build and test UDS Core" actions: @@ -60,6 +79,12 @@ tasks: - task: deploy:k3d-standard-bundle - task: validate-packages + - name: uds-core-e2e + description: "Build and test UDS Core e2e" + actions: + - task: uds-core + - task: e2e-tests + - name: uds-core-ha description: "Build and test UDS Core" actions: @@ -76,6 +101,7 @@ tasks: - task: create:standard-package - task: deploy:standard-package - task: validate-packages + - task: e2e-tests - name: compliance-validate description: "validate against the required compliance" diff --git a/tasks/utils.yaml b/tasks/utils.yaml index 298551e72..8ca6899d1 100644 --- a/tasks/utils.yaml +++ b/tasks/utils.yaml @@ -29,3 +29,38 @@ tasks: mute: true setVariables: - name: TARGET_REPO + + - name: keycloak-admin-user + actions: + - description: Sets up the Keycloak admin user for dev/testing if not already created + cmd: | + # Check if the secret exists + if ./zarf tools kubectl get secret keycloak-admin-password -n keycloak > /dev/null 2>&1; then + echo "Admin user exists, skipping..." + else + # Start port-forward with zarf + ./zarf tools kubectl port-forward -n keycloak svc/keycloak-http 8080:8080 & + PF_PID=$! + + # Wait a bit to ensure port-forward is ready + sleep 5 + + # Create admin user with curl + PASSWORD=$(openssl rand -base64 12) + STATE_COOKIE=$(curl --silent --output /dev/null --cookie-jar - http://localhost:8080/ | grep "WELCOME_STATE_CHECKER" | awk '{print $7}') + curl --silent --show-error http://localhost:8080/ \ + -H "Cookie: WELCOME_STATE_CHECKER=${STATE_COOKIE}" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + --data-urlencode "username=admin" \ + --data-urlencode "password=${PASSWORD}" \ + --data-urlencode "passwordConfirmation=${PASSWORD}" \ + --data-urlencode "stateChecker=${STATE_COOKIE}" + + # Kill the port-forward + kill $PF_PID + + ./zarf tools kubectl create secret generic keycloak-admin-password \ + --from-literal=username=admin \ + --from-literal=password=${PASSWORD} \ + -n keycloak + fi diff --git a/tsconfig.json b/tsconfig.json index 70638f3a6..7d3c4fc52 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,9 @@ "declarationMap": true, "emitDeclarationOnly": true, "esModuleInterop": true, - "lib": ["ES2022"], + "lib": [ + "ES2022" + ], "module": "CommonJS", "moduleResolution": "node", "outDir": "dist", @@ -15,5 +17,11 @@ "target": "ES2022", "useUnknownInCatchVariables": false }, - "include": ["**/*.ts"] + "include": [ + "**/*.ts" + ], + "exclude": [ + "e2e", + "dist" + ] }