Skip to content

Commit db34a83

Browse files
Merge pull request #171 from fullstackdev0110/feature/safe-env-everywhere
Safe .env loading everywhere: add load_env_file(), fix token-spy, unify scripts, add test
2 parents d1bd2d0 + 7739575 commit db34a83

13 files changed

Lines changed: 135 additions & 156 deletions

File tree

dream-server/docs/EXTENSIONS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,4 @@ npm run build
316316
- Unknown/malformed manifests are skipped with warnings, not fatal crashes.
317317
- Keep extension files ASCII and small; one service per directory is preferred.
318318
- The service registry (`lib/service-registry.sh`) provides bash functions for resolving aliases and discovering enabled services.
319+
- **Scripts that load `.env`:** Source `lib/safe-env.sh` and use `load_env_file "<path>"`; do not use `eval` or `export $(grep ... .env | xargs)` (injection risk).

dream-server/dream-cli

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,6 @@ _env_set() {
4141
fi
4242
}
4343

44-
# B6 fix: Safe .env loading (prevents shell injection)
45-
load_env() {
46-
[[ -f "$INSTALL_DIR/.env" ]] || return 0
47-
set -a
48-
while IFS='=' read -r key value; do
49-
# Skip comments and empty lines
50-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
51-
[[ -z "$key" ]] && continue
52-
# Only allow alphanumeric + underscore in key names
53-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
54-
# Strip quotes from value
55-
value="${value%\"}"
56-
value="${value#\"}"
57-
value="${value%\'}"
58-
value="${value#\'}"
59-
export "$key=$value"
60-
done < "$INSTALL_DIR/.env"
61-
set +a
62-
}
63-
6444
check_install() {
6545
if [[ ! -d "$INSTALL_DIR" ]]; then
6646
error "Dream Server not found at $INSTALL_DIR. Set DREAM_HOME or run installer first."
@@ -73,6 +53,12 @@ check_install() {
7353
fi
7454
}
7555

56+
#=============================================================================
57+
# Safe .env loading (no eval; use lib/safe-env.sh)
58+
#=============================================================================
59+
[[ -f "$SCRIPT_DIR/lib/safe-env.sh" ]] && . "$SCRIPT_DIR/lib/safe-env.sh"
60+
load_env() { load_env_file "${INSTALL_DIR}/.env"; }
61+
7662
#=============================================================================
7763
# Service Registry
7864
#=============================================================================

dream-server/dream-preflight.sh

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,10 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
1010
DREAM_DIR="$SCRIPT_DIR"
1111
LOG_FILE="$DREAM_DIR/preflight-$(date +%Y%m%d-%H%M%S).log"
1212

13-
# Load config from .env safely (line-by-line, no eval/source)
14-
if [ -f "$DREAM_DIR/.env" ]; then
15-
while IFS='=' read -r key value; do
16-
# Skip comments and empty lines
17-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
18-
[[ -z "$key" ]] && continue
19-
# Only allow safe variable names
20-
key=$(echo "$key" | xargs) # trim whitespace
21-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
22-
# Strip surrounding quotes from value
23-
value="${value%\"}" && value="${value#\"}"
24-
value="${value%\'}" && value="${value#\'}"
25-
export "$key=$value"
26-
done < "$DREAM_DIR/.env"
27-
fi
13+
# Safe .env loading (no eval; use lib/safe-env.sh)
14+
[[ -f "$DREAM_DIR/lib/safe-env.sh" ]] && . "$DREAM_DIR/lib/safe-env.sh"
15+
load_env_file "$DREAM_DIR/.env"
16+
2817
SERVICE_HOST="${SERVICE_HOST:-localhost}"
2918

3019
# Auto-detect backend from .env or hardware probing.

dream-server/extensions/services/token-spy/start.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ set -e
1616
cd "$(dirname "$0")"
1717
mkdir -p data
1818

19-
# Load env file if exists
20-
if [ -f .env ]; then
21-
export $(grep -v '^#' .env | xargs)
22-
fi
19+
# Safe .env loading (no eval; use Dream Server lib/safe-env.sh)
20+
DREAM_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
21+
[[ -f "$DREAM_ROOT/lib/safe-env.sh" ]] && . "$DREAM_ROOT/lib/safe-env.sh"
22+
load_env_file "$(pwd)/.env"
2323

2424
# Database backend (sqlite or postgres)
2525
export DB_BACKEND="${DB_BACKEND:-sqlite}"

dream-server/lib/safe-env.sh

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,34 @@
22
# ============================================================================
33
# Dream Server — Safe environment loading (no eval)
44
# ============================================================================
5-
# Parses KEY="value" lines (with \" and \\ escapes) from stdin and exports
6-
# them in the current shell. Use instead of eval for output from
7-
# build-capability-profile.sh, preflight-engine.sh, resolve-compose-stack.sh,
8-
# load-backend-contract.sh, etc.
5+
# Scripts that need to load .env should use load_env_file from this script.
6+
# Do not use eval or "export $(grep ... .env | xargs)" — they allow injection.
7+
#
8+
# - load_env_file <path> — parse a .env file and export vars (safe keys, no eval)
9+
# - load_env_from_output — parse KEY="value" lines from stdin (for script output)
910
# ============================================================================
1011

12+
# Load a .env file safely: comments and empty lines skipped; key names must be
13+
# valid identifiers; values may be unquoted or quoted; no eval or word-splitting.
14+
load_env_file() {
15+
local path="$1"
16+
[[ -f "$path" ]] || return 0
17+
local key value
18+
while IFS='=' read -r key value; do
19+
[[ "$key" =~ ^[[:space:]]*# ]] && continue
20+
key="${key#"${key%%[![:space:]]*}"}"
21+
key="${key%"${key##*[![:space:]]}"}"
22+
[[ -z "$key" ]] && continue
23+
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
24+
value="${value# }"
25+
value="${value%\"}"
26+
value="${value#\"}"
27+
value="${value%\'}"
28+
value="${value#\'}"
29+
export "$key=$value"
30+
done < "$path"
31+
}
32+
1133
load_env_from_output() {
1234
local line key value
1335
while IFS= read -r line; do

dream-server/scripts/dream-preflight.sh

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,9 @@ cd "$SCRIPT_DIR"
1111
. "$SCRIPT_DIR/lib/service-registry.sh"
1212
sr_load
1313

14-
# Safe .env loading for port overrides
15-
if [[ -f "$SCRIPT_DIR/.env" ]]; then
16-
set -a
17-
while IFS='=' read -r key value; do
18-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
19-
[[ -z "$key" ]] && continue
20-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
21-
value="${value%\"}"
22-
value="${value#\"}"
23-
value="${value%\'}"
24-
value="${value#\'}"
25-
export "$key=$value"
26-
done < "$SCRIPT_DIR/.env"
27-
set +a
28-
fi
14+
# Safe .env loading for port overrides (no eval; use lib/safe-env.sh)
15+
[[ -f "$SCRIPT_DIR/lib/safe-env.sh" ]] && . "$SCRIPT_DIR/lib/safe-env.sh"
16+
load_env_file "$SCRIPT_DIR/.env"
2917

3018
# Resolve compose flags for accurate status checks
3119
COMPOSE_FLAGS=""

dream-server/scripts/dream-test-functional.sh

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,8 @@ if [[ -f "$_FT_DIR/lib/service-registry.sh" ]]; then
2525
export SCRIPT_DIR="$_FT_DIR"
2626
. "$_FT_DIR/lib/service-registry.sh"
2727
sr_load
28-
if [[ -f "$_FT_DIR/.env" ]]; then
29-
set -a
30-
while IFS='=' read -r key value; do
31-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
32-
[[ -z "$key" ]] && continue
33-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
34-
value="${value%\"}"
35-
value="${value#\"}"
36-
value="${value%\'}"
37-
value="${value#\'}"
38-
export "$key=$value"
39-
done < "$_FT_DIR/.env"
40-
set +a
41-
fi
28+
[[ -f "$_FT_DIR/lib/safe-env.sh" ]] && . "$_FT_DIR/lib/safe-env.sh"
29+
load_env_file "$_FT_DIR/.env"
4230
fi
4331

4432
# Service endpoints — resolved from registry

dream-server/scripts/dream-test.sh

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,8 @@ if [[ -f "$_DT_DIR/lib/service-registry.sh" ]]; then
3636
export SCRIPT_DIR="$_DT_DIR"
3737
. "$_DT_DIR/lib/service-registry.sh"
3838
sr_load
39-
if [[ -f "$_DT_DIR/.env" ]]; then
40-
set -a
41-
while IFS='=' read -r key value; do
42-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
43-
[[ -z "$key" ]] && continue
44-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
45-
value="${value%\"}"
46-
value="${value#\"}"
47-
value="${value%\'}"
48-
value="${value#\'}"
49-
export "$key=$value"
50-
done < "$_DT_DIR/.env"
51-
set +a
52-
fi
39+
[[ -f "$_DT_DIR/lib/safe-env.sh" ]] && . "$_DT_DIR/lib/safe-env.sh"
40+
load_env_file "$_DT_DIR/.env"
5341
fi
5442

5543
# Service endpoints — resolved from registry
@@ -98,11 +86,8 @@ RESULTS_DETAILS=()
9886
#--------------------------------------------------------------------------
9987

10088
load_env() {
101-
if [[ -f "$ENV_FILE" ]]; then
102-
set -a
103-
source "$ENV_FILE" 2>/dev/null || true
104-
set +a
105-
fi
89+
[[ -f "$_DT_DIR/lib/safe-env.sh" ]] && . "$_DT_DIR/lib/safe-env.sh"
90+
load_env_file "$ENV_FILE"
10691
}
10792

10893
log() {

dream-server/scripts/first-boot-demo.sh

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,8 @@ if [[ -f "$_DEMO_DIR/lib/service-registry.sh" ]]; then
2727
export SCRIPT_DIR="$_DEMO_DIR"
2828
. "$_DEMO_DIR/lib/service-registry.sh"
2929
sr_load
30-
if [[ -f "$_DEMO_DIR/.env" ]]; then
31-
set -a
32-
while IFS='=' read -r key value; do
33-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
34-
[[ -z "$key" ]] && continue
35-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
36-
value="${value%\"}"
37-
value="${value#\"}"
38-
value="${value%\'}"
39-
value="${value#\'}"
40-
export "$key=$value"
41-
done < "$_DEMO_DIR/.env"
42-
set +a
43-
fi
30+
[[ -f "$_DEMO_DIR/lib/safe-env.sh" ]] && . "$_DEMO_DIR/lib/safe-env.sh"
31+
load_env_file "$_DEMO_DIR/.env"
4432
fi
4533

4634
LLM_URL="${LLM_URL:-http://localhost:${SERVICE_PORTS[llama-server]:-8080}}"

dream-server/scripts/health-check.sh

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,9 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
2828
. "$SCRIPT_DIR/lib/service-registry.sh"
2929
sr_load
3030

31-
# Load env for port overrides
32-
ENV_FILE="${INSTALL_DIR}/.env"
33-
if [[ -f "$ENV_FILE" ]]; then
34-
set -a
35-
while IFS='=' read -r key value; do
36-
[[ "$key" =~ ^[[:space:]]*# ]] && continue
37-
[[ -z "$key" ]] && continue
38-
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
39-
value="${value%\"}"
40-
value="${value#\"}"
41-
export "$key=$value"
42-
done < "$ENV_FILE"
43-
set +a
44-
fi
31+
# Safe .env loading for port overrides (no eval; use lib/safe-env.sh)
32+
[[ -f "$SCRIPT_DIR/lib/safe-env.sh" ]] && . "$SCRIPT_DIR/lib/safe-env.sh"
33+
load_env_file "${INSTALL_DIR}/.env"
4534

4635
# Colors (disabled for JSON/quiet)
4736
if $JSON_OUTPUT || $QUIET; then

0 commit comments

Comments
 (0)