diff --git a/projects/plugins/protect/changelog/add-firewall-e2e-tests b/projects/plugins/protect/changelog/add-firewall-e2e-tests new file mode 100644 index 0000000000000..cc356ec71f7ca --- /dev/null +++ b/projects/plugins/protect/changelog/add-firewall-e2e-tests @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Additional E2E test coverage. diff --git a/projects/plugins/protect/tests/e2e/flows/connection.js b/projects/plugins/protect/tests/e2e/flows/connection.js new file mode 100644 index 0000000000000..d94eb76d0ddac --- /dev/null +++ b/projects/plugins/protect/tests/e2e/flows/connection.js @@ -0,0 +1,32 @@ +import { expect } from '_jetpack-e2e-commons/fixtures/base-test.js'; +import logger from '_jetpack-e2e-commons/logger.js'; + +/** + * Connect Jetpack Protect + * @param {page} page - Playwright page object + * @param {admin} admin - Playwright admin object + */ +export async function connect( page, admin ) { + 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, + } ); +} diff --git a/projects/plugins/protect/tests/e2e/specs/start.test.js b/projects/plugins/protect/tests/e2e/specs/start.test.js index 75ff629fd4fc4..d9fe3d6f92a1e 100644 --- a/projects/plugins/protect/tests/e2e/specs/start.test.js +++ b/projects/plugins/protect/tests/e2e/specs/start.test.js @@ -1,37 +1,130 @@ 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 { + BASE_DOCKER_CMD, + execSyncShellCommand, + execWpCommand, +} from '_jetpack-e2e-commons/helpers/utils-helper.js'; +import { connect } from '../flows/connection'; -test.describe( 'Jetpack Protect plugin', () => { - test.beforeEach( async ( { page } ) => { +test.describe( 'Jetpack Protect Plugin', () => { + test.beforeEach( async ( { page, admin } ) => { await prerequisitesBuilder( page ) .withCleanEnv() .withActivePlugins( [ 'protect' ] ) + .withInactivePlugins( [ 'e2e-waf-data-interceptor' ] ) .withLoggedIn( true ) .build(); + + /** + * Connect the site via the initial setup page's "start for free" option. + */ + await connect( page, admin ); + + /** + * Ensure the WAF rules are generated ahead of time, and + * enforce compatible permissions for the E2E environment. + */ + await execWpCommand( 'jetpack-waf generate_rules' ); + execSyncShellCommand( + `${ BASE_DOCKER_CMD } exec-silent -- chown -R www-data:www-data /var/www/html/wp-content/jetpack-waf` + ); + + // to do: should not need to manually reload the page here + // currently needed to ensure the waf module is available in initial state + await page.reload(); } ); - 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 test.step( 'Navigate to firewall page', async () => { + await admin.visitAdminPage( 'admin.php', 'page=jetpack-protect#/firewall' ); + await expect( page.getByText( 'Firewall is on' ) ).toBeVisible(); + } ); + + await test.step( 'Test the brute force protection setting', async () => { + // Test the setting is present and enabled by default + 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(); + + // Test turning brute force off + await bruteForceToggle.click(); + await expect( page.getByText( 'Changes saved' ) ).toBeVisible(); + await expect( bruteForceToggle ).toBeEnabled(); + await expect( bruteForceToggle ).not.toBeChecked(); + + // Test turning brute force on + 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' ); + + // Test 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(); - await admin.visitAdminPage( 'admin.php', 'page=jetpack-protect' ); + // 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(); + } ); - 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( 'Test the data sharing settings', async () => { + const basicDataSharingToggle = page.locator( '#inspector-toggle-control-4' ); + const advancedDataSharingToggle = page.locator( '#inspector-toggle-control-5' ); - 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(); + // Test the default state + await expect( basicDataSharingToggle ).toBeEnabled(); + await expect( basicDataSharingToggle ).toBeChecked(); + await expect( advancedDataSharingToggle ).toBeEnabled(); + await expect( advancedDataSharingToggle ).not.toBeChecked(); - logger.action( 'Click the start for free button' ); - await startForFreeButton.click(); + // Test turning basic data sharing off + await basicDataSharingToggle.click(); + await expect( page.getByText( 'Changes saved' ) ).toBeVisible(); - 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 advanced data sharing on + await advancedDataSharingToggle.click(); + await expect( page.getByText( 'Changes saved' ) ).toBeVisible(); + await expect( basicDataSharingToggle ).toBeChecked(); + await expect( advancedDataSharingToggle ).toBeChecked(); + } ); } ); } ); diff --git a/tools/docker/jetpack-docker-config-default.yml b/tools/docker/jetpack-docker-config-default.yml index 652b755b7972d..88386c3f13d3c 100644 --- a/tools/docker/jetpack-docker-config-default.yml +++ b/tools/docker/jetpack-docker-config-default.yml @@ -58,6 +58,7 @@ dev: e2e: # Volumes to mount inside the environment, as above. Merged with those above. volumeMappings: + tools/e2e-commons/plugins/e2e-direct-filesystem.php: /var/www/html/wp-content/plugins/e2e-direct-filesystem.php tools/e2e-commons/plugins/e2e-plugin-updater.php: /var/www/html/wp-content/plugins/e2e-plugin-updater.php tools/e2e-commons/plugins/e2e-plan-data-interceptor.php: /var/www/html/wp-content/plugins/e2e-plan-data-interceptor.php tools/e2e-commons/plugins/e2e-waf-data-interceptor.php: /var/www/html/wp-content/plugins/e2e-waf-data-interceptor.php diff --git a/tools/e2e-commons/bin/e2e-env.sh b/tools/e2e-commons/bin/e2e-env.sh index 9c5a05783d5e0..ad396c2254fa3 100755 --- a/tools/e2e-commons/bin/e2e-env.sh +++ b/tools/e2e-commons/bin/e2e-env.sh @@ -55,9 +55,12 @@ gb_setup() { configure_wp_env() { $BASE_CMD exec-silent -- chown -R www-data:www-data /var/www/html/wp-content/uploads + $BASE_CMD exec-silent -- mkdir -p /var/www/html/wp-content/jetpack-waf + $BASE_CMD exec-silent -- chown -R www-data:www-data /var/www/html/wp-content/jetpack-waf $BASE_CMD wp plugin status $BASE_CMD wp plugin activate jetpack + $BASE_CMD wp plugin activate e2e-direct-filesystem $BASE_CMD wp plugin activate e2e-plan-data-interceptor $BASE_CMD wp plugin activate e2e-waf-data-interceptor $BASE_CMD wp plugin activate e2e-search-test-helper diff --git a/tools/e2e-commons/plugins/e2e-direct-filesystem.php b/tools/e2e-commons/plugins/e2e-direct-filesystem.php new file mode 100644 index 0000000000000..bdb8cdd5db87f --- /dev/null +++ b/tools/e2e-commons/plugins/e2e-direct-filesystem.php @@ -0,0 +1,17 @@ +