OeditusCredo (OeditusCredo v0.11.1)
View SourceOeditusCredo provides custom Credo checks for detecting common Elixir/Phoenix anti-patterns.
Usage
Add to your .credo.exs:
%{
configs: [
%{
name: "default",
checks: %{
enabled: [
{OeditusCredo.Check.Warning.MissingErrorHandling, []},
{OeditusCredo.Check.Warning.SilentErrorCase, []},
{OeditusCredo.Check.Warning.InefficientFilter, []},
# ... other checks
]
}
}
]
}False Positives
All these checks are somewhat opinionated and might produce false positives.
If a warning does not apply to your specific case, suppress it with
# credo:disable-for-next-line
or any other Credo config comment directive.
General Parameters
All checks support the standard Credo general parameters:
false-- disable the check entirely:{OeditusCredo.Check.Warning.NPlusOneQuery, false}exit_status-- override the exit status for issues from this check (default is16for the:warningcategory). Set to0to make a check advisory-only (still reports issues but won't affect the exit code):{OeditusCredo.Check.Warning.NPlusOneQuery, exit_status: 0}priority-- override the base priority for the check.files-- restrict which files the check runs on.
Additionally, every OeditusCredo check accepts exclude_test_files to skip
files ending in _test.exs or living under a test/ directory. It defaults
to false everywhere except
OeditusCredo.Check.Refactoring.ChangeRiskAntiPatterns, where it defaults to
true.
Available Checks
Error Handling
OeditusCredo.Check.Warning.MissingErrorHandling- Detects{:ok, x} =without error handlingOeditusCredo.Check.Warning.SilentErrorCase- Detects case statements missing error branchesOeditusCredo.Check.Warning.SwallowingException- Detects try/rescue without re-raising or logging
Query & Data Access
OeditusCredo.Check.Warning.NPlusOneQuery- Detects N+1 query patternsOeditusCredo.Check.Warning.InefficientFilter- Detects Repo.all followed by Enum filteringOeditusCredo.Check.Warning.MissingPreload- Detects Ecto queries without proper preloading
Concurrency & Performance
OeditusCredo.Check.Warning.UnmanagedTask- Detects unsupervised Task.async callsOeditusCredo.Check.Warning.SyncOverAsync- Detects blocking operations in LiveView/GenServerOeditusCredo.Check.Warning.MissingHandleAsync- Detects blocking in handle_event without async pattern
Readability
OeditusCredo.Check.Readability.UnnecessaryInterpolatingSigil- Detects~s/~c/~wwithout interpolation (suggests~S/~C/~W)
Code Organization & Idiomatic Refactoring
OeditusCredo.Check.Refactoring.PreferCasePatternMatching- Detectsif/condwherecasepattern matching is preferredOeditusCredo.Check.Refactoring.PreferMultiHeadFunction- Detects parameter branching inside function body instead of multi-head clausesOeditusCredo.Check.Refactoring.PreferPipelineOperator- Detects sequential assignments instead of pipe operator|>OeditusCredo.Check.Refactoring.PreferInplaceMapMatching- Detectsis_map/1guard instead of inplace%{} = mappattern matchingOeditusCredo.Check.Refactoring.PreferInplaceListMatching- Detects O(N)length/1calls in guards instead of[_ | _]or[]OeditusCredo.Check.Refactoring.PreferInplaceBinaryMatching- Detectsis_binarynon-empty guards instead of<<_::utf8, _::binary>>OeditusCredo.Check.Refactoring.PreferDestructuring- Detectselem/2orMap.get/2instead of pattern match destructuringOeditusCredo.Check.Refactoring.PreferMultiHeadForNil- Detectsis_nilguards instead of multi-head matching onnilOeditusCredo.Check.Refactoring.PreferWithClause- Detects nestedcasestatements (pyramid of doom) instead ofwithOeditusCredo.Check.Refactoring.PreferTaggedTuplesForErrors- Detectstry...rescuecontrol flow instead of tagged tuplesOeditusCredo.Check.Refactoring.PreferForComprehensionOverFilterMap- DetectsEnum.filter |> Enum.mapinstead offorcomprehensionOeditusCredo.Check.Refactoring.PreferListPrepend- Detects O(N)list ++ [item]appends instead of prepending[item | list]OeditusCredo.Check.Refactoring.PreferPatternMatchingForEmptiness- DetectsEnum.count(list) > 0instead of[_ | _]or[]OeditusCredo.Check.Refactoring.AvoidSinglePipe- Detects single-stagex |> f()pipes instead off(x)OeditusCredo.Check.Refactoring.PreferDotAccessForStructs- Detectsstruct[:field]bracket access instead ofstruct.fieldOeditusCredo.Check.Refactoring.PreferStringBoundariesOverRegex- DetectsRegex.match?for simple prefix/suffix checksOeditusCredo.Check.Refactoring.PreferFunctionCapture- Detectsfn x -> Module.func(x) endinstead of&Module.func/1OeditusCredo.Check.Refactoring.PreferShortFieldAccessCapture- Detectsfn x -> x.field endinstead of& &1.fieldOeditusCredo.Check.Refactoring.PreferMapMerge- Detects chainedMap.putcalls for literal keys instead ofMap.mergeOeditusCredo.Check.Refactoring.AvoidUnawaitedTaskAsync- Detects un-awaitedTask.asyncfire-and-forget calls
Code Quality
OeditusCredo.Check.Warning.DirectStructUpdate- Detects struct updates instead of changesetsOeditusCredo.Check.Warning.CallbackHell- Detects chained case statementsOeditusCredo.Check.Warning.BlockingInPlug- Detects blocking operations in Plug functionsOeditusCredo.Check.Warning.UnsafeMapAccess- Detects bracket access on maps where dot access is safer (requirestypleand Elixir 1.20+)
Refactoring Suggestions
OeditusCredo.Check.Refactoring.SuggestFSM- Detects imperative status/state management (suggestsFinitomataor:gen_statem)OeditusCredo.Check.Refactoring.ChangeRiskAntiPatterns- Flags functions with a high CRAP score (complex and under-tested); opt-in, requires persisted coverage data
LiveView & Templates
OeditusCredo.Check.Warning.MissingThrottle- Detects form inputs without phx-debounce/throttleOeditusCredo.Check.Warning.InlineJavascript- Detects inline JS handlers instead of phx-* bindings
Telemetry & Observability
OeditusCredo.Check.Warning.TelemetryInRecursiveFunction- Detects telemetry in recursive functions (anti-pattern)OeditusCredo.Check.Warning.MissingTelemetryInAuthPlug- Detects auth plugs without telemetryOeditusCredo.Check.Warning.MissingTelemetryForExternalHttp- Detects HTTP calls without telemetry
Security Checks (CWE Top 25)
Injection (CWE-89, CWE-78, CWE-94, CWE-79)
OeditusCredo.Check.Security.SQLInjection- Detects string interpolation in Ecto queriesOeditusCredo.Check.Security.OSCommandInjection- Detects user input in System.cmd/os:cmd callsOeditusCredo.Check.Security.CodeInjection- Detects dynamic code execution via Code.eval_stringOeditusCredo.Check.Security.XSSVulnerability- Detects raw/1 with user input in templates
Authentication & Authorization (CWE-306, CWE-862, CWE-863, CWE-639)
OeditusCredo.Check.Security.MissingAuthentication- Detects controllers/routers without auth plugsOeditusCredo.Check.Security.MissingAuthorization- Detects actions without authorization checksOeditusCredo.Check.Security.IncorrectAuthorization- Detects role checks using negation patternsOeditusCredo.Check.Security.InsecureDirectObjectReference- Detects direct DB lookups from user params
Data Protection (CWE-200, CWE-798, CWE-502)
OeditusCredo.Check.Security.SensitiveDataExposure- Detects sensitive fields in JSON/inspect outputOeditusCredo.Check.Security.HardcodedCredentials- Detects hardcoded passwords, API keys, tokensOeditusCredo.Check.Security.UnsafeDeserialization- Detects :erlang.binary_to_term without :safe
Input & File Handling (CWE-20, CWE-22, CWE-434)
OeditusCredo.Check.Security.ImproperInputValidation- Detects missing validation of external inputOeditusCredo.Check.Security.PathTraversal- Detects user input in file paths without sanitizationOeditusCredo.Check.Security.UnrestrictedFileUpload- Detects file uploads without type validation
Web Security (CWE-352, CWE-918)
OeditusCredo.Check.Security.MissingCSRFProtection- Detects API pipelines without CSRF protectionOeditusCredo.Check.Security.SSRFVulnerability- Detects HTTP requests with user-controlled URLs
Race Conditions (CWE-367)
OeditusCredo.Check.Security.TOCTOU- Detects File.exists? followed by file operations