MikaCredoRules.NoApplicationEnvOutsideConfig (MikaCredoRules v0.1.0)

Copy Markdown View Source

Application environment must only be read or written from a config module.

Scattered Application.get_env/2 and Application.put_env/3 calls make configuration unauditable and untestable. Wrap every environment read and write in a single config module per app, and have the rest of the app call that module.

# BAD — env read in a service module
defmodule MyApp.Worker do
  def provider, do: Application.get_env(:my_app, :provider)
end

# GOOD — config.ex owns the env, the worker calls it
defmodule MyApp.Config do
  def provider, do: Application.get_env(:my_app, :provider)
end

defmodule MyApp.Worker do
  def provider, do: MyApp.Config.provider()
end

Config modules are identified by filename via the :config_files param, so this works the same in an umbrella (apps/my_app/lib/my_app/config.ex) and a single app (lib/my_app/config.ex).

There are no other exemptions. Test files and application.ex are checked too — a test reaching for Application.put_env/3 is exactly the case this rule exists to catch.

Env access is caught through every spelling of the module:

alias Application, as: App
App.get_env(:my_app, :provider)          # caught
Elixir.Application.get_env(:my_app, :x)  # caught
:application.get_env(:my_app, :x)        # caught

Aliases are resolved from a flat, file-level table rather than a lexical scope stack. An alias declared inside one function is treated as applying to the whole file. Being wrong would require the same alias name to mean two different modules in two functions of one file.

Aliases injected by a macro (via __using__) are invisible to Credo and cannot be resolved.