Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trivy Action Inputs Not Respected In Subsequent Invocations #422

Open
jtl-novatec opened this issue Oct 22, 2024 · 2 comments
Open

Trivy Action Inputs Not Respected In Subsequent Invocations #422

jtl-novatec opened this issue Oct 22, 2024 · 2 comments

Comments

@jtl-novatec
Copy link

jtl-novatec commented Oct 22, 2024

I encountered an issue while setting up shared composite actions for our teams to easily use Trivy in their workflows. Specifically, the problem arises from how the Trivy action uses >> $GITHUB_ENV to process inputs and make them available to subsequent steps.

- name: Set Trivy environment variables
  shell: bash
  run: |
    # Note: There is currently no way to distinguish between undefined variables and empty strings in GitHub Actions.
    # This limitation affects how we handle default values and empty inputs.
    # For more information, see: https://github.com/actions/runner/issues/924

    set_env_var_if_provided() {
      local var_name="$1"
      local input_value="$2"
      local default_value="$3"
    
      if [ ! -z "$input_value" ] && [ "$input_value" != "$default_value" ]; then
        echo "$var_name=$input_value" >> $GITHUB_ENV
      fi
    }

Expected Behavior:

The Trivy action documentation suggests running the action multiple times in sequence, for example, to generate different outputs (e.g., SBOM, SARIF, Markdown) or to fail the build only for high-severity vulnerabilities. Each step should be able to set its own input variables.

Actual Behavior:

In practice, it looks like inputs can only be set once per job and cannot be overwritten by subsequent steps. For example, the first step in the workflow sets the output format (e.g., github), but later steps ignore their own inputs and continue using the values from the first step. This seems related to this GitHub Actions runner issue.

Workaround:

A possible workaround is to avoid using action inputs and rely on env: variables prefixed with TRIVY_ across steps. However, this has significant drawbacks:

  • Input precedence violation: Inputs should typically have higher precedence than environment variables, but this approach flips that assumption.
    (- Question?: Passing sensitive data (like tokens) via env: could lead to leaks, as environment variables might not be handled as securely as inputs)

Request:

Is there a better way to handle action inputs to avoid this limitation? It would ensure consistent behavior across steps without needing hacky workarounds

@jtl-novatec
Copy link
Author

jtl-novatec commented Oct 22, 2024

Maybe it's possible to use github_output instead of github_env and access it via the step? Another idea would be to get rid of the set env step and pass action inputs straight to the entrypoint.sh. The wrapper then checks for user-supplied inputs and passes only those as cli flags preserving the viper precedence. Here is a rough sketch:

runs:
  using: 'composite'
  steps:
    - ... 
    - name: Run entrypoint script
      shell: bash
      run: |
        ./entrypoint.sh \
          --input "${{ inputs.input }}" \
          --exit-code "${{ inputs.exit-code }}" \
          --ignore-unfixed "${{ inputs.ignore-unfixed }}" \
          --vuln-type "${{ inputs.vuln-type }}" \ 

Here a little example of how this could look like in entrypoint.sh (neglecting the current exceptions which it currently handles)

# Default values (as defined by composite action inputs)
declare -A action_input_defaults=(
  ["--input"]=""
  ["--exit-code"]=""
  ["--ignore-unfixed"]="false"
  ["--vuln-type"]="os,library"
  ["--severity"]="UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
  ["--format"]="table"
  ["--template"]=""
  ["--output"]=""
  ["--skip-dirs"]=""
  ["--skip-files"]=""
  ["--timeout"]=""
  ["--ignore-policy"]=""
  ["--quiet"]="false"
  ["--list-all-pkgs"]="false"
  ["--scanners"]=""
  ["--config"]=""
  ["--tf-vars"]=""
  ["--docker-host"]=""
)

# maps cli flags to supplied inputs
declare -A cli_to_action_input

# stores inputs that are passed to the cli via flags
declare -A cli_inputs

# Function to check if action input should be added to cli_inputs array
validate_input() {
  local flag="$1"
  local value="$2"
  local default="${action_input_defaults[$flag]}"

  # Skip if no value or value matches default
  [[ -z "$value" || "$value" == "$default" ]] && return

  # Store the valid flag and value in cli_inputs
  cli_inputs["$flag"]="$value"
}


# Argument parsing function
parse_args() {
  while [[ "$#" -gt 0 ]]; do
    case "$1" in
      --input|--exit-code|--ignore-unfixed|--vuln-type|--severity|--format|--template|--output|--skip-dirs|--skip-files|--timeout|--ignore-policy|--hide-progress|--list-all-pkgs|--scanners|--trivy-config|--tf-vars|--docker-host)
        cli_to_action_input["$1"]="$2";
        shift
        ;;
      --help)
        show_help
        ;;
      *)
        echo "Error: Unknown option $1"
        show_help
        ;;
    esac
    shift
  done
}


# Main function
main() {
  # Parse input arguments
  parse_args "$@"

  # compare passed inputs against defaults to detect user-supplied values
  for flag in "${!cli_to_action_input[@]}"; do
    validate_input "$flag" "${cli_to_action_input[$flag]}"
  done

  # Construct the CLI command
  local cli_command="trivy image"

  for flag in "${!cli_inputs[@]}"; do
    cli_command+=" $flag ${cli_inputs[$flag]}"
  done

  # Execute the command
  echo "Executing: $cli_command"
}

# Execute the main function with the provided arguments
main "$@"

@jtl-novatec jtl-novatec changed the title Trivy Action Inputs Can't Be Overwritten Across Steps Trivy Action Inputs Not Respected In Subsequent Invocations Oct 23, 2024
@GuiGarnier
Copy link

I guess I have a similar issue.
I launch scan analysis twice, changing the format output 'github' then 'table'.
But I only get 'github' format and I guess this is linked to the same code condition.
May just adding a condition could help or unset env value first ?

if [ ! -z "$input_value" ] && [ "$input_value" != "$default_value" ] && [ "$input_value" != "$var_name" ]; then

or

    set_env_var_if_provided() {
      local var_name="$1"
      local input_value="$2"
      local default_value="$3"
      unset $var_name
      if [ ! -z "$input_value" ] && [ "$input_value" != "$default_value" ]; then
        echo "$var_name=$input_value" >> $GITHUB_ENV
      fi
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants