Skip to content

Support options from task and config #170

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

Closed
wants to merge 12 commits into from
Closed
76 changes: 35 additions & 41 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,63 @@ on:
pull_request:
push:
branches:
- master
- main

env:
MIX_ENV: test

jobs:
mix_test:
name: mix test (Elixir ${{matrix.elixir}} | OTP ${{matrix.otp}})
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- elixir: '1.7.x'
otp: 22.3.4.26
- elixir: '1.8.x'
otp: 22.3.4.26
- elixir: '1.9.x'
otp: 22.3.4.26
- elixir: '1.10.x'
otp: 22.3.4.26
- elixir: '1.11.x'
otp: 23.3.4.18
- elixir: '1.12.x'
- elixir: "1.12.x"
otp: 24
- elixir: '1.13.x'
- elixir: "1.13.x"
otp: 25.1
- elixir: '1.14.x'
- elixir: "1.14.x"
otp: 25.1
- elixir: '1.15.x'
- elixir: "1.15.x"
otp: 26.0
- elixir: '1.16.x'
- elixir: "1.16.x"
otp: 26.2
- elixir: "1.17.x"
otp: 27
- elixir: "1.18.x"
otp: 27

steps:
- name: Setup Elixir
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}
- name: Setup Elixir
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}

- name: Checkout Code
uses: actions/checkout@v3
- name: Checkout Code
uses: actions/checkout@v3

- name: Install Dependencies
run: |
mix local.hex --force
mix local.rebar --force
mix deps.get --only test
- name: Install Dependencies
run: |
mix local.hex --force
mix local.rebar --force
mix deps.get --only test

- name: Hex Audit
run: mix hex.audit
- name: Hex Audit
run: mix hex.audit

- name: Check Formatting
if: ${{ matrix.elixir == '1.16.x' }} # we only care about formatting for latest version of Elixir
run: mix format --check-formatted
- name: Check Formatting
if: ${{ matrix.elixir == '1.16.x' }} # we only care about formatting for latest version of Elixir
run: mix format --check-formatted

- name: Compiles w/o Warnings
if: ${{ matrix.elixir == '1.16.x' }} # we only care about warnings for latest version of Elixir
run: mix compile --warnings-as-errors
- name: Compiles w/o Warnings
if: ${{ matrix.elixir == '1.16.x' }} # we only care about warnings for latest version of Elixir
run: mix compile --warnings-as-errors

- name: Credo
run: mix credo --all --strict
- name: Credo
run: mix credo --all --strict

