Close XCA parity gaps: advanced extensions, CA/revocation UI, imports, ZIP export, E2E
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
// Advanced extensions, preview/validation and vault ZIP export.
|
||||
const { test, expect } = require("@playwright/test");
|
||||
|
||||
function unique(prefix) {
|
||||
return `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
async function field(page, label) {
|
||||
return page.locator("label").filter({ hasText: label }).first().locator("..").locator("input, select, textarea").first();
|
||||
}
|
||||
|
||||
async function login(page, username) {
|
||||
await page.goto("/login");
|
||||
await page.getByRole("link", { name: "Sign in with default" }).click();
|
||||
await page.getByPlaceholder("Enter any user/subject").fill(username);
|
||||
await page.getByRole("button", { name: "Sign-in" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Vaults" })).toBeVisible();
|
||||
}
|
||||
|
||||
test("advanced extensions, validation and vault export", async ({ page }) => {
|
||||
const user = unique("advanced");
|
||||
const vaultName = unique("Advanced");
|
||||
const certName = unique("advanced.example");
|
||||
|
||||
await login(page, user);
|
||||
await page.getByRole("button", { name: "New vault" }).click();
|
||||
await page.getByPlaceholder("Production PKI").fill(vaultName);
|
||||
await page.getByRole("button", { name: "Create vault" }).click();
|
||||
await page.getByRole("link", { name: vaultName }).click();
|
||||
const vaultUrl = page.url();
|
||||
|
||||
await page.goto(`${vaultUrl}/certificates/new`);
|
||||
await expect(page.getByRole("heading", { name: "New certificate" })).toBeVisible();
|
||||
await (await field(page, "Internal name")).fill(certName);
|
||||
await (await field(page, "Common name (CN)")).fill(certName);
|
||||
await (await field(page, "Organization (O)")).fill("KCA E2E");
|
||||
await (await field(page, "Country (C)")).fill("DE");
|
||||
await page.locator("#new-key").check();
|
||||
await page.locator("textarea[placeholder='http://example.com/ca.crl']").fill("http://example.com/ca.crl");
|
||||
await page.locator("textarea[placeholder='http://ocsp.example.com']").fill("http://ocsp.example.com");
|
||||
await page.locator("textarea[placeholder*='raw']").fill(
|
||||
'{"raw":[{"oid":"1.2.3.4","critical":false,"der_hex":"0c03616263"}]}'
|
||||
);
|
||||
|
||||
await page.getByRole("button", { name: "Validate extensions" }).click();
|
||||
await expect(page.getByText("Extension preview")).toBeVisible();
|
||||
await expect(page.getByText("CRL Distribution Points", { exact: false })).toBeVisible();
|
||||
await expect(page.getByText("1.2.3.4", { exact: false })).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "Create certificate" }).click();
|
||||
await expect(page.getByRole("heading", { name: certName })).toBeVisible();
|
||||
await expect(page.getByText("CRL Distribution Points", { exact: false })).toBeVisible();
|
||||
await expect(page.getByText("1.2.3.4", { exact: false })).toBeVisible();
|
||||
|
||||
// ZIP export prompts for the private-key password.
|
||||
await page.goto(vaultUrl);
|
||||
page.once("dialog", (dialog) => dialog.accept("secret"));
|
||||
const downloadPromise = page.waitForEvent("download");
|
||||
await page.getByRole("button", { name: "Export ZIP" }).click();
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toMatch(/\.zip$/);
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
// End-to-end smoke test for the KCA PKI workflow.
|
||||
const { test, expect } = require("@playwright/test");
|
||||
|
||||
function unique(prefix) {
|
||||
return `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
async function field(page, label) {
|
||||
return page.locator("label").filter({ hasText: label }).first().locator("..").locator("input, select, textarea").first();
|
||||
}
|
||||
|
||||
async function login(page, username) {
|
||||
await page.goto("/login");
|
||||
await page.getByRole("link", { name: "Sign in with default" }).click();
|
||||
await page.getByPlaceholder("Enter any user/subject").fill(username);
|
||||
await page.getByRole("button", { name: "Sign-in" }).click();
|
||||
await expect(page).toHaveURL(/\/$/);
|
||||
await expect(page.getByRole("heading", { name: "Vaults" })).toBeVisible();
|
||||
}
|
||||
|
||||
test("core PKI workflow", async ({ page }) => {
|
||||
const user = unique("e2e");
|
||||
const vaultName = unique("Vault");
|
||||
const caName = unique("E2E CA");
|
||||
const leafName = unique("www.e2e.example");
|
||||
|
||||
await login(page, user);
|
||||
|
||||
// Vault
|
||||
await page.getByRole("button", { name: "New vault" }).click();
|
||||
await page.getByPlaceholder("Production PKI").fill(vaultName);
|
||||
await page.getByRole("button", { name: "Create vault" }).click();
|
||||
await page.getByRole("link", { name: vaultName }).click();
|
||||
await expect(page.getByRole("heading", { name: vaultName })).toBeVisible();
|
||||
const vaultUrl = page.url();
|
||||
|
||||
// Key
|
||||
await page.getByRole("link", { name: "New key" }).click();
|
||||
await page.getByPlaceholder("webserver-key").fill(`${caName} key`);
|
||||
await page.getByRole("button", { name: "Generate key" }).click();
|
||||
await expect(page.getByRole("heading", { name: `${caName} key` })).toBeVisible();
|
||||
|
||||
// CA certificate
|
||||
await page.goto(`${vaultUrl}/certificates/new`);
|
||||
await expect(page.getByRole("heading", { name: "New certificate" })).toBeVisible();
|
||||
await (await field(page, "Internal name")).fill(caName);
|
||||
await (await field(page, "Common name (CN)")).fill(caName);
|
||||
await (await field(page, "Organization (O)")).fill("KCA E2E");
|
||||
await (await field(page, "Country (C)")).fill("DE");
|
||||
await page.locator("#new-key").check();
|
||||
await (await field(page, "Basic constraints")).selectOption("ca");
|
||||
await page.locator("label").filter({ hasText: "Certificate sign" }).locator("..").locator("input[type=checkbox]").check();
|
||||
await page.locator("label").filter({ hasText: "CRL sign" }).locator("..").locator("input[type=checkbox]").check();
|
||||
await page.getByRole("button", { name: "Create certificate" }).click();
|
||||
await expect(page.getByText("CA certificate", { exact: false })).toBeVisible();
|
||||
const caUrl = page.url();
|
||||
|
||||
// Leaf signed by the CA
|
||||
await page.goto(`${vaultUrl}/certificates/new`);
|
||||
await (await field(page, "Internal name")).fill(leafName);
|
||||
await (await field(page, "Issuer")).selectOption({ label: caName });
|
||||
await (await field(page, "Common name (CN)")).fill(leafName);
|
||||
await (await field(page, "Organization (O)")).fill("KCA E2E");
|
||||
await (await field(page, "Country (C)")).fill("DE");
|
||||
await page.locator("#new-key").check();
|
||||
await page.locator("input[placeholder*='DNS:example.com']").fill(`DNS:${leafName}`);
|
||||
await page.locator("label").filter({ hasText: "TLS server" }).locator("..").locator("input[type=checkbox]").check();
|
||||
await page.getByRole("button", { name: "Create certificate" }).click();
|
||||
await expect(page.getByRole("heading", { name: leafName })).toBeVisible();
|
||||
await expect(page.getByText("serverAuth", { exact: false })).toBeVisible();
|
||||
|
||||
// Search
|
||||
await page.goto(`${vaultUrl}/search`);
|
||||
await page.locator("input[placeholder='Search…']").fill(leafName);
|
||||
await page.getByRole("button", { name: "Search" }).click();
|
||||
await expect(page.getByRole("link", { name: leafName, exact: true })).toBeVisible();
|
||||
|
||||
// Revoke
|
||||
await page.getByRole("link", { name: leafName, exact: true }).click();
|
||||
await page.getByRole("button", { name: "Revoke certificate" }).click();
|
||||
await expect(page.getByText("revoked", { exact: true })).toBeVisible();
|
||||
|
||||
// CRL from the CA
|
||||
await page.goto(caUrl);
|
||||
await expect(page.getByRole("heading", { name: caName })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Generate CRL" }).click();
|
||||
await expect(page).toHaveURL(/\/crls\//);
|
||||
await expect(page.getByText(/CRL number \d+ · 1 revoked/)).toBeVisible();
|
||||
|
||||
|
||||
// API token
|
||||
await page.goto("/tokens");
|
||||
await page.getByPlaceholder("CI uploader").fill(unique("token"));
|
||||
await page.getByRole("button", { name: "Create" }).click();
|
||||
await expect(page.getByText("Token created", { exact: false })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user