Skip to content

Commit 1f90422

Browse files
authored
Added Credo (nccgroup#132)
1 parent 6fb0fcb commit 1f90422

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+664
-102
lines changed

.credo.exs

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# This file contains the configuration for Credo and you are probably reading
2+
# this after creating it with `mix credo.gen.config`.
3+
#
4+
# If you find anything wrong or unclear in this file, please report an
5+
# issue on GitHub: https://github.com/rrrene/credo/issues
6+
#
7+
%{
8+
#
9+
# You can have as many configs as you like in the `configs:` field.
10+
configs: [
11+
%{
12+
#
13+
# Run any config using `mix credo -C <name>`. If no config name is given
14+
# "default" is used.
15+
#
16+
name: "default",
17+
#
18+
# These are the files included in the analysis:
19+
files: %{
20+
#
21+
# You can give explicit globs or simply directories.
22+
# In the latter case `**/*.{ex,exs}` will be used.
23+
#
24+
included: [
25+
"lib/",
26+
"src/",
27+
"web/",
28+
"apps/*/lib/",
29+
"apps/*/src/",
30+
"apps/*/test/",
31+
"apps/*/web/"
32+
],
33+
excluded: [
34+
~r"/_build/",
35+
~r"/deps/",
36+
~r"/node_modules/",
37+
"test/"
38+
]
39+
},
40+
#
41+
# Load and configure plugins here:
42+
#
43+
plugins: [],
44+
#
45+
# If you create your own checks, you must specify the source files for
46+
# them here, so they can be loaded by Credo before running the analysis.
47+
#
48+
requires: [],
49+
#
50+
# If you want to enforce a style guide and need a more traditional linting
51+
# experience, you can change `strict` to `true` below:
52+
#
53+
strict: false,
54+
#
55+
# To modify the timeout for parsing files, change this value:
56+
#
57+
parse_timeout: 5000,
58+
#
59+
# If you want to use uncolored output by default, you can change `color`
60+
# to `false` below:
61+
#
62+
color: true,
63+
#
64+
# You can customize the parameters of any check by adding a second element
65+
# to the tuple.
66+
#
67+
# To disable a check put `false` as second element:
68+
#
69+
# {Credo.Check.Design.DuplicatedCode, false}
70+
#
71+
checks: %{
72+
enabled: [
73+
#
74+
## Consistency Checks
75+
#
76+
{Credo.Check.Consistency.ExceptionNames, []},
77+
{Credo.Check.Consistency.LineEndings, []},
78+
{Credo.Check.Consistency.ParameterPatternMatching, []},
79+
{Credo.Check.Consistency.SpaceAroundOperators, []},
80+
{Credo.Check.Consistency.SpaceInParentheses, []},
81+
{Credo.Check.Consistency.TabsOrSpaces, []},
82+
83+
#
84+
## Design Checks
85+
#
86+
# You can customize the priority of any check
87+
# Priority values are: `low, normal, high, higher`
88+
#
89+
{Credo.Check.Design.AliasUsage,
90+
[priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
91+
# You can also customize the exit_status of each check.
92+
# If you don't want TODO comments to cause `mix credo` to fail, just
93+
# set this value to 0 (zero).
94+
#
95+
{Credo.Check.Design.TagTODO, [exit_status: 2]},
96+
{Credo.Check.Design.TagFIXME, []},
97+
98+
#
99+
## Readability Checks
100+
#
101+
{Credo.Check.Readability.AliasOrder, []},
102+
{Credo.Check.Readability.FunctionNames, []},
103+
{Credo.Check.Readability.LargeNumbers, []},
104+
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
105+
{Credo.Check.Readability.ModuleAttributeNames, []},
106+
{Credo.Check.Readability.ModuleDoc, []},
107+
{Credo.Check.Readability.ModuleNames, []},
108+
{Credo.Check.Readability.ParenthesesInCondition, []},
109+
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
110+
{Credo.Check.Readability.PipeIntoAnonymousFunctions, []},
111+
{Credo.Check.Readability.PredicateFunctionNames, []},
112+
{Credo.Check.Readability.PreferImplicitTry, []},
113+
{Credo.Check.Readability.RedundantBlankLines, []},
114+
{Credo.Check.Readability.Semicolons, []},
115+
{Credo.Check.Readability.SpaceAfterCommas, []},
116+
{Credo.Check.Readability.StringSigils, []},
117+
{Credo.Check.Readability.TrailingBlankLine, []},
118+
{Credo.Check.Readability.TrailingWhiteSpace, []},
119+
{Credo.Check.Readability.UnnecessaryAliasExpansion, []},
120+
{Credo.Check.Readability.VariableNames, []},
121+
{Credo.Check.Readability.WithSingleClause, []},
122+
123+
#
124+
## Refactoring Opportunities
125+
#
126+
{Credo.Check.Refactor.Apply, false}, # should re-enable at some point
127+
{Credo.Check.Refactor.CondStatements, []},
128+
{Credo.Check.Refactor.CyclomaticComplexity, false}, # should re-enable at some point
129+
{Credo.Check.Refactor.FunctionArity, []},
130+
{Credo.Check.Refactor.LongQuoteBlocks, []},
131+
{Credo.Check.Refactor.MatchInCondition, []},
132+
{Credo.Check.Refactor.MapJoin, []},
133+
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
134+
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
135+
{Credo.Check.Refactor.Nesting, false}, # should re-enable at some point
136+
{Credo.Check.Refactor.UnlessWithElse, []},
137+
{Credo.Check.Refactor.WithClauses, []},
138+
{Credo.Check.Refactor.FilterCount, []},
139+
{Credo.Check.Refactor.FilterFilter, []},
140+
{Credo.Check.Refactor.RejectReject, []},
141+
{Credo.Check.Refactor.RedundantWithClauseResult, []},
142+
143+
#
144+
## Warnings
145+
#
146+
{Credo.Check.Warning.ApplicationConfigInModuleAttribute, []},
147+
{Credo.Check.Warning.BoolOperationOnSameValues, []},
148+
{Credo.Check.Warning.Dbg, []},
149+
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
150+
{Credo.Check.Warning.IExPry, []},
151+
{Credo.Check.Warning.IoInspect, []},
152+
{Credo.Check.Warning.MissedMetadataKeyInLoggerConfig, []},
153+
{Credo.Check.Warning.OperationOnSameValues, []},
154+
{Credo.Check.Warning.OperationWithConstantResult, []},
155+
{Credo.Check.Warning.RaiseInsideRescue, []},
156+
{Credo.Check.Warning.SpecWithStruct, []},
157+
{Credo.Check.Warning.WrongTestFileExtension, []},
158+
{Credo.Check.Warning.UnusedEnumOperation, []},
159+
{Credo.Check.Warning.UnusedFileOperation, []},
160+
{Credo.Check.Warning.UnusedKeywordOperation, []},
161+
{Credo.Check.Warning.UnusedListOperation, []},
162+
{Credo.Check.Warning.UnusedPathOperation, []},
163+
{Credo.Check.Warning.UnusedRegexOperation, []},
164+
{Credo.Check.Warning.UnusedStringOperation, []},
165+
{Credo.Check.Warning.UnusedTupleOperation, []},
166+
{Credo.Check.Warning.UnsafeExec, []}
167+
],
168+
disabled: [
169+
#
170+
# Checks scheduled for next check update (opt-in for now, just replace `false` with `[]`)
171+
172+
#
173+
# Controversial and experimental checks (opt-in, just move the check to `:enabled`
174+
# and be sure to use `mix credo --strict` to see low priority checks)
175+
#
176+
{Credo.Check.Consistency.MultiAliasImportRequireUse, []},
177+
{Credo.Check.Consistency.UnusedVariableNames, []},
178+
{Credo.Check.Design.DuplicatedCode, []},
179+
{Credo.Check.Design.SkipTestWithoutComment, []},
180+
{Credo.Check.Readability.AliasAs, []},
181+
{Credo.Check.Readability.BlockPipe, []},
182+
{Credo.Check.Readability.ImplTrue, []},
183+
{Credo.Check.Readability.MultiAlias, []},
184+
{Credo.Check.Readability.NestedFunctionCalls, []},
185+
{Credo.Check.Readability.OneArityFunctionInPipe, []},
186+
{Credo.Check.Readability.SeparateAliasRequire, []},
187+
{Credo.Check.Readability.SingleFunctionToBlockPipe, []},
188+
{Credo.Check.Readability.SinglePipe, []},
189+
{Credo.Check.Readability.Specs, []},
190+
{Credo.Check.Readability.StrictModuleLayout, []},
191+
{Credo.Check.Readability.WithCustomTaggedTuple, []},
192+
{Credo.Check.Readability.OnePipePerLine, []},
193+
{Credo.Check.Refactor.ABCSize, []},
194+
{Credo.Check.Refactor.AppendSingleItem, []},
195+
{Credo.Check.Refactor.DoubleBooleanNegation, []},
196+
{Credo.Check.Refactor.FilterReject, []},
197+
{Credo.Check.Refactor.IoPuts, []},
198+
{Credo.Check.Refactor.MapMap, []},
199+
{Credo.Check.Refactor.ModuleDependencies, []},
200+
{Credo.Check.Refactor.NegatedIsNil, []},
201+
{Credo.Check.Refactor.PassAsyncInTestCases, []},
202+
{Credo.Check.Refactor.PipeChainStart, []},
203+
{Credo.Check.Refactor.RejectFilter, []},
204+
{Credo.Check.Refactor.VariableRebinding, []},
205+
{Credo.Check.Warning.LazyLogging, []},
206+
{Credo.Check.Warning.LeakyEnvironment, []},
207+
{Credo.Check.Warning.MapGetUnsafePass, []},
208+
{Credo.Check.Warning.MixEnv, []},
209+
{Credo.Check.Warning.UnsafeToAtom, []}
210+
211+
# {Credo.Check.Refactor.MapInto, []},
212+
213+
#
214+
# Custom checks can be created using `mix credo.gen.check`.
215+
#
216+
]
217+
}
218+
}
219+
]
220+
}

.github/workflows/elixir.yml

+17-9
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,11 @@ env:
1212
jobs:
1313
mix_test:
1414
name: mix test (Elixir ${{matrix.elixir}} | OTP ${{matrix.otp}})
15-
runs-on: ubuntu-18.04
15+
runs-on: ubuntu-20.04
1616
strategy:
1717
fail-fast: false
1818
matrix:
1919
include:
20-
- elixir: '1.5.x'
21-
otp: 20.3.8.26
22-
- elixir: '1.6.6'
23-
otp: 21.3.8.24
2420
- elixir: '1.7.x'
2521
otp: 22.3.4.26
2622
- elixir: '1.8.x'
@@ -37,15 +33,13 @@ jobs:
3733
otp: 25.1
3834
- elixir: '1.14.x'
3935
otp: 25.1
40-
#warnings_as_errors: true # temporarily disabled due to separate issue that requires fixing, see: https://github.com/nccgroup/sobelow/issues/115
41-
check_formatted: true
4236

4337
steps:
4438
- name: Setup Elixir
4539
uses: erlef/setup-beam@v1
4640
with:
47-
otp-version: ${{matrix.otp}}
48-
elixir-version: ${{matrix.elixir}}
41+
otp-version: ${{ matrix.otp }}
42+
elixir-version: ${{ matrix.elixir }}
4943

5044
- name: Checkout Code
5145
uses: actions/checkout@v3
@@ -56,5 +50,19 @@ jobs:
5650
mix local.rebar --force
5751
mix deps.get --only test
5852
53+
- name: Hex Audit
54+
run: mix hex.audit
55+
56+
- name: Check Formatting
57+
if: ${{ matrix.elixir == '1.14.x' }} # we only care about formatting for latest version of Elixir
58+
run: mix format --check-formatted
59+
60+
- name: Compiles w/o Warnings
61+
if: ${{ matrix.elixir == '1.14.x' }} # we only care about warnings for latest version of Elixir
62+
run: mix compile --warnings-as-errors
63+
64+
- name: Credo
65+
run: mix credo --all --strict
66+
5967
- name: Run Tests
6068
run: mix test

CHANGELOG.md

+16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## v0.13.0
4+
* Removed
5+
* 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)
6+
* Enhancements
7+
* Fixed all `credo` warnings
8+
* Implemented all `credo` "Code Readability" adjustments
9+
* Took advantage of _some_ `credo` refactoring opportunities
10+
* Added (sub)module documentation that was missing for some vulnerabilities and unified presentation of others
11+
* Misc
12+
* Added `mix credo --strict` to project
13+
* Improvements to GitHub CI
14+
* Hex Audit
15+
* Compiler Warnings as Errors
16+
* Checks Formatting
17+
* Added helper `mix test.all` alias
18+
319
## v0.12.2
420
* Bug fixes
521
* 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

lib/mix/tasks/sobelow.ex

+11-7
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,17 @@ defmodule Mix.Tasks.Sobelow do
192192

193193
# This diff check is strictly used for testing/debugging and
194194
# isn't meant for general use.
195+
#
196+
# Useful for comapring the output of two different runs of Sobelow
195197
def run_diff(argv) do
196198
diff_idx = Enum.find_index(argv, fn i -> i === "--diff" end)
197199
{_, list} = List.pop_at(argv, diff_idx)
198200
{diff_target, list} = List.pop_at(list, diff_idx)
199-
args = Enum.join(list, " ") |> to_charlist()
200-
diff_target = to_charlist(diff_target)
201-
:os.cmd('mix sobelow ' ++ args ++ ' > sobelow.tempdiff')
202-
IO.puts(:os.cmd('diff sobelow.tempdiff ' ++ diff_target))
201+
args = Enum.join(list, " ")
202+
diff_target = to_string(diff_target)
203+
System.shell("mix sobelow #{args} > sobelow.tempdiff")
204+
{diff, _} = System.shell("diff sobelow.tempdiff #{diff_target}")
205+
IO.puts(diff)
203206
end
204207

205208
def set_env(key, value) do
@@ -279,9 +282,10 @@ defmodule Mix.Tasks.Sobelow do
279282
defp out_format("", format), do: format
280283

281284
defp out_format(_out, format) do
282-
cond do
283-
format in ["json", "quiet", "sarif"] -> format
284-
true -> "json"
285+
if format in ["json", "quiet", "sarif"] do
286+
format
287+
else
288+
"json"
285289
end
286290
end
287291
end

0 commit comments

Comments
 (0)