@cyanautomation/kaseki-agent 1.36.10 → 1.37.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 +8 -0
- package/package.json +1 -1
- package/scripts/kaseki-setup-host.sh +170 -13
package/README.md
CHANGED
|
@@ -604,6 +604,14 @@ ssh pi@192.168.1.100 'tmp=$(mktemp) && curl -fsSL https://raw.githubusercontent.
|
|
|
604
604
|
ssh pi@192.168.1.100 '/agents/kaseki-agent/scripts/kaseki-setup-host.sh --fix'
|
|
605
605
|
```
|
|
606
606
|
|
|
607
|
+
If checkout freshness fails, remediation is now specific to the failure mode:
|
|
608
|
+
|
|
609
|
+
- `.git` access failures (for example: `permission denied`, `not a git repository`,
|
|
610
|
+
or inaccessible `.git`) keep permission-focused remediation.
|
|
611
|
+
- UID/GID impersonation failures (for example: unknown user/group or `sudo`/`runuser`
|
|
612
|
+
invocation errors) return remediation that asks you to configure a valid way to
|
|
613
|
+
execute as UID:GID `10000:10000` (or provide passwd/group mappings), then rerun setup.
|
|
614
|
+
|
|
607
615
|
#### Local Activation (No SSH)
|
|
608
616
|
|
|
609
617
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanautomation/kaseki-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.37.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",
|
|
@@ -100,6 +100,37 @@ check_writable() {
|
|
|
100
100
|
fi
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
fix_checkout_permissions_if_exists() {
|
|
104
|
+
# If checkout directory exists with potentially problematic ownership,
|
|
105
|
+
# try to fix it to match container UID:GID (only when --fix is set)
|
|
106
|
+
if [ "$KASEKI_FIX" != "1" ]; then
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
if [ ! -d "$KASEKI_CHECKOUT_DIR" ]; then
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
# Attempt to fix ownership to container UID:GID for consistency
|
|
113
|
+
run_privileged chown -R "$KASEKI_CONTAINER_UID:$KASEKI_CONTAINER_GID" "$KASEKI_CHECKOUT_DIR" 2>/dev/null || true
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resolve_uid_to_name() {
|
|
117
|
+
local uid="$1"
|
|
118
|
+
if ! command -v getent >/dev/null 2>&1; then
|
|
119
|
+
printf ''
|
|
120
|
+
return 0
|
|
121
|
+
fi
|
|
122
|
+
getent passwd "$uid" 2>/dev/null | awk -F: 'NR==1 && NF>=6 {print $1}'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
resolve_gid_to_name() {
|
|
126
|
+
local gid="$1"
|
|
127
|
+
if ! command -v getent >/dev/null 2>&1; then
|
|
128
|
+
printf ''
|
|
129
|
+
return 0
|
|
130
|
+
fi
|
|
131
|
+
getent group "$gid" 2>/dev/null | awk -F: 'NR==1 && NF>=4 {print $1}'
|
|
132
|
+
}
|
|
133
|
+
|
|
103
134
|
normalize_secrets_dir() {
|
|
104
135
|
local secrets_dir="$1"
|
|
105
136
|
if [ ! -d "$secrets_dir" ]; then
|
|
@@ -133,12 +164,20 @@ run_checkout_freshness_probe() {
|
|
|
133
164
|
local probe_status="skipped"
|
|
134
165
|
local probe_detail="Checkout freshness probe skipped because setup did not run bootstrap."
|
|
135
166
|
local probe_remediation=""
|
|
167
|
+
local stderr_file=""
|
|
168
|
+
|
|
169
|
+
cleanup_probe_stderr_file() {
|
|
170
|
+
if [ -n "$stderr_file" ]; then
|
|
171
|
+
rm -f "$stderr_file"
|
|
172
|
+
fi
|
|
173
|
+
}
|
|
136
174
|
|
|
137
175
|
if [ ! -d "$checkout_dir" ]; then
|
|
138
176
|
probe_status="failed"
|
|
139
177
|
probe_detail="Checkout freshness probe failed: expected checkout path ${checkout_dir} does not exist."
|
|
140
178
|
probe_remediation="Fix ownership/permissions so ${checkout_dir} and ${checkout_dir}/.git are readable by UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID}."
|
|
141
179
|
printf '%s|%s|%s\n' "$probe_status" "$probe_detail" "$probe_remediation"
|
|
180
|
+
cleanup_probe_stderr_file
|
|
142
181
|
return 0
|
|
143
182
|
fi
|
|
144
183
|
|
|
@@ -147,23 +186,33 @@ run_checkout_freshness_probe() {
|
|
|
147
186
|
probe_detail="Checkout freshness probe failed: ${checkout_dir}/.git is missing or inaccessible."
|
|
148
187
|
probe_remediation="Fix ownership/permissions so ${checkout_dir} and ${checkout_dir}/.git are readable by UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID}."
|
|
149
188
|
printf '%s|%s|%s\n' "$probe_status" "$probe_detail" "$probe_remediation"
|
|
189
|
+
cleanup_probe_stderr_file
|
|
150
190
|
return 0
|
|
151
191
|
fi
|
|
152
192
|
|
|
153
|
-
local stderr_file
|
|
154
193
|
stderr_file="$(mktemp)"
|
|
155
|
-
|
|
156
|
-
# Ensure cleanup on exit
|
|
157
|
-
trap 'rm -f "$stderr_file"' EXIT INT TERM
|
|
158
|
-
|
|
194
|
+
|
|
159
195
|
local probe_command=(git -C "$checkout_dir" rev-parse HEAD)
|
|
160
196
|
|
|
197
|
+
local resolved_user_name=""
|
|
198
|
+
local resolved_group_name=""
|
|
199
|
+
resolved_user_name="$(resolve_uid_to_name "$KASEKI_CONTAINER_UID")"
|
|
200
|
+
resolved_group_name="$(resolve_gid_to_name "$KASEKI_CONTAINER_GID")"
|
|
201
|
+
|
|
161
202
|
if [ "$(id -u)" -eq "$KASEKI_CONTAINER_UID" ] && [ "$(id -g)" -eq "$KASEKI_CONTAINER_GID" ]; then
|
|
162
203
|
"${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
163
|
-
elif command -v
|
|
164
|
-
|
|
165
|
-
elif command -v runuser >/dev/null 2>&1 && [ "$
|
|
166
|
-
runuser -u "
|
|
204
|
+
elif [ "$(id -u)" -eq 0 ] && command -v setpriv >/dev/null 2>&1; then
|
|
205
|
+
setpriv --reuid "$KASEKI_CONTAINER_UID" --regid "$KASEKI_CONTAINER_GID" --clear-groups -- "${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
206
|
+
elif [ "$(id -u)" -eq 0 ] && command -v runuser >/dev/null 2>&1 && [ -n "$resolved_user_name" ] && [ -n "$resolved_group_name" ]; then
|
|
207
|
+
runuser -u "$resolved_user_name" -g "$resolved_group_name" -- "${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
208
|
+
elif [ "$(id -u)" -eq 0 ] && command -v sudo >/dev/null 2>&1; then
|
|
209
|
+
if [ -n "$resolved_user_name" ] && [ -n "$resolved_group_name" ]; then
|
|
210
|
+
sudo -u "$resolved_user_name" -g "$resolved_group_name" -- "${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
211
|
+
elif [ -n "$resolved_user_name" ]; then
|
|
212
|
+
sudo -u "$resolved_user_name" -- "${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
213
|
+
else
|
|
214
|
+
sudo -u "#${KASEKI_CONTAINER_UID}" -g "#${KASEKI_CONTAINER_GID}" -- "${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
215
|
+
fi
|
|
167
216
|
else
|
|
168
217
|
"${probe_command[@]}" >/dev/null 2>"$stderr_file" || true
|
|
169
218
|
fi
|
|
@@ -172,13 +221,18 @@ run_checkout_freshness_probe() {
|
|
|
172
221
|
probe_status="failed"
|
|
173
222
|
local stderr_tail
|
|
174
223
|
stderr_tail="$(tail -n 1 "$stderr_file" | tr -d '\r')"
|
|
175
|
-
|
|
176
|
-
|
|
224
|
+
if printf '%s' "$stderr_tail" | grep -Eiq 'unknown user|unknown group|no passwd entry|user .* does not exist|group .* does not exist|sudo: .*unknown|sudo: .*invalid|runuser: .*does not exist|runuser: user .* does not exist|runuser: group .* does not exist|unable to initialize policy plugin|unable to set user context'; then
|
|
225
|
+
probe_detail="Checkout freshness probe failed: probe could not impersonate UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID} due to host user/group mapping or privilege-tool configuration issue: ${stderr_tail}"
|
|
226
|
+
probe_remediation="Configure a valid host method to run commands as UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID} (or ensure passwd/group mappings exist for that UID/GID), then rerun ./scripts/kaseki-setup-host.sh --fix."
|
|
227
|
+
else
|
|
228
|
+
probe_detail="Checkout freshness probe failed when running git metadata access as UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID}: ${stderr_tail}"
|
|
229
|
+
probe_remediation="Fix ownership/permissions so ${checkout_dir} and ${checkout_dir}/.git are readable by UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID}."
|
|
230
|
+
fi
|
|
177
231
|
else
|
|
178
232
|
probe_status="ok"
|
|
179
233
|
probe_detail="Checkout freshness probe passed for ${checkout_dir} as UID:GID ${KASEKI_CONTAINER_UID}:${KASEKI_CONTAINER_GID}."
|
|
180
234
|
fi
|
|
181
|
-
|
|
235
|
+
cleanup_probe_stderr_file
|
|
182
236
|
|
|
183
237
|
printf '%s|%s|%s\n' "$probe_status" "$probe_detail" "$probe_remediation"
|
|
184
238
|
}
|
|
@@ -288,6 +342,94 @@ bootstrap_checkout_if_possible() {
|
|
|
288
342
|
return 1
|
|
289
343
|
}
|
|
290
344
|
|
|
345
|
+
ensure_git_safe_directory() {
|
|
346
|
+
if ! command -v git >/dev/null 2>&1; then
|
|
347
|
+
printf 'warning: git is unavailable; skipping safe.directory preflight for %s\n' "$KASEKI_CHECKOUT_DIR"
|
|
348
|
+
return 0
|
|
349
|
+
fi
|
|
350
|
+
|
|
351
|
+
if [ ! -d "$KASEKI_CHECKOUT_DIR/.git" ]; then
|
|
352
|
+
printf 'warning: %s/.git is missing; skipping safe.directory preflight\n' "$KASEKI_CHECKOUT_DIR"
|
|
353
|
+
return 0
|
|
354
|
+
fi
|
|
355
|
+
|
|
356
|
+
local status_code=0
|
|
357
|
+
|
|
358
|
+
# Configure safe.directory for current context (usually root when run via sudo)
|
|
359
|
+
local existing_safe_dirs
|
|
360
|
+
existing_safe_dirs="$(git config --global --get-all safe.directory 2>/dev/null || true)"
|
|
361
|
+
if printf '%s\n' "$existing_safe_dirs" | grep -Fxq "$KASEKI_CHECKOUT_DIR"; then
|
|
362
|
+
printf 'ok: git safe.directory already present for current user context\n'
|
|
363
|
+
else
|
|
364
|
+
if git config --global --add safe.directory "$KASEKI_CHECKOUT_DIR" >/dev/null 2>&1; then
|
|
365
|
+
printf 'ok: configured git safe.directory for current user context\n'
|
|
366
|
+
else
|
|
367
|
+
printf 'warning: failed to configure git safe.directory for current user context\n'
|
|
368
|
+
status_code=1
|
|
369
|
+
fi
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
# If running via sudo, also configure safe.directory for the invoking user
|
|
373
|
+
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
|
|
374
|
+
local invoking_user_config
|
|
375
|
+
invoking_user_config="$(sudo -u "$SUDO_USER" git config --global --get-all safe.directory 2>/dev/null || true)"
|
|
376
|
+
if printf '%s\n' "$invoking_user_config" | grep -Fxq "$KASEKI_CHECKOUT_DIR"; then
|
|
377
|
+
printf 'ok: git safe.directory already present for invoking user (%s)\n' "$SUDO_USER"
|
|
378
|
+
else
|
|
379
|
+
if sudo -u "$SUDO_USER" git config --global --add safe.directory "$KASEKI_CHECKOUT_DIR" >/dev/null 2>&1; then
|
|
380
|
+
printf 'ok: configured git safe.directory for invoking user (%s)\n' "$SUDO_USER"
|
|
381
|
+
else
|
|
382
|
+
printf 'warning: failed to configure git safe.directory for invoking user (%s)\n' "$SUDO_USER"
|
|
383
|
+
status_code=1
|
|
384
|
+
fi
|
|
385
|
+
fi
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
if [ "$status_code" -ne 0 ]; then
|
|
389
|
+
printf 'remediation: if you see dubious ownership errors, try manually running as the invoking user:\n'
|
|
390
|
+
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
|
|
391
|
+
printf ' sudo -u %s git config --global --add safe.directory "%s"\n' "$SUDO_USER" "$KASEKI_CHECKOUT_DIR"
|
|
392
|
+
fi
|
|
393
|
+
printf ' And as root: git config --global --add safe.directory "%s"\n' "$KASEKI_CHECKOUT_DIR"
|
|
394
|
+
fi
|
|
395
|
+
|
|
396
|
+
return 0
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
verify_git_safe_directory() {
|
|
400
|
+
# Verify that safe.directory is actually configured before bootstrap
|
|
401
|
+
if ! command -v git >/dev/null 2>&1; then
|
|
402
|
+
return 0
|
|
403
|
+
fi
|
|
404
|
+
|
|
405
|
+
if [ ! -d "$KASEKI_CHECKOUT_DIR/.git" ]; then
|
|
406
|
+
return 0
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
local existing_safe_dirs
|
|
410
|
+
existing_safe_dirs="$(git config --global --get-all safe.directory 2>/dev/null || true)"
|
|
411
|
+
if printf '%s\n' "$existing_safe_dirs" | grep -Fxq "$KASEKI_CHECKOUT_DIR"; then
|
|
412
|
+
return 0
|
|
413
|
+
fi
|
|
414
|
+
|
|
415
|
+
# Not configured in current context; check if sudo user context has it
|
|
416
|
+
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
|
|
417
|
+
local invoking_user_config
|
|
418
|
+
invoking_user_config="$(sudo -u "$SUDO_USER" git config --global --get-all safe.directory 2>/dev/null || true)"
|
|
419
|
+
if printf '%s\n' "$invoking_user_config" | grep -Fxq "$KASEKI_CHECKOUT_DIR"; then
|
|
420
|
+
return 0
|
|
421
|
+
fi
|
|
422
|
+
fi
|
|
423
|
+
|
|
424
|
+
# Safe.directory not configured anywhere; warn but don't fail (bootstrap might still work)
|
|
425
|
+
printf 'warning: git safe.directory not found for checkout. If bootstrap fails with "dubious ownership", run:\n'
|
|
426
|
+
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
|
|
427
|
+
printf ' sudo -u %s git config --global --add safe.directory "%s"\n' "$SUDO_USER" "$KASEKI_CHECKOUT_DIR"
|
|
428
|
+
fi
|
|
429
|
+
printf ' git config --global --add safe.directory "%s"\n' "$KASEKI_CHECKOUT_DIR"
|
|
430
|
+
return 0
|
|
431
|
+
}
|
|
432
|
+
|
|
291
433
|
recreate_api_if_requested() {
|
|
292
434
|
if [ "$KASEKI_RECREATE_API" != "1" ]; then
|
|
293
435
|
return 0
|
|
@@ -322,6 +464,9 @@ check_writable "$KASEKI_ROOT/kaseki-results" || status=1
|
|
|
322
464
|
printf 'using host secrets directory: %s\n' "$KASEKI_HOST_SECRETS_DIR"
|
|
323
465
|
normalize_secrets_dir "$KASEKI_HOST_SECRETS_DIR"
|
|
324
466
|
|
|
467
|
+
fix_checkout_permissions_if_exists
|
|
468
|
+
ensure_git_safe_directory
|
|
469
|
+
verify_git_safe_directory
|
|
325
470
|
bootstrap_checkout_if_possible || status=$?
|
|
326
471
|
|
|
327
472
|
probe_payload="$(run_checkout_freshness_probe "$KASEKI_CHECKOUT_DIR")"
|
|
@@ -347,7 +492,19 @@ fi
|
|
|
347
492
|
recreate_api_if_requested || status=$?
|
|
348
493
|
|
|
349
494
|
if [ "$status" -ne 0 ]; then
|
|
350
|
-
printf 'kaseki host setup incomplete.
|
|
495
|
+
printf 'kaseki host setup incomplete. Details above. Common remediation steps:\n' >&2
|
|
496
|
+
printf '\n' >&2
|
|
497
|
+
printf '1. Ensure git safe.directory is configured:\n' >&2
|
|
498
|
+
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
|
|
499
|
+
printf ' sudo -u %s git config --global --add safe.directory "%s"\n' "$SUDO_USER" "$KASEKI_CHECKOUT_DIR" >&2
|
|
500
|
+
fi
|
|
501
|
+
printf ' git config --global --add safe.directory "%s"\n' "$KASEKI_CHECKOUT_DIR" >&2
|
|
502
|
+
printf '\n' >&2
|
|
503
|
+
printf '2. Fix directory permissions/ownership:\n' >&2
|
|
504
|
+
printf ' sudo chown -R %d:%d "%s"\n' "$KASEKI_CONTAINER_UID" "$KASEKI_CONTAINER_GID" "$KASEKI_ROOT" >&2
|
|
505
|
+
printf '\n' >&2
|
|
506
|
+
printf '3. Retry setup:\n' >&2
|
|
507
|
+
printf ' sudo kaseki-agent host setup --fix\n' >&2
|
|
351
508
|
fi
|
|
352
509
|
|
|
353
510
|
exit "$status"
|