Allow single-label hostnames as a Host target (#126)

The target ("ip") field validator required at least two dot-separated
labels, rejecting legitimate single-label hostnames like Docker Compose
service names ("sso-manager"), /etc/hosts entries, or anything resolved
via a search domain. This was enforced identically client-side
(public/lib/js/val.js) and server-side (utils/hostname_validate.js,
routes/host.js), so there was no way to set one through the UI or API
— only by writing to the Host model directly, bypassing validation
entirely (which is how theta-env's setup.sh registers sso-manager as a
target today, working only because it calls Host.create() directly).

Relax HOSTNAME in both places to accept either a bare single label or
the existing dotted-FQDN pattern. Flips the one existing test that
codified the old behavior (isValidHostname('localhost') was asserted
false) and adds coverage for the reported case.
This commit is contained in:
2026-07-14 01:12:02 -04:00
committed by GitHub
parent f926d92f3a
commit a9dfebc481
4 changed files with 21 additions and 8 deletions
+9 -2
View File
@@ -32,8 +32,12 @@ describe('isValidHostname (strict, for target)', () => {
assert.ok(isValidHostname('example.com'));
assert.ok(isValidHostname('app.internal.net'));
});
test('rejects bare labels, numeric TLDs, wildcards', () => {
assert.ok(!isValidHostname('localhost'));
test('accepts a bare single-label hostname (Docker service names, /etc/hosts)', () => {
assert.ok(isValidHostname('localhost'));
assert.ok(isValidHostname('sso-manager'));
assert.ok(isValidHostname('redis'));
});
test('rejects numeric-looking targets, wildcards', () => {
assert.ok(!isValidHostname('10.10.10.10'));
assert.ok(!isValidHostname('*.example.com'));
assert.ok(!isValidHostname(''));
@@ -81,6 +85,9 @@ describe('isValidTargetField (target: hostname or IP, no wildcard)', () => {
assert.ok(isValidTargetField('app.internal.net'));
assert.ok(isValidTargetField('10.0.0.5'));
});
test('accepts a bare single-label hostname (e.g. a Docker Compose service name)', () => {
assert.ok(isValidTargetField('sso-manager'));
});
test('rejects wildcards, protocol, port, path', () => {
assert.ok(!isValidTargetField('*.example.com'));
assert.ok(!isValidTargetField('**'));