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

Protect: Add Firewall E2E Tests #42273

Open
wants to merge 8 commits into
base: add/protect/e2e-tests
Choose a base branch
from
Open
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
29 changes: 21 additions & 8 deletions projects/packages/waf/src/class-rest-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public static function waf() {
* @return WP_REST_Response|WP_Error
*/
public static function update_waf( $request ) {

// Automatic Rules Enabled
if ( isset( $request[ Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ] ) ) {
update_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME, $request->get_param( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ) ? '1' : '' );
Expand Down Expand Up @@ -181,16 +182,28 @@ public static function update_waf( $request ) {
}
}

// Only attempt to update the WAF if the module is supported
if ( Waf_Runner::is_supported_environment() ) {
try {
Waf_Runner::update_waf();
} catch ( Waf_Exception $e ) {
return $e->get_wp_error();
try {
// Only attempt to update the WAF if the module is supported
if ( Waf_Runner::is_supported_environment() ) {
try {
Waf_Runner::update_waf();
} catch ( Waf_Exception $e ) {
return new WP_Error(
'test_waf_failed_2',
$e->getMessage(),
array( 'status' => 500 )
);
}
}
}

return self::waf();
return self::waf();
} catch ( Waf_Exception $e ) {
return new WP_Error(
'test_waf_failed',
$e->getMessage(),
array( 'status' => 500 )
);
}
}

/**
Expand Down
5 changes: 5 additions & 0 deletions projects/plugins/protect/src/js/data/waf/use-waf-mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ export default function useWafMutation(): UseMutationResult<
// Reset the WAF config to its previous state.
queryClient.setQueryData( [ QUERY_WAF_KEY ], context.initialValue );

// console.error( error );
// console.error( variables );
// console.error( context );
// throw error;

showErrorNotice( getCustomErrorMessage( error ) );
},
} );
Expand Down
38 changes: 38 additions & 0 deletions projects/plugins/protect/tests/e2e/flows/connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { expect } from '_jetpack-e2e-commons/fixtures/base-test.js';
import logger from '_jetpack-e2e-commons/logger.js';
// import { AuthorizePage } from '_jetpack-e2e-commons/pages/wpcom/index.js';

/**
* Connect Jetpack Protect
* @param {page} page - Playwright page object
* @param {admin} admin - Playwright admin object
* @param {boolean} premium - Whether to connect with a Premium plan
*/
export async function connect( page, admin, premium = false ) {
logger.step( 'Connect Jetpack Protect' );

await admin.visitAdminPage( 'admin.php', 'page=jetpack-protect' );

logger.action( 'Checking for button "Get Jetpack Protect"' );
const getJetpackProtectButton = page.getByRole( 'button', { name: 'Get Jetpack Protect' } );
await expect( getJetpackProtectButton ).toBeVisible();
await expect( getJetpackProtectButton ).toBeEnabled();

logger.action( 'Checking for button "Start for free"' );
const startForFreeButton = page.getByRole( 'button', { name: 'Start for free' } );
await expect( startForFreeButton ).toBeVisible();
await expect( startForFreeButton ).toBeEnabled();

logger.action( 'Click the start for free button' );
await startForFreeButton.click();

await expect(
page.getByText( 'vulnerabilities found' ).or( page.getByText( 'ready soon' ) )
).toBeVisible( {
timeout: 30_000,
} );

if ( premium ) {
// todo add purchase steps
}
}
2 changes: 1 addition & 1 deletion projects/plugins/protect/tests/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"license": "GPL-2.0-or-later",
"author": "Automattic",
"scripts": {
"build": "pnpm jetpack build packages/assets packages/connection plugins/protect plugins/jetpack -v --no-pnpm-install --production",
"build": "pnpm jetpack build packages/assets packages/connection plugins/protect plugins/jetpack packages/waf packages/protect-models packages/protect-status -v --no-pnpm-install --production",
"clean": "rm -rf output",
"config:decrypt": "openssl enc -md sha1 -aes-256-cbc -d -pass env:CONFIG_KEY -in ./node_modules/_jetpack-e2e-commons/config/encrypted.enc -out ./config/local.cjs",
"distclean": "rm -rf node_modules",
Expand Down
95 changes: 76 additions & 19 deletions projects/plugins/protect/tests/e2e/specs/start.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { prerequisitesBuilder } from '_jetpack-e2e-commons/env/prerequisites.js';
import { expect, test } from '_jetpack-e2e-commons/fixtures/base-test.js';
import logger from '_jetpack-e2e-commons/logger.js';
import { connect } from '../flows/connection';

test.describe( 'Jetpack Protect plugin', () => {
test.describe( 'Jetpack Protect plugin - Pre-Connection', () => {
test.beforeEach( async ( { page } ) => {
await prerequisitesBuilder( page )
.withCleanEnv()
Expand All @@ -11,27 +11,84 @@ test.describe( 'Jetpack Protect plugin', () => {
.build();
} );

test( 'Jetpack Protect admin page', async ( { page, admin } ) => {
logger.action( 'Visit the Jetpack Protect admin page and start for free' );
test( 'Jetpack Protect firewall page', async ( { page, admin } ) => {
await connect( page, admin );

await admin.visitAdminPage( 'admin.php', 'page=jetpack-protect' );
// to do: should not need to manually reload the page here to ensure the waf module is available
await page.reload();

logger.action( 'Checking for button "Get Jetpack Protect"' );
const getJetpackProtectButton = page.getByRole( 'button', { name: 'Get Jetpack Protect' } );
await expect( getJetpackProtectButton ).toBeVisible();
await expect( getJetpackProtectButton ).toBeEnabled();
await test.step( 'Navigate to firewall page', async () => {
await admin.visitAdminPage( 'admin.php', 'page=jetpack-protect#/firewall' );
await expect( page.getByText( 'Firewall is on' ) ).toBeVisible();
} );

logger.action( 'Checking for button "Start for free"' );
const startForFreeButton = page.getByRole( 'button', { name: 'Start for free' } );
await expect( startForFreeButton ).toBeVisible();
await expect( startForFreeButton ).toBeEnabled();
// await test.step( 'Test the automatic firewall setting is disabled for free plans', async () => {
// const automaticFirewallToggle = page.locator( '#inspector-toggle-control-0' );
// await expect( automaticFirewallToggle ).toBeDisabled();
// await expect( automaticFirewallToggle ).not.toBeChecked();
// } );

logger.action( 'Click the start for free button' );
await startForFreeButton.click();
await test.step( 'Test the brute force protection setting', async () => {
const bruteForceToggle = page.locator( '#inspector-toggle-control-1' );
await expect( page.getByRole( 'heading', { name: 'Brute force protection' } ) ).toBeVisible();
await expect( bruteForceToggle ).toBeEnabled();
await expect( bruteForceToggle ).toBeChecked();

logger.action( 'Checking for heading "Stay one step ahead of threats"' );
await expect(
page.getByRole( 'heading', { name: 'Stay one step ahead of threats' } )
).toBeVisible();
// Test turning brute force off and then on again
await bruteForceToggle.click();
await expect( page.getByText( 'Changes saved' ) ).toBeVisible( {
timeout: 15_000,
} );
await expect( bruteForceToggle ).toBeEnabled();
await expect( bruteForceToggle ).not.toBeChecked();
await bruteForceToggle.click();
await expect( page.getByText( 'Changes saved' ) ).toBeVisible();
await expect( bruteForceToggle ).toBeEnabled();
await expect( bruteForceToggle ).toBeChecked();
} );

await test.step( 'Test the IP block list settings', async () => {
const blockListTextarea = page.locator( '#jetpack_waf_ip_block_list' );
const blockListToggle = page.locator( '#inspector-toggle-control-2' );

// Validate the default block list state
await expect( page.getByRole( 'heading', { name: 'Block IP addresses' } ) ).toBeVisible();
await expect( blockListToggle ).toBeEnabled();
await expect( blockListToggle ).not.toBeChecked();
// Test turning the block list on
await blockListToggle.click();
await expect( blockListToggle ).toBeEnabled();
await expect( blockListToggle ).toBeChecked();
await expect( blockListTextarea ).toBeVisible();

// Test adding an IP address to the block list
await blockListTextarea.fill( '192.168.1.1' );
await page.getByRole( 'button', { name: 'Save block list' } ).click();
await expect( blockListToggle ).toBeEnabled();
await expect( page.getByText( 'Changes saved' ) ).toBeVisible();
} );

await test.step( 'Test the IP allow list settings', async () => {
const trustedIPsToggle = page.locator( '#inspector-toggle-control-3' );
const allowListTextarea = page.locator( '#jetpack_waf_ip_allow_list' );
const saveAllowListButton = page.getByRole( 'button', { name: 'Save allow list' } );

// Validate the default allow list state
await expect( page.getByRole( 'heading', { name: 'Trusted IP addresses' } ) ).toBeVisible();
await expect( trustedIPsToggle ).toBeEnabled();
await expect( trustedIPsToggle ).not.toBeChecked();

// Test turning the allow list on
await trustedIPsToggle.click();
await expect( trustedIPsToggle ).toBeEnabled();
await expect( trustedIPsToggle ).toBeChecked();
await expect( allowListTextarea ).toBeVisible();

// Test adding an IP address to the allow list
await allowListTextarea.fill( '192.168.1.1' );
await saveAllowListButton.click();
await expect( trustedIPsToggle ).toBeEnabled();
await expect( page.getByText( 'Changes saved' ) ).toBeVisible();
} );
} );
} );
Loading