diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f112162d..1c84844d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. - **mxGraph**: Updated the vendored mxGraph from 4.1.0 to 4.2.2, the final release before the project was archived. Upstream changed the modifier that deletes a cell together with its connected edges from Shift to Ctrl. - **Editor**: The sidebar node palettes now open expanded, the export dialog offers only the XML and SVG formats the server can produce, and the Help button opens the phēnix documentation instead of the defunct `minimega.org`. - **Topology validation**: Reject the node hostnames `all`, all-digit names, and `phenix` on Windows nodes, and warn about hostnames that may cause problems. +- **Topology schema**: Require node hostnames to be at least 2 characters long. ### Fixed diff --git a/src/go/types/schema_topology_test.go b/src/go/types/schema_topology_test.go index 62b33a79a..045d612ac 100644 --- a/src/go/types/schema_topology_test.go +++ b/src/go/types/schema_topology_test.go @@ -90,6 +90,19 @@ func TestTopologySchema(t *testing.T) { node: withHostname(validNode(), ""), wantErr: true, }, + { + name: "1-character hostname is rejected", + node: withHostname(validNode(), "a"), + wantErr: true, + }, + { + name: "2-character hostname is valid", + node: withHostname(validNode(), "a1"), + }, + { + name: "63-character hostname is valid", + node: withHostname(validNode(), strings.Repeat("a", 63)), + }, { name: "invalid vm_type is rejected", node: func() map[string]any { diff --git a/src/go/types/version/schemas/v1.yaml b/src/go/types/version/schemas/v1.yaml index fad8af5e1..d9a16ba32 100644 --- a/src/go/types/version/schemas/v1.yaml +++ b/src/go/types/version/schemas/v1.yaml @@ -224,10 +224,21 @@ components: - hostname properties: hostname: + # 2 to 63 letters, digits, and interior hyphens. Guest operating + # systems phenix configures reject 1-character hostnames. + # + # VyOS and Vyatta validate `system host-name` against + # `[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]`, which needs at least 2 + # characters: + # https://docs.vyos.io/en/latest/configuration/system/host-name.html + # https://github.com/vyos/vyos-1x/blob/ed218c254d964775ddf24158ac6520972d575faf/interface-definitions/include/constraint/host-name.xml.i + # + # Windows DNS host names have a 2-character minimum: + # https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/naming-conventions-for-computer-domain-site-ou#dns-host-names type: string - minLength: 1 + minLength: 2 maxLength: 63 - pattern: '^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$' + pattern: '^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$' example: ADServer description: type: string diff --git a/src/go/types/version/schemas/v2.yaml b/src/go/types/version/schemas/v2.yaml index adb8cd8da..a2cd3f67f 100644 --- a/src/go/types/version/schemas/v2.yaml +++ b/src/go/types/version/schemas/v2.yaml @@ -251,10 +251,21 @@ components: - hostname properties: hostname: + # 2 to 63 letters, digits, and interior hyphens. Guest operating + # systems phenix configures reject 1-character hostnames. + # + # VyOS and Vyatta validate `system host-name` against + # `[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]`, which needs at least 2 + # characters: + # https://docs.vyos.io/en/latest/configuration/system/host-name.html + # https://github.com/vyos/vyos-1x/blob/ed218c254d964775ddf24158ac6520972d575faf/interface-definitions/include/constraint/host-name.xml.i + # + # Windows DNS host names have a 2-character minimum: + # https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/naming-conventions-for-computer-domain-site-ou#dns-host-names type: string - minLength: 1 + minLength: 2 maxLength: 63 - pattern: '^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$' + pattern: '^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$' example: ADServer description: type: string diff --git a/src/go/web/public/grapheditor/utils/schemas/container_schema.json b/src/go/web/public/grapheditor/utils/schemas/container_schema.json index 81bb559c5..e047271a2 100644 --- a/src/go/web/public/grapheditor/utils/schemas/container_schema.json +++ b/src/go/web/public/grapheditor/utils/schemas/container_schema.json @@ -34,13 +34,13 @@ "$id": "#/nodes/properties/general/properties/hostname", "type": "string", "title": "Hostname", - "minLength": 1, + "minLength": 2, "default": "", "examples": [ "power-provider" ], "maxLength": 63, - "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$" }, "description": { "$id": "#/nodes/properties/general/properties/description", diff --git a/src/go/web/public/grapheditor/utils/schemas/kvm_schema.json b/src/go/web/public/grapheditor/utils/schemas/kvm_schema.json index 6a1c93cc7..afc39a314 100644 --- a/src/go/web/public/grapheditor/utils/schemas/kvm_schema.json +++ b/src/go/web/public/grapheditor/utils/schemas/kvm_schema.json @@ -82,12 +82,12 @@ "$id": "#/nodes/properties/general/properties/hostname", "type": "string", "title": "Hostname", - "minLength": 1, + "minLength": 2, "examples": [ "ADServer" ], "maxLength": 63, - "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$" }, "description": { "$id": "#/nodes/properties/general/properties/description", diff --git a/src/go/web/public/grapheditor/utils/schemas/node_schema.json b/src/go/web/public/grapheditor/utils/schemas/node_schema.json index 54b0dad88..0fa279e20 100644 --- a/src/go/web/public/grapheditor/utils/schemas/node_schema.json +++ b/src/go/web/public/grapheditor/utils/schemas/node_schema.json @@ -73,12 +73,12 @@ "$id": "#/nodes/properties/general/properties/hostname", "type": "string", "title": "Hostname", - "minLength": 1, + "minLength": 2, "examples": [ "ADServer" ], "maxLength": 63, - "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$" }, "description": { "$id": "#/nodes/properties/general/properties/description", diff --git a/src/go/web/public/grapheditor/utils/schemas/schema.json b/src/go/web/public/grapheditor/utils/schemas/schema.json index 3d22138b4..fd80fd302 100644 --- a/src/go/web/public/grapheditor/utils/schemas/schema.json +++ b/src/go/web/public/grapheditor/utils/schemas/schema.json @@ -102,13 +102,13 @@ "$id": "#/properties/nodes/items/properties/general/properties/hostname", "type": "string", "title": "Hostname", - "minLength": 1, + "minLength": 2, "default": "", "examples": [ "power-provider" ], "maxLength": 63, - "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$" }, "description": { "$id": "#/properties/nodes/items/properties/general/properties/description", diff --git a/src/go/web/public/grapheditor/utils/schemas/topo_schema.json b/src/go/web/public/grapheditor/utils/schemas/topo_schema.json index 2453e4283..167342aeb 100644 --- a/src/go/web/public/grapheditor/utils/schemas/topo_schema.json +++ b/src/go/web/public/grapheditor/utils/schemas/topo_schema.json @@ -122,12 +122,12 @@ "$id": "#/nodes/properties/general/properties/hostname", "type": "string", "title": "Hostname", - "minLength": 1, + "minLength": 2, "examples": [ "ADServer" ], "maxLength": 63, - "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$" }, "description": { "$id": "#/nodes/properties/general/properties/description", @@ -1076,12 +1076,12 @@ "$id": "#/nodes/properties/general/properties/hostname", "type": "string", "title": "Hostname", - "minLength": 1, + "minLength": 2, "examples": [ "ADServer" ], "maxLength": 63, - "pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$" }, "description": { "$id": "#/nodes/properties/general/properties/description",