@cyanautomation/kaseki-agent 1.31.0 → 1.32.0
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/README.md +1 -1
- package/package.json +1 -1
- package/scripts/startup-checks.sh +157 -8
package/README.md
CHANGED
|
@@ -1373,7 +1373,7 @@ to opt out of GitHub publishing for a specific API run.
|
|
|
1373
1373
|
| Variable | Default | Notes |
|
|
1374
1374
|
|---|---|---|
|
|
1375
1375
|
| `OPENROUTER_API_KEY` | — | Required (or use file) |
|
|
1376
|
-
| `OPENROUTER_API_KEY_FILE` |
|
|
1376
|
+
| `OPENROUTER_API_KEY_FILE` | `~/.kaseki/secrets.json` | Preferred; set by setup wizard |
|
|
1377
1377
|
| `REPO_URL` | CyanAutomation/crudmapper | Target repository |
|
|
1378
1378
|
| `GIT_REF` | main | Branch/tag/commit |
|
|
1379
1379
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanautomation/kaseki-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "Admin/helper/doctor toolbox and local API client for Kaseki diagnostics, setup, and API-backed coding-agent task workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -303,6 +303,101 @@ is_path_on_readonly_mount() {
|
|
|
303
303
|
return 1 # Not read-only
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
# Check if a file is readable by UID 10000 OR GID 10000 (group-based access)
|
|
307
|
+
# This is important for read-only mounts where we can't change permissions
|
|
308
|
+
is_file_readable_by_uid_or_gid() {
|
|
309
|
+
local file_path="$1"
|
|
310
|
+
local uid="${2:-$CONTAINER_UID}"
|
|
311
|
+
local gid="${3:-$CONTAINER_GID}"
|
|
312
|
+
|
|
313
|
+
if [ ! -f "$file_path" ]; then
|
|
314
|
+
return 1
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
# Test direct readability
|
|
318
|
+
if [ -r "$file_path" ]; then
|
|
319
|
+
return 0
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
# Check if file is readable by our group
|
|
323
|
+
local mode
|
|
324
|
+
mode=$(get_current_permissions "$file_path")
|
|
325
|
+
|
|
326
|
+
if [ "$mode" = "unknown" ] || [ "$mode" = "nonexistent" ]; then
|
|
327
|
+
return 1
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
# Extract group read permission (second digit in octal mode)
|
|
331
|
+
# For mode like 0640: group digit is 4 (read permission)
|
|
332
|
+
local group_digit
|
|
333
|
+
group_digit=$(echo "$mode" | cut -c2)
|
|
334
|
+
|
|
335
|
+
# Check if group has read permission (4 = read)
|
|
336
|
+
if [ "$group_digit" -ge 4 ] && [ "$group_digit" -le 7 ]; then
|
|
337
|
+
# Group has read permission - verify our GID matches
|
|
338
|
+
local file_gid
|
|
339
|
+
if command -v stat &>/dev/null; then
|
|
340
|
+
file_gid=$(stat -c "%g" "$file_path" 2>/dev/null || echo "unknown")
|
|
341
|
+
else
|
|
342
|
+
file_gid=$(ls -ld "$file_path" 2>/dev/null | awk '{print $4}' || echo "unknown")
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
# If file GID matches our GID, we can read it via group membership
|
|
346
|
+
if [ "$file_gid" = "$gid" ]; then
|
|
347
|
+
return 0
|
|
348
|
+
fi
|
|
349
|
+
fi
|
|
350
|
+
|
|
351
|
+
return 1
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
# Check if a directory is traversable by UID or GID (for group-based access)
|
|
355
|
+
is_directory_traversable_by_uid_or_gid() {
|
|
356
|
+
local dir_path="$1"
|
|
357
|
+
local uid="${2:-$CONTAINER_UID}"
|
|
358
|
+
local gid="${3:-$CONTAINER_GID}"
|
|
359
|
+
|
|
360
|
+
if [ ! -d "$dir_path" ]; then
|
|
361
|
+
return 1
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
# Test direct traversability
|
|
365
|
+
if [ -x "$dir_path" ]; then
|
|
366
|
+
return 0
|
|
367
|
+
fi
|
|
368
|
+
|
|
369
|
+
# Check if directory is traversable by our group
|
|
370
|
+
local mode
|
|
371
|
+
mode=$(get_current_permissions "$dir_path")
|
|
372
|
+
|
|
373
|
+
if [ "$mode" = "unknown" ] || [ "$mode" = "nonexistent" ]; then
|
|
374
|
+
return 1
|
|
375
|
+
fi
|
|
376
|
+
|
|
377
|
+
# Extract group execute permission (second digit in octal mode)
|
|
378
|
+
# For mode like 0750: group digit is 5 (read+execute permission)
|
|
379
|
+
local group_digit
|
|
380
|
+
group_digit=$(echo "$mode" | cut -c2)
|
|
381
|
+
|
|
382
|
+
# Check if group has execute permission (1, 3, 5, 7)
|
|
383
|
+
# The last bit (1) means execute, so odd numbers have execute
|
|
384
|
+
if [ "$((group_digit % 2))" -eq 1 ]; then
|
|
385
|
+
# Group has execute permission - verify our GID matches
|
|
386
|
+
local dir_gid
|
|
387
|
+
if command -v stat &>/dev/null; then
|
|
388
|
+
dir_gid=$(stat -c "%g" "$dir_path" 2>/dev/null || echo "unknown")
|
|
389
|
+
else
|
|
390
|
+
dir_gid=$(ls -ld "$dir_path" 2>/dev/null | awk '{print $4}' || echo "unknown")
|
|
391
|
+
fi
|
|
392
|
+
|
|
393
|
+
if [ "$dir_gid" = "$gid" ]; then
|
|
394
|
+
return 0
|
|
395
|
+
fi
|
|
396
|
+
fi
|
|
397
|
+
|
|
398
|
+
return 1
|
|
399
|
+
}
|
|
400
|
+
|
|
306
401
|
get_current_permissions() {
|
|
307
402
|
local path="$1"
|
|
308
403
|
|
|
@@ -420,9 +515,28 @@ check_directory_traversable() {
|
|
|
420
515
|
return 2
|
|
421
516
|
fi
|
|
422
517
|
else
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
518
|
+
# Check if this is a read-only mount
|
|
519
|
+
if is_path_on_readonly_mount "$dir_path"; then
|
|
520
|
+
# Check if directory is traversable by group
|
|
521
|
+
if is_directory_traversable_by_uid_or_gid "$dir_path"; then
|
|
522
|
+
log_warn "$dir_name is on a read-only mount but is traversable by GID $CONTAINER_GID"
|
|
523
|
+
log_warn "Note: Some operations may fail if they require write access"
|
|
524
|
+
return 3 # Warning: accessible but on read-only mount
|
|
525
|
+
fi
|
|
526
|
+
|
|
527
|
+
# Not traversable even by group
|
|
528
|
+
log_error "$dir_name is on a read-only mount and not traversable"
|
|
529
|
+
log_error ""
|
|
530
|
+
log_error "To fix on HOST (before docker-compose up or container start):"
|
|
531
|
+
log_error " sudo chmod 0750 $dir_path"
|
|
532
|
+
log_error ""
|
|
533
|
+
return 2
|
|
534
|
+
else
|
|
535
|
+
# Writable mount but still can't fix permissions
|
|
536
|
+
log_error "Cannot auto-fix $dir_name permissions"
|
|
537
|
+
log_error " sudo chmod 0750 $dir_path"
|
|
538
|
+
return 2
|
|
539
|
+
fi
|
|
426
540
|
fi
|
|
427
541
|
fi
|
|
428
542
|
|
|
@@ -450,11 +564,40 @@ check_file_readable() {
|
|
|
450
564
|
return 2
|
|
451
565
|
fi
|
|
452
566
|
else
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
567
|
+
# Check if this is a read-only mount
|
|
568
|
+
if is_path_on_readonly_mount "$file_path"; then
|
|
569
|
+
# Check if file is readable by group
|
|
570
|
+
if is_file_readable_by_uid_or_gid "$file_path"; then
|
|
571
|
+
log_warn "$file_name is on a read-only mount but is readable by GID $CONTAINER_GID"
|
|
572
|
+
log_warn "Note: Using group-based access from UID $CONTAINER_UID"
|
|
573
|
+
return 3 # Warning: accessible but on read-only mount
|
|
574
|
+
fi
|
|
575
|
+
|
|
576
|
+
# Not readable even by group - must fix on host
|
|
577
|
+
log_error "$file_name is on a read-only mount and not readable"
|
|
578
|
+
log_error ""
|
|
579
|
+
log_error "To fix on HOST (before docker-compose up or container start):"
|
|
580
|
+
local dir_path
|
|
581
|
+
dir_path=$(dirname "$file_path")
|
|
582
|
+
# Get current mode for helpful feedback
|
|
583
|
+
local current_mode
|
|
584
|
+
current_mode=$(get_current_permissions "$file_path")
|
|
585
|
+
log_error " Current mode: $current_mode"
|
|
586
|
+
log_error " Fix: sudo chmod 0640 $file_path"
|
|
587
|
+
log_error " Or: sudo chmod 0644 $file_path (world-readable)"
|
|
588
|
+
log_error ""
|
|
589
|
+
log_error "Make sure parent directory is traversable:"
|
|
590
|
+
log_error " sudo chmod 0750 $dir_path"
|
|
591
|
+
log_error ""
|
|
592
|
+
return 2
|
|
593
|
+
else
|
|
594
|
+
# Writable mount but still can't fix permissions
|
|
595
|
+
log_error "Cannot auto-fix $file_name permissions"
|
|
596
|
+
local dir_path
|
|
597
|
+
dir_path=$(dirname "$file_path")
|
|
598
|
+
log_error " sudo chmod 0640 $file_path"
|
|
599
|
+
return 2
|
|
600
|
+
fi
|
|
458
601
|
fi
|
|
459
602
|
fi
|
|
460
603
|
|
|
@@ -518,6 +661,12 @@ check_api_key() {
|
|
|
518
661
|
if [ -n "$api_key_file" ] && [ -f "$api_key_file" ]; then
|
|
519
662
|
if [ -r "$api_key_file" ]; then
|
|
520
663
|
log_pass "OPENROUTER_API_KEY_FILE is readable ($api_key_file)"
|
|
664
|
+
# Warn if using legacy Docker secrets path
|
|
665
|
+
if [[ "$api_key_file" == "/run/secrets/"* ]]; then
|
|
666
|
+
log_warn "Using legacy Docker secrets path: $api_key_file"
|
|
667
|
+
log_info " Migrate to ~/.kaseki/secrets.json for better portability"
|
|
668
|
+
log_info " See docs/TROUBLESHOOTING.md#migrating-from-legacy-docker-secrets"
|
|
669
|
+
fi
|
|
521
670
|
return 0
|
|
522
671
|
else
|
|
523
672
|
log_error "OPENROUTER_API_KEY_FILE exists but is not readable ($api_key_file)"
|