Sigra.OptionalDeps (Sigra v1.0.0)

Copy Markdown View Source

Single source of truth for optional-dependency availability predicates.

Sigra guards several runtime features behind optional dependencies. This module centralises those availability checks so a maintainer can answer "is this optional dep available?" for every guarded dep by reading one module, and so mix sigra.doctor (Phase 138) has a stable, predictable surface to query.

Scope — runtime call-site guards only

These predicates are for runtime call-site guards only — the if/unless checks that decide whether to invoke an optional dep at call time. Two categories of guard are explicitly out of scope and remain literal Code.ensure_loaded?/1 calls:

  • Compile-time defmodule wrappers (lib/sigra/workers/*.ex, lib/sigra/audit/forwarders/threadline.ex) run before this module may be compiled and therefore do not delegate here (D-04). Routing a compile-time guard through this SOT risks compile-ordering circularity; those wrappers stay literal.

  • Dynamic module atoms (host schema variables, internal conditionally-compiled workers) are not named optional deps and are also out of scope.

The one known non-delegated runtime check is lib/sigra/application.ex:77 (Code.ensure_loaded?(Oban) boot-warning cond), left literal by deliberate decision (Open Question 1 default — minimal phase).

Encryption posture — config-driven, not load-driven

encryption_active?/1 answers "is the host configured with a real vault (not the plaintext stub)?" by mirroring the __sigra_encryption_mode__/0 config check in the internal verify_vault!/1 in Sigra.Application. It does not call Code.ensure_loaded?(Cloak) — a load check would return true even when the host app is still on the plaintext stub, which is a silent at-rest encryption regression (ASVS V6, D-07).

Covered optional dependencies

PredicateModuleOptional dep
oban_available?/0Oban{:oban, ...}
bcrypt_available?/0Bcrypt{:bcrypt_elixir, ...}
eqrcode_available?/0EQRCode{:eqrcode, ...}
threadline_available?/0Threadline{:threadline, ...}
assent_available?/0Assent{:assent, ...}
swoosh_available?/0Swoosh{:swoosh, ...}
joken_available?/0Joken{:joken, ...}
hammer_available?/0Hammer{:hammer, ...}
req_available?/0Req{:req, ...}

swoosh_available?/0 and req_available?/0 are present for SOT completeness and Phase 138 consumption. In the current codebase, Swoosh's only lib/ guard is in the out-of-scope test-helper testing.ex:98, and Req is a transitive dep guarded only at the compound check in enterprise_connections/validation.ex:91 (whose load-half is delegated by plan 03). The absence of further delegation sites for these two predicates is intentional, not a missing-delegation gap.

Summary

Functions

Returns true when Assent is available as a loaded module.

Returns true when Bcrypt is available as a loaded module.

Returns true when the host app's encryption module is configured with a real vault (not the plaintext stub).

Returns true when EQRCode is available as a loaded module.

Returns true when Hammer is available as a loaded module.

Returns true when Joken is available as a loaded module.

Returns true when Oban is available as a loaded module.

Returns true when Req is available as a loaded module.

Returns true when Swoosh is available as a loaded module.

Returns true when Threadline is available as a loaded module.

Functions

assent_available?()

(since 0.1.0)
@spec assent_available?() :: boolean()

Returns true when Assent is available as a loaded module.

Used to gate OAuth / OIDC strategy execution. When false, calling any OAuth strategy raises with an actionable message asking the adopter to add {:assent, "~> 0.3"} to mix.exs.

bcrypt_available?()

(since 0.1.0)
@spec bcrypt_available?() :: boolean()

Returns true when Bcrypt is available as a loaded module.

Used to gate the bcrypt transparent-migration path in Sigra.Crypto and Sigra.Hashers.Bcrypt. When false, bcrypt hash verification falls back to a constant-time no-op that prevents timing side-channels.

encryption_active?(host_sigra)

(since 0.1.0)
@spec encryption_active?(keyword()) :: boolean()

Returns true when the host app's encryption module is configured with a real vault (not the plaintext stub).

Derives the host's *.Encrypted.Binary module from the :user_schema key in host_sigra (same derivation as the internal verify_vault!/1 in Sigra.Application and encrypted_binary_module/1), then checks whether that module exports __sigra_encryption_mode__/0 and returns a non-:stub value.

Returns false in any of these cases:

  • :user_schema is absent or not an atom.
  • The derived *.Encrypted.Binary module does not export __sigra_encryption_mode__/0.
  • __sigra_encryption_mode__/0 returns :stub (plaintext passthrough active).

Does not call Code.ensure_loaded?(Cloak) — a load check would return true even while the app is still on the plaintext stub, silently misreporting encryption posture (D-07, ASVS V6).

eqrcode_available?()

(since 0.1.0)
@spec eqrcode_available?() :: boolean()

Returns true when EQRCode is available as a loaded module.

Used to gate QR code SVG generation in Sigra.MFA. When false, generate_qr_svg/1 returns nil.

hammer_available?()

(since 0.1.0)
@spec hammer_available?() :: boolean()

Returns true when Hammer is available as a loaded module.

Used to gate rate-limiter resolution in Sigra.Plug.RateLimit. When false, Sigra.RateLimiters.Noop is used as a fail-open fallback with a logged warning.

joken_available?()

(since 0.1.0)
@spec joken_available?() :: boolean()

Returns true when Joken is available as a loaded module.

Used to gate JWT signing/verification in Sigra.JWT.Signer. When false, calling Joken-dependent functions raises with an actionable message.

oban_available?()

(since 0.1.0)
@spec oban_available?() :: boolean()

Returns true when Oban is available as a loaded module.

Used to gate Oban job-queue features (background email delivery, token cleanup, audit forwarding). When false, Sigra falls back to inline behaviour.

req_available?()

(since 0.1.0)
@spec req_available?() :: boolean()

Returns true when Req is available as a loaded module.

Included for SOT completeness and mix sigra.doctor consumption. Req is a transitive dep; the runtime guard in enterprise_connections/validation.ex:91 checks both availability and a specific function export (function_exported?(Req, :get, 1)) — the load-half delegates here, the function-export half stays at the call site (D-06).

swoosh_available?()

(since 0.1.0)
@spec swoosh_available?() :: boolean()

Returns true when Swoosh is available as a loaded module.

Included for SOT completeness and mix sigra.doctor consumption. The only lib/ guard for Swoosh in the current codebase is the test-helper Sigra.Testing module (out of runtime scope).

threadline_available?()

(since 0.1.0)
@spec threadline_available?() :: boolean()

Returns true when Threadline is available as a loaded module.

Used to gate the Threadline audit-forwarding path in Sigra.Audit.Forwarders.Threadline. When false, the Noop forwarder is used.