Contributing to ExkPasswd
Mix.install([
{:exk_passwd, path: Path.join(__DIR__, "..")}
])
This notebook is a small architecture tour. The terminal quality gates remain the source of truth for a contribution.
Generation path
config =
ExkPasswd.Config.new!(
num_words: 3,
word_length: 4..6,
separator: "-",
case_transform: :capitalize
)
password = ExkPasswd.Password.create(config)
report = ExkPasswd.Entropy.calculate(password, config)
%{config: config, password: password, report: report}
The main responsibilities are:
-
ConfigandConfig.Schema: strict construction and validation -
RandomandBuffer: unbiased cryptographic range generation -
Dictionary: EFF indexes and:persistent_termcustom dictionaries -
Password: generation orchestration -
Transform: extension protocol and built-in transforms -
EntropyandStrength: output-space analysis and project ratings -
Batch: buffered, unique, and parallel generation APIs
Inspect dictionary ranges
%{
total_eff_words: ExkPasswd.Dictionary.size(),
eligible_4_to_6: ExkPasswd.Dictionary.count_between(4, 6),
sample: ExkPasswd.Dictionary.random_word_between(4, 6)
}
Common EFF ranges are precomputed. Custom and uncommon ranges use a by-length fallback; avoid claiming that every dictionary API has the same complexity.
Exercise custom input validation
results = [
ExkPasswd.Config.new(num_words: 0),
ExkPasswd.Config.new(unknown: true),
ExkPasswd.Config.new(padding: :invalid)
]
results
Expected caller errors should be tagged tuples from new/1 or ArgumentError
from bang/public generation functions. Do not let malformed maps fail later with
unrelated KeyError or protocol errors.
Add a custom dictionary
:ok = ExkPasswd.Dictionary.load_custom(:contributor_demo, ["alpha", "bravo", "delta", "hotel"])
custom =
ExkPasswd.Config.new!(
dictionary: :contributor_demo,
word_length: 5..5,
num_words: 3,
separator: "-"
)
ExkPasswd.generate(custom)
Custom dictionaries are NFC-normalized and reject duplicates. Loading writes to
:persistent_term; it belongs in application startup code, not a hot path.
Add a transform
defmodule ContributorSuffix do
defstruct suffix: ""
defimpl ExkPasswd.Transform do
def apply(%{suffix: suffix}, word, _config), do: word <> suffix
def entropy_bits(_, _config), do: 0.0
end
end
transformed =
ExkPasswd.Config.new!(
num_words: 2,
meta: %{transforms: [%ContributorSuffix{suffix: "."}]}
)
ExkPasswd.generate(transformed)
Document whether a transform is deterministic, whether it can merge source words, and which scripts it covers. Add regression tests for every linguistic example shown in public documentation.
Required checks
Run these from the project root:
mix format
mix compile --warnings-as-errors
mix credo --strict
mix test
mix coveralls.html
mix dialyzer
mix doctor
mix docs
mix deps.audit
Use Conventional Commits. Do not update benchmark claims without recording a fresh run and its environment. Security-sensitive randomness changes need tests for boundary values, rejection behavior, buffered and unbuffered paths, and invalid inputs.