PluginProbe
Extendify / 3.1.1
Extendify v3.1.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / tests / Integration / Toolbar / BrandLeakGuardTest.php

BrandLeakGuardTest.php in Extendify 3.1.1, at tests/Integration/Toolbar/BrandLeakGuardTest.php

74 lines 2.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Extendify\Tests\Integration\Toolbar;
4
5 use WP_UnitTestCase;
6
7 /**
8 * Brand-leak guard for the Toolbar + Quick Edit features.
9 *
10 * On white-label partner sites the "Extendify" brand must never reach
11 * a user-facing surface. This statically scans every WP i18n call in
12 * app/Toolbar + app/QuickEdit and fails if any translatable string
13 * contains "Extendify" — catching reintroduction anywhere in those
14 * features, not just the one aria-label we neutralized.
15 *
16 * Pairs with .github/translations/scan-redflags.py, which guards the
17 * translated side (no "Extendify" in any locale's msgstr).
18 */
19 class BrandLeakGuardTest extends WP_UnitTestCase
20 {
21 public function testNoExtendifyInToolbarOrQuickEditStrings(): void
22 {
23 $root = dirname(__DIR__, 3);
24 $offenders = [];
25 foreach (['app/Toolbar', 'app/QuickEdit'] as $dir) {
26 foreach ($this->i18nStrings($root, $dir) as [$where, $text]) {
27 if (stripos($text, 'extendify') !== false) {
28 $offenders[] = sprintf('%s "%s"', $where, $text);
29 }
30 }
31 }
32
33 $this->assertSame(
34 [],
35 $offenders,
36 "User-facing string(s) leak the Extendify brand:\n" . implode("\n", $offenders)
37 );
38 }
39
40 /**
41 * Yield ["relPath:line", firstStringArg] for every WP i18n call in
42 * the .php files under $root/$dir.
43 *
44 * @return \Generator<array{0:string,1:string}>
45 */
46 private function i18nStrings(string $root, string $dir): \Generator
47 {
48 $abs = $root . '/' . $dir;
49 if (!is_dir($abs)) {
50 return;
51 }
52 // Quote-aware: i18n fn, opening quote, escape-aware body, matching close.
53 $re = <<<'REGEX'
54 /\b(?:esc_html_x|esc_attr_x|esc_html__|esc_attr__|esc_html_e|esc_attr_e|_nx|_x|_n|__|_e)\s*\(\s*(['"])((?:\\.|(?!\1).)*)\1/
55 REGEX;
56 $it = new \RecursiveIteratorIterator(
57 new \RecursiveDirectoryIterator($abs, \FilesystemIterator::SKIP_DOTS)
58 );
59 foreach ($it as $file) {
60 if (strtolower($file->getExtension()) !== 'php') {
61 continue;
62 }
63 $rel = $dir . substr($file->getPathname(), strlen($abs));
64 foreach (file($file->getPathname(), FILE_IGNORE_NEW_LINES) as $n => $text) {
65 if (preg_match_all($re, $text, $matches, PREG_SET_ORDER)) {
66 foreach ($matches as $hit) {
67 yield [$rel . ':' . ($n + 1), $hit[2]];
68 }
69 }
70 }
71 }
72 }
73 }
74