feat: dnsname argument type
This commit is contained in:
parent
ecc5c64046
commit
6eb3827ddd
|
|
@ -10,6 +10,7 @@ A full list of argument types are below;
|
||||||
| (default) | xref:args/input.adoc[Textbox] | If a `type:` is not set, and `choices:` is empty, then ascii will be used, and a warning will be logged. It is recommended that you set the type explicitly, rather than relying on defaults.
|
| (default) | xref:args/input.adoc[Textbox] | If a `type:` is not set, and `choices:` is empty, then ascii will be used, and a warning will be logged. It is recommended that you set the type explicitly, rather than relying on defaults.
|
||||||
| ascii | xref:args/input.adoc[Textbox] | a-z (case insensitive), 0-9, but no spaces or punctuation
|
| ascii | xref:args/input.adoc[Textbox] | a-z (case insensitive), 0-9, but no spaces or punctuation
|
||||||
| ascii_identifier | xref:args/input.adoc[Textbox] | Like a DNS name, a-Z (case insensitive), 0-9, `-`, `.`, and `_`.
|
| ascii_identifier | xref:args/input.adoc[Textbox] | Like a DNS name, a-Z (case insensitive), 0-9, `-`, `.`, and `_`.
|
||||||
|
| dnsname | xref:args/input.adoc[Textbox] | A DNS hostname (RFC 1123). Short names (e.g. `webserver`) and FQDNs (e.g. `webserver.example.com`). Letters/digits/hyphens only, no underscores. Optional trailing dot allowed.
|
||||||
| shell_safe_identifier | xref:args/input.adoc[Textbox] | Like an ascii identifier, but also allows `@` and `+`. Useful for shell-safe usernames and email-style identifiers.
|
| shell_safe_identifier | xref:args/input.adoc[Textbox] | Like an ascii identifier, but also allows `@` and `+`. Useful for shell-safe usernames and email-style identifiers.
|
||||||
| ascii_sentence | xref:args/input.adoc[Textbox] | a-z (case insensitive), 0-9, with spaces, `.` and `,`.
|
| ascii_sentence | xref:args/input.adoc[Textbox] | a-z (case insensitive), 0-9, with spaces, `.` and `,`.
|
||||||
| unicode_identifier | xref:args/input.adoc[Textbox] | Like an ascii identifier, but allows unicode characters. This is useful for languages that use non-ascii characters, such as Chinese, Japanese, etc.
|
| unicode_identifier | xref:args/input.adoc[Textbox] | Like an ascii identifier, but allows unicode characters. This is useful for languages that use non-ascii characters, such as Chinese, Japanese, etc.
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ function getInputType (arg) {
|
||||||
return 'checkbox'
|
return 'checkbox'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg.type === 'ascii_identifier' || arg.type === 'shell_safe_identifier' || arg.type === 'ascii' || arg.type === 'ascii_sentence') {
|
if (arg.type === 'ascii_identifier' || arg.type === 'dnsname' || arg.type === 'shell_safe_identifier' || arg.type === 'ascii' || arg.type === 'ascii_sentence') {
|
||||||
return 'text'
|
return 'text'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ var (
|
||||||
"shell_safe_identifier": `^[a-zA-Z0-9@\.\_\+\-]+$`,
|
"shell_safe_identifier": `^[a-zA-Z0-9@\.\_\+\-]+$`,
|
||||||
"ascii_sentence": `^[a-zA-Z0-9\-\._, ]+$`,
|
"ascii_sentence": `^[a-zA-Z0-9\-\._, ]+$`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dnsNameLabelPattern = regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`)
|
||||||
|
dnsNameAllNumericPattern = regexp.MustCompile(`^[0-9]+$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// parseExecArray parses all exec arguments in the action.
|
// parseExecArray parses all exec arguments in the action.
|
||||||
|
|
@ -223,6 +226,8 @@ func TypeSafetyCheck(name string, value string, argumentType string) error {
|
||||||
return typeSafetyCheckUrl(value)
|
return typeSafetyCheckUrl(value)
|
||||||
case "datetime":
|
case "datetime":
|
||||||
return typeSafetyCheckDatetime(value)
|
return typeSafetyCheckDatetime(value)
|
||||||
|
case "dnsname":
|
||||||
|
return typeSafetyCheckDnsName(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeSafetyCheckRegex(name, value, argumentType)
|
return typeSafetyCheckRegex(name, value, argumentType)
|
||||||
|
|
@ -304,6 +309,33 @@ func typeSafetyCheckEmail(value string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// typeSafetyCheckDnsName validates a DNS hostname (RFC 1123 LDH labels).
|
||||||
|
// Accepts short names (e.g. webserver) and FQDNs (e.g. webserver.example.com).
|
||||||
|
// An optional trailing dot is allowed.
|
||||||
|
func typeSafetyCheckDnsName(value string) error {
|
||||||
|
hostname := strings.TrimSuffix(value, ".")
|
||||||
|
if hostname == "" || len(hostname) > 253 {
|
||||||
|
return fmt.Errorf("invalid dnsname length")
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeSafetyCheckDnsNameLabels(strings.Split(hostname, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeSafetyCheckDnsNameLabels(labels []string) error {
|
||||||
|
for _, label := range labels {
|
||||||
|
if !dnsNameLabelPattern.MatchString(label) {
|
||||||
|
return fmt.Errorf("invalid dnsname label %q", label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tld := labels[len(labels)-1]
|
||||||
|
if dnsNameAllNumericPattern.MatchString(tld) {
|
||||||
|
return fmt.Errorf("dnsname top-level label must not be all-numeric")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func typeSafetyCheckDatetime(value string) error {
|
func typeSafetyCheckDatetime(value string) error {
|
||||||
_, err := time.Parse("2006-01-02T15:04:05", value)
|
_, err := time.Parse("2006-01-02T15:04:05", value)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,44 @@ func TestTypeSafetyCheckAsciiIdentifier(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTypeSafetyCheckDnsName(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
hasError bool
|
||||||
|
}{
|
||||||
|
{"Short name", "webserver", false},
|
||||||
|
{"Localhost", "localhost", false},
|
||||||
|
{"Simple domain", "example.com", false},
|
||||||
|
{"Host with subdomain", "webserver.example.com", false},
|
||||||
|
{"Deep subdomain", "a.b.c.example.co.uk", false},
|
||||||
|
{"Label starting with digit", "1host.example.com", false},
|
||||||
|
{"Trailing dot", "example.com.", false},
|
||||||
|
{"Punycode IDN", "xn--bcher-kva.example", false},
|
||||||
|
{"Underscore", "my_host.example.com", true},
|
||||||
|
{"Space", "example .com", true},
|
||||||
|
{"Leading hyphen label", "-host.example.com", true},
|
||||||
|
{"Trailing hyphen label", "host-.example.com", true},
|
||||||
|
{"Empty label", "example..com", true},
|
||||||
|
{"IP address", "192.168.1.1", true},
|
||||||
|
{"All numeric TLD", "example.123", true},
|
||||||
|
{"All numeric short name", "12345", true},
|
||||||
|
{"Special chars", "exam!ple.com", true},
|
||||||
|
{"Unicode label", "bücher.example.com", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := TypeSafetyCheck("host", tt.value, "dnsname")
|
||||||
|
if tt.hasError {
|
||||||
|
assert.NotNil(t, err, "Expected error for value '%s'", tt.value)
|
||||||
|
} else {
|
||||||
|
assert.Nil(t, err, "Expected no error for value '%s', but got: %v", tt.value, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTypeSafetyCheckShellSafeIdentifier(t *testing.T) {
|
func TestTypeSafetyCheckShellSafeIdentifier(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue