Skip to content

Commit 5599dd1

Browse files
wojtekmachvoughtdq
authored andcommitted
Document how to use ExDoc with encrypted debug info
Closes elixir-lang#1928. - Update documentation - Update test helper so that debug info options are forwarded to the compiler - Add basic tests - Update changelog - Use "CI" environment variable to skip test
1 parent 8948c6a commit 5599dd1

File tree

6 files changed

+66
-60
lines changed

6 files changed

+66
-60
lines changed

.github/workflows/ci.yml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
runs-on: ubuntu-20.04
1313
env:
1414
MIX_ENV: test
15+
CI: true
1516
strategy:
1617
fail-fast: false
1718
matrix:

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Improve warning when referencing type from a private module
77
* Rename "Search HexDocs package" modal to "Go to package docs". Support built-in Erlang/OTP
88
apps.
9-
* Support modules with encrypted debug info
9+
* Document how to use `.erlang.crypt` with ExDoc
1010

1111
* Bug fixes
1212
* Switch anchor `title` to `aria-label`

lib/mix/tasks/docs.ex

+4-58
Original file line numberDiff line numberDiff line change
@@ -213,64 +213,10 @@ defmodule Mix.Tasks.Docs do
213213
## Encrypted debug info
214214
215215
If a module is compiled with [encrypted debug info](`:compile.file/2`), ExDoc will not be able to
216-
extract its documentation without first setting a decryption function or utilizing
217-
`.erlang.crypt` as prescribed by `m::beam_lib#module-encrypted-debug-information`. Two
218-
convenience options (see below) are provided to avoid having to call `:beam_lib.crypto_key_fun/1`
219-
out-of-band and/or to avoid using `.erlang.crypt`.
220-
221-
If you prefer to set the key out-of-band, follow the instructions provided in the
222-
`m::beam_lib#module-encrypted-debug-information` module documentation.
223-
224-
> ### Key exposure {: .warning}
225-
>
226-
> Avoid adding keys directly to your `mix.exs` file. Instead, use an environment variable, an
227-
> external documentation config file, or a
228-
> [closure](https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/sensitive_data#wrapping).
229-
230-
### `:debug_info_key`
231-
232-
This option can be provided if you only have one key for all encrypted modules. A `t:charlist/0`,
233-
`t:String.t/0`, or tuple of `{:des3_cbc, charlist() | String.t()}` can be used.
234-
235-
### `:debug_info_fn` / `:debug_info_fun`
236-
237-
This option can be provided if you have multiple keys, want more control over key retrieval, or
238-
would like to wrap your key(s) in a closure. `:debug_info_key` will be ignored if this option is
239-
also present. `:debug_info_fun` will be ignored if `:debug_info_fn` is already present.
240-
241-
While a module can be encrypted using a tuple key such as `{:des3_cbc, ~c"secret"}`, the function
242-
that provides the key must return a regular charlist. In other words, the function should return
243-
`~c"secret"`, not `{:des3_cbc, ~c"secret"}`.
244-
245-
A basic function that provides the decryption key `SECRET`:
246-
247-
<!-- tabs-open -->
248-
249-
### Elixir
250-
251-
⚠️ The key returned must be a `t:charlist/0`!
252-
253-
```elixir
254-
fn
255-
:init -> :ok,
256-
{:debug_info, _mode, _module, _filename} -> ~c"SECRET"
257-
:clear -> :ok
258-
end
259-
```
260-
261-
### Erlang
262-
263-
```erlang
264-
fun
265-
(init) -> ok;
266-
({debug_info, _Mode, _Module, _Filename}) -> "SECRET";
267-
(clear) -> ok
268-
end.
269-
```
270-
271-
<!-- tabs-close -->
272-
273-
See `:beam_lib.crypto_key_fun/1` for more information.
216+
extract its documentation without preparation. ExDoc supports using `.erlang.crypt` to decrypt
217+
debug information. Consult the
218+
[`.erlang.crypt` section in the `:beam_lib` documentation](`m::beam_lib#module-erlang-crypt`)
219+
for more information.
274220
275221
## Groups
276222

test/ex_doc/retriever/erlang_test.exs

+55
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,61 @@ defmodule ExDoc.Retriever.ErlangTest do
410410
|> Erlang.autolink_spec(current_module: :mod, current_kfa: {:type, :type, 0}) ==
411411
"type() :: #a{a :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:pos_integer/0\">pos_integer</a>(), b :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:non_neg_integer/0\">non_neg_integer</a>(), c :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:atom/0\">atom</a>(), d :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:term/0\">term</a>(), e :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:term/0\">term</a>()}."
412412
end
413+
414+
@tag :ci
415+
test "modules with encrypted debug info", c do
416+
File.cp!("test/fixtures/.erlang.crypt", ".erlang.crypt")
417+
418+
erlc(
419+
c,
420+
:debug_info_mod,
421+
~S"""
422+
-module(debug_info_mod).
423+
-moduledoc("mod docs.").
424+
-export([function1/0]).
425+
-export_type([foo/0]).
426+
427+
-doc("foo/0 docs.").
428+
-type foo() :: atom().
429+
430+
-doc("function1/0 docs.").
431+
-spec function1() -> atom().
432+
function1() -> ok.
433+
""",
434+
debug_info_key: ~c"SECRET"
435+
)
436+
437+
{[mod], []} = Retriever.docs_from_modules([:debug_info_mod], %ExDoc.Config{})
438+
439+
assert %ExDoc.ModuleNode{
440+
moduledoc_file: moduledoc_file,
441+
docs: [function1],
442+
id: "debug_info_mod",
443+
module: :debug_info_mod,
444+
title: "debug_info_mod",
445+
typespecs: [foo]
446+
} = mod
447+
448+
assert DocAST.to_string(mod.doc) =~ "mod docs."
449+
assert DocAST.to_string(function1.doc) =~ "function1/0 docs."
450+
assert DocAST.to_string(foo.doc) =~ "foo/0 docs."
451+
assert moduledoc_file =~ "debug_info_mod.erl"
452+
453+
erlc(
454+
c,
455+
:debug_info_mod2,
456+
~S"""
457+
-module(debug_info_mod2).
458+
-moduledoc("mod docs.").
459+
""",
460+
debug_info_key: {:des3_cbc, ~c"PASSWORD"}
461+
)
462+
463+
assert {[%ExDoc.ModuleNode{module: :debug_info_mod2}], []} =
464+
Retriever.docs_from_modules([:debug_info_mod2], %ExDoc.Config{})
465+
466+
File.rm!(".erlang.crypt")
467+
end
413468
end
414469

415470
describe "docs_from_modules/2 edoc" do

test/fixtures/.erlang.crypt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[{debug_info, des3_cbc, debug_info_mod, "SECRET"},
2+
{debug_info, des3_cbc, [], "PASSWORD"}].

test/test_helper.exs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
otp_eep48? = Code.ensure_loaded?(:edoc_doclet_chunks)
22
otp_eep59? = Code.ensure_loaded?(:beam_doc)
3+
ci? = System.get_env("CI") == "true"
34

45
exclude = [
56
otp_eep48: not otp_eep48?,
67
otp_eep59: not otp_eep59?,
7-
otp_has_docs: not match?({:docs_v1, _, _, _, _, _, _}, Code.fetch_docs(:array))
8+
otp_has_docs: not match?({:docs_v1, _, _, _, _, _, _}, Code.fetch_docs(:array)),
9+
ci: not ci?
810
]
911

1012
ExUnit.start(exclude: Enum.filter(exclude, &elem(&1, 1)))

0 commit comments

Comments
 (0)