caffeinated-whale-cli 3.1.2__tar.gz → 3.1.3__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.
Files changed (99) hide show
  1. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/PKG-INFO +1 -1
  2. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/pyproject.toml +1 -1
  3. caffeinated_whale_cli-3.1.3/src/caffeinated_whale_cli/__init__.py +1 -0
  4. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/credbridge.py +5 -0
  5. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/cred_daemon.py +17 -6
  6. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/shared_home.py +27 -0
  7. caffeinated_whale_cli-3.1.2/src/caffeinated_whale_cli/__init__.py +0 -1
  8. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/LICENSE +0 -0
  9. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/README.md +0 -0
  10. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/setup.cfg +0 -0
  11. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/__main__.py +0 -0
  12. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/__init__.py +0 -0
  13. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/apps.py +0 -0
  14. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/axi.py +0 -0
  15. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/backup.py +0 -0
  16. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/config.py +0 -0
  17. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/console.html +0 -0
  18. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/doctor.py +0 -0
  19. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/init.py +0 -0
  20. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/inspect.py +0 -0
  21. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/label.py +0 -0
  22. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/list.py +0 -0
  23. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/logs.py +0 -0
  24. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/open.py +0 -0
  25. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/restart.py +0 -0
  26. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/restore.py +0 -0
  27. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/rm.py +0 -0
  28. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/rm_bench.py +0 -0
  29. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/rm_site.py +0 -0
  30. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/run.py +0 -0
  31. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/scale.py +0 -0
  32. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/self_update.py +0 -0
  33. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/serve.py +0 -0
  34. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/setup.py +0 -0
  35. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/start.py +0 -0
  36. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/status.py +0 -0
  37. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/stop.py +0 -0
  38. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/unlock.py +0 -0
  39. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/update.py +0 -0
  40. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/utils.py +0 -0
  41. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/commands/where.py +0 -0
  42. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/__init__.py +0 -0
  43. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/apps.py +0 -0
  44. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/auto_inspect.py +0 -0
  45. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/backup.py +0 -0
  46. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/bench_ops.py +0 -0
  47. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/config.py +0 -0
  48. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/cred_bridge.py +0 -0
  49. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/docker.py +0 -0
  50. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/doctor.py +0 -0
  51. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/envelope.py +0 -0
  52. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/errors.py +0 -0
  53. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/exec_stream.py +0 -0
  54. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/fleet.py +0 -0
  55. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/init.py +0 -0
  56. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/inspect.py +0 -0
  57. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/label.py +0 -0
  58. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/list.py +0 -0
  59. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/logs.py +0 -0
  60. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/open.py +0 -0
  61. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/resolvers.py +0 -0
  62. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/restart.py +0 -0
  63. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/restore.py +0 -0
  64. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/rm.py +0 -0
  65. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/rm_bench.py +0 -0
  66. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/rm_site.py +0 -0
  67. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/run.py +0 -0
  68. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/scale.py +0 -0
  69. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/setup.py +0 -0
  70. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/start.py +0 -0
  71. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/status.py +0 -0
  72. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/stop.py +0 -0
  73. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/supervision.py +0 -0
  74. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/unlock.py +0 -0
  75. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/update.py +0 -0
  76. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/url.py +0 -0
  77. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/version.py +0 -0
  78. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/core/where.py +0 -0
  79. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/main.py +0 -0
  80. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/update_notice.py +0 -0
  81. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/__init__.py +0 -0
  82. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/agent_hooks.py +0 -0
  83. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/auto_inspect.py +0 -0
  84. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/bench_labels.py +0 -0
  85. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/bench_sites.py +0 -0
  86. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/cache.py +0 -0
  87. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/completion_utils.py +0 -0
  88. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/config_utils.py +0 -0
  89. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/console.py +0 -0
  90. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/daemon_identity.py +0 -0
  91. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/db_utils.py +0 -0
  92. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/docker_utils.py +0 -0
  93. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/port_utils.py +0 -0
  94. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/sendme_utils.py +0 -0
  95. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/startup.py +0 -0
  96. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/tips.py +0 -0
  97. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/toon.py +0 -0
  98. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli/utils/vscode_utils.py +0 -0
  99. {caffeinated_whale_cli-3.1.2 → caffeinated_whale_cli-3.1.3}/src/caffeinated_whale_cli.egg-info/SOURCES.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: caffeinated-whale-cli
3
- Version: 3.1.2
3
+ Version: 3.1.3
4
4
  Summary: A CLI tool to help manage Frappe Docker instances.
5
5
  Author-email: Christopher McKay <mckay.christopher73@outlook.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "caffeinated-whale-cli"
7
- version = "3.1.2"
7
+ version = "3.1.3"
8
8
  authors = [
9
9
  { name = "Christopher McKay", email = "mckay.christopher73@outlook.com" },
10
10
  ]
@@ -0,0 +1 @@
1
+ __version__ = "3.1.3"
@@ -465,6 +465,11 @@ def credential_bridge(container, bench_path: str) -> Iterator[None]:
465
465
  sock_name = _SOCK_NAME_FMT.format(uid)
466
466
  sock_host = host_dir / sock_name
