From e379bb78b0f6e33667a84ea3133964bac9994880 Mon Sep 17 00:00:00 2001 From: DanMat Date: Sun, 30 Aug 2026 16:59:18 -0400 Subject: [PATCH] fix: move admin styling to a nonce'd '; + } + private function notice(?string $notice): string { if ($notice === null || !isset(self::NOTICES[$notice])) { @@ -293,8 +319,8 @@ private function forms(string $csrf): string { $t = ''; - return '
' - . '
' + return '
' + . '' . '

Receive stock

' . $t . $this->field('SKU', 'sku', 'e.g. house-blend', 'inv-skus') . $this->field('Location', 'location', 'main', 'inv-locs') @@ -302,7 +328,7 @@ private function forms(string $csrf): string . $this->field('Unit', 'uom', 'each') . '' - . '
' + . '' . '

Adjust stock

' . $t . $this->field('SKU', 'sku', 'e.g. house-blend', 'inv-skus') . $this->field('Location', 'location', 'main', 'inv-locs') @@ -310,15 +336,15 @@ private function forms(string $csrf): string . $this->field('Reason', 'reason', 'waste') . '
' - . '
' + . '' . '

Count stock

' . $t - . '

Set on-hand to a counted figure; the correction is recorded as a movement.

' + . '

Set on-hand to a counted figure; the correction is recorded as a movement.

' . $this->field('SKU', 'sku', 'e.g. house-blend', 'inv-skus') . $this->field('Location', 'location', 'main', 'inv-locs') . $this->field('Counted', 'qty', 'e.g. 40') . '
' - . '
' + . '' . '

Transfer stock

' . $t . $this->field('SKU', 'sku', 'e.g. house-blend', 'inv-skus') . $this->field('From', 'from', 'main', 'inv-locs') @@ -331,8 +357,8 @@ private function forms(string $csrf): string /** A SKU substring filter for the stock table (GET, no JS). */ private function filterForm(string $q): string { - return '' - . '
' + return '' + . '
' . '
' . '' . ($q === '' ? '' : ' Clear') diff --git a/src/InventoryPlugin.php b/src/InventoryPlugin.php index 06d7cc1..e998afa 100644 --- a/src/InventoryPlugin.php +++ b/src/InventoryPlugin.php @@ -61,7 +61,7 @@ public function register(PluginContext $context): void 'inventory', 'Inventory', '📦', - static fn (Request $r, string $nonce = '', string $csrf = ''): string => (new InventoryAdmin($storage))->render($csrf, $r->query('ok') ?? $r->query('err'), $r->query('q'), $r->query('sku')), + static fn (Request $r, string $nonce = '', string $csrf = ''): string => (new InventoryAdmin($storage))->render($csrf, $r->query('ok') ?? $r->query('err'), $r->query('q'), $r->query('sku'), $nonce), self::ID . ':write', ); $context->adminPages()->action('inventory', 'receive', static function (Request $r) use ($ledger): Response { diff --git a/tests/InventoryAdminTest.php b/tests/InventoryAdminTest.php index d45f907..0473ab6 100644 --- a/tests/InventoryAdminTest.php +++ b/tests/InventoryAdminTest.php @@ -135,4 +135,17 @@ public function test_an_unknown_sku_shows_a_helpful_note(): void $html = $this->admin->render('tok', null, null, 'no-such-sku'); self::assertStringContainsString('Nothing recorded for this SKU', $html); } + + public function test_styling_is_a_nonced_style_block_not_inline_attributes(): void + { + // The admin CSP is nonce-only for style-src, so inline style= is dropped. + // Both the overview and the drill-down must style via one nonce'd block. + $overview = $this->admin->render('tok', null, null, null, 'NONCE123'); + self::assertStringContainsString('