Webapp redesign: fixes from the functional regression test

- Unattend: a command's '...' menu stayed open after Move up/down and
  covered the next row's menu, so the next click could stage removing the
  wrong command. The menu now closes and focus returns to its button.
- '...' menus close on an outside click, on Escape and when another
  opens (static/app.js), for every page.
- Drivers: Remove asks to confirm again, as before the redesign. Long zip
  paths in a row body wrap (the page scrolled sideways at 390 px).
- Rollback review returns to the page it was opened from (Dell page or
  Updates overview), for both Cancel and the rollback itself.
- To-do: the ServiceNow period offers a year again (366 days).
- Imaging floor: a search that matches a log-only bay opens that group;
  its open state survives the live refresh. 'Clear all' states the
  number of session files it deletes, hidden finished ones included.
- Dashboard: the image key pattern is valid under the browser's v flag
  (client-side validation was silently skipped).
- Import: allowed_import_source() compares real paths, so
  '<upload dir>/../..' is refused. This path traversal predates the
  redesign; the import moves the source tree, so it mattered.
This commit is contained in:
cproudlock
2026-10-14 14:48:10 -04:00
parent 2bcc9d8016
commit 2ed2cbe2e9
11 changed files with 61 additions and 15 deletions

View File

@@ -105,9 +105,12 @@ def import_deploy(src_deploy, dst_deploy, target="", move=False):
def allowed_import_source(source):
"""True if source is a USB mount or under the upload dir."""
usb = find_usb_mounts()
if any(source == m or source.startswith(m + "/") for m in usb):
# Compare real paths: "<upload dir>/../.." passes a plain prefix test.
real = os.path.realpath(source)
usb = [os.path.realpath(m) for m in find_usb_mounts()]
if any(real == m or real.startswith(m + "/") for m in usb):
return True
if source == config.UPLOAD_DIR or source.startswith(config.UPLOAD_DIR + "/"):
return os.path.isdir(source)
up = os.path.realpath(config.UPLOAD_DIR)
if real == up or real.startswith(up + "/"):
return os.path.isdir(real)
return False