devstack-cli 11.0.84__tar.gz → 11.0.85__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: devstack-cli
3
- Version: 11.0.84
3
+ Version: 11.0.85
4
4
  Summary: Command-line access to Cloud Development Environments (CDEs) created by Cloudomation DevStack
5
5
  Author-email: Stefan Mückstein <stefan@cloudomation.com>
6
6
  Project-URL: Homepage, https://cloudomation.com/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devstack-cli"
3
- version = "11.0.84"
3
+ version = "11.0.85"
4
4
  authors = [
5
5
  { name="Stefan Mückstein", email="stefan@cloudomation.com" },
6
6
  ]
@@ -10,6 +10,7 @@ import json
10
10
  import logging
11
11
  import os
12
12
  import pathlib
13
+ import re
13
14
  import readline
14
15
  import shlex
15
16
  import shutil
@@ -1222,6 +1223,12 @@ class Cli:
1222
1223
  self.port_forwarding_task = None
1223
1224
 
1224
1225
  async def _bg_port_forwarding(self: 'Cli') -> None:
1226
+ remote_username = self.cde_type['value']['remote-username']
1227
+ if re.match(r'[^a-zA-Z0-9]', remote_username):
1228
+ raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
1229
+ hostname = self.hostname
1230
+ if re.match(r'[^a-zA-Z0-9]', hostname):
1231
+ raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
1225
1232
  service_ports = self.cde_type['value'].get('service-ports')
1226
1233
  if service_ports is None:
1227
1234
  service_ports = [
@@ -1238,6 +1245,11 @@ class Cli:
1238
1245
  for port
1239
1246
  in service_ports
1240
1247
  ]
1248
+ for port in service_ports:
1249
+ if port[0] < 1 or port[0] > 65535:
1250
+ raise Exception(f'Invalid port: "{port[0]}". Only numbers between 1 and 65535 are allowed.')
1251
+ if port[1] < 1 or port[1] > 65535:
1252
+ raise Exception(f'Invalid port: "{port[1]}". Only numbers between 1 and 65535 are allowed.')
1241
1253
  while True:
1242
1254
  logger.info('Starting port forwarding of %s', ', '.join(str(port[0]) for port in service_ports))
1243
1255
  try:
@@ -1247,7 +1259,7 @@ class Cli:
1247
1259
  '-o', 'ConnectTimeout=10',
1248
1260
  '-o', f'UserKnownHostsFile={self.known_hosts_file.name}',
1249
1261
  '-NT',
