test(ui): add GCP provider support in ProvidersPage tests

- Introduced GCP provider data and credential interfaces to the ProvidersPage.
- Implemented methods for filling GCP provider details and service account key credentials.
- Added end-to-end tests for adding a GCP provider using service account key authentication.
- Updated documentation to include new test case for GCP provider integration.
This commit is contained in:
StylusFrost
2025-10-27 09:34:13 +01:00
parent 477de791a9
commit 2409049c88
3 changed files with 241 additions and 0 deletions
+77
View File
@@ -25,6 +25,12 @@ export interface KubernetesProviderData {
alias?: string;
}
// GCP provider data
export interface GCPProviderData {
projectId: string;
alias?: string;
}
// AWS credential options
export const AWS_CREDENTIAL_OPTIONS = {
AWS_ROLE_ARN: "role",
@@ -91,6 +97,20 @@ export interface KubernetesProviderCredential {
kubeconfigContent:string;
}
// GCP credential options
export const GCP_CREDENTIAL_OPTIONS = {
GCP_SERVICE_ACCOUNT: "service_account"
} as const;
// GCP credential type
type GCPCredentialType = (typeof GCP_CREDENTIAL_OPTIONS)[keyof typeof GCP_CREDENTIAL_OPTIONS];
// GCP provider credential
export interface GCPProviderCredential {
type: GCPCredentialType;
serviceAccountKey:string;
}
// Providers page
export class ProvidersPage extends BasePage {
@@ -147,6 +167,11 @@ export class ProvidersPage extends BasePage {
readonly kubernetesContextInput: Locator;
readonly kubernetesKubeconfigContentInput: Locator;
// GCP provider form elements
readonly gcpProjectIdInput: Locator;
readonly gcpServiceAccountKeyInput: Locator;
readonly gcpServiceAccountRadio: Locator;
// Delete button
readonly deleteProviderConfirmationButton: Locator;
@@ -197,6 +222,10 @@ export class ProvidersPage extends BasePage {
this.kubernetesContextInput = page.getByRole("textbox", { name: "Context" });
this.kubernetesKubeconfigContentInput = page.getByRole("textbox", { name: "Kubeconfig Content" });
// GCP provider form inputs
this.gcpProjectIdInput = page.getByRole("textbox", { name: "Project ID" });
this.gcpServiceAccountKeyInput = page.getByRole("textbox", { name: "Service Account Key" });
// Alias input
this.aliasInput = page.getByRole("textbox", { name: "Provider alias (optional)" });
@@ -231,6 +260,11 @@ export class ProvidersPage extends BasePage {
name: /App Certificate Credentials/i,
});
// Radios for selecting GCP credentials method
this.gcpServiceAccountRadio = page.getByRole("radio", {
name: /Service Account Key/i,
});
// Inputs for IAM Role credentials
this.roleArnInput = page.getByRole("textbox", { name: "Role ARN" });
this.externalIdInput = page.getByRole("textbox", { name: "External ID" });
@@ -287,6 +321,13 @@ export class ProvidersPage extends BasePage {
await this.waitForPageLoad();
}
async selectGCPProvider(): Promise<void> {
// Select the GCP provider
await this.gcpProviderRadio.click({ force: true });
await this.waitForPageLoad();
}
async fillAWSProviderDetails(data: AWSProviderData): Promise<void> {
// Fill the AWS provider details
@@ -327,6 +368,15 @@ export class ProvidersPage extends BasePage {
}
}
async fillGCPProviderDetails(data: GCPProviderData): Promise<void> {
// Fill the GCP provider details
await this.gcpProjectIdInput.fill(data.projectId);
if (data.alias) {
await this.aliasInput.fill(data.alias);
}
}
async clickNext(): Promise<void> {
// The wizard interface may use different labels for its primary action button on each step.
// This function determines which button to click depending on the current URL and page content.
@@ -464,6 +514,19 @@ export class ProvidersPage extends BasePage {
await this.waitForPageLoad();
}
async selectGCPCredentialsType(type: GCPCredentialType): Promise<void> {
// Ensure we are on the add-credentials page where the selector exists
await expect(this.page).toHaveURL(/\/providers\/add-credentials/);
if (type === GCP_CREDENTIAL_OPTIONS.GCP_SERVICE_ACCOUNT) {
await this.gcpServiceAccountRadio.click({ force: true });
} else {
throw new Error(`Invalid GCP credential type: ${type}`);
}
// Wait for the page to load
await this.waitForPageLoad();
}
async fillRoleCredentials(credentials: AWSProviderCredential): Promise<void> {
// Fill the role credentials form
@@ -545,6 +608,13 @@ export class ProvidersPage extends BasePage {
}
}
async fillGCPServiceAccountKeyCredentials(credentials: GCPProviderCredential): Promise<void> {
// Fill the GCP credentials form
if (credentials.serviceAccountKey) {
await this.gcpServiceAccountKeyInput.fill(credentials.serviceAccountKey);
}
}
async verifyPageLoaded(): Promise<void> {
// Verify the providers page is loaded
@@ -593,6 +663,13 @@ export class ProvidersPage extends BasePage {
await expect(this.kubernetesContextInput).toBeVisible();
}
async verifyGCPServiceAccountPageLoaded(): Promise<void> {
// Verify the GCP service account page is loaded
await expect(this.page).toHaveTitle(/Prowler/);
await expect(this.gcpServiceAccountKeyInput).toBeVisible();
}
async verifyLaunchScanPageLoaded(): Promise<void> {
// Verify the launch scan page is loaded
+57
View File
@@ -323,3 +323,60 @@
- Requires valid Kubernetes cluster with accessible kubeconfig
- Kubeconfig must have sufficient permissions for security scanning
- Test validates that kubeconfig content goes to the correct field (not the context field)
---
## Test Case: `PROVIDER-E2E-007` - Add GCP Provider with Service Account Key
**Priority:** `critical`
**Tags:**
- type → @e2e, @serial
- feature → @providers
- provider → @gcp
**Description/Objective:** Validates the complete flow of adding a new GCP provider using service account key authentication
**Preconditions:**
- Admin user authentication required (admin.auth.setup setup)
- Environment variables configured: E2E_GCP_PROJECT_ID, E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY
- Remove any existing provider with the same Project ID before starting the test
- This test must be run serially and never in parallel with other tests, as it requires the Project ID not to be already registered beforehand.
### Flow Steps:
1. Navigate to providers page
2. Click "Add Provider" button
3. Select GCP provider type
4. Fill provider details (project ID and alias)
5. Select service account credentials type
6. Fill GCP service account key credentials
7. Launch initial scan
8. Verify redirect to provider management page
### Expected Result:
- GCP provider successfully added with service account key
- Initial scan launched successfully
- User redirected to provider details page
### Key verification points:
- Provider page loads correctly
- Connect account page displays GCP option
- Provider details form accepts project ID and alias
- Service account credentials page loads with service account key field
- Service account key is properly filled in the correct field
- Launch scan page appears
- Successful redirect to provider page after scan launch
### Notes:
- Test uses environment variables for GCP project ID and service account key
- Service account key is provided as base64 encoded JSON content
- Provider cleanup performed before each test to ensure clean state
- Requires valid GCP project with service account having appropriate permissions
- Service account must have sufficient permissions for security scanning
- Test validates that service account key goes to the correct field
+107
View File
@@ -14,6 +14,9 @@ import {
KubernetesProviderData,
KubernetesProviderCredential,
KUBERNETES_CREDENTIAL_OPTIONS,
GCPProviderData,
GCPProviderCredential,
GCP_CREDENTIAL_OPTIONS,
} from "./providers-page";
import { ScansPage } from "../scans/scans-page";
import fs from "fs";
@@ -541,4 +544,108 @@ test.describe("Add Provider", () => {
},
);
});
test.describe.serial("Add GCP Provider", () => {
// Providers page object
let providersPage: ProvidersPage;
let scansPage: ScansPage;
// Test data from environment variables
const projectId = process.env.E2E_GCP_PROJECT_ID;
// Validate required environment variables
if (!projectId ) {
throw new Error(
"E2E_GCP_PROJECT_ID environment variable is not set",
);
}
// Setup before each test
test.beforeEach(async ({ page }) => {
providersPage = new ProvidersPage(page);
// Clean up existing provider to ensure clean test state
await providersPage.deleteProviderIfExists(projectId);
});
// Use admin authentication for provider management
test.use({ storageState: "playwright/.auth/admin_user.json" });
test(
"should add a new GCP provider with service account key",
{
tag: [
"@critical",
"@e2e",
"@providers",
"@gcp",
"@serial",
"@PROVIDER-E2E-007",
],
},
async ({ page }) => {
// Validate required environment variables
const serviceAccountKeyB64 = process.env.E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY;
// Verify service account key is base64 encoded
if (!serviceAccountKeyB64) {
throw new Error("E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY environment variable is not set");
}
// Decode service account key from base64
const serviceAccountKey = Buffer.from(serviceAccountKeyB64, 'base64').toString('utf8');
// Verify service account key is valid JSON
if (!JSON.parse(serviceAccountKey)) {
throw new Error("Invalid service account key format");
}
// Prepare test data for GCP provider
const gcpProviderData: GCPProviderData = {
projectId: projectId,
alias: "Test E2E GCP Account - Service Account Key",
};
// Prepare static credentials
const gcpCredentials: GCPProviderCredential = {
type: GCP_CREDENTIAL_OPTIONS.GCP_SERVICE_ACCOUNT,
serviceAccountKey: serviceAccountKey
};
// Navigate to providers page
await providersPage.goto();
await providersPage.verifyPageLoaded();
// Start adding new provider
await providersPage.clickAddProvider();
await providersPage.verifyConnectAccountPageLoaded();
// Select M365 provider
await providersPage.selectGCPProvider();
// Fill provider details
await providersPage.fillGCPProviderDetails(gcpProviderData);
await providersPage.clickNext();
// Select static credentials type
await providersPage.selectGCPCredentialsType(
GCP_CREDENTIAL_OPTIONS.GCP_SERVICE_ACCOUNT,
);
// Verify GCP service account page is loaded
await providersPage.verifyGCPServiceAccountPageLoaded();
// Fill static service account key details
await providersPage.fillGCPServiceAccountKeyCredentials(gcpCredentials);
await providersPage.clickNext();
// Launch scan
await providersPage.verifyLaunchScanPageLoaded();
await providersPage.clickNext();
// Wait for redirect to scan page
scansPage = new ScansPage(page);
await scansPage.verifyPageLoaded();
},
);
});
});