Skip to content

Commit 5bc5699

Browse files
committed
Update for rules of instance names (#423)
* Instance names allow leading digits * Cloud instance name max length: 62 * Dashes are allowed, except for consecutive ones like -- * Ban underscores for the cloud
1 parent ffe74a1 commit 5bc5699

File tree

3 files changed

+35
-17
lines changed

3 files changed

+35
-17
lines changed

edgedb/con_utils.py

+32-16
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,18 @@
7474
r'((?:(?:\s|^)-\s*)?\d*\.?\d*)\s*(?i:us(\s|\d|\.|$)|microseconds?(\s|$))',
7575
)
7676
INSTANCE_NAME_RE = re.compile(
77-
r'^([A-Za-z_]\w*)(?:/([A-Za-z_]\w*))?$',
77+
r'^(\w(?:-?\w)*)$',
78+
re.ASCII,
7879
)
80+
CLOUD_INSTANCE_NAME_RE = re.compile(
81+
r'^([A-Za-z0-9](?:-?[A-Za-z0-9])*)/([A-Za-z0-9](?:-?[A-Za-z0-9])*)$',
82+
re.ASCII,
83+
)
84+
DSN_RE = re.compile(
85+
r'^[a-z]+://',
86+
re.IGNORECASE,
87+
)
88+
DOMAIN_LABEL_MAX_LENGTH = 63
7989

8090

8191
class ClientConfiguration(typing.NamedTuple):
@@ -519,11 +529,10 @@ def _parse_connect_dsn_and_args(
519529
):
520530
resolved_config = ResolvedConnectConfig()
521531

522-
dsn, instance_name = (
523-
(dsn, None)
524-
if dsn is not None and re.match('(?i)^[a-z]+://', dsn)
525-
else (None, dsn)
526-
)
532+
if dsn and DSN_RE.match(dsn):
533+
instance_name = None
534+
else:
535+
instance_name, dsn = dsn, None
527536

528537
has_compound_options = _resolve_config_options(
529538
resolved_config,
@@ -861,6 +870,13 @@ def _parse_cloud_instance_name_into_config(
861870
org_slug: str,
862871
instance_name: str,
863872
):
873+
label = f"{instance_name}--{org_slug}"
874+
if len(label) > DOMAIN_LABEL_MAX_LENGTH:
875+
raise ValueError(
876+
f"invalid instance name: cloud instance name length cannot exceed "
877+
f"{DOMAIN_LABEL_MAX_LENGTH - 1} characters: "
878+
f"{org_slug}/{instance_name}"
879+
)
864880
secret_key = resolved_config.secret_key
865881
if secret_key is None:
866882
try:
@@ -889,7 +905,7 @@ def _parse_cloud_instance_name_into_config(
889905
raise errors.ClientConnectionError("Invalid secret key")
890906
payload = f"{org_slug}/{instance_name}".encode("utf-8")
891907
dns_bucket = binascii.crc_hqx(payload, 0) % 100
892-
host = f"{instance_name}--{org_slug}.c-{dns_bucket:02d}.i.{dns_zone}"
908+
host = f"{label}.c-{dns_bucket:02d}.i.{dns_zone}"
893909
resolved_config.set_host(host, source)
894910

895911

@@ -973,23 +989,23 @@ def _resolve_config_options(
973989
else:
974990
creds = cred_utils.validate_credentials(cred_data)
975991
source = "credentials"
992+
elif INSTANCE_NAME_RE.match(instance_name[0]):
993+
source = instance_name[1]
994+
creds = cred_utils.read_credentials(
995+
cred_utils.get_credentials_path(instance_name[0]),
996+
)
976997
else:
977-
name_match = INSTANCE_NAME_RE.match(instance_name[0])
998+
name_match = CLOUD_INSTANCE_NAME_RE.match(instance_name[0])
978999
if name_match is None:
9791000
raise ValueError(
9801001
f'invalid DSN or instance name: "{instance_name[0]}"'
9811002
)
9821003
source = instance_name[1]
9831004
org, inst = name_match.groups()
984-
if inst is not None:
985-
_parse_cloud_instance_name_into_config(
986-
resolved_config, source, org, inst
987-
)
988-
return True
989-
990-
creds = cred_utils.read_credentials(
991-
cred_utils.get_credentials_path(instance_name[0]),
1005+
_parse_cloud_instance_name_into_config(
1006+
resolved_config, source, org, inst
9921007
)
1008+
return True
9931009

9941010
resolved_config.set_host(creds.get('host'), source)
9951011
resolved_config.set_port(creds.get('port'), source)

tests/test_con_utils.py

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class TestConUtils(unittest.TestCase):
4646
RuntimeError, 'cannot read credentials'),
4747
'invalid_dsn_or_instance_name': (
4848
ValueError, 'invalid DSN or instance name'),
49+
'invalid_instance_name': (
50+
ValueError, 'invalid instance name'),
4951
'invalid_dsn': (ValueError, 'invalid DSN'),
5052
'unix_socket_unsupported': (
5153
ValueError, 'unix socket paths not supported'),

0 commit comments

Comments
 (0)