gitarsenal-cli 1.2.6 โ 1.2.8
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.
- package/package.json +1 -1
- package/python/README.md +6 -9
- package/python/modal_proxy_service.py +6 -120
- package/python/test_modalSandboxScript.py +7 -124
package/package.json
CHANGED
package/python/README.md
CHANGED
@@ -18,15 +18,12 @@ The GitArsenal CLI integrates with Modal for creating sandboxes and SSH containe
|
|
18
18
|
For enhanced security, GitArsenal CLI now automatically cleans up Modal tokens after SSH containers are created. This ensures that your Modal token is not left in the environment or on disk after the container is started.
|
19
19
|
|
20
20
|
The cleanup process:
|
21
|
-
1. Removes
|
22
|
-
2. Deletes
|
23
|
-
3.
|
24
|
-
4.
|
25
|
-
|
26
|
-
|
27
|
-
7. Runs on service shutdown via signal handlers
|
28
|
-
|
29
|
-
This prevents potential token leakage when containers are shared or when the service is stopped, and ensures that users cannot continue to use Modal CLI commands like `modal shell` after the container is created.
|
21
|
+
1. Removes Modal token environment variables (MODAL_TOKEN_ID, MODAL_TOKEN, MODAL_TOKEN_SECRET)
|
22
|
+
2. Deletes the ~/.modal.toml file which contains the authentication token
|
23
|
+
3. Runs automatically after SSH container creation
|
24
|
+
4. Runs on service shutdown via signal handlers
|
25
|
+
|
26
|
+
This simple but effective approach prevents potential token leakage when containers are shared or when the service is stopped, and ensures that users cannot continue to use Modal CLI commands like `modal shell` after the container is created.
|
30
27
|
|
31
28
|
## Usage
|
32
29
|
|
@@ -215,7 +215,7 @@ def cleanup_modal_token():
|
|
215
215
|
logger.info("๐งน Cleaning up Modal token for security...")
|
216
216
|
|
217
217
|
try:
|
218
|
-
# Remove
|
218
|
+
# Remove token from environment variables
|
219
219
|
if "MODAL_TOKEN_ID" in os.environ:
|
220
220
|
del os.environ["MODAL_TOKEN_ID"]
|
221
221
|
logger.info("โ
Removed MODAL_TOKEN_ID from environment")
|
@@ -228,127 +228,13 @@ def cleanup_modal_token():
|
|
228
228
|
del os.environ["MODAL_TOKEN_SECRET"]
|
229
229
|
logger.info("โ
Removed MODAL_TOKEN_SECRET from environment")
|
230
230
|
|
231
|
-
# Delete
|
231
|
+
# Delete ~/.modal.toml file
|
232
232
|
from pathlib import Path
|
233
|
-
|
234
|
-
if
|
235
|
-
|
236
|
-
|
237
|
-
if token_file.exists():
|
238
|
-
token_file.unlink()
|
239
|
-
logger.info(f"โ
Deleted token file at {token_file}")
|
240
|
-
|
241
|
-
# Delete token_alt.json if it exists
|
242
|
-
token_alt_file = modal_dir / "token_alt.json"
|
243
|
-
if token_alt_file.exists():
|
244
|
-
token_alt_file.unlink()
|
245
|
-
logger.info(f"โ
Deleted alternative token file at {token_alt_file}")
|
233
|
+
modal_toml = Path.home() / ".modal.toml"
|
234
|
+
if modal_toml.exists():
|
235
|
+
modal_toml.unlink()
|
236
|
+
logger.info(f"โ
Deleted Modal token file at {modal_toml}")
|
246
237
|
|
247
|
-
# Delete .modalconfig file
|
248
|
-
modalconfig_file = Path.home() / ".modalconfig"
|
249
|
-
if modalconfig_file.exists():
|
250
|
-
modalconfig_file.unlink()
|
251
|
-
logger.info(f"โ
Deleted .modalconfig file at {modalconfig_file}")
|
252
|
-
|
253
|
-
# Try to invalidate Modal sessions
|
254
|
-
try:
|
255
|
-
logger.info("๐ Invalidating Modal sessions...")
|
256
|
-
|
257
|
-
# Try to directly modify Modal's session files
|
258
|
-
try:
|
259
|
-
# Check for session files in .modal directory
|
260
|
-
session_dir = modal_dir / "sessions"
|
261
|
-
if session_dir.exists():
|
262
|
-
import shutil
|
263
|
-
shutil.rmtree(session_dir)
|
264
|
-
logger.info(f"โ
Removed Modal sessions directory at {session_dir}")
|
265
|
-
|
266
|
-
# Also check for any other potential session files
|
267
|
-
for file in os.listdir(modal_dir) if modal_dir.exists() else []:
|
268
|
-
if "session" in file.lower() or "auth" in file.lower():
|
269
|
-
file_path = modal_dir / file
|
270
|
-
if file_path.is_file():
|
271
|
-
file_path.unlink()
|
272
|
-
logger.info(f"โ
Removed Modal session file: {file_path}")
|
273
|
-
except Exception as e:
|
274
|
-
logger.warning(f"โ ๏ธ Error removing Modal sessions: {e}")
|
275
|
-
|
276
|
-
except Exception as e:
|
277
|
-
logger.warning(f"โ ๏ธ Error during Modal session invalidation: {e}")
|
278
|
-
|
279
|
-
# Create corrupted token files that will cause Modal CLI to fail
|
280
|
-
try:
|
281
|
-
logger.info("๐ Creating corrupted Modal token files...")
|
282
|
-
|
283
|
-
# Create .modal directory if it doesn't exist
|
284
|
-
if not modal_dir.exists():
|
285
|
-
modal_dir.mkdir(parents=True)
|
286
|
-
logger.info(f"โ
Created Modal directory at {modal_dir}")
|
287
|
-
|
288
|
-
# Create a corrupted token.json file
|
289
|
-
token_file = modal_dir / "token.json"
|
290
|
-
with open(token_file, 'w') as f:
|
291
|
-
f.write('{"corrupted": true, "message": "Token has been invalidated for security reasons"}')
|
292
|
-
logger.info(f"โ
Created corrupted token file at {token_file}")
|
293
|
-
|
294
|
-
# Create a corrupted .modalconfig file
|
295
|
-
modalconfig_file = Path.home() / ".modalconfig"
|
296
|
-
with open(modalconfig_file, 'w') as f:
|
297
|
-
f.write("# This file has been corrupted for security reasons\n")
|
298
|
-
f.write("corrupted = true\n")
|
299
|
-
logger.info(f"โ
Created corrupted .modalconfig file at {modalconfig_file}")
|
300
|
-
|
301
|
-
# Try to disable the modal shell command specifically
|
302
|
-
try:
|
303
|
-
# Find the modal executable path
|
304
|
-
result = subprocess.run(
|
305
|
-
["which", "modal"],
|
306
|
-
capture_output=True,
|
307
|
-
text=True
|
308
|
-
)
|
309
|
-
modal_path = result.stdout.strip()
|
310
|
-
|
311
|
-
if modal_path:
|
312
|
-
logger.info(f"๐ Found Modal CLI at: {modal_path}")
|
313
|
-
|
314
|
-
# Create a wrapper script that intercepts the shell command
|
315
|
-
modal_shell_wrapper = """#!/bin/bash
|
316
|
-
if [[ "$1" == "shell" ]]; then
|
317
|
-
echo "โ Modal shell has been disabled for security reasons."
|
318
|
-
echo "Modal token has been removed after SSH container creation."
|
319
|
-
exit 1
|
320
|
-
fi
|
321
|
-
|
322
|
-
# Pass all other commands to the real modal CLI
|
323
|
-
REAL_MODAL=$(which modal.real 2>/dev/null)
|
324
|
-
if [ -n "$REAL_MODAL" ]; then
|
325
|
-
exec "$REAL_MODAL" "$@"
|
326
|
-
else
|
327
|
-
echo "โ Modal CLI has been disabled for security reasons."
|
328
|
-
echo "Modal token has been removed after SSH container creation."
|
329
|
-
exit 1
|
330
|
-
fi
|
331
|
-
"""
|
332
|
-
|
333
|
-
# Rename the original modal executable
|
334
|
-
os.rename(modal_path, f"{modal_path}.real")
|
335
|
-
logger.info(f"โ
Renamed original Modal CLI to {modal_path}.real")
|
336
|
-
|
337
|
-
# Create a new modal script
|
338
|
-
with open(modal_path, 'w') as f:
|
339
|
-
f.write(modal_shell_wrapper)
|
340
|
-
|
341
|
-
# Make it executable
|
342
|
-
os.chmod(modal_path, 0o755)
|
343
|
-
logger.info(f"โ
Created Modal CLI wrapper at {modal_path}")
|
344
|
-
else:
|
345
|
-
logger.warning("โ ๏ธ Could not find Modal CLI path")
|
346
|
-
except Exception as e:
|
347
|
-
logger.warning(f"โ ๏ธ Error creating Modal CLI wrapper: {e}")
|
348
|
-
|
349
|
-
except Exception as e:
|
350
|
-
logger.warning(f"โ ๏ธ Error creating corrupted token files: {e}")
|
351
|
-
|
352
238
|
logger.info("โ
Modal token cleanup completed successfully")
|
353
239
|
except Exception as e:
|
354
240
|
logger.error(f"โ Error during Modal token cleanup: {e}")
|
@@ -3298,7 +3298,7 @@ def cleanup_modal_token():
|
|
3298
3298
|
print("๐งน Cleaning up Modal token for security...")
|
3299
3299
|
|
3300
3300
|
try:
|
3301
|
-
# Remove
|
3301
|
+
# Remove token from environment variables
|
3302
3302
|
if "MODAL_TOKEN_ID" in os.environ:
|
3303
3303
|
del os.environ["MODAL_TOKEN_ID"]
|
3304
3304
|
print("โ
Removed MODAL_TOKEN_ID from environment")
|
@@ -3311,130 +3311,13 @@ def cleanup_modal_token():
|
|
3311
3311
|
del os.environ["MODAL_TOKEN_SECRET"]
|
3312
3312
|
print("โ
Removed MODAL_TOKEN_SECRET from environment")
|
3313
3313
|
|
3314
|
-
# Delete
|
3314
|
+
# Delete ~/.modal.toml file
|
3315
3315
|
home_dir = os.path.expanduser("~")
|
3316
|
-
|
3317
|
-
if os.path.exists(
|
3318
|
-
|
3319
|
-
|
3320
|
-
|
3321
|
-
os.remove(token_file)
|
3322
|
-
print(f"โ
Deleted token file at {token_file}")
|
3323
|
-
|
3324
|
-
# Delete token_alt.json if it exists
|
3325
|
-
token_alt_file = os.path.join(modal_dir, "token_alt.json")
|
3326
|
-
if os.path.exists(token_alt_file):
|
3327
|
-
os.remove(token_alt_file)
|
3328
|
-
print(f"โ
Deleted alternative token file at {token_alt_file}")
|
3329
|
-
|
3330
|
-
# Delete .modalconfig file
|
3331
|
-
modalconfig_file = os.path.join(home_dir, ".modalconfig")
|
3332
|
-
if os.path.exists(modalconfig_file):
|
3333
|
-
os.remove(modalconfig_file)
|
3334
|
-
print(f"โ
Deleted .modalconfig file at {modalconfig_file}")
|
3335
|
-
|
3336
|
-
# Try to invalidate Modal sessions
|
3337
|
-
try:
|
3338
|
-
print("๐ Invalidating Modal sessions...")
|
3339
|
-
|
3340
|
-
# Try to directly modify Modal's session files
|
3341
|
-
try:
|
3342
|
-
# Check for session files in .modal directory
|
3343
|
-
session_dir = os.path.join(modal_dir, "sessions")
|
3344
|
-
if os.path.exists(session_dir):
|
3345
|
-
import shutil
|
3346
|
-
shutil.rmtree(session_dir)
|
3347
|
-
print(f"โ
Removed Modal sessions directory at {session_dir}")
|
3348
|
-
|
3349
|
-
# Also check for any other potential session files
|
3350
|
-
for file in os.listdir(modal_dir) if os.path.exists(modal_dir) else []:
|
3351
|
-
if "session" in file.lower() or "auth" in file.lower():
|
3352
|
-
file_path = os.path.join(modal_dir, file)
|
3353
|
-
if os.path.isfile(file_path):
|
3354
|
-
os.remove(file_path)
|
3355
|
-
print(f"โ
Removed Modal session file: {file_path}")
|
3356
|
-
except Exception as e:
|
3357
|
-
print(f"โ ๏ธ Error removing Modal sessions: {e}")
|
3358
|
-
|
3359
|
-
except Exception as e:
|
3360
|
-
print(f"โ ๏ธ Error during Modal session invalidation: {e}")
|
3361
|
-
|
3362
|
-
# Create corrupted token files that will cause Modal CLI to fail
|
3363
|
-
try:
|
3364
|
-
print("๐ Creating corrupted Modal token files...")
|
3365
|
-
|
3366
|
-
# Create .modal directory if it doesn't exist
|
3367
|
-
if not os.path.exists(modal_dir):
|
3368
|
-
os.makedirs(modal_dir)
|
3369
|
-
print(f"โ
Created Modal directory at {modal_dir}")
|
3370
|
-
|
3371
|
-
# Create a corrupted token.json file
|
3372
|
-
token_file = os.path.join(modal_dir, "token.json")
|
3373
|
-
with open(token_file, 'w') as f:
|
3374
|
-
f.write('{"corrupted": true, "message": "Token has been invalidated for security reasons"}')
|
3375
|
-
print(f"โ
Created corrupted token file at {token_file}")
|
3376
|
-
|
3377
|
-
# Create a corrupted .modalconfig file
|
3378
|
-
modalconfig_file = os.path.join(home_dir, ".modalconfig")
|
3379
|
-
with open(modalconfig_file, 'w') as f:
|
3380
|
-
f.write("# This file has been corrupted for security reasons\n")
|
3381
|
-
f.write("corrupted = true\n")
|
3382
|
-
print(f"โ
Created corrupted .modalconfig file at {modalconfig_file}")
|
3383
|
-
|
3384
|
-
# Try to disable the modal shell command specifically
|
3385
|
-
try:
|
3386
|
-
import subprocess
|
3387
|
-
import sys
|
3388
|
-
|
3389
|
-
# Find the modal executable path
|
3390
|
-
result = subprocess.run(
|
3391
|
-
["which", "modal"],
|
3392
|
-
capture_output=True,
|
3393
|
-
text=True
|
3394
|
-
)
|
3395
|
-
modal_path = result.stdout.strip()
|
3396
|
-
|
3397
|
-
if modal_path:
|
3398
|
-
print(f"๐ Found Modal CLI at: {modal_path}")
|
3399
|
-
|
3400
|
-
# Create a wrapper script that intercepts the shell command
|
3401
|
-
modal_shell_wrapper = """#!/bin/bash
|
3402
|
-
if [[ "$1" == "shell" ]]; then
|
3403
|
-
echo "โ Modal shell has been disabled for security reasons."
|
3404
|
-
echo "Modal token has been removed after SSH container creation."
|
3405
|
-
exit 1
|
3406
|
-
fi
|
3407
|
-
|
3408
|
-
# Pass all other commands to the real modal CLI
|
3409
|
-
REAL_MODAL=$(which modal.real 2>/dev/null)
|
3410
|
-
if [ -n "$REAL_MODAL" ]; then
|
3411
|
-
exec "$REAL_MODAL" "$@"
|
3412
|
-
else
|
3413
|
-
echo "โ Modal CLI has been disabled for security reasons."
|
3414
|
-
echo "Modal token has been removed after SSH container creation."
|
3415
|
-
exit 1
|
3416
|
-
fi
|
3417
|
-
"""
|
3418
|
-
|
3419
|
-
# Rename the original modal executable
|
3420
|
-
os.rename(modal_path, f"{modal_path}.real")
|
3421
|
-
print(f"โ
Renamed original Modal CLI to {modal_path}.real")
|
3422
|
-
|
3423
|
-
# Create a new modal script
|
3424
|
-
with open(modal_path, 'w') as f:
|
3425
|
-
f.write(modal_shell_wrapper)
|
3426
|
-
|
3427
|
-
# Make it executable
|
3428
|
-
os.chmod(modal_path, 0o755)
|
3429
|
-
print(f"โ
Created Modal CLI wrapper at {modal_path}")
|
3430
|
-
else:
|
3431
|
-
print("โ ๏ธ Could not find Modal CLI path")
|
3432
|
-
except Exception as e:
|
3433
|
-
print(f"โ ๏ธ Error creating Modal CLI wrapper: {e}")
|
3434
|
-
|
3435
|
-
except Exception as e:
|
3436
|
-
print(f"โ ๏ธ Error creating corrupted token files: {e}")
|
3437
|
-
|
3316
|
+
modal_toml = os.path.join(home_dir, ".modal.toml")
|
3317
|
+
if os.path.exists(modal_toml):
|
3318
|
+
os.remove(modal_toml)
|
3319
|
+
print(f"โ
Deleted Modal token file at {modal_toml}")
|
3320
|
+
|
3438
3321
|
print("โ
Modal token cleanup completed successfully")
|
3439
3322
|
except Exception as e:
|
3440
3323
|
print(f"โ Error during Modal token cleanup: {e}")
|