Skip to content

Commit 574e330

Browse files
committed
✨ The terminal tool supports password login #1052
1 parent b55b234 commit 574e330

File tree

8 files changed

+179
-191
lines changed

8 files changed

+179
-191
lines changed

backend/database/tool_db.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ def add_tool_field(tool_info):
164164
# add tool params
165165
tool_params = tool.params
166166
for ele in tool_params:
167-
ele["default"] = tool_info["params"][ele["name"]]
167+
param_name = ele["name"]
168+
param_value = tool_info["params"].get(param_name)
169+
ele["default"] = param_value
168170

169171
tool_dict = as_dict(tool)
170172
tool_dict["params"] = tool_params

docker/deploy.sh

Lines changed: 59 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -127,127 +127,6 @@ generate_supabase_keys() {
127127
fi
128128
}
129129

130-
generate_ssh_keys() {
131-
# Function to generate SSH key pair for Terminal tool
132-
133-
if [ "$ENABLE_TERMINAL_TOOL" = "true" ]; then
134-
# Create ssh-keys directory
135-
create_dir_with_permission "$ROOT_DIR/openssh-server/ssh-keys" 700
136-
create_dir_with_permission "$ROOT_DIR/openssh-server/config" 755
137-
138-
# Check if SSH keys already exist
139-
if [ -f "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key" ] && [ -f "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub" ]; then
140-
echo "🚧 SSH key pair already exists, skipping generation..."
141-
echo "🔑 Private key: $ROOT_DIR/openssh-server/ssh-keys/openssh_server_key"
142-
echo "🗝️ Public key: $ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub"
143-
144-
# Ensure authorized_keys is set up correctly with ONLY our public key
145-
cp "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub" "$ROOT_DIR/openssh-server/config/authorized_keys"
146-
chmod 644 "$ROOT_DIR/openssh-server/config/authorized_keys"
147-
148-
# Set SSH key path in environment
149-
SSH_PRIVATE_KEY_PATH="$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key"
150-
export SSH_PRIVATE_KEY_PATH
151-
152-
# Add to .env file
153-
update_env_var "SSH_PRIVATE_KEY_PATH" "$SSH_PRIVATE_KEY_PATH"
154-
155-
echo ""
156-
echo "--------------------------------"
157-
echo ""
158-
return 0
159-
fi
160-
161-
echo "🔑 Generating SSH key pair for Terminal tool..."
162-
163-
# Generate SSH key pair using Docker (cross-platform compatible)
164-
echo " 🔐 Using Docker to generate SSH key pair..."
165-
166-
# Create temporary file to capture output
167-
TEMP_OUTPUT="/tmp/ssh_keygen_output_$$.txt"
168-
169-
# Generate ed25519 key pair using the openssh-server container
170-
if docker run --rm -i "$OPENSSH_SERVER_IMAGE" bash -c "ssh-keygen -t ed25519 -f /tmp/id_ed25519 -N '' && cat /tmp/id_ed25519 && echo '---' && cat /tmp/id_ed25519.pub" > "$TEMP_OUTPUT" 2>&1; then
171-
echo " 🔍 SSH key generation completed, extracting keys..."
172-
173-
# Extract private key (everything between -----BEGIN and -----END)
174-
PRIVATE_KEY=$(sed -n '/-----BEGIN OPENSSH PRIVATE KEY-----/,/-----END OPENSSH PRIVATE KEY-----/p' "$TEMP_OUTPUT")
175-
176-
# Extract public key (line that starts with ssh-)
177-
PUBLIC_KEY=$(grep "^ssh-" "$TEMP_OUTPUT" | head -1)
178-
179-
# Remove leading/trailing whitespace
180-
PRIVATE_KEY=$(echo "$PRIVATE_KEY" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
181-
PUBLIC_KEY=$(echo "$PUBLIC_KEY" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
182-
183-
# Validate extracted keys
184-
if [ -z "$PRIVATE_KEY" ]; then
185-
echo " ❌ Failed to extract private key"
186-
ERROR_OCCURRED=1
187-
return 1
188-
fi
189-
190-
if [ -z "$PUBLIC_KEY" ]; then
191-
echo " ❌ Failed to extract public key"
192-
ERROR_OCCURRED=1
193-
return 1
194-
fi
195-
196-
echo " ✅ SSH keys extracted successfully"
197-
198-
if [ -n "$PRIVATE_KEY" ] && [ -n "$PUBLIC_KEY" ]; then
199-
# Save private key
200-
echo "$PRIVATE_KEY" > "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key"
201-
chmod 600 "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key"
202-
203-
# Save public key
204-
echo "$PUBLIC_KEY" > "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub"
205-
chmod 644 "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub"
206-
207-
# Copy public key to authorized_keys with correct permissions (ensure ONLY our key)
208-
cp "$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub" "$ROOT_DIR/openssh-server/config/authorized_keys"
209-
chmod 644 "$ROOT_DIR/openssh-server/config/authorized_keys"
210-
211-
# Set SSH key path in environment
212-
SSH_PRIVATE_KEY_PATH="$ROOT_DIR/openssh-server/ssh-keys/openssh_server_key"
213-
export SSH_PRIVATE_KEY_PATH
214-
215-
# Add to .env file
216-
update_env_var "SSH_PRIVATE_KEY_PATH" "$SSH_PRIVATE_KEY_PATH"
217-
218-
# Fix SSH host key permissions (must be 600)
219-
find "$ROOT_DIR/openssh-server/config" -name "*_key" -type f -exec chmod 600 {} \; 2>/dev/null || true
220-
221-
echo " ✅ SSH key pair generated successfully!"
222-
echo " 🔑 Private key: $ROOT_DIR/openssh-server/ssh-keys/openssh_server_key"
223-
echo " 🗝️ Public key: $ROOT_DIR/openssh-server/ssh-keys/openssh_server_key.pub"
224-
echo " ⚙️ SSH config: $ROOT_DIR/openssh-server/config/sshd_config (60min session timeout)"
225-
else
226-
echo " ❌ ERROR Failed to extract SSH keys from Docker output"
227-
echo " 📋 Full output saved to: $TEMP_OUTPUT for debugging"
228-
ERROR_OCCURRED=1
229-
return 1
230-
fi
231-
else
232-
echo " ❌ ERROR Docker key generation command failed"
233-
if [ -f "$TEMP_OUTPUT" ]; then
234-
echo "📋 Error output:"
235-
cat "$TEMP_OUTPUT"
236-
fi
237-
ERROR_OCCURRED=1
238-
return 1
239-
fi
240-
241-
# Clean up temp file (only if successful)
242-
if [ "$ERROR_OCCURRED" -eq 0 ]; then
243-
rm -f "$TEMP_OUTPUT"
244-
fi
245-
246-
echo ""
247-
echo "--------------------------------"
248-
echo ""
249-
fi
250-
}
251130

252131
generate_elasticsearch_api_key() {
253132
# Function to generate Elasticsearch API key
@@ -534,7 +413,7 @@ deploy_infrastructure() {
534413
fi
535414

536415
# Start Supabase services
537-
if ! ${docker_compose_command} -p nexent -f "docker-compose-supabase${COMPOSE_FILE_SUFFIX}" up -d; then
416+
if ! $docker_compose_command -p nexent -f "docker-compose-supabase${COMPOSE_FILE_SUFFIX}" up -d; then
538417
echo " ❌ ERROR Failed to start supabase services"
539418
ERROR_OCCURRED=1
540419
return 1
@@ -653,6 +532,7 @@ select_terminal_tool() {
653532
export COMPOSE_PROFILES="${COMPOSE_PROFILES:+$COMPOSE_PROFILES,}terminal"
654533
echo "✅ Terminal tool enabled 🔧"
655534
echo " 🔧 Deploying an openssh-server container for secure command execution"
535+
update_env_var "ENABLE_TERMINAL_TOOL" "true"
656536

657537
# Ask user to specify directory mapping
658538
default_terminal_dir="/opt/terminal"
@@ -672,10 +552,66 @@ select_terminal_tool() {
672552
echo " 📁 Terminal mount configuration:"
673553
echo " • Host: $TERMINAL_MOUNT_DIR"
674554
echo " • Container: /opt/terminal"
555+
echo " • This directory will be created if it doesn't exist"
556+
echo ""
557+
558+
# Setup SSH credentials for Terminal tool
559+
echo "🔐 Setting up SSH credentials for Terminal tool..."
560+
561+
# Check if SSH credentials are already set
562+
if [ -n "$SSH_USERNAME" ] && [ -n "$SSH_PASSWORD" ]; then
563+
echo "🚧 SSH credentials already configured, skipping setup..."
564+
echo "👤 Username: $SSH_USERNAME"
565+
echo "🔑 Password: [HIDDEN]"
566+
else
567+
# Prompt for SSH credentials
568+
echo "Please enter SSH credentials for Terminal tool:"
569+
echo ""
570+
571+
# Get SSH username
572+
if [ -z "$SSH_USERNAME" ]; then
573+
read -p "SSH Username (default: root): " input_username
574+
SSH_USERNAME=${input_username:-root}
575+
fi
576+
577+
# Get SSH password
578+
if [ -z "$SSH_PASSWORD" ]; then
579+
echo "SSH Password (will be hidden): "
580+
read -s input_password
581+
echo ""
582+
if [ -z "$input_password" ]; then
583+
echo "❌ SSH password cannot be empty"
584+
ERROR_OCCURRED=1
585+
return 1
586+
fi
587+
SSH_PASSWORD="$input_password"
588+
fi
589+
590+
# Validate credentials
591+
if [ -z "$SSH_USERNAME" ] || [ -z "$SSH_PASSWORD" ]; then
592+
echo "❌ Both username and password are required"
593+
ERROR_OCCURRED=1
594+
return 1
595+
fi
596+
597+
# Export environment variables
598+
export SSH_USERNAME
599+
export SSH_PASSWORD
600+
601+
# Add to .env file
602+
update_env_var "SSH_USERNAME" "$SSH_USERNAME"
603+
update_env_var "SSH_PASSWORD" "$SSH_PASSWORD"
604+
605+
echo " ✅ SSH credentials configured successfully!"
606+
echo " 👤 Username: $SSH_USERNAME"
607+
echo " 🔑 Password: [HIDDEN]"
608+
echo " ⚙️ Authentication: Password-based"
609+
fi
610+
echo ""
675611
else
676612
export ENABLE_TERMINAL_TOOL="false"
677613
echo "🚫 Terminal tool disabled"
678-
614+
update_env_var "ENABLE_TERMINAL_TOOL" "false"
679615
fi
680616
echo ""
681617
echo "--------------------------------"
@@ -747,9 +683,6 @@ main_deploy() {
747683
prepare_directory_and_data || { echo "❌ Permission setup failed"; exit 1; }
748684
generate_minio_ak_sk || { echo "❌ MinIO key generation failed"; exit 1; }
749685

750-
if [ "$ENABLE_TERMINAL_TOOL" = "true" ]; then
751-
generate_ssh_keys || { echo "❌ SSH key generation failed"; exit 1; }
752-
fi
753686

754687
# Generate Supabase secrets
755688
generate_supabase_keys || { echo "❌ Supabase secrets generation failed"; exit 1; }

docker/docker-compose.prod.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,10 @@ services:
200200
container_name: nexent-openssh-server
201201
hostname: nexent-openssh-server
202202
environment:
203-
- DEV_USER=linuxserver.io
203+
- DEV_USER=${SSH_USERNAME:-linuxserver.io}
204+
- DEV_PASSWORD=${SSH_PASSWORD:-nexent123}
204205
volumes:
205206
- ${TERMINAL_MOUNT_DIR:-./workspace}:/opt/terminal
206-
- ${ROOT_DIR}/openssh-server/config:/tmp/ssh_keys:ro # 只读挂载SSH公钥
207207
networks:
208208
- nexent
209209
restart: always

docker/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,12 @@ services:
214214
container_name: nexent-openssh-server
215215
hostname: nexent-openssh-server
216216
environment:
217-
- DEV_USER=linuxserver.io
217+
- DEV_USER=${SSH_USERNAME:-linuxserver.io}
218+
- DEV_PASSWORD=${SSH_PASSWORD:-nexent123}
218219
ports:
219220
- "2222:22" # SSH port
220221
volumes:
221222
- ${TERMINAL_MOUNT_DIR:-./workspace}:/opt/terminal
222-
- ${ROOT_DIR}/openssh-server/ssh-keys:/tmp/ssh_keys:ro
223223
networks:
224224
- nexent
225225
restart: always

docker/generate_env.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,25 @@ update_env_file() {
7373
echo "ELASTICSEARCH_API_KEY=$ELASTICSEARCH_API_KEY" >> ../.env
7474
fi
7575
fi
76+
77+
# Update or add SSH credentials (only if they were set)
78+
if [ -n "$SSH_USERNAME" ]; then
79+
if grep -q "^SSH_USERNAME=" ../.env; then
80+
sed -i.bak "s~^SSH_USERNAME=.*~SSH_USERNAME=$SSH_USERNAME~" ../.env
81+
else
82+
echo "" >> ../.env
83+
echo "# SSH Terminal Tool Credentials" >> ../.env
84+
echo "SSH_USERNAME=$SSH_USERNAME" >> ../.env
85+
fi
86+
fi
87+
88+
if [ -n "$SSH_PASSWORD" ]; then
89+
if grep -q "^SSH_PASSWORD=" ../.env; then
90+
sed -i.bak "s~^SSH_PASSWORD=.*~SSH_PASSWORD=$SSH_PASSWORD~" ../.env
91+
else
92+
echo "SSH_PASSWORD=$SSH_PASSWORD" >> ../.env
93+
fi
94+
fi
7695
echo " ✅ Generated keys updated successfully"
7796

7897
# Force update development environment service URLs for localhost access
@@ -218,6 +237,12 @@ show_summary() {
218237
if [ -n "$SERVICE_ROLE_KEY" ]; then
219238
echo " 🔑 SERVICE_ROLE_KEY: $SERVICE_ROLE_KEY"
220239
fi
240+
if [ -n "$SSH_USERNAME" ]; then
241+
echo " 👤 SSH_USERNAME: $SSH_USERNAME"
242+
fi
243+
if [ -n "$SSH_PASSWORD" ]; then
244+
echo " 🔑 SSH_PASSWORD: [HIDDEN]"
245+
fi
221246
if [ -z "$ELASTICSEARCH_API_KEY" ]; then
222247
echo " ⚠️ Note: To generate ELASTICSEARCH_API_KEY later, please:"
223248
echo " 1. Start Elasticsearch: docker-compose -p nexent up -d nexent-elasticsearch"

make/terminal/Dockerfile

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,38 +19,31 @@ RUN apt-get clean && \
1919
&& rm -rf /var/lib/apt/lists/* \
2020
&& apt-get clean
2121

22-
# Create development user
23-
ARG DEV_USER=linuxserver.io
24-
RUN useradd -m -s /bin/bash $DEV_USER && \
25-
usermod -aG sudo $DEV_USER && \
26-
echo "$DEV_USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
22+
# Using root user - no additional user creation needed
2723

28-
# Configure SSH - disable root login + disable password authentication
24+
# Configure SSH - enable root login + enable password authentication
2925
RUN mkdir /var/run/sshd && \
30-
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config && \
31-
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
26+
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
27+
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config
3228

3329
# Install Miniconda
3430
ARG TARGETARCH
3531
RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-$(if [ "$TARGETARCH" = "amd64" ]; then echo "x86_64"; elif [ "$TARGETARCH" = "arm64" ]; then echo "aarch64"; else echo "$TARGETARCH"; fi).sh -O /tmp/miniconda.sh && \
3632
bash /tmp/miniconda.sh -b -p $CONDA_DIR && \
3733
rm /tmp/miniconda.sh
3834

39-
# Set conda permissions
40-
RUN chown -R $DEV_USER:$DEV_USER $CONDA_DIR
35+
# Conda permissions - root owns everything by default
4136

4237
# Add conda to PATH and initialize
4338
ENV PATH="$CONDA_DIR/bin:$PATH"
4439
RUN conda init
4540

46-
# Create .ssh directory
47-
RUN mkdir -p /home/$DEV_USER/.ssh && \
48-
chown $DEV_USER:$DEV_USER /home/$DEV_USER/.ssh && \
49-
chmod 700 /home/$DEV_USER/.ssh
41+
# Create .ssh directory for root
42+
RUN mkdir -p /root/.ssh && \
43+
chmod 700 /root/.ssh
5044

5145
# Create default working directory
52-
RUN mkdir -p /opt/terminal && \
53-
chown $DEV_USER:$DEV_USER /opt/terminal
46+
RUN mkdir -p /opt/terminal
5447

5548
# Set working directory
5649
WORKDIR /opt

0 commit comments

Comments
 (0)