1250
- f"{self.cde_type['value']['remote-username']}@{self.hostname}",
1262
+ f'{remote_username}@{hostname}',
1251
1263
  *itertools.chain.from_iterable([
1252
1264
  ('-L', f'{port[0]}:localhost:{port[1]}')
1253
1265
  for port
@@ -1427,13 +1439,22 @@ class Cli:
1427
1439
  return await self._process_remote_item_copy_file(file_info.filename)
1428
1440
 
1429
1441
  async def _process_remote_item_copy_dir(self: 'Cli', filename: str) -> str:
1442
+ remote_username = self.cde_type['value']['remote-username']
1443
+ if re.match(r'[^a-zA-Z0-9]', remote_username):
1444
+ raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
1445
+ hostname = self.hostname
1446
+ if re.match(r'[^a-zA-Z0-9]', hostname):
1447
+ raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
1448
+ remote_source_directory = self.cde_type['value']['remote-source-directory']
1449
+ if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
1450
+ raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
1430
1451
  await run_subprocess(
1431
1452
  'rsync',
1432
1453
  [
1433
1454
  '-e', f'ssh -o ConnectTimeout=10 -o UserKnownHostsFile={self.known_hosts_file.name}',
1434
1455
  '--archive',
1435
1456
  '--checksum',
1436
- f"{self.cde_type['value']['remote-username']}@{self.hostname}:{self.cde_type['value']['remote-source-directory']}/{filename}/",
1457
+ f'{remote_username}@{hostname}:{remote_source_directory}/{filename}/',
1437
1458
  str(self.local_source_directory / filename),
1438
1459
  ],
1439
1460
  name='Copy remote directory',
@@ -1441,23 +1462,35 @@ class Cli:
1441
1462
  return f'Copied directory "{filename}"'
1442
1463
 
1443
1464
  async def _process_remote_item_copy_file(self: 'Cli', filename: str) -> str:
1465
+ remote_source_directory = self.cde_type['value']['remote-source-directory']
1466
+ if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
1467
+ raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
1444
1468
  await self.loop.run_in_executor(
1445
1469
  executor=None,
1446
1470
  func=functools.partial(
1447
1471
  self.sftp_client.get,
1448
- remotepath=f"{self.cde_type['value']['remote-source-directory']}/{filename}",
1472
+ remotepath=f'{remote_source_directory}/{filename}',
1449
1473
  localpath=str(self.local_source_directory / filename),
1450
1474
  ),
1451
1475
  )
1452
1476
  return f'Copied file "{filename}"'
1453
1477
 
1454
1478
  async def _process_remote_item_clone(self: 'Cli', filename: str) -> str:
1479
+ remote_username = self.cde_type['value']['remote-username']
1480
+ if re.match(r'[^a-zA-Z0-9]', remote_username):
1481
+ raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
1482
+ hostname = self.hostname
1483
+ if re.match(r'[^a-zA-Z0-9]', hostname):
1484
+ raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
1485
+ remote_source_directory = self.cde_type['value']['remote-source-directory']
1486
+ if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
1487
+ raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
1455
1488
  await run_subprocess(
1456
1489
  'git',
1457
1490
  [
1458
1491
  'clone',
1459
1492
  '-q',
1460
- f"{self.cde_type['value']['remote-username']}@{self.hostname}:{self.cde_type['value']['remote-source-directory']}/{filename}",
1493
+ f'{remote_username}@{hostname}:{remote_source_directory}/{filename}',
1461
1494
  ],
1462
1495
  name='Git clone',
1463
1496
  cwd=self.local_source_directory,
@@ -1472,7 +1505,7 @@ class Cli:
1472
1505
  shlex.join([
1473
1506
  'git',
1474
1507
  '-C',
1475
- f"{self.cde_type['value']['remote-source-directory']}/{filename}",
1508
+ f'{remote_source_directory}/{filename}',
1476
1509
  'config',
1477
1510
  '--get',
1478
1511
  'remote.origin.url',
@@ -1497,10 +1530,19 @@ class Cli:
1497
1530
  return f'Cloned repository "{filename}"'
1498
1531
 
1499
1532
  async def _background_sync(self: 'Cli') -> None:
1533
+ remote_username = self.cde_type['value']['remote-username']
1534
+ if re.match(r'[^a-zA-Z0-9]', remote_username):
1535
+ raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
1536
+ hostname = self.hostname
1537
+ if re.match(r'[^a-zA-Z0-9]', hostname):
1538
+ raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
1539
+ remote_source_directory = self.cde_type['value']['remote-source-directory']
1540
+ if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
1541
+ raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
1500
1542
  logger.debug('Starting background sync')
1501
1543
  self.local_source_directory.mkdir(parents=True, exist_ok=True)
1502
1544
  with contextlib.suppress(OSError):
1503
- self.sftp_client.mkdir(self.cde_type['value']['remote-source-directory'])
1545
+ self.sftp_client.mkdir(remote_source_directory)
1504
1546
  file_sync_exclusions = self.cde_type['value'].get('file-sync-exclusions')
1505
1547
  if file_sync_exclusions is None:
1506
1548
  file_sync_exclusions = [
@@ -1548,7 +1590,7 @@ class Cli:
1548
1590
  '--human-readable',
1549
1591
  '--verbose',
1550
1592
  f'{self.local_source_directory}/',
1551
- f"{self.cde_type['value']['remote-username']}@{self.hostname}:{self.cde_type['value']['remote-source-directory']}",
1593
+ f'{remote_username}@{hostname}:{remote_source_directory}',
1552
1594
  ],
1553
1595
  name='Background sync',
1554
1596
  print_to_debug_log=True,
@@ -1564,19 +1606,31 @@ class Cli:
1564
1606
  logger.info('Background sync done')
1565
1607
 
1566
1608
  async def _reverse_background_sync(self: 'Cli') -> None:
1609
+ remote_username = self.cde_type['value']['remote-username']
1610
+ if re.match(r'[^a-zA-Z0-9]', remote_username):
1611
+ raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
1612
+ hostname = self.hostname
1613
+ if re.match(r'[^a-zA-Z0-9]', hostname):
1614
+ raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
1615
+ remote_source_directory = self.cde_type['value']['remote-source-directory']
1616
+ if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
1617
+ raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
1567
1618
  logger.debug('Starting reverse background sync')
1619
+ remote_output_directory = self.cde_type['value']['remote-output-directory']
1620
+ if re.match(r'[^a-zA-Z0-9/_.-]', remote_output_directory):
1621
+ raise Exception(f'Invalid remote output directory: "{remote_output_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
1568
1622
  with contextlib.suppress(OSError):
1569
- self.sftp_client.mkdir(self.cde_type['value']['remote-output-directory'])
1623
+ self.sftp_client.mkdir(remote_output_directory)
1570
1624
  self.local_output_directory.mkdir(parents=True, exist_ok=True)
1571
1625
  try:
1572
- stdout, stderr = await run_subprocess(
1626
+ await run_subprocess(
1573
1627
  'rsync',
1574
1628
  [
1575
1629
  '-e', f'ssh -o ConnectTimeout=10 -o UserKnownHostsFile={self.known_hosts_file.name}',
1576
1630
  '--archive',
1577
1631
  '--exclude', '__pycache__',
1578
1632
  '--human-readable',
1579
- f"{self.cde_type['value']['remote-username']}@{self.hostname}:{self.cde_type['value']['remote-output-directory']}/",
1633
+ f'{remote_username}@{hostname}:{remote_output_directory}/',
1580
1634
  str(self.local_output_directory),
1581
1635
  ],
1582
1636
  name='Reverse background sync',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: devstack-cli
3
- Version: 11.0.84
3
+ Version: 11.0.85
4
4
  Summary: Command-line access to Cloud Development Environments (CDEs) created by Cloudomation DevStack
5
5
  Author-email: Stefan Mückstein <stefan@cloudomation.com>
6
6
  Project-URL: Homepage, https://cloudomation.com/
@@ -0,0 +1,9 @@
1
+ """
2
+ constants, set by build
3
+ """
4
+
5
+ MAJOR = '11'
6
+ BRANCH_NAME = 'release-11'
7
+ BUILD_DATE = '2025-02-10-115139'
8
+ SHORT_SHA = 'f9e1188'
9
+ VERSION = '11+release-11.2025-02-10-115139.f9e1188'
@@ -1,9 +0,0 @@
1
- """
2
- constants, set by build
3
- """
4
-
5
- MAJOR = '11'
6
- BRANCH_NAME = 'release-11'
7
- BUILD_DATE = '2025-02-10-112610'
8
- SHORT_SHA = '5cc11b4'
9
- VERSION = '11+release-11.2025-02-10-112610.5cc11b4'
File without changes
File without changes
File without changes