467
467
  helper_host.write_text(_CONTAINER_HELPER_SRC.format(sock_name=sock_name))
468
+ # The container's frappe git process (a different uid - image default,
469
+ # aligned host uid, or the low shared-mode service uid) must be able to
470
+ # OPEN this shim; make it world-readable so it can, regardless of
471
+ # alignment. See shared_home.secure_bridge_helper.
472
+ shared_home.secure_bridge_helper(helper_host)
468
473
  with contextlib.suppress(FileNotFoundError):
469
474
  sock_host.unlink()
470
475
 
@@ -295,6 +295,11 @@ def ensure_bridge(container, bench_path: str, project_name: str) -> EnsureOutcom
295
295
  else:
296
296
  with contextlib.suppress(OSError):
297
297
  helper_host.write_text(credbridge.persistent_helper_unix())
298
+ # This ensure runs as whoever launched open/start (often NOT the
299
+ # service account the daemon and remapped frappe user share), so
300
+ # make the shim world-readable for that frappe uid. See
301
+ # shared_home.secure_bridge_helper.
302
+ shared_home.secure_bridge_helper(helper_host)
298
303
 
299
304
  config_value, added = _ensure_container_config(container, container_dir)
300
305
 
@@ -370,9 +375,12 @@ def disable_bridge_artifacts() -> None:
370
375
  for project, ws in registry.items():
371
376
  host_dir = Path(ws)
372
377
  with contextlib.suppress(OSError):
373
- (host_dir / credbridge.PERSISTENT_HELPER_NAME).write_text(
374
- credbridge.persistent_helper_stub()
375
- )
378
+ stub = host_dir / credbridge.PERSISTENT_HELPER_NAME
379
+ stub.write_text(credbridge.persistent_helper_stub())
380
+ # git may still be pointed at this shim (a container that missed the
381
+ # config unset); the frappe uid must be able to READ it or git hard-
382
+ # errors instead of the intended silent no-op. See secure_bridge_helper.
383
+ shared_home.secure_bridge_helper(stub)
376
384
  with contextlib.suppress(OSError):
377
385
  (host_dir / credbridge.PERSISTENT_SOCK_NAME).unlink(missing_ok=True)
378
386
  _best_effort_container_unset(project)
@@ -432,9 +440,12 @@ def _start_unix_listener(
432
440
  with contextlib.suppress(FileNotFoundError):
433
441
  sock_path.unlink()
434
442
  with contextlib.suppress(OSError):
435
- (host_dir / credbridge.PERSISTENT_HELPER_NAME).write_text(
436
- credbridge.persistent_helper_unix()
437
- )
443
+ helper = host_dir / credbridge.PERSISTENT_HELPER_NAME
444
+ helper.write_text(credbridge.persistent_helper_unix())
445
+ # Readable by the container frappe uid regardless of alignment (the shim
446
+ # carries no secret; the credential stays behind the socket below). See
447
+ # shared_home.secure_bridge_helper.
448
+ shared_home.secure_bridge_helper(helper)
438
449
 
439
450
  srv = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
440
451
  prev_cwd = os.getcwd()
@@ -196,6 +196,33 @@ def secure_file_shared_only(path: Path | str) -> None:
196
196
  apply_group(path)
197
197
 
198
198
 
199
+ def secure_bridge_helper(path: Path | str) -> None:
200
+ """Make a credential-bridge helper SCRIPT readable by the container git process.
201
+
202
+ git runs the shim via ``!/usr/bin/python3 <shim>``, so python OPENS the ``.py``
203
+ as the container's ``frappe`` user - a DIFFERENT identity from whoever wrote
204
+ it: the image default uid 1000, the aligned host uid, or (shared mode) the low
205
+ ``cwcli`` service uid. An umask-derived mode plus incidental setgid group
206
+ inheritance does not reliably grant that user READ, so git dies with
207
+ ``[Errno 13] Permission denied`` opening the shim before it can even reach the
208
+ socket. Make it world-READABLE (``0644``) so any container uid can open it
209
+ regardless of alignment - the 0666-socket rationale, for a file that only
210
+ needs read. Called after EVERY shim (re)write, because the shim is regenerated
211
+ per invocation / per boot.
212
+
213
+ Safe to widen the read: the AF_UNIX shim carries NO secret (the credential
214
+ lives behind the socket, which stays group-gated), so exposing the shim only
215
+ reveals the socket path a non-group user still cannot connect to. ``0644`` is
216
+ NOT group/world WRITABLE, so it is no code-injection vector for a file git
217
+ executes - it in fact TIGHTENS the prior umask-``0660`` group-writable shim in
218
+ shared mode. NOT for the TCP shim, which bakes the per-invocation auth token;
219
+ that transport is Docker Desktop, which has no host-uid remap and reads the
220
+ bind mount through its file-sharing layer regardless of host perms.
221
+ """
222
+ with contextlib.suppress(OSError):
223
+ os.chmod(path, 0o644)
224
+
225
+
199
226
  def apply_process_umask() -> None:
200
227
  """Relax the process umask to 0007 in shared mode, so incidental files cwcli
201
228
  (or a library) creates inside the setgid tree stay group-writable without an
@@ -1 +0,0 @@
1
- __version__ = "3.1.2"