- name: Run Tests
run: mix test
- name: Run Tests
run: mix test
53 changes: 35 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## v0.14.0
* Removed
* Support for minimum Elixir versions 1.7 - 1.11 (**POTENTIALLY BREAKING** - only applies if you relied on Elixir 1.7 through 1.11, 1.12+ is still supported)
* Enhancements
* Added support for multiple variations of `SQL.query()`
* Added support for `System.shell' command introduced in Elixir v1.12
* Ignore runtime config during `Config.HSTS`
* Updated developer dependencies (`ex_doc` & `credo`)
* Bug fixes
* Fixed `is_endpoint?` error in main
* Fixed findings normalization bug
* Fixed truncation error
* Misc
* GitHub Actions test matrix updated (hence the large drop in support for old Elixir versions)
* Addressed compiler warnings from Elixir v1.18.x
* Moved from `master` branch to `main`

## v0.13.0
* Removed
* Support for minimum Elixir versions 1.5 & 1.6 (**POTENTIALLY BREAKING** - only applies if you relied on Elixir 1.5 or 1.6, 1.7+ is still supported)
Expand All @@ -18,7 +35,7 @@
* Compiler Warnings as Errors
* Checks Formatting
* Added helper `mix test.all` alias

## v0.12.2
* Bug fixes
* Removed `:castore` and introduced `:verify_none` to quiet warning and unblock escript usage, see [#133](https://github.com/nccgroup/sobelow/issues/133) for more context on why this is necessary
Expand Down Expand Up @@ -55,19 +72,19 @@
## v0.11.1
* Enhancements
* Sarif output with `--out` flag
* `--strict` flag, which throws compilation errors instead of suppressing them.
* `--strict` flag, which throws compilation errors instead of suppressing them.

## v0.11.0
* Enhancements
* Sarif output for GitHub integration
* `--flycheck` flag, which reverses output of `--compact`
* Bug fixes
* Non-compiling files now return an empty syntax tree instead of
* Non-compiling files now return an empty syntax tree instead of
causing Sobelow errors.
* Command Injection finding description are properly formatted
* Misc
* If you use Sobelow as a standalone utility (i.e. not as part of
a Phoenix application), you now need to install as an escript with
* If you use Sobelow as a standalone utility (i.e. not as part of
a Phoenix application), you now need to install as an escript with
`mix escript.install hex sobelow`.
* Custom JSON serialization replaced with Jason.

Expand Down Expand Up @@ -105,7 +122,7 @@
## v0.9.3
* Enhancements
* Improved checks for all aliased functions

* Bug Fixes
* JSON output for Raw findings is now properly normalized
* `send_download` correctly flags aliased function calls
Expand All @@ -124,7 +141,7 @@
* Add `--mark-skip-all` and `--clear-skip` flags
* New CSRF via action reuse checks
* Sobelow can now be run in umbrella apps

* Bug Fixes
* Fix an error when printing some kinds of variables

Expand All @@ -134,26 +151,26 @@
* All JSON findings contain `type`, `file`, and `line` keys
* "Line" output now refers directly to the vulnerable line
* Default output headers have been normalized
**Note:** If you depend on the structure of the output, this
may be a breaking change. More information can be found at

**Note:** If you depend on the structure of the output, this
may be a breaking change. More information can be found at
[https://sobelow.io](https://sobelow.io).

## v0.7.8
* Enhancements
* Add `--threshold` flag
* Add module names to finding output

* Deprecations
* File/Path check has been deprecated
* File/Path check has been deprecated

* Bug Fixes
* Fix inaccurate CSRF details

## v0.7.7
* Enhancements
* Add check for insecure websocket settings

* Bug Fixes
* Accept module attributes for application name

Expand Down Expand Up @@ -231,7 +248,7 @@

* Bug Fixes
* Allow RCE module to be appropriately ignored.

## v0.6.4

* Enhancements
Expand All @@ -241,8 +258,8 @@

* Enhancements
* Add RCE module to check for code execution via `Code` and `EEx`.

* Deprecations
* The `--with-code` flag has been changed to `--verbose`. The `--with-code`
flag will continue to work as expected until v1.0.0, but will print a
* The `--with-code` flag has been changed to `--verbose`. The `--with-code`
flag will continue to work as expected until v1.0.0, but will print a
warning message.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ from the command line:

$ mix escript.install hex sobelow

To install from the master branch, rather than the latest release,
To install from the `main` branch, rather than the latest release,
the following command can be used:

$ mix escript.install github nccgroup/sobelow
$ mix escript.install github sobelow/sobelow

### To Use

Expand Down
39 changes: 18 additions & 21 deletions lib/mix/tasks/sobelow.ex
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ defmodule Mix.Tasks.Sobelow do
{opts, _, _} = OptionParser.parse(argv, aliases: @aliases, switches: @switches)

root = Keyword.get(opts, :root, ".")
config = Keyword.get(opts, :config, false)
config = Keyword.get(opts, :config, true)
conf_file = root <> "/.sobelow-conf"
conf_file? = config && File.exists?(conf_file)

Expand All @@ -134,15 +134,16 @@ defmodule Mix.Tasks.Sobelow do

opts =
if conf_file? do
{:ok, opts} = File.read!(conf_file) |> Code.string_to_quoted()
opts
{:ok, file_opts} = File.read!(conf_file) |> Code.string_to_quoted()
# CLI args take precedence
Keyword.merge(file_opts, opts)
else
opts
end

{verbose, diff, details, private, strict, skip, mark_skip_all, clear_skip, router, exit_on,
format, ignored, ignored_files, all_details, out, threshold,
version} = get_opts(opts, root, conf_file?)
version} = get_opts(opts, root)

set_env(:verbose, verbose)

Expand Down Expand Up @@ -198,7 +199,7 @@ defmodule Mix.Tasks.Sobelow do
# This diff check is strictly used for testing/debugging and
# isn't meant for general use.
#
# Useful for comapring the output of two different runs of Sobelow
# Useful for comparing the output of two different runs of Sobelow
def run_diff(argv) do
diff_idx = Enum.find_index(argv, fn i -> i === "--diff" end)
{_, list} = List.pop_at(argv, diff_idx)
Expand All @@ -214,7 +215,7 @@ defmodule Mix.Tasks.Sobelow do
Application.put_env(:sobelow, key, value)
end

defp get_opts(opts, root, conf_file?) do
defp get_opts(opts, root) do
verbose = Keyword.get(opts, :verbose, false)
details = Keyword.get(opts, :details, nil)
all_details = Keyword.get(opts, :all_details)
Expand Down Expand Up @@ -249,22 +250,18 @@ defmodule Mix.Tasks.Sobelow do

format = out_format(out, format)

{ignored, ignored_files} =
if conf_file? do
{Keyword.get(opts, :ignore, []),
Keyword.get(opts, :ignore_files, []) |> Enum.map(&Path.expand(&1, root))}
else
ignored =
Keyword.get(opts, :ignore, "")
|> String.split(",")

ignored_files =
Keyword.get(opts, :ignore_files, "")
|> String.split(",")
|> Enum.reject(fn file -> file == "" end)
|> Enum.map(&Path.expand(&1, root))
ignored =
case Keyword.get(opts, :ignore, []) do
ignore_str when is_binary(ignore_str) -> String.split(ignore_str, ",")
ignore -> ignore
end

{ignored, ignored_files}
ignored_files =
case Keyword.get(opts, :ignore_files, []) do
ignore_files when is_list(ignore_files) ->
Enum.map(ignore_files, &Path.expand(&1, root))
ignore_files_str when is_binary(ignore_files_str) ->
for i <- String.split(ignore_files_str, ",", trim: true), do: Path.expand(i, root)
end

threshold =
Expand Down
12 changes: 10 additions & 2 deletions lib/sobelow/ci/system.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Sobelow.CI.System do
@moduledoc """
# Command Injection in `System.cmd`
# Command Injection via `System`

This submodule of the `CI` module checks for Command Injection
vulnerabilities through usage of the `System.cmd` function.
Expand All @@ -12,7 +12,7 @@ defmodule Sobelow.CI.System do
$ mix sobelow -i CI.System
"""
@uid 2
@finding_type "CI.System: Command Injection in `System.cmd`"
@finding_type "CI.System: Command Injection via `System` function"

use Sobelow.Finding

Expand All @@ -22,9 +22,17 @@ defmodule Sobelow.CI.System do
Finding.init(@finding_type, meta_file.filename, confidence)
|> Finding.multi_from_def(fun, parse_def(fun))
|> Enum.each(&Print.add_finding(&1))

Finding.init(@finding_type, meta_file.filename, confidence)
|> Finding.multi_from_def(fun, parse_def_shell(fun))
|> Enum.each(&Print.add_finding(&1))
end

def parse_def(fun) do
Parse.get_fun_vars_and_meta(fun, 0, :cmd, [:System])
end

def parse_def_shell(fun) do
Parse.get_fun_vars_and_meta(fun, 0, :shell, [:System])
end
end
14 changes: 13 additions & 1 deletion lib/sobelow/finding_log.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,21 @@ defmodule Sobelow.FindingLog do

defp format_sarif(finding) do
[mod, _] = String.split(finding.type, ":", parts: 2)
mod_struct = Sobelow.get_mod(mod)

# 1) We got a module and exports id/0 ─ call it via apply/3
rule_id =
if is_atom(mod_struct) and
Code.ensure_loaded?(mod_struct) and
function_exported?(mod_struct, :id, 0) do
apply(mod_struct, :id, [])
else
# 2) Anything else – we have no id
nil
end

%{
ruleId: Sobelow.get_mod(mod).id,
ruleId: rule_id,
message: %{
text: finding.type
},
Expand Down
Loading