diff --git a/lib/Settings/register.d/publication-field-rules.json b/lib/Settings/register.d/publication-field-rules.json index a939858af..bfd6ae997 100644 --- a/lib/Settings/register.d/publication-field-rules.json +++ b/lib/Settings/register.d/publication-field-rules.json @@ -139,7 +139,7 @@ } }, "catalogService": { - "version": "0.2.2", + "version": "0.2.3", "properties": { "contactPerson": { "authorization": { @@ -477,7 +477,7 @@ } }, "organization": { - "version": "0.5.3", + "version": "0.5.4", "properties": { "contactsUid": { "authorization": { diff --git a/lib/Settings/register.d/topdesk-cmdb-import.json b/lib/Settings/register.d/topdesk-cmdb-import.json index 5fb300099..bcbd3c986 100644 --- a/lib/Settings/register.d/topdesk-cmdb-import.json +++ b/lib/Settings/register.d/topdesk-cmdb-import.json @@ -2,7 +2,7 @@ "components": { "schemas": { "module": { - "version": "0.3.8", + "version": "0.3.9", "properties": { "externalId": { "type": "string", @@ -72,7 +72,7 @@ } }, "usage": { - "version": "1.5.6", + "version": "1.5.7", "configuration": { "x-openregister-lifecycle": { "transitions": { diff --git a/lib/Settings/softwarecatalogus_register.json b/lib/Settings/softwarecatalogus_register.json index 7a2976760..bb6b24de4 100644 --- a/lib/Settings/softwarecatalogus_register.json +++ b/lib/Settings/softwarecatalogus_register.json @@ -3,8 +3,8 @@ "info": { "title": "Software Catalog Register", "description": "Register containing AMEF and Voorzieningen schemas for the VNG Software Catalog application. This configuration includes schemas for applications, services, organizations, and compliance tracking.", - "version": "2.5.7", - "changelog": "2.5.7: a contract no longer requires a catalogue service, because a licence bought for an application in use has none; the service desk exchange imports such licences (sharing-itsm-exchange). The fragment sharing-itsm-exchange.json adds the service desk reference to usage (1.5.4), connection (0.3.4) and catalogContract (0.1.4), and the licence fields vendorReference, currency and supplier to catalogContract. 2.5.6: contactsUid is no longer required on organization (0.5.2) and contactPerson (0.0.28). It is a link to the Nextcloud addressbook that the contacts sync fills in after the record exists (MigrateContactsToNc, OrganizationContactSyncJob), so a required column made OpenRegister create it NOT NULL and every seed organisation failed to save on a fresh install (the organization table stayed empty). OpenRegister drops the NOT NULL on the existing column when the schema syncs. 2.5.5: the maintenanceWindow schema (0.1.0) joins the stackiq register, for maintenance a supplier plans on its products, with the owners of every usage notified (lifecycle-maintenance-and-supplier-roadmap). 2.5.4: usage (1.5.2) gains businessOwner and technicalOwner, contact persons of the consumer organisation; a usage is named after its application and organisation; status becomes facetable for the Applications in use filters (landscape-usage-registration). 2.5.3: the aiSystem schema (0.1.0) joins the stackiq register, for the AI systems an organisation uses and their EU AI Act classification (landscape-ai-system-inventory). 2.5.2: the connection schema (0.3.3) asked its national provision picker for gemmaType Buitengemeentenlijke voorziening, a spelling the GEMMA model does not use (it says Buitengemeentelijke voorziening), so the picker found nothing; its name template named the keys gegevensuitwisselingRichting and buitengemeentelijkVoorziening and the values AnaarB, BnaarA and bi-directioneel, all renamed since, so a connection had no readable name; and type, status and dataExchangeDirection become facetable for the new Connections page (connections-catalogue-pages). 2.5.1: the x-openregister-lifecycle blocks of usage, catalogContract, connection and moduleVersion still named the Dutch states (Verwerving/Gepland/In productie/Uit te faseren/Uitgefaseerd, In onderhandeling/Actief/Verlopen, in ontwikkeling/in gebruik/einde ondersteuning/teruggetrokken) while their status enums and the rows RenameDutchCatalogValues migrated are English, so no transition was ever offered on those records (stackiq#1140). The states now use the enum values, and the four schema versions are bumped (usage 1.5.1, catalogContract 0.1.2, connection 0.3.2, moduleVersion 0.1.5) because a lifecycle-only edit does not deploy without one, as 2.4.4 records. 2.4.4: organization.status was left behind by #520's enum translation — its `default` was still 'Concept' and its whole x-openregister-lifecycle block still named Concept/Actief/Deactief, while the enum and the migrated rows are Draft/Active/Inactive/merged. A default outside its own enum makes every newly created organisation fall out of the Organisations index filter, and a lifecycle whose from/to values match no row offers no transition at all — neither raises an error. The schema version is bumped with it because a deployed version >= the declared one makes the import SKIP, and OpenRegister's schemaContentDiffers() escape hatch compares only properties/required/authorization — never `configuration` — so a lifecycle-only edit would never have deployed. 2.4.3: Re-authored Dutch schema-level titles to English (dienst, kwetsbaarheid, contactpersoon, organisatie, gebruik, koppeling, beoordeeling, module, bioMaatregel, moduleVersie, sbomComponent); schema keys unchanged, Dutch labels now come from the app's l10n translation files. 2.4.2: Moved SBOM provenance properties (sbomLastImportedAt, sbomFormat, sbomFileName, sbomComponents) from the organisatie schema to moduleVersie, where SBOM imports actually record them; without this the moduleVersie magic table lacked the columns so recordProvenance() writes were silently dropped and the import-status endpoint always reported 'never imported'. 2.4.1: Re-authored Dutch schema property titles to English (property keys unchanged); Dutch labels now come from the app's l10n translation files." + "version": "2.5.8", + "changelog": "2.5.8: schema properties no longer carry null validation keywords (minimum, maximum, multipleOf, minItems, maxItems, minLength, maxLength). OpenRegister's JSON Schema validator rejects a null there ('minimum must contain a valid number'), so no object could be created on a schema with hardValidation, such as element, and the E2E seed failed. Bumped: catalogService (0.2.2), contactPerson (0.0.29), organization (0.5.3), usage (1.5.3), element (0.0.12), view (0.0.8), model (0.0.44), property-definition (0.0.9), relation (0.0.9), module (0.3.4). The loader keeps the highest version per schema, so the fragments that carry the effective version of catalogService and organization (publication-field-rules.json: 0.2.3, 0.5.4) and of usage and module (topdesk-cmdb-import.json: 1.5.7, 0.3.9) are bumped too; an equal version is skipped on upgrade. 2.5.7: a contract no longer requires a catalogue service, because a licence bought for an application in use has none; the service desk exchange imports such licences (sharing-itsm-exchange). The fragment sharing-itsm-exchange.json adds the service desk reference to usage (1.5.4), connection (0.3.4) and catalogContract (0.1.4), and the licence fields vendorReference, currency and supplier to catalogContract. 2.5.6: contactsUid is no longer required on organization (0.5.2) and contactPerson (0.0.28). It is a link to the Nextcloud addressbook that the contacts sync fills in after the record exists (MigrateContactsToNc, OrganizationContactSyncJob), so a required column made OpenRegister create it NOT NULL and every seed organisation failed to save on a fresh install (the organization table stayed empty). OpenRegister drops the NOT NULL on the existing column when the schema syncs. 2.5.5: the maintenanceWindow schema (0.1.0) joins the stackiq register, for maintenance a supplier plans on its products, with the owners of every usage notified (lifecycle-maintenance-and-supplier-roadmap). 2.5.4: usage (1.5.2) gains businessOwner and technicalOwner, contact persons of the consumer organisation; a usage is named after its application and organisation; status becomes facetable for the Applications in use filters (landscape-usage-registration). 2.5.3: the aiSystem schema (0.1.0) joins the stackiq register, for the AI systems an organisation uses and their EU AI Act classification (landscape-ai-system-inventory). 2.5.2: the connection schema (0.3.3) asked its national provision picker for gemmaType Buitengemeentenlijke voorziening, a spelling the GEMMA model does not use (it says Buitengemeentelijke voorziening), so the picker found nothing; its name template named the keys gegevensuitwisselingRichting and buitengemeentelijkVoorziening and the values AnaarB, BnaarA and bi-directioneel, all renamed since, so a connection had no readable name; and type, status and dataExchangeDirection become facetable for the new Connections page (connections-catalogue-pages). 2.5.1: the x-openregister-lifecycle blocks of usage, catalogContract, connection and moduleVersion still named the Dutch states (Verwerving/Gepland/In productie/Uit te faseren/Uitgefaseerd, In onderhandeling/Actief/Verlopen, in ontwikkeling/in gebruik/einde ondersteuning/teruggetrokken) while their status enums and the rows RenameDutchCatalogValues migrated are English, so no transition was ever offered on those records (stackiq#1140). The states now use the enum values, and the four schema versions are bumped (usage 1.5.1, catalogContract 0.1.2, connection 0.3.2, moduleVersion 0.1.5) because a lifecycle-only edit does not deploy without one, as 2.4.4 records. 2.4.4: organization.status was left behind by #520's enum translation — its `default` was still 'Concept' and its whole x-openregister-lifecycle block still named Concept/Actief/Deactief, while the enum and the migrated rows are Draft/Active/Inactive/merged. A default outside its own enum makes every newly created organisation fall out of the Organisations index filter, and a lifecycle whose from/to values match no row offers no transition at all — neither raises an error. The schema version is bumped with it because a deployed version >= the declared one makes the import SKIP, and OpenRegister's schemaContentDiffers() escape hatch compares only properties/required/authorization — never `configuration` — so a lifecycle-only edit would never have deployed. 2.4.3: Re-authored Dutch schema-level titles to English (dienst, kwetsbaarheid, contactpersoon, organisatie, gebruik, koppeling, beoordeeling, module, bioMaatregel, moduleVersie, sbomComponent); schema keys unchanged, Dutch labels now come from the app's l10n translation files. 2.4.2: Moved SBOM provenance properties (sbomLastImportedAt, sbomFormat, sbomFileName, sbomComponents) from the organisatie schema to moduleVersie, where SBOM imports actually record them; without this the moduleVersie magic table lacked the columns so recordProvenance() writes were silently dropped and the import-status endpoint always reported 'never imported'. 2.4.1: Re-authored Dutch schema property titles to English (property keys unchanged); Dutch labels now come from the app's l10n translation files." }, "x-openregister": { "type": "application", @@ -1329,7 +1329,7 @@ "x-schema-org": "schema:Service", "title": "Service", "description": "Een specifiek aanbod van een dienst op een of meerdere applicaties door een leverancier", - "version": "0.2.1", + "version": "0.2.2", "omschrijving": "", "icon": "Handshake", "required": [ @@ -1344,13 +1344,7 @@ "required": true, "visible": true, "order": 1, - "minLength": null, "maxLength": 200, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "table": { "default": true @@ -1791,7 +1785,7 @@ "x-schema-org": "schema:Person", "title": "Contact person", "description": "Contactgegevens van een persoon", - "version": "0.0.28", + "version": "0.0.29", "omschrijving": "", "icon": "AccountMultiple", "required": [], @@ -1810,13 +1804,7 @@ "description": "Functie van de medewerker", "type": "string", "visible": true, - "minLength": null, "maxLength": 100, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -1868,13 +1856,6 @@ "visible": true, "facetable": false, "order": 7, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "register": "", @@ -2022,7 +2003,7 @@ "x-schema-org": "schema:Organization", "title": "Organization", "description": "An organisation that offers provisions. Absorbs the former ArchiMate `organization` schema: its identity and statutory identifiers (name, summary, description, oin, tooi, rsin, pki, image) and its ArchiMate round-trip `xml` are declared here, so there is one organisation schema rather than two that shared no property.", - "version": "0.5.2", + "version": "0.5.3", "omschrijving": "", "icon": "OfficeBuildingOutline", "required": [ @@ -2156,13 +2137,6 @@ "type": "array", "visible": true, "order": 4, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "#/components/schemas/contactPerson", "x-relation-filter": { "organization": "@objectId" }, @@ -2199,13 +2173,6 @@ "type": "array", "visible": true, "order": 5, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "#/components/schemas/organization", "items": { @@ -2235,13 +2202,6 @@ "type": "array", "visible": true, "order": 6, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "#/components/schemas/organization", "items": { @@ -2282,14 +2242,7 @@ "order": null }, "order": 3, - "minLength": null, - "maxLength": null, "immutable": true, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2320,13 +2273,6 @@ "hideOnCollection": true, "facetable": false, "order": 17, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2397,13 +2343,6 @@ "visible": false, "facetable": true, "order": 14, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2653,7 +2592,7 @@ "slug": "usage", "title": "Usage", "description": "Het gebruik van applicaties, diensten en koppelingen door afnemers", - "version": "1.5.2", + "version": "1.5.3", "omschrijving": "", "icon": "Gauge", "x-openregister-notifications": { @@ -2745,13 +2684,6 @@ "format": "date", "visible": true, "order": 16, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2775,13 +2707,6 @@ "format": "date", "visible": true, "order": 14, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2805,13 +2730,6 @@ "format": "date", "visible": true, "order": 15, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2835,13 +2753,6 @@ "format": "date", "visible": true, "order": 15, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2866,13 +2777,6 @@ "required": true, "visible": true, "order": 17, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -2903,13 +2807,6 @@ "visible": true, "hideOnCollection": true, "order": 10, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": { @@ -4129,7 +4026,7 @@ "slug": "element", "title": "Element", "description": "AMEF Element - Architectuur elementen uit het ArchiMate model", - "version": "0.0.11", + "version": "0.0.12", "omschrijving": "", "icon": "Cube", "required": [ @@ -4141,14 +4038,7 @@ "identifier": { "description": "De identifier van dit Element", "type": "string", - "minLength": null, - "maxLength": null, "example": "id-009fa62f25844aa3a87d252bf2b6bb0c", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -4171,14 +4061,7 @@ "type": { "description": "Het type van dit Element", "type": "string", - "minLength": null, - "maxLength": null, "example": "Capability", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -4202,14 +4085,7 @@ "name": { "description": "De naam van dit Element", "type": "string", - "minLength": null, - "maxLength": null, "example": "Publiceren en gebruiken van informatie over datadiensten", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -4236,11 +4112,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -4264,14 +4135,7 @@ "documentation": { "description": "De documentation van dit Element", "type": "string", - "minLength": null, - "maxLength": null, "example": "Dienstenafnemers moeten in online catalogi kunnen opvragen welke diensten, met welke kenmerken, door dienstenaanbieder worden aangeboden. \\nOnder andere ontwikkelaars hebben baat bij informatie over beschikbare diensten en de vereisten voor het gebruik van de dienst (bijv. specificatie van een dienst conform de OAS-standaard).", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -4298,11 +4162,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -4326,13 +4185,6 @@ "properties": { "description": "De properties van dit Element", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -5298,7 +5150,7 @@ "slug": "view", "title": "View", "description": "AMEF View - Architectuur views en diagrammen uit het ArchiMate model", - "version": "0.0.7", + "version": "0.0.8", "omschrijving": "", "icon": "EyeOutline", "required": [ @@ -5313,14 +5165,7 @@ "identifier": { "description": "De identifier van deze View", "type": "string", - "minLength": null, - "maxLength": null, "example": "id-a6ee6077d3094afa91fc6ea92a9a2a40", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5338,14 +5183,7 @@ "type": { "description": "De type van deze View", "type": "string", - "minLength": null, - "maxLength": null, "example": "Diagram", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5364,14 +5202,7 @@ "viewpoint": { "description": "De viewpoint van deze View", "type": "string", - "minLength": null, - "maxLength": null, "example": "Application Structure", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5389,14 +5220,7 @@ "name": { "description": "De name van deze View", "type": "string", - "minLength": null, - "maxLength": null, "example": "LV01 BGT basisregistratie en SVB view", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5415,14 +5239,7 @@ "nameLong": { "description": "De name-language van deze View", "type": "string", - "minLength": null, - "maxLength": null, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5440,14 +5257,7 @@ "documentation": { "description": "De documentation van deze View", "type": "string", - "minLength": null, - "maxLength": null, "example": "Toont de referentiecomponenten ter ondersteuning van applicatieservices voor publieksdiensten", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5468,11 +5278,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5490,13 +5295,6 @@ "properties": { "description": "De properties van deze View", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -5519,13 +5317,6 @@ "nodes": { "description": "De nodes van deze View", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -5547,13 +5338,6 @@ "connections": { "description": "De connections van deze View", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -5688,7 +5472,7 @@ "slug": "model", "title": "Model", "description": "AMEF Model - Volledig ArchiMate model met alle elementen, relaties en views", - "version": "0.0.43", + "version": "0.0.44", "omschrijving": "", "icon": "Database", "required": [ @@ -5712,14 +5496,7 @@ "xmlns": { "description": "De xmlns van dit GEMMA Model", "type": "string", - "minLength": null, - "maxLength": null, "example": "http://www.opengroup.org/xsd/archimate/3.0/", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5737,14 +5514,7 @@ "xsi": { "description": "De xsi van dit GEMMA Model", "type": "string", - "minLength": null, - "maxLength": null, "example": "http://www.w3.org/2001/XMLSchema-instance", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5762,14 +5532,7 @@ "schemaLocation": { "description": "De schemaLocation van dit GEMMA Model", "type": "string", - "minLength": null, - "maxLength": null, "example": "http://www.opengroup.org/xsd/archimate/3.0/ http://www.opengroup.org/xsd/archimate/3.1/archimate3_Diagram.xsd", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5787,14 +5550,7 @@ "identifier": { "description": "De identifier van dit GEMMA Model", "type": "string", - "minLength": null, - "maxLength": null, "example": "id-b58b6b03-a59d-472b-bd87-88ba77ded4e6", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5812,14 +5568,7 @@ "name": { "description": "De name van dit GEMMA Model", "type": "string", - "minLength": null, - "maxLength": null, "example": "GEMMA release (test)", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5840,11 +5589,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5863,13 +5607,7 @@ "description": "De version van dit GEMMA Model", "type": "string", "minLength": 3, - "maxLength": null, "example": "3.0", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5887,14 +5625,7 @@ "documentation": { "description": "De documentation van dit GEMMA Model", "type": "string", - "minLength": null, - "maxLength": null, "example": "De GEMeentelijk Model Architectuur (GEMMA) bevat een blauwdruk van de gemeente en haar informatievoorziening. De GEMMA kan worden gebruikt als basis voor de projectmodellen", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5915,11 +5646,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -5937,13 +5663,7 @@ "properties": { "description": "De properties van dit GEMMA Model", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "minItems": 1, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -5966,13 +5686,7 @@ "elements": { "description": "De elements van dit GEMMA Model", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "minItems": 1, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -5995,13 +5709,7 @@ "relationships": { "description": "De relationships van dit GEMMA Model", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "minItems": 1, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -6024,13 +5732,7 @@ "organizations": { "description": "De organizations van dit GEMMA Model", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "minItems": 1, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -6053,13 +5755,7 @@ "propertyDefinitions": { "description": "De propertyDefinitions van dit GEMMA Model", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "minItems": 1, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -6082,13 +5778,7 @@ "views": { "description": "De views van dit GEMMA Model", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "minItems": 1, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -6139,7 +5829,7 @@ "slug": "property-definition", "title": "Property Definition", "description": "AMEF Property Definition - Definitie van eigenschappen voor ArchiMate elementen", - "version": "0.0.8", + "version": "0.0.9", "omschrijving": "", "icon": "CogOutline", "required": [ @@ -6150,14 +5840,7 @@ "identifier": { "description": "De identifier van deze Property Definition", "type": "string", - "minLength": null, - "maxLength": null, "example": "propid-43", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6180,14 +5863,7 @@ "type": { "description": "De type van deze Property Definition", "type": "string", - "minLength": null, - "maxLength": null, "example": "string", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6211,14 +5887,7 @@ "name": { "description": "De name van deze Property Definition", "type": "string", - "minLength": null, - "maxLength": null, "example": "API-portaal", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6244,11 +5913,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6299,7 +5963,7 @@ "slug": "relation", "title": "Relation", "description": "AMEF Relation - Relaties tussen architectuur elementen uit het ArchiMate model", - "version": "0.0.8", + "version": "0.0.9", "omschrijving": "", "icon": "ArrowRight", "required": [ @@ -6313,14 +5977,7 @@ "identifier": { "description": "De identifier van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "id-1b46181d68e5477a9c0b5a95a0677924", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6343,14 +6000,7 @@ "source": { "description": "De source van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "id-d143a1fc-02dc-11e6-11ba-005056a85f9c", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6373,14 +6023,7 @@ "target": { "description": "De target van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "id-a85f22d89af14222a914fcb9ecfe6815", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6403,14 +6046,7 @@ "type": { "description": "De type van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "Access", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6434,14 +6070,7 @@ "accessType": { "description": "De accessType van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "Read", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6464,14 +6093,7 @@ "isDirected": { "description": "De isDirected van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "true", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6494,14 +6116,7 @@ "name": { "description": "De name van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "Verplicht", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6527,11 +6142,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6554,14 +6164,7 @@ "documentation": { "description": "De documentation van deze Relation", "type": "string", - "minLength": null, - "maxLength": null, "example": "Op basis van het zaaktype routeert de servicebuscomponent de aanvraag naar een Zaakafhandelcomponent (generiek of specifiek).", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6587,11 +6190,6 @@ "minLength": 2, "maxLength": 2, "example": "nl", - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "objectConfiguration": { "handling": "nested-object", @@ -6614,13 +6212,6 @@ "properties": { "description": "De properties van deze Relation", "type": "array", - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "$ref": "", "items": { "cascadeDelete": true, @@ -6792,7 +6383,7 @@ }, "title": "Application", "description": "Een applicatie is een softwarecomponent (applicatie of systeemsoftware)", - "version": "0.3.3", + "version": "0.3.4", "omschrijving": "", "icon": "Package", "required": [ @@ -6936,16 +6527,9 @@ "type": "string", "visible": true, "order": 9, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, "table": { "default": true }, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "default": "Closed source", @@ -6964,13 +6548,6 @@ "type": "string", "visible": true, "order": 10, - "minLength": null, - "maxLength": null, - "minimum": null, - "maximum": null, - "multipleOf": null, - "minItems": null, - "maxItems": null, "inversedBy": "", "$ref": "", "objectConfiguration": [], diff --git a/tests/Integration/README.md b/tests/Integration/README.md index 20fd2b13a..50539e746 100644 --- a/tests/Integration/README.md +++ b/tests/Integration/README.md @@ -37,7 +37,7 @@ composer install --dev This installs: - PHPUnit 10.5+ for test execution -- Guzzle HTTP Client 7.8+ for API requests +- Guzzle HTTP Client 8.2+ for API requests ## Running Tests diff --git a/tests/Unit/Settings/PublicationFieldRulesTest.php b/tests/Unit/Settings/PublicationFieldRulesTest.php index f5ee7d5b7..84026c2a6 100644 --- a/tests/Unit/Settings/PublicationFieldRulesTest.php +++ b/tests/Unit/Settings/PublicationFieldRulesTest.php @@ -173,7 +173,7 @@ public function testAFragmentNeverLowersAVersion(): void { $this->assertSame('1.5.5', $merged['components']['schemas']['usage']['version']); $schemas = $this->register()['components']['schemas']; - $this->assertSame('1.5.6', $schemas['usage']['version'], 'topdesk-cmdb-import.json bumps it past publication-field-rules.json; value-assessment.json, sorting last, does not lower it'); + $this->assertSame('1.5.7', $schemas['usage']['version'], 'topdesk-cmdb-import.json bumps it past publication-field-rules.json; value-assessment.json, sorting last, does not lower it'); $this->assertSame('0.3.5', $schemas['connection']['version']); $this->assertSame('0.1.6', $schemas['moduleVersion']['version']); }//end testAFragmentNeverLowersAVersion() diff --git a/tests/Unit/Settings/RegisterNullKeywordsTest.php b/tests/Unit/Settings/RegisterNullKeywordsTest.php new file mode 100644 index 000000000..a37b37b22 --- /dev/null +++ b/tests/Unit/Settings/RegisterNullKeywordsTest.php @@ -0,0 +1,90 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @link https://github.com/ConductionNL/stackiq + */ + +declare(strict_types=1); + +namespace OCA\Stackiq\Tests\Unit\Settings; + +use PHPUnit\Framework\TestCase; + +/** + * Scans the register file and its register.d fragments for null keywords. + */ +class RegisterNullKeywordsTest extends TestCase { + private const KEYWORDS = [ + 'minimum', + 'maximum', + 'exclusiveMinimum', + 'exclusiveMaximum', + 'multipleOf', + 'minLength', + 'maxLength', + 'minItems', + 'maxItems', + 'minProperties', + 'maxProperties', + ]; + + /** + * Collect the paths of null validation keywords below a node. + * + * @param mixed $node The decoded JSON node. + * @param string $path The path to the node. + * + * @return array The offending paths. + */ + private function findNullKeywords(mixed $node, string $path): array { + $found = []; + if (is_array($node) === false) { + return $found; + } + + foreach ($node as $key => $value) { + $child = $path.'/'.$key; + if ($value === null && in_array($key, self::KEYWORDS, true) === true) { + $found[] = $child; + continue; + } + + $found = array_merge($found, $this->findNullKeywords($value, $child)); + } + + return $found; + }//end findNullKeywords() + + /** + * No schema in the register or its fragments carries a null keyword. + * + * @return void + */ + public function testNoSchemaCarriesNullValidationKeywords(): void { + $dir = __DIR__.'/../../../lib/Settings'; + $files = array_merge([$dir.'/softwarecatalogus_register.json'], glob($dir.'/register.d/*.json') ?: []); + + $found = []; + foreach ($files as $file) { + $this->assertFileExists($file); + $decoded = json_decode((string)file_get_contents($file), true); + $this->assertIsArray($decoded, basename($file).' must be valid JSON'); + $schemas = $decoded['components']['schemas'] ?? []; + $found = array_merge($found, $this->findNullKeywords($schemas, basename($file))); + } + + $this->assertSame([], array_slice($found, 0, 10), 'Null validation keywords make OpenRegister refuse the schema (showing first 10)'); + }//end testNoSchemaCarriesNullValidationKeywords() +}//end class diff --git a/tests/Unit/Settings/TopdeskCmdbFragmentTest.php b/tests/Unit/Settings/TopdeskCmdbFragmentTest.php index 7ef15d1f9..631ffc002 100644 --- a/tests/Unit/Settings/TopdeskCmdbFragmentTest.php +++ b/tests/Unit/Settings/TopdeskCmdbFragmentTest.php @@ -58,14 +58,14 @@ private function mergedRegister(): array { }//end mergedRegister() /** - * The merged module is 0.3.8, carries the six optional, titled properties and allows BBN2+. + * The merged module is 0.3.9, carries the six optional, titled properties and allows BBN2+. * * @return void */ - public function testTheMergedModuleIsVersion038WithTheExternalIds(): void { + public function testTheMergedModuleIsVersion039WithTheExternalIds(): void { $module = $this->mergedRegister()['components']['schemas']['module']; - $this->assertSame('0.3.8', $module['version'], 'a fragment sorting after topdesk-cmdb-import.json overwrote the bump'); + $this->assertSame('0.3.9', $module['version'], 'a fragment sorting after topdesk-cmdb-import.json overwrote the bump'); foreach (self::PROPERTIES as $property) { $this->assertArrayHasKey($property, $module['properties']); $this->assertNotEmpty($module['properties'][$property]['title'] ?? '', $property); @@ -91,7 +91,7 @@ public function testTheMergedModuleIsVersion038WithTheExternalIds(): void { $this->assertSame(['BBN1', 'BBN2', 'BBN3', 'BBN2+'], $module['properties']['bbnLevel']['enum'], 'the fragment adds BBN2+ to the BIO levels'); $this->assertArrayHasKey('roadmapStatement', $module['properties'], 'the 0.3.4 fragment still applies'); $this->assertSame(['name'], $module['required']); - }//end testTheMergedModuleIsVersion038WithTheExternalIds() + }//end testTheMergedModuleIsVersion039WithTheExternalIds() /** * A CMDB import sets the usage status TOPdesk records from any state; only an administrator may. @@ -104,7 +104,7 @@ public function testTheMergedModuleIsVersion038WithTheExternalIds(): void { */ public function testAnAdministratorMayMoveAUsageToAnyStateTheSourceRecords(): void { $usage = $this->mergedRegister()['components']['schemas']['usage']; - $this->assertSame('1.5.6', $usage['version'], 'a lifecycle-only edit deploys only with a version bump'); + $this->assertSame('1.5.7', $usage['version'], 'a lifecycle-only edit deploys only with a version bump'); $lifecycle = $usage['configuration']['x-openregister-lifecycle']; $states = $usage['properties']['status']['enum'];