fix: SECURITY: Replace eval usage with safer alternatives (#59) #63
3 changed files with 42 additions and 15 deletions
22
lib/env.sh
22
lib/env.sh
|
|
@ -29,8 +29,26 @@ if [ -f "$FACTORY_ROOT/.env.enc" ] && command -v sops &>/dev/null; then
|
||||||
set -a
|
set -a
|
||||||
_saved_forge_url="${FORGE_URL:-}"
|
_saved_forge_url="${FORGE_URL:-}"
|
||||||
_saved_forge_token="${FORGE_TOKEN:-}"
|
_saved_forge_token="${FORGE_TOKEN:-}"
|
||||||
eval "$(sops -d --output-type dotenv "$FACTORY_ROOT/.env.enc" 2>/dev/null)" \
|
# Use temp file + validate dotenv format before sourcing (avoids eval injection)
|
||||||
|| echo "Warning: failed to decrypt .env.enc — secrets not loaded" >&2
|
_tmpenv=$(mktemp) || { echo "Warning: failed to create temp file for .env.enc" >&2; exit 1; }
|
||||||
|
if sops -d --output-type dotenv "$FACTORY_ROOT/.env.enc" > "$_tmpenv" 2>/dev/null; then
|
||||||
|
# Validate: non-empty, non-comment lines must match KEY=value pattern
|
||||||
|
# Filter out blank lines and comments before validation
|
||||||
|
_validated=$(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$_tmpenv" 2>/dev/null || true)
|
||||||
|
if [ -n "$_validated" ]; then
|
||||||
|
# Write validated content to a second temp file and source it
|
||||||
|
_validated_env=$(mktemp)
|
||||||
|
printf '%s\n' "$_validated" > "$_validated_env"
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$_validated_env"
|
||||||
|
rm -f "$_validated_env"
|
||||||
|
else
|
||||||
|
echo "Warning: .env.enc decryption output failed format validation" >&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Warning: failed to decrypt .env.enc — secrets not loaded" >&2
|
||||||
|
fi
|
||||||
|
rm -f "$_tmpenv"
|
||||||
set +a
|
set +a
|
||||||
[ -n "$_saved_forge_url" ] && export FORGE_URL="$_saved_forge_url"
|
[ -n "$_saved_forge_url" ] && export FORGE_URL="$_saved_forge_url"
|
||||||
[ -n "$_saved_forge_token" ] && export FORGE_TOKEN="$_saved_forge_token"
|
[ -n "$_saved_forge_token" ] && export FORGE_TOKEN="$_saved_forge_token"
|
||||||
|
|
|
||||||
|
|
@ -45,16 +45,16 @@ _ilc_log() {
|
||||||
# Label ID caching — lookup once per name, cache in globals.
|
# Label ID caching — lookup once per name, cache in globals.
|
||||||
# Pattern follows ci-helpers.sh (ensure_blocked_label_id).
|
# Pattern follows ci-helpers.sh (ensure_blocked_label_id).
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
_ILC_BACKLOG_ID=""
|
declare -A _ILC_LABEL_IDS
|
||||||
_ILC_IN_PROGRESS_ID=""
|
_ILC_LABEL_IDS["backlog"]=""
|
||||||
_ILC_BLOCKED_ID=""
|
_ILC_LABEL_IDS["in-progress"]=""
|
||||||
|
_ILC_LABEL_IDS["blocked"]=""
|
||||||
|
|
||||||
# _ilc_ensure_label_id VARNAME LABEL_NAME [COLOR]
|
# _ilc_ensure_label_id LABEL_NAME [COLOR]
|
||||||
# Generic: looks up label by name, creates if missing, caches in the named var.
|
# Looks up label by name, creates if missing, caches in associative array.
|
||||||
_ilc_ensure_label_id() {
|
_ilc_ensure_label_id() {
|
||||||
local varname="$1" name="$2" color="${3:-#e0e0e0}"
|
local name="$1" color="${2:-#e0e0e0}"
|
||||||
local current
|
local current="${_ILC_LABEL_IDS[$name]:-}"
|
||||||
eval "current=\"\${${varname}:-}\""
|
|
||||||
if [ -n "$current" ]; then
|
if [ -n "$current" ]; then
|
||||||
printf '%s' "$current"
|
printf '%s' "$current"
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -71,14 +71,14 @@ _ilc_ensure_label_id() {
|
||||||
| jq -r '.id // empty' 2>/dev/null || true)
|
| jq -r '.id // empty' 2>/dev/null || true)
|
||||||
fi
|
fi
|
||||||
if [ -n "$label_id" ]; then
|
if [ -n "$label_id" ]; then
|
||||||
eval "${varname}=\"${label_id}\""
|
_ILC_LABEL_IDS["$name"]="$label_id"
|
||||||
fi
|
fi
|
||||||
printf '%s' "$label_id"
|
printf '%s' "$label_id"
|
||||||
}
|
}
|
||||||
|
|
||||||
_ilc_backlog_id() { _ilc_ensure_label_id _ILC_BACKLOG_ID "backlog" "#0075ca"; }
|
_ilc_backlog_id() { _ilc_ensure_label_id "backlog" "#0075ca"; }
|
||||||
_ilc_in_progress_id() { _ilc_ensure_label_id _ILC_IN_PROGRESS_ID "in-progress" "#1d76db"; }
|
_ilc_in_progress_id() { _ilc_ensure_label_id "in-progress" "#1d76db"; }
|
||||||
_ilc_blocked_id() { _ilc_ensure_label_id _ILC_BLOCKED_ID "blocked" "#e11d48"; }
|
_ilc_blocked_id() { _ilc_ensure_label_id "blocked" "#e11d48"; }
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# issue_claim — assign issue to bot, add "in-progress" label, remove "backlog".
|
# issue_claim — assign issue to bot, add "in-progress" label, remove "backlog".
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,16 @@ mirror_push() {
|
||||||
|
|
||||||
local name url
|
local name url
|
||||||
for name in $MIRROR_NAMES; do
|
for name in $MIRROR_NAMES; do
|
||||||
url=$(eval "echo \"\$MIRROR_$(echo "$name" | tr '[:lower:]' '[:upper:]')\"") || true
|
# Convert name to uppercase env var name safely (only alphanumeric allowed)
|
||||||
|
local upper_name
|
||||||
|
upper_name=$(printf '%s' "$name" | tr '[:lower:]' '[:upper:]')
|
||||||
|
# Validate: only allow alphanumeric + underscore in var name
|
||||||
|
if [[ ! "$upper_name" =~ ^[A-Z_][A-Z0-9_]*$ ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Use indirect expansion safely (no eval) — MIRROR_ prefix required
|
||||||
|
local varname="MIRROR_${upper_name}"
|
||||||
|
url="${!varname:-}"
|
||||||
[ -z "$url" ] && continue
|
[ -z "$url" ] && continue
|
||||||
|
|
||||||
# Ensure remote exists with correct URL
|
# Ensure remote exists with correct URL
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue