# `Dune.Allowlist`
[🔗](https://github.com/functional-rewire/dune/blob/v0.3.18/lib/dune/allowlist.ex#L1)

Behaviour to customize the modules and functions that are allowed or restricted.

## Warning: security considerations

The default implementation is `Dune.Allowlist.Default`, and should only allow safe
functions: no atom leaks, no execution of arbitrary code, no access to the filesystem / network...
Defining or extending a custom `Dune.Allowlist` module can introduce security risks or bugs.

Please also note that using custom allowlists is still **experimental** and the API for it
might change faster than the rest of the library.

## Defining a new allowlist

In order to define a custom allowlist from scratch, `use Dune.Allowlist` can be used:

    defmodule CustomAllowlist do
      use Dune.Allowlist

      allow Kernel, only: [:+, :*, :-, :/, :div, :rem]
    end

    Dune.eval_string("4 + 9", allowlist: CustomAllowlist)

## Extending an existing allowlist

Defining an allowlist from scratch can be both daunting and risky.
It is possible to extend an exisiting allowlist instead using the `extend` option:

    defmodule ExtendedAllowlist do
      use Dune.Allowlist, extend: Dune.Allowlist.Default

      allow SomeModule, only: [:authorized]
    end

    Dune.eval_string("SomeModule.authorized(123)", allowlist: ExtendedAllowlist)

Note: currently, it is not possible to add or restrict functions from modules
that have already been specified.

## Documentation generation

The list of modules and functions with their status can be generated in the `@moduledoc`.
An example can be found in the  `Dune.Allowlist.Default` documentation.

If the `__DUNE_ALLOWLIST_FUNCTIONS__` string is found in the `@moduledoc` string,
it will be replaced.

    defmodule CustomAllowlist do
      @moduledoc """
      Only allows simple arithmetic

      ## Allowlist functions

      __DUNE_ALLOWLIST_FUNCTIONS__
      """

      use Dune.Allowlist

      allow Kernel, only: [:+, :*, :-, :/, :div, :rem]
    end

# `status`

```elixir
@type status() :: :allowed | :restricted | {:shimmed, module(), atom()}
```

# `fun_status`

```elixir
@callback fun_status(module(), atom(), non_neg_integer()) :: status()
```

Returns the trust status of a function or macro, specified as a `module`, `fun_name` and `arity` (`mfa`):
- `:allowed` if can be safely use
- `:restricted` if its usage should be forbidden
- a `{:shimmed, module, function_name}` if the function call should be replaced with an alternative implementation

# `allow`
*macro* 

Adds a new module to the allowlist and specifices which functions to use.

The module must not be already specified in the allowlist.

Must be called after `use Dune.Allowlist`.

## Examples

    # allow all functions in a module
    allow Time, :all

    # only allow specific functions
    allow Function, only: [:identity]

    # exclude specific functions
    allow Calendar, except: [:put_time_zone_database]

Note: `only` and `except` will cover all arities if several functions
share a name.

# `ensure_implements_behaviour!`

```elixir
@spec ensure_implements_behaviour!(module()) :: module()
```

Validates the fact that a module implements the `Dune.Allowlist` behaviour.

Raises if not the case.

## Examples

    iex> Dune.Allowlist.ensure_implements_behaviour!(DoesNotExists)
    ** (ArgumentError) could not load module DoesNotExists due to reason :nofile

    iex> Dune.Allowlist.ensure_implements_behaviour!(List)
    ** (ArgumentError) List does not implement the Dune.Allowlist behaviour

---

*Consult [api-reference.md](api-reference.md) for complete listing*
