change: import the config files the user picks, not their whole directory #101

Merged
mysticalsoap merged 1 commit from change/multi-file-import into trunk 2026-08-20 19:07:31 -04:00
Owner

Problem

The custom-provider import was directory-shaped end to end: a single-file picker captioned "Choose Folder" discarded the chosen file, took its parent directory via absolutePath(), and the root service copytree'd that entire tree — guarded by sanity_check, which aborted when the folder held ten or more files outside an extension whitelist (a recursive count against a top-level import, with .crt missing from the whitelist). Importing one .ovpn out of ~/downloads was impossible; when import did work, unrelated files rode along into a root-owned directory.

Fix

  • GUI: getOpenFileNames multi-select, honestly captioned. The selection travels in the credentials dict as a JSON list under configfiles; folderpath is gone everywhere.
  • Importer: add_folderadd_config_files — copies exactly the selected files, plus the companion files (ca, cert, key, tls-auth, …) each config references relative to its own directory, which must travel with the config since openvpn resolves them against the imported copy's location (tunnel.py starts it with the config's dir as cwd). Absolute, inline, and directory-escaping references are left alone. sanity_check, the whole-tree copytree, and the dead cert_files assignment are deleted.
  • CLI: the prompt accepts a config file or a folder (expanded client-side to its top-level configs). update defaulting to "0" unbreaks the CLI import, which never sent that key.
  • Service: sweeps TEMPDIR at startup — an import interrupted by cancel_import or a crash never reaches remove_temp_dir, and a dangling temp dir from exactly that was found on this live install.

Verification

New TestFileSelectionImport in tests/test_update.py: one config out of a messy folder imports (the case that used to abort), companions travel (same dir, subdir, quoted names), absolute/inline refs untouched, missing companion warns but imports, ..-escaping ref refused, duplicate basenames keep the first, nothing-importable fails with the 3-field message and no temp leftovers. Full suite: 169 passed.

Live teardown exercised while testing: aqomui-cli --delete-provider removed the orphaned "ProtonVPN (manual)" dir (stale root-owned auth file included) even though no server referenced it.

Closes #74

🤖 Generated with Claude Code

**Problem** The custom-provider import was directory-shaped end to end: a single-file picker captioned "Choose Folder" discarded the chosen file, took its parent directory via `absolutePath()`, and the root service `copytree`'d that entire tree — guarded by `sanity_check`, which aborted when the folder held ten or more files outside an extension whitelist (a recursive count against a top-level import, with `.crt` missing from the whitelist). Importing one `.ovpn` out of `~/downloads` was impossible; when import did work, unrelated files rode along into a root-owned directory. **Fix** - GUI: `getOpenFileNames` multi-select, honestly captioned. The selection travels in the credentials dict as a JSON list under `configfiles`; `folderpath` is gone everywhere. - Importer: `add_folder` → `add_config_files` — copies exactly the selected files, plus the companion files (`ca`, `cert`, `key`, `tls-auth`, …) each config references *relative to its own directory*, which must travel with the config since openvpn resolves them against the imported copy's location (tunnel.py starts it with the config's dir as cwd). Absolute, inline, and directory-escaping references are left alone. `sanity_check`, the whole-tree `copytree`, and the dead `cert_files` assignment are deleted. - CLI: the prompt accepts a config file or a folder (expanded client-side to its top-level configs). `update` defaulting to `"0"` unbreaks the CLI import, which never sent that key. - Service: sweeps `TEMPDIR` at startup — an import interrupted by `cancel_import` or a crash never reaches `remove_temp_dir`, and a dangling temp dir from exactly that was found on this live install. **Verification** New `TestFileSelectionImport` in tests/test_update.py: one config out of a messy folder imports (the case that used to abort), companions travel (same dir, subdir, quoted names), absolute/inline refs untouched, missing companion warns but imports, `..`-escaping ref refused, duplicate basenames keep the first, nothing-importable fails with the 3-field message and no temp leftovers. Full suite: 169 passed. Live teardown exercised while testing: `aqomui-cli --delete-provider` removed the orphaned "ProtonVPN (manual)" dir (stale root-owned auth file included) even though no server referenced it. Closes #74 🤖 Generated with [Claude Code](https://claude.com/claude-code)
change: import the config files the user picks, not their whole directory
All checks were successful
ci / test (pull_request) Successful in 35s
ci / test (push) Successful in 27s
18e7088be7
The custom-provider import was directory-shaped end to end: a
single-file picker captioned "Choose Folder" discarded the chosen
file, took its parent directory, and the root service copytree'd that
entire tree -- guarded by a heuristic that aborted the import when the
folder held ten files outside an extension whitelist. Importing one
.ovpn out of a downloads directory was impossible, and nine unrelated
files rode along into a root-owned dir when it did work.

The picker is now multi-select and the importer consumes exactly the
selected files, plus the companion files (ca, cert, key, tls-auth ...)
each config references relative to its own directory -- those must
travel with the config since openvpn resolves them against the imported
copy's location. References that are absolute, inline, or escape the
config's directory are left alone. sanity_check, the whole-tree
copytree, and the dead cert_files assignment are gone.

The CLI prompt accepts a config file or a folder, expanding a folder to
its top-level configs client-side. The credentials dict carries the
selection as a JSON list under "configfiles"; "folderpath" is gone,
and "update" defaulting to "0" unbreaks the CLI import, which never
sent that key.

The service now also sweeps TEMPDIR at startup: an import interrupted
by cancel_import or a crash never reaches remove_temp_dir, and a
dangling temp dir from exactly that was found on a live install.

Closes #74

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mysticalsoap deleted branch change/multi-file-import 2026-08-20 19:07:31 -04:00
Sign in to join this conversation.
No description provided.