// Vault settings: explicit DN order, mandatory DN and template application. 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(); } async function api(page, method, url, body) { return page.evaluate( async ({ method, url, body }) => { const response = await fetch(url, { method, headers: { "content-type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), }); const text = await response.text(); return { status: response.status, json: text ? JSON.parse(text) : null }; }, { method, url, body } ); } test("explicit DN order, mandatory DN and template apply", async ({ page }) => { const user = unique("settings"); const vaultName = unique("Settings Vault"); const certName = unique("ordered.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(); const vaultId = vaultUrl.split("/").pop(); const settings = await api(page, "GET", `/api/vaults/${vaultId}/settings`); const updated = await api(page, "PATCH", `/api/vaults/${vaultId}/settings`, { version: settings.json.version, settings: { explicit_dn: ["CN", "O"], mandatory_dn: ["CN"] }, }); expect(updated.status).toBe(200); await page.goto(`${vaultUrl}/certificates/new`); await expect(page.getByText("Additional subject attributes")).toBeVisible(); await expect(page.locator("label").filter({ hasText: "Country (C)" })).toHaveCount(0); const labels = await page.locator("label").allTextContents(); const cnIndex = labels.findIndex((label) => label.trim() === "Common name (CN)"); const oIndex = labels.findIndex((label) => label.trim() === "Organization (O)"); expect(cnIndex).toBeGreaterThan(-1); expect(oIndex).toBeGreaterThan(cnIndex); // Applying a template uses the server merge endpoint and updates typed fields. await page.locator("select").nth(2).selectOption("builtin:tls-server"); await page.locator("select").nth(3).selectOption("extensions"); await page.getByRole("button", { name: "Apply", exact: true }).click(); await expect(page.locator("label").filter({ hasText: "TLS server" }).locator("..").locator("input[type=checkbox]")).toBeChecked(); await (await field(page, "Internal name")).fill(certName); await (await field(page, "Organization (O)")).fill("KCA E2E"); await page.locator("#new-key").check(); await page.getByRole("button", { name: "Create certificate" }).click(); await expect(page.getByText("missing mandatory subject entries: CN")).toBeVisible(); await (await field(page, "Common name (CN)")).fill(certName); await page.locator("label").filter({ hasText: "No well-defined expiration" }).locator("..").locator("input[type=checkbox]").check(); await page.getByRole("button", { name: "Create certificate" }).click(); await expect(page.getByRole("heading", { name: certName })).toBeVisible(); await expect(page.getByText("No expiration", { exact: true })).toBeVisible(); const cert = await api(page, "GET", `/api/vaults/${vaultId}/certificates`); const created = cert.json.results.find((item) => item.name === certName); // RFC 4514 renders the most specific RDN first, so CN follows O. expect(created.subject).toBe(`O=KCA E2E,CN=${certName}`); });