Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add audit scanner test #505

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 11 additions & 20 deletions tests/e2e/00-installation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { test, expect } from './rancher-test';
import { RancherCommonPage } from './pages/rancher-common.page';
import { RancherExtensionsPage } from './pages/rancher-extensions.page';
import { OverviewPage } from './pages/overview.page';
import { KubewardenPage } from './pages/kubewarden.page';
import { PolicyServersPage } from './pages/policyservers.page';
import { policyTitles } from './pages/basepolicypage';
import { RancherAppsPage } from './pages/rancher-apps.page';

// source (yarn dev) | rc (add github repo) | released (just install)
const ORIGIN = process.env.ORIGIN || (process.env.API ? 'source' : 'rc');
Expand Down Expand Up @@ -42,14 +43,12 @@ test('01 Enable extension support', async({ page, ui }) => {
test('02 Install extension', async({ page }) => {
// Add UI charts repository
if (ORIGIN === 'rc') {
const rancher = new RancherCommonPage(page);

await rancher.addRepository('kubewarden-extension-rc', 'https://rancher.github.io/kubewarden-ui/');
const apps = new RancherAppsPage(page);
await apps.addRepository('kubewarden-extension-rc', 'https://rancher.github.io/kubewarden-ui/');
}

// Install or developer load extension
const extensions = new RancherExtensionsPage(page);

await extensions.goto();
if (ORIGIN === 'source') {
await extensions.developerLoad('http://127.0.0.1:4500/kubewarden-0.0.1/kubewarden-0.0.1.umd.min.js');
Expand All @@ -59,8 +58,7 @@ test('02 Install extension', async({ page }) => {
});

test('03 Install kubewarden', async({ page, ui }) => {
const kwPage = new OverviewPage(page);

const kwPage = new KubewardenPage(page);
await kwPage.installKubewarden();

// Check UI is active
Expand All @@ -72,31 +70,24 @@ test('03 Install kubewarden', async({ page, ui }) => {

test('04 Install default policyserver', async({ page, ui }) => {
const psPage = new PolicyServersPage(page);
const kwPage = new KubewardenPage(page);

// Check banner is also visible on overview page
const kwPage = new OverviewPage(page);

// Banner is visible on Overview page
await kwPage.goto();
await expect(psPage.noDefaultPsBanner).toBeVisible();

// Banner is visible on Policy Servers page
await psPage.goto();
await expect(psPage.noDefaultPsBanner).toBeVisible();

await page.getByRole('button', { name: 'Install Chart', exact: true }).click();
await expect(page).toHaveURL(/.*\/apps\/charts\/install.*chart=kubewarden-defaults/);

// Handle PolicyServer Installer Dialog
await expect(page.getByRole('heading', { name: 'Install: Step 1' })).toBeVisible();
await page.getByRole('button', { name: 'Next' }).click();

await expect(page.getByRole('heading', { name: 'Install: Step 2' })).toBeVisible();
await psPage.installDefaultDialog({ enable: true, mode: 'monitor' });

await page.getByRole('button', { name: 'Install' }).click();
await expect(ui.helmPassRegex('rancher-kubewarden-defaults')).toBeVisible({ timeout: 40_000 });
await psPage.installDefault({recommended: true, mode: 'monitor'})
});

test('05 Whitelist artifacthub', async({ page }) => {
const kwPage = new OverviewPage(page);
const kwPage = new KubewardenPage(page);

await page.goto('/dashboard/c/local/kubewarden/policies.kubewarden.io.clusteradmissionpolicy/create');
await expect(page.getByRole('heading', { name: 'Custom Policy' })).toBeVisible();
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/10-landing.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { test, expect } from './rancher-test';
import { OverviewPage } from './pages/overview.page';
import { KubewardenPage } from './pages/kubewarden.page';
import { PolicyServersPage } from './pages/policyservers.page';
import { AdmissionPoliciesPage } from './pages/admissionpolicies.page';
import { ClusterAdmissionPoliciesPage } from './pages/clusteradmissionpolicies.page';

test('Kubewarden Landing page', async({ page, ui }) => {
const kwPage = new OverviewPage(page);
const kwPage = new KubewardenPage(page);
await kwPage.goto();
await expect(page.getByRole('heading', { name: 'Welcome to Kubewarden' })).toBeVisible()

Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/50-policyreports.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ test('PolicyReports', async({ page, ui }) => {
await den.getByRole('textbox').fill('unsafelbl')

// Customize because audit for "*" rules is skipped
await capPage.editYaml()
await ui.editYaml(ui.page, d => {
await ui.openYamlEditor()
await ui.editYaml(d => {
d.spec.rules[0].apiGroups[0] = ""
d.spec.rules[0].apiVersions[0] = "v1"
d.spec.rules[0].resources[0] = "namespaces"
Expand Down
67 changes: 67 additions & 0 deletions tests/e2e/60-tracing.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { test, expect } from './rancher-test';
import { Chart, RancherAppsPage } from './pages/rancher-apps.page';
import { PolicyServersPage } from './pages/policyservers.page';

/**
* Expect timeout has to be increased after telemetry installation on local cluster
*
*/
test('Install opentelemetry & jaeger', async ({ page }) => {
const apps = new RancherAppsPage(page)
const otelChart: Chart = { title: 'opentelemetry-operator', name: 'opentelemetry-operator', namespace: 'open-telemetry', version: '0.38.0', check: 'opentelemetry-operator' }
const jaegerChart: Chart = { title: 'Jaeger Operator', namespace: 'jaeger', check: "jaeger-operator" }

// Install OpenTelemetry
await apps.addRepository('open-telemetry', 'https://open-telemetry.github.io/opentelemetry-helm-charts')
await apps.installChart(otelChart)

// Install Jaeger
await apps.installChart(jaegerChart, d => {
d.jaeger.create = "true"
d.rbac.clusterRole = "true"
})
});

test('Enable tracing in Kubewarden', async ({ page, ui }) => {
const apps = new RancherAppsPage(page)
await apps.updateApp('rancher-kubewarden-controller', d => {
d.telemetry.enabled = true
jordojordo marked this conversation as resolved.
Show resolved Hide resolved
d.telemetry.tracing.jaeger.endpoint = "jaeger-operator-jaeger-collector.jaeger.svc.cluster.local:14250"
d.telemetry.tracing.jaeger.tls = {}
d.telemetry.tracing.jaeger.tls.insecure = true
})

// Wait until kubewarden controller and policyserver are restarted, it takes around 1m
await ui.shell(`for i in $(seq 60); do
echo "Retry #$i";
k logs -l app=kubewarden-policy-server-default -n cattle-kubewarden-system -c otc-container | grep -F 'Everything is ready.' && break || sleep 5;
done`)
});

test('Check traces are visible', async ({ page, ui }) => {
const tracingTab = page.getByRole('tablist').locator('li#policy-tracing')
const policiesTab = page.getByRole('tablist').locator('li#related-policies')
const logline = ui.getRow('tracing-privpod').row.first()

const psPage = new PolicyServersPage(page)
await psPage.goto()

// Create trace log line
await ui.shell('k run tracing-privpod --image=nginx:alpine --privileged')
console.warn('Workaround: Opentelemetry not installed warning before I generate traces')
await page.reload()

// Check logs on policy server
await ui.getRow('default').open()
await tracingTab.click()
await expect(logline).toBeVisible()

// Check logs on the policy
await policiesTab.click()
await ui.getRow('no-privileged-pod').open()
await tracingTab.click()
await expect(logline).toBeVisible()

// Cleanup
await ui.shell('k delete pod tracing-privpod')
})
27 changes: 20 additions & 7 deletions tests/e2e/components/table-row.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { expect, Locator } from '@playwright/test';
import { RancherUI } from '../pages/rancher-ui';

/**
* Builds xpath expression to get column index by it's name
* @param name Name of the table column
* @returns xpath expression to get index of the column
*/
function xpath_colIndex(...names: string[]):string {
// Transform: names > normalize-space(.)="names[0]" [or ...]
const selector = names.map(str => `normalize-space(.)="${str}"`).join(" or ")
// Find thead > th with requested name and count how many th was before it
return `count(ancestor::table[1]/thead/tr/th[${selector}]/preceding-sibling::th)+1`
}

export class TableRow {

private readonly ui: RancherUI
Expand All @@ -10,8 +22,8 @@ export class TableRow {

/**
*
* @param page required by actions menu since it's not child of the table
* @param name of the row, has to be a link to the resource
* @param page is required by row actions menu since it's not child of the table
* @param name of the row, it is searched under "Name" column by default
* @param group When there are multiple tbodies filter by group-tab
*
*/
Expand All @@ -22,7 +34,7 @@ export class TableRow {
}

this.ui = ui
this.row = tbody.locator('tr.main-row').filter({has: ui.page.getByRole('link', {name: name, exact: true})})
this.row = tbody.locator(`xpath=tr[td[${xpath_colIndex("Name")}][normalize-space(.)="${name}"]]`)
this.name = this.column('Name')
this.status = this.column('Status', 'State')
}
Expand All @@ -37,11 +49,12 @@ export class TableRow {
await expect(this.status).toHaveText('Active', {timeout: timeout})
}

/**
* @param names header of the column, you can provide alternative names (State|Status)
* @returns table cell (td) that is under requested column. Returns first cell if no match was found
*/
column(...names: string[]) {
// Transform: names > normalize-space(.)="names[0]" [or ...]
const selector = names.map(str => `normalize-space(.)="${str}"`).join(" or ")
// https://stackoverflow.com/questions/14745478/how-to-select-table-column-by-column-header-name-with-xpath
return this.row.locator(`xpath=/td[count(ancestor::table[1]/thead/tr/th[${selector}]/preceding-sibling::th)+1]`)
return this.row.locator(`xpath=td[${xpath_colIndex(...names)}]`)
}

async action(name: string) {
Expand Down
18 changes: 9 additions & 9 deletions tests/e2e/exec.spec.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { test } from './rancher-test'
import { type Chart, RancherCommonPage } from './pages/rancher-common.page';
import { type Chart, RancherAppsPage } from './pages/rancher-apps.page';

const charts: Chart[] = [
{title: 'Jaeger Operator', namespace: 'jaeger', name: "jaeger-operator"},
{title: 'Monitoring', project: '(None)', name: "rancher-monitoring"},
{title: 'Kubewarden', project: 'Default', name: "rancher-kubewarden-controller"},
{title: 'Jaeger Operator', namespace: 'jaeger', check: "jaeger-operator"},
{title: 'Monitoring', project: '(None)', check: "rancher-monitoring"},
{title: 'Kubewarden', project: 'Default', check: "rancher-kubewarden-controller"},
]

// Install chart from apps menu
// app=Monitoring pw test exec -g 'appInstall' --headed
test('appInstall', async({ page}) => {
const chart = charts.find(o => o.title === process.env.app) || charts[0]

const rancher = new RancherCommonPage(page)
await rancher.installApp(chart)
const apps = new RancherAppsPage(page)
await apps.installChart(chart)
});

// Upgrade without any changes will reload app yaml (patched by kubectl)
// app='Jaeger Operator' pw test exec -g 'appUpdate' --headed
test('appUpdate', async({ page }) => {
const chart = charts.find(o => o.title === process.env.app) || charts[0]
const app = process.env.app || 'jaeger-operator'

const rancher = new RancherCommonPage(page)
await rancher.updateApp(chart)
const apps = new RancherAppsPage(page)
await apps.updateApp(app)
});
10 changes: 1 addition & 9 deletions tests/e2e/pages/basepolicypage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,6 @@ export class BasePolicyPage extends BasePage {
await this.ui.checkbox('Ignore Rancher Namespaces').setChecked(checked)
}

async editYaml() {
// Give generated fields time to get registered
await this.page.waitForTimeout(200)
// Show yaml with edited settings
await this.page.getByRole('button', { name: 'Edit YAML' }).click()
await expect(this.page.getByTestId('kw-policy-config-yaml-editor')).toBeVisible()
}

async open(p: Policy) {
// Open list of policies
await this.ui.createBtn.click()
Expand Down Expand Up @@ -91,7 +83,7 @@ export class BasePolicyPage extends BasePage {
// Extra policy settings
if (p.settings) {
await p.settings(this.ui)
await this.editYaml()
await this.ui.openYamlEditor()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { expect, Locator, Page } from '@playwright/test';
import { BasePage } from './basepage';
import { RancherAppsPage } from './rancher-apps.page';

export class OverviewPage extends BasePage {
export class KubewardenPage extends BasePage {
readonly createPsBtn: Locator;
readonly createApBtn: Locator;
readonly createCapBtn: Locator;
Expand Down Expand Up @@ -58,21 +59,21 @@ export class OverviewPage extends BasePage {

// ==================================================================================================
// Rancher Application Metadata
await this.page.getByRole('button', { name: 'Next' }).click();
const apps = new RancherAppsPage(this.page)
await expect(apps.step1).toBeVisible()
await apps.nextBtn.click()
await expect(apps.step2).toBeVisible()

// Rancher Application Values
const schedule = this.ui.input('Schedule')
await expect(schedule).toHaveValue('*/60 * * * *')
await schedule.fill('*/1 * * * *')
await this.ui.checkbox('Enable Policy Reporter').check()

// Enable telemetry
// await page.getByRole('button', { name: 'Edit YAML' }).click()
// await editYaml(page, d => d.telemetry.enabled = true )
// await page.getByRole('button', { name: 'Compare Changes' }).click()

await this.page.getByRole('button', { name: 'Install' }).click();
await expect(this.ui.helmPassRegex('rancher-kubewarden-crds')).toBeVisible({ timeout: 30_000 });
await expect(this.ui.helmPassRegex('rancher-kubewarden-controller')).toBeVisible({ timeout: 60_000 });
// Start installation
await apps.installBtn.click()
await apps.waitHelmSuccess('rancher-kubewarden-crds')
await apps.waitHelmSuccess('rancher-kubewarden-controller')
}

async whitelistArtifacthub() {
Expand Down
26 changes: 20 additions & 6 deletions tests/e2e/pages/policyservers.page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Locator, Page } from '@playwright/test';
import type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test';
import { BasePage } from './basepage';
import { RancherAppsPage } from './rancher-apps.page';

export class PolicyServersPage extends BasePage {
readonly noDefaultPsBanner: Locator;
Expand Down Expand Up @@ -33,12 +35,24 @@ export class PolicyServersPage extends BasePage {
await this.ui.getRow(name).delete()
}

async installDefaultDialog(recommended: {enable: boolean, mode?: 'monitor' | 'protect'}) {
await this.ui.checkbox('Enable recommended policies').check()
async installDefault(options?: {recommended?: boolean, mode?: 'monitor' | 'protect'}) {
const apps = new RancherAppsPage(this.page)
// Skip metadata
await expect(apps.step1).toBeVisible()
await apps.nextBtn.click()
await expect(apps.step2).toBeVisible()

if (recommended.enable && recommended.mode) {
await this.ui.select('Execution mode', recommended.mode)
// Handle questions
if (options?.recommended) {
await this.ui.checkbox('Enable recommended policies').setChecked(options.recommended)
}
};
if (options?.mode) {
await this.ui.select('Execution mode', options.mode)
}

// Install
await apps.installBtn.click();
await apps.waitHelmSuccess('rancher-kubewarden-defaults')
}

}
Loading