From c9a9b55f72d8e14ac64e47a6ae7c5f573a938619 Mon Sep 17 00:00:00 2001 From: Sebastien Monterisi Date: Fri, 3 Apr 2026 14:17:14 +0200 Subject: [PATCH 1/2] tag entry not allowed for netdiscovery requests with friendly error message (initial message was "Not {} expected, "mytag" received at #->then->properties:tag->not") + added some 'tag' in phpunit test and xml files (to ensure it's allowed in other requests) --- inventory.schema.json | 11 ++++++ lib/php/Schema.php | 37 ++++++++++++++++++++- tests/Glpi/Inventory/tests/units/Schema.php | 29 +++++++++++++++- tests/data/1.xml | 1 + tests/data/5.xml | 1 + tests/data/8.xml | 3 +- 6 files changed, 79 insertions(+), 3 deletions(-) diff --git a/inventory.schema.json b/inventory.schema.json index 222cb4d..6d525a0 100644 --- a/inventory.schema.json +++ b/inventory.schema.json @@ -2983,5 +2983,16 @@ "type": "string" } }, + "if": { + "properties": { + "action": { "const": "netdiscovery" } + }, + "required": ["action"] + }, + "then": { + "properties": { + "tag": false + } + }, "additionalProperties": false } diff --git a/lib/php/Schema.php b/lib/php/Schema.php index b7719e8..8f9a7f6 100644 --- a/lib/php/Schema.php +++ b/lib/php/Schema.php @@ -210,13 +210,22 @@ public function getPatterns(): array */ public function validate($json): bool { + $rawSchema = null; try { - $schema = \Swaggest\JsonSchema\Schema::import($this->build()); + $rawSchema = $this->build(); + $schema = \Swaggest\JsonSchema\Schema::import($rawSchema); $context = new Context(); $context->tolerateStrings = (!defined('TU_USER')); $schema->in($json, $context); return true; + } catch (\Swaggest\JsonSchema\InvalidValue $e) { + throw new RuntimeException( + sprintf( + "JSON does not validate. Violations:\n%1\$s\n", + $rawSchema !== null ? $this->improveErrorMessage($e, $rawSchema) : $e->getMessage() + ) + ); } catch (Exception $e) { throw new RuntimeException( sprintf( @@ -227,6 +236,32 @@ public function validate($json): bool } } + /** + * Translate a swaggest InvalidValue exception into a human-readable message. + * Handles the case where a property is forbidden by an if/then conditional rule. + * + * @param \Swaggest\JsonSchema\InvalidValue $e + * @param object $rawSchema The raw (decoded) schema object + * @return string + */ + private function improveErrorMessage(\Swaggest\JsonSchema\InvalidValue $e, object $rawSchema): string + { + $path = $e->path ?? ''; + // Pattern: "->then->properties:PROP->not" means PROP is forbidden by a conditional rule + if (preg_match('/->then->properties:(\w+)->not$/', $path, $matches)) { + $property = $matches[1]; + if (isset($rawSchema->{'if'}->properties->action->const)) { + return sprintf( + 'Property "%s" is not allowed when action is "%s"', + $property, + $rawSchema->{'if'}->properties->action->const + ); + } + return sprintf('Property "%s" is not allowed in this context', $property); + } + return $e->getMessage(); + } + /** * Get current schema version * diff --git a/tests/Glpi/Inventory/tests/units/Schema.php b/tests/Glpi/Inventory/tests/units/Schema.php index bda21a5..718a77a 100644 --- a/tests/Glpi/Inventory/tests/units/Schema.php +++ b/tests/Glpi/Inventory/tests/units/Schema.php @@ -29,7 +29,7 @@ public function testSchemaPath(): void public function testValidateOK(): void { - $json = json_decode(json_encode(['deviceid' => 'myid', 'content' => ['versionclient' => 'GLPI-Agent_v1.0', 'hardware' => ['name' => 'my inventory']]])); + $json = json_decode(json_encode(['deviceid' => 'myid', 'tag' => 'mytag', 'content' => ['versionclient' => 'GLPI-Agent_v1.0', 'hardware' => ['name' => 'my inventory']]])); $instance = new \Glpi\Inventory\Schema(); $this->assertTrue($instance->validate($json)); } @@ -155,4 +155,31 @@ public function testVersion(): void $instance = new \Glpi\Inventory\Schema(); $this->assertIsFloat($instance->getVersion()); } + + public function testNoTagOnNetdiscoveryRequests(): void + { + $json = json_decode(json_encode([ + 'content' => [ + 'hardware' => [ + 'workgroup' => 'WORKGROUP', + ], + 'versionclient' => '5.1', + 'network_device' => [ + 'type' => 'Unmanaged', + 'mac' => '4c:cc:6a:02:13:a9', + 'name' => 'DESKTOP-A3J16LF', + 'ips' => ['192.168.1.20'], + ], + ], + 'deviceid' => 'asus-desktop-2022-09-20-16-43-09', + 'action' => 'netdiscovery', + 'jobid' => 189, + 'itemtype' => 'Unmanaged', + 'tag' => 'tag_is_not_allowed_in_netdiscovery', + ])); + $instance = new \Glpi\Inventory\Schema(); + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Property "tag" is not allowed when action is "netdiscovery"'); + $instance->validate($json); + } } diff --git a/tests/data/1.xml b/tests/data/1.xml index ecd4683..4957116 100644 --- a/tests/data/1.xml +++ b/tests/data/1.xml @@ -1734,4 +1734,5 @@ LF014-2016-06-13-14-03-53 INVENTORY + Mytag diff --git a/tests/data/5.xml b/tests/data/5.xml index 4cb1958..26f6227 100644 --- a/tests/data/5.xml +++ b/tests/data/5.xml @@ -311,4 +311,5 @@ ARM Bios Ver 7.59u v46 454MHz B987-M995-F80-O0,0 MAC:00042d076b88 foo SNMPQUERY + Mytag diff --git a/tests/data/8.xml b/tests/data/8.xml index 9fa63b6..5df79c8 100644 --- a/tests/data/8.xml +++ b/tests/data/8.xml @@ -1,5 +1,6 @@ - + + 0 0g From e76412cac0a2510c1c0f12ec473e732a04f20dc9 Mon Sep 17 00:00:00 2001 From: Sebastien Monterisi Date: Fri, 3 Apr 2026 14:33:15 +0200 Subject: [PATCH 2/2] fix phpstan --- lib/php/Schema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/php/Schema.php b/lib/php/Schema.php index 8f9a7f6..0a1900c 100644 --- a/lib/php/Schema.php +++ b/lib/php/Schema.php @@ -223,7 +223,7 @@ public function validate($json): bool throw new RuntimeException( sprintf( "JSON does not validate. Violations:\n%1\$s\n", - $rawSchema !== null ? $this->improveErrorMessage($e, $rawSchema) : $e->getMessage() + $this->improveErrorMessage($e, $rawSchema) ) ); } catch (Exception $e) {