@@ -784,28 +784,28 @@ should_skip_env_for_auth() {
784784 case " ${AUTH_METHOD:- claude} " in
785785 claude)
786786 case " $name " in
787- ANTHROPIC_API_KEY | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN | OPENAI_API_KEY | OPENAI_BASE_URL | openai_base_url)
787+ ANTHROPIC_API_KEY | ANTHROPIC_AUTH_TOKEN | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN | OPENAI_API_KEY | OPENAI_BASE_URL | openai_base_url)
788788 return 0
789789 ;;
790790 esac
791791 ;;
792792 api-key | oat)
793793 case " $name " in
794- ANTHROPIC_API_KEY | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN | OPENAI_API_KEY | OPENAI_BASE_URL | openai_base_url)
794+ ANTHROPIC_API_KEY | ANTHROPIC_AUTH_TOKEN | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN | OPENAI_API_KEY | OPENAI_BASE_URL | openai_base_url)
795795 return 0
796796 ;;
797797 esac
798798 ;;
799799 copilot)
800800 case " $name " in
801- ANTHROPIC_API_KEY | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN)
801+ ANTHROPIC_API_KEY | ANTHROPIC_AUTH_TOKEN | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN)
802802 return 0
803803 ;;
804804 esac
805805 ;;
806806 bedrock | vertex | credentials-file)
807807 case " $name " in
808- ANTHROPIC_API_KEY | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN | OPENAI_API_KEY | OPENAI_BASE_URL | openai_base_url)
808+ ANTHROPIC_API_KEY | ANTHROPIC_AUTH_TOKEN | ANTHROPIC_BASE_URL | CLAUDE_CODE_OAUTH_TOKEN | OPENAI_API_KEY | OPENAI_BASE_URL | openai_base_url)
809809 return 0
810810 ;;
811811 esac
@@ -938,20 +938,36 @@ mount_config_home() {
938938 [ -e " $item " ] || continue
939939 local name
940940 name=" $( basename " $item " ) "
941- if [ " $name " = " . " ] || [ " $name " = " .. " ] ; then
941+ if ! should_mount_home_item " $item " " $name " ; then
942942 continue
943943 fi
944944 DOCKER_ARGS+=(-v " $item :/home/deva/$name " )
945945 done
946946}
947947
948- # Credential backup system.
949- # - .claude.json: always cp'd to XDG_STATE (outside mount tree, corruption protection).
950- # - Credential files: mv'd to tmpdir when auth override is detected.
951- # - Auth override = non-default --auth-with OR auth env vars reaching container.
952- # Entries are "orig_path:backup_path" pairs for restore.
953- BACKED_UP_CREDS=()
954- CRED_BACKUP_TMPDIR=" "
948+ should_mount_home_item () {
949+ local item=" $1 "
950+ local name=" $2 "
951+
952+ case " $name " in
953+ . | .. | .DS_Store | .git | .gitignore)
954+ return 1
955+ ;;
956+ .claude.json.backup | .claude.json.backup.* | .claude.json.bak.after-corrupted.* )
957+ return 1
958+ ;;
959+ * .credentials.json | auth.json | mcp-oauth-tokens-v2.json)
960+ # Loose credential files should only enter the container through explicit auth mounts.
961+ [ -f " $item " ] && return 1
962+ ;;
963+ esac
964+
965+ if [ -n " ${CUSTOM_CREDENTIALS_FILE:- } " ] && [ " $item " = " $CUSTOM_CREDENTIALS_FILE " ]; then
966+ return 1
967+ fi
968+
969+ return 0
970+ }
955971
956972# Effective config base: where agent config dirs (.claude/, .codex/, .gemini/) live.
957973resolve_config_base () {
@@ -1004,18 +1020,10 @@ has_auth_override() {
10041020 return 1
10051021}
10061022
1007- backup_credentials () {
1023+ backup_claude_json () {
10081024 local config_base
10091025 config_base=$( resolve_config_base)
10101026
1011- local agent_dir cred_file
1012- case " $ACTIVE_AGENT " in
1013- claude) agent_dir=" .claude" ; cred_file=" .credentials.json" ;;
1014- codex) agent_dir=" .codex" ; cred_file=" auth.json" ;;
1015- gemini) agent_dir=" .gemini" ; cred_file=" mcp-oauth-tokens-v2.json" ;;
1016- * ) return 0 ;;
1017- esac
1018-
10191027 # .claude.json corruption backup: persistent, outside container mount tree.
10201028 if [ " $ACTIVE_AGENT " = " claude" ]; then
10211029 local state_dir=" ${XDG_STATE_HOME:- $HOME / .local/ state} /deva/backups"
@@ -1026,31 +1034,66 @@ backup_credentials() {
10261034 fi
10271035 fi
10281036
1029- # Credential backup: tmpdir outside all mount trees.
1030- if has_auth_override; then
1031- local cred_path=" $config_base /$agent_dir /$cred_file "
1032- if [ -f " $cred_path " ]; then
1033- CRED_BACKUP_TMPDIR=$( mktemp -d " ${TMPDIR:-/ tmp} /deva-cred.XXXXXX" )
1034- mv " $cred_path " " $CRED_BACKUP_TMPDIR /$cred_file "
1035- BACKED_UP_CREDS+=(" $cred_path :$CRED_BACKUP_TMPDIR /$cred_file " )
1036- echo " info: backed up $cred_file -> tmpdir (auth override active)" >&2
1037- fi
1037+ }
1038+
1039+ default_credential_target_path () {
1040+ case " $ACTIVE_AGENT " in
1041+ claude)
1042+ printf ' %s' " /home/deva/.claude/.credentials.json"
1043+ ;;
1044+ codex)
1045+ printf ' %s' " /home/deva/.codex/auth.json"
1046+ ;;
1047+ gemini)
1048+ printf ' %s' " /home/deva/.gemini/mcp-oauth-tokens-v2.json"
1049+ ;;
1050+ * )
1051+ return 1
1052+ ;;
1053+ esac
1054+ }
1055+
1056+ append_auth_credential_overlay () {
1057+ if ! has_auth_override; then
1058+ return
1059+ fi
1060+
1061+ case " $ACTIVE_AGENT :$AUTH_METHOD " in
1062+ claude:credentials-file | codex:credentials-file)
1063+ # Explicit file mount already overlays the default auth file path.
1064+ return
1065+ ;;
1066+ esac
1067+
1068+ local target_path
1069+ if ! target_path=$( default_credential_target_path) ; then
1070+ return
1071+ fi
1072+
1073+ local state_dir=" ${XDG_STATE_HOME:- $HOME / .local/ state} /deva/auth-overlays/$ACTIVE_AGENT "
1074+ local overlay_key=" ${AUTH_METHOD:- default} "
1075+ case " $ACTIVE_AGENT :$AUTH_METHOD " in
1076+ claude:claude | codex:chatgpt | gemini:oauth | gemini:gemini-app-oauth)
1077+ overlay_key=" env"
1078+ ;;
1079+ esac
1080+ local overlay_file
1081+ overlay_file=" $state_dir /$( workspace_hash) .${overlay_key} .blank"
1082+ if [ " $DRY_RUN " != true ]; then
1083+ mkdir -p " $state_dir "
1084+ printf ' {}\n' > " $overlay_file "
10381085 fi
1086+ DOCKER_ARGS+=(" -v" " $overlay_file :$target_path " )
10391087}
10401088
1041- restore_backed_up_credentials () {
1042- local entry
1043- for entry in " ${BACKED_UP_CREDS[@]+" ${BACKED_UP_CREDS[@]} " } " ; do
1044- local orig=" ${entry%%:* } "
1045- local backup=" ${entry##*: } "
1046- if [ -f " $backup " ]; then
1047- mv " $backup " " $orig "
1048- echo " info: restored $( basename " $orig " ) " >&2
1049- fi
1050- done
1051- if [ -n " $CRED_BACKUP_TMPDIR " ] && [ -d " $CRED_BACKUP_TMPDIR " ]; then
1052- rm -rf " $CRED_BACKUP_TMPDIR "
1089+ mount_loose_home_item () {
1090+ local item=" $1 "
1091+ local name
1092+ name=" $( basename " $item " ) "
1093+ if ! should_mount_home_item " $item " " $name " ; then
1094+ return
10531095 fi
1096+ DOCKER_ARGS+=(-v " $item :/home/deva/$name " )
10541097}
10551098
10561099mount_dir_contents_into_home () {
@@ -1059,12 +1102,7 @@ mount_dir_contents_into_home() {
10591102 local item
10601103 for item in " $base " /.* " $base " /* ; do
10611104 [ -e " $item " ] || continue
1062- local name
1063- name=" $( basename " $item " ) "
1064- if [ " $name " = " ." ] || [ " $name " = " .." ]; then
1065- continue
1066- fi
1067- DOCKER_ARGS+=(-v " $item :/home/deva/$name " )
1105+ mount_loose_home_item " $item "
10681106 done
10691107}
10701108
20352073
20362074autolink_legacy_into_deva_root () {
20372075 [ " $AUTOLINK " = true ] || return 0
2076+ [ " $DRY_RUN " != true ] || return 0
20382077 [ " $CONFIG_HOME_FROM_CLI " = false ] || return 0
20392078 [ -n " ${CONFIG_ROOT:- } " ] || return 0
20402079 [ -d " $CONFIG_ROOT " ] || mkdir -p " $CONFIG_ROOT "
@@ -2259,10 +2298,9 @@ DOCKER_ARGS+=(-e "DEVA_CONTAINER_NAME=${CONTAINER_NAME}")
22592298DOCKER_ARGS+= (-e " DEVA_WORKSPACE=$( pwd) " )
22602299DOCKER_ARGS+= (-e " DEVA_EPHEMERAL=${EPHEMERAL_MODE} " )
22612300
2262- # Credential backup: move credential files to tmpdir before mounting.
2263- # Skipped during --dry-run to avoid side effects (mkdir, cp, mv).
2301+ # Back up .claude.json before mounting, without touching live credential files.
22642302if [ " $QUICK_MODE " != true ] && [ " $DRY_RUN " != true ]; then
2265- backup_credentials
2303+ backup_claude_json
22662304fi
22672305
22682306# Centralized mounting logic.
@@ -2286,6 +2324,12 @@ else
22862324 fi
22872325fi
22882326
2327+ # Hide default OAuth credential files for non-default auth modes.
2328+ # For credentials-file auth on Claude/Codex, the agent-specific file mount already overlays the path.
2329+ if [ " $QUICK_MODE " = false ]; then
2330+ append_auth_credential_overlay
2331+ fi
2332+
22892333# Set statusline log paths via env vars (XDG-compliant)
22902334DOCKER_ARGS+= (" -e" " CLAUDE_DATA_DIR=/home/deva/.config/deva/claude" )
22912335DOCKER_ARGS+= (" -e" " CLAUDE_CACHE_DIR=/home/deva/.cache/deva/claude/sessions" )
@@ -2335,7 +2379,7 @@ mask_secrets_in_args() {
23352379 local name=" ${BASH_REMATCH[1]} "
23362380 local value=" ${BASH_REMATCH[2]} "
23372381 case " $name " in
2338- * TOKEN* |* KEY* |* SECRET* |* PASSWORD* |* CREDENTIALS* | * BARK_KEY * )
2382+ * TOKEN* |* KEY* |* SECRET* |* PASSWORD* |* CREDENTIALS* )
23392383 printf ' %s=<redacted> ' " $name "
23402384 ;;
23412385 * )
@@ -2364,11 +2408,6 @@ if [ "$DEBUG_MODE" = true ]; then
23642408 echo " " >&2
23652409fi
23662410
2367- # Restore backed-up credential files on exit (covers crashes, signals, normal exit)
2368- if [ ${# BACKED_UP_CREDS[@]} -gt 0 ]; then
2369- trap restore_backed_up_credentials EXIT
2370- fi
2371-
23722411if [ " $DRY_RUN " = true ]; then
23732412 exit 0
23742413fi
@@ -2429,8 +2468,6 @@ if [ "$EPHEMERAL_MODE" = false ]; then
24292468 update_session_file
24302469 fi
24312470
2432- # Restore credentials before exec (exec replaces the process, trap won't fire)
2433- restore_backed_up_credentials
24342471 exec docker exec -it " $CONTAINER_NAME " /usr/local/bin/docker-entrypoint.sh " ${AGENT_COMMAND[@]} "
24352472else
24362473 echo " Launching ${ACTIVE_AGENT} (ephemeral mode) via ${DEVA_DOCKER_IMAGE} :${DEVA_DOCKER_TAG} "
0 commit comments