All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Planning milestones vs Hex releases
This changelog uses Semantic Versioning headings like [0.2.0] for published Hex releases. Separately, maintainers track planning milestones labeled v1.0–v1.4 in .planning/MILESTONES.md — those v1.x labels describe shipped tranches of work, not a second installable version axis on Hex (this repo remains 0.x on Hex until a real 1.0.0). Each dated release below may include a Roadmap traceability subsection (H3) linking back to the milestone narrative. When in doubt, treat MILESTONES.md as canonical for dates and archive paths.
Unreleased
1.20.0 (2026-04-28)
Summary
- v1.20.0 GA Launch: Sigra reaches General Availability. This release finalizes the audit completeness evidence and production UAT documentation, providing operators the guarantees needed to deploy with confidence.
Changed
- planning: Phase 85 / AUD-21 closes the impersonation audit-atomicity gap: the default Ecto session store now co-fates impersonation session writes with
admin.impersonation.start/admin.impersonation.stop, while non-Ecto stores keep the legacycreate/delete+log_safepath. - planning (Phase 87 / GAUAT-03..06 verification-approach correction): v1.20 GAUAT OAuth slice (gen smoke + Google register/login + provider linking + email-match confirmation) reshaped from "human runs
mix sigra.gen.oauth+ clicks real Google + captures screenshots" to a fully automated end-to-end harness —Sigra.Testing.OAuthIssuer(TestServer-backed in-process OIDC issuer mirroring Assent's ownOIDCTestCase) drives Sigra's real HTTP stack from three Playwright specs (oauth-register / oauth-link / oauth-email-match) on every PR. Generator smoke extendsscripts/ci/install-smoke.shto addmix teston the freshly-generated host. Adopter-side real-credential check ships asmix sigra.oauth.smoketest --provider=google+docs/oauth-google-setup.md. 0 human UAT for v1.20 launch — matches Auth.js / Spring Security / Assent / pow_assent / Devise+omniauth ecosystem convention. REQUIREMENTS.md GAUAT-03..06, ROADMAP.md Phase 87, anddocs/uat-ci-coverage.mdSEED-001 row updated in the same commit (Phase 86 D-86-08 precedent).
0.2.5 (2026-04-25)
Summary
- Several audit-backed MFA, JWT, account, and API-token flows now succeed or fail as one unit instead of risking a data change without the matching audit row.
- Malformed refresh tokens fail earlier with
{:error, :invalid_token}instead of going through the normal hash-and-lookup path first. - Most apps do not need new upgrade steps for this release; it is mainly a safety, correctness, and observability improvement.
Changed
- mfa: When
:audit_schemais configured,Sigra.MFA.confirm_enrollment/5writesmfa.enroll.failurefor invalid TOTP (pre-enrollment DB work) insideRepo.transaction/1viaEcto.Multi+Sigra.Audit.log_multi_safe/3, using the samecommit_ad_hoc_mfa_audit/5shell as other MFA ad-hoc audits (AUD-20-01 / AUD-04-022). The caller still receives{:error, :invalid_code}regardless of audit insert outcome; audit failures emit[:sigra, :audit, :log_safe_error]. Evidence:test/sigra/mfa_audit_atomicity_test.exs. - jwt: When
:audit_schemais configured,Sigra.JWT.refresh/3(andSigra.Auth.refresh_jwt/2) runs refresh-tokenuser_tokenspersistence andapi.jwt_refresh/api.jwt_refresh_reuseaudit inserts in a singleRepo.transaction/1viaEcto.Multi+Sigra.Audit.log_multi_safe/3(persistence + audit co-fate / AUD-08 for the guided path). Any step failure in that transaction returns{:error, :jwt_refresh_aborted}instead of issuing new tokens without a matching audit row. Evidence:test/sigra/jwt_refresh_audit_cofate_test.exs. - jwt: Refresh-token classify/revoke paths now base64url-decode the raw refresh token before hashing, so malformed or non-decodable inputs return
{:error, :invalid_token}instead of hashing the encoded wrapper bytes. - audit: When
:audit_schemais configured,Sigra.APIToken.audit_jwt_refresh/2andaudit_jwt_refresh_reuse/2writeapi.jwt_refresh/api.jwt_refresh_reuseinsideRepo.transaction/1via audit-onlyEcto.Multi+Sigra.Audit.log_multi_safe/3(audit-row atomicity only — standalone helpers; preferJWT.refresh/3for co-fate so audit is not double-emitted). - audit: When
:audit_schemais configured,Sigra.Account.clear_password_change_requirement/3clearsmust_change_passwordand writesaccount.password_change(metadata: %{forced: true}) in oneRepo.transaction/1viaEcto.Multi+Sigra.Audit.log_multi_safe/3.Sigra.Account.audit_forced_password_change/2is deprecated for that path — do not call both or you may duplicate audit rows. - audit: When
:audit_schemais configured,Sigra.APIToken.verify/2now writesapi.token_verify.failureaudit rows insideRepo.transaction/1viaEcto.Multi+Sigra.Audit.log_multi_safe/3(invalid, revoked, and expired branches). Success remains telemetry-only (D-27). Insert failures emit[:sigra, :audit, :log_safe_error](:invalid_changesetor:constraint_violation) while the caller still receives{:error, reason}.
Documentation
- planning: Milestone v1.19 (phase 83, AUD-20) — AUD-04-022 + EX-44-02 appendix, 09-VERIFICATION C-1 row 022, 09-03-SUMMARY, 44-AUD-04-INVENTORY for
Sigra.MFA.confirm_enrollment/5invalid-code transactional audit. See.planning/phases/83-mfa-confirm-enrollment-022/83-VERIFICATION.md. - planning: Milestone v1.19 (phase 82, AUD-19) — AUD-04-048 / 049 + 09-VERIFICATION C-1 rows, 44/45 inventories, 09-03-SUMMARY for
Sigra.JWT.refresh/3persistence + audit co-fate; AUD-08 closure for guidedJWT.refreshpath. See.planning/phases/82-jwt-refresh-persistence-audit-cofate/82-VERIFICATION.md. - planning: Milestone v1.18 (phase 81, AUD-18) — AUD-04-048 / 049 + 09-VERIFICATION C-1 rows, 44/45 inventories, 09-03-SUMMARY note for transactional JWT refresh/reuse audit in
lib/sigra/api_token.ex; AUD-08 explicitly out of scope. See.planning/phases/81-jwt-refresh-audit-atomicity/81-VERIFICATION.md. - planning: Milestone v1.17 (phase 80, AUD-17) — AUD-04-043 / EX-44-05 closure: 44-AUD-04-INVENTORY, 09-VERIFICATION C-1 row 043, 09-03-SUMMARY note; forced-clear audit atomicity in
lib/sigra/account.ex. See.planning/REQUIREMENTS.md. - planning: Milestone v1.16 (phase 79, AUD-16) — 44-AUD-04-INVENTORY + 09-VERIFICATION C-1 rows AUD-04-044..046 aligned to transactional
verify/2inlib/sigra/api_token.ex; 09-03-SUMMARY bounded-batch note; EX-44-01 verify slice retired. See.planning/REQUIREMENTS.mdand.planning/phases/79-api-token-verify-failure-audit/79-VERIFICATION.md. - planning: Milestone v1.15 (phase 78, AUD-14) — 44-AUD-04-INVENTORY + 09-VERIFICATION C-1 rows for AUD-04-035..042 and 047 aligned to
lib/sigra/account.ex/lib/sigra/api_token.ex; 09-03-SUMMARY bounded-batch note. See.planning/phases/78-account-api-c1-planning-truth/78-VERIFICATION.md.
Added
- tests:
test/sigra/jwt_refresh_audit_cofate_test.exscoversSigra.JWT.refresh/3persistence + audit co-fate (happy path, audit-off, reuse + audit,CHECKfault injection on happy and reuse branches). - tests:
test/sigra/api_token_audit_atomic_test.exscoversapi.jwt_refresh/api.jwt_refresh_reuse(happy path, audit-off,CHECKfault injection +log_safe_errortelemetry). - tests:
test/sigra/api_token_audit_atomic_test.exscoversapi.token_verify.failurefor invalid / revoked / expired paths plus audit-table fault injection (constraint / telemetry parity). - tests:
test/sigra/account_audit_atomicity_test.exsexercisesSigra.Account.request_email_change/4,confirm_email_change/3, andcancel_email_change/3with PostgresCHECKfault injection so domain mutations roll back when the pairedaccount.email_change_*audit insert is rejected — complements AUD-04-035..037 C-1 evidence alongsidechange_password. - tests:
test/sigra/account_audit_atomicity_test.exscoversSigra.Account.clear_password_change_requirement/3(happy path, audit-off branch, andaccount.password_changeCHECKrollback) for AUD-04-043 / AUD-17.
0.2.4 (2026-04-24)
Summary
- MFA backup-code regeneration and trust-browser audit writes are now more durable when audit logging is enabled.
- A database-level audit insert failure now falls back to the same telemetry-first behavior as other safe audit helpers instead of surfacing a rougher failure mode.
- This release is mostly operational hardening and docs polish; most host apps do not need a new install or migration step.
Changed
- audit:
Sigra.MFA.audit_backup_codes_regenerate/3andSigra.MFA.audit_trust_browser/2now emit audit rows viaEcto.Multi+Sigra.Audit.log_multi_safe/3insideRepo.transaction/1when:audit_schemais configured (bounded SEED-002 closure for AUD-04-033 / AUD-04-034;regenerate_backup_codes/4remains the authoritative rotation path).
Fixed
- audit:
commit_ad_hoc_mfa_audit/5rescuesEcto.ConstraintError(and related DB constraint failures) when the audit insert is rejected at the database layer without a matching changeset constraint, preservinglog_safe/3-class behavior: emit[:sigra, :audit, :log_safe_error]withreason: :constraint_violationand return:ok.
Documentation
- planning: v1.11 adoption stabilization — triage notes (
.planning/v1.11-TRIAGE.md),upgrading-to-v1.11.md, ExDoc extras, intro upgrade cross-links, andMAINTAINING.mdmilestone pause guidance (STAB-01..STAB-04). - planning: v1.12 trust bundle — upgrading-to-v1.12.md (ExDoc extra), docs/uat-ci-coverage.md (v1.12 launch evidence subsection), and milestone UAT index on GitHub (TRN-01..TRN-03 doc polish).
Roadmap traceability
- Planning milestone v1.14 (phase 77, AUD-13) — operator-trust slice for MFA ad-hoc audit atomicity; see
.planning/milestones/v1.14-ROADMAP.md.
0.2.3 (2026-04-23)
Summary
- Release automation and maintainer docs are clearer, especially around token setup for Release Please and downstream CI behavior.
- No new library features or upgrade steps for host apps.
Bug Fixes
0.2.2 (2026-04-23)
Summary
- Hex package metadata was trimmed to satisfy Hex.pm limits.
- No runtime behavior change for host apps.
Bug Fixes
0.2.1 (2026-04-23)
Summary
- Sigra became easier to discover and evaluate on Hex: docs links, package metadata, and first-pass release presentation all improved.
- This was mostly a packaging and documentation release around the existing
0.2.0line.
Features
- 053-01: add Hex docs link and ExDoc publish reminder (3362bf0)
- 053-01: refresh Hex description for PUB-01 (acd275e)
- 06-01: add MFA deps, config, error types, and Credential struct (52a25f4)
- 06-01: implement MFA orchestrator, BackupCodes, Trust, and Lockout modules (e913806)
- 06-02: add MFA-aware authenticate flow and complete_mfa_verification (db192a1)
- 06-02: add RequireMFA and RequireMFAEnrolled plugs with mfa_pending session type (d3bb45b)
- 06-03: add MFA telemetry event catalog and integration (826945c)
- 06-03: add MFA testing helpers and TokenCleanup mfa_pending extension (bf17b7c)
- 06-04: add MFA email templates, Auth context delegation, and test fixtures (8a93edb)
- 06-04: add MFA migration tables and generated Ecto schemas (e66b8f4)
- 06-05: add MFA challenge page templates (controller + HTML + LiveView) (8efd59d)
- 06-05: add MFA settings templates, require_mfa plug, and generator wiring (89cc608)
- 07-01: APIToken module and RequireScopes plug with full test coverage (953adbe)
- 07-01: config extensions, StringList type, ScopeRegistry, error types, telemetry events (e1e0e39)
- 07-02: add Joken dependency, ClaimsBuilder behaviour, and Signer module (8c79f0c)
- 07-02: add JWT module and RefreshToken with family-based reuse detection (2d00c6e)
- 07-03: add Auth delegation, TokenCleanup extension, Testing helpers, Email notification (611e5f6)
- 07-03: rewrite FetchBearer with auto-detection and scope assignment (425527a)
- 07-04: add API controllers, email template, injector, and install task (86f9be4)
- 07-04: add API token migration and schema templates (9b13525)
- 08-01: add config extensions, email templates, and data export behaviour (cd3ef15)
- 08-01: implement hooks engine with Ecto.Multi integration and tests (b635995)
- 08-02: add Account orchestrator with unified delegation API (44ea30a)
- 08-02: implement Account Deletion module with 3 strategies (cd31c37)
- 08-02: implement EmailChange and PasswordChange modules (601d35f)
- 08-03: add telemetry events and Auth module lifecycle delegation (34e6f2b)
- 08-03: implement RequirePasswordChange plug and AccountDeletion Oban worker (6c26dce)
- 08-04: add 7 account lifecycle email templates (36363df)
- 08-04: auth context lifecycle delegation and hooks stub module (ada92fb)
- 08-04: migration template, user schema, and token TTL for account lifecycle (21332d3)
- 08-05: add generator injector for lifecycle routes, plugs, and tests (ba5d3c5)
- 08-05: add settings LiveView, reactivation page, and lifecycle testing helpers (61112c9)
- 09-01: add audit_events migration template (02ae340)
- 09-01: add AuditEvent schema template and wire install task (bd3f69f)
- 09-02: add Sigra.Audit changeset, cursor, query submodules (01f75de)
- 09-02: add Sigra.Audit public API (ce6dc7c)
- 09-03: integrate audit logging into auth + session + security subsystems (0724d96)
- 09-03: integrate audit logging into mfa + oauth + api_token + account (68e222c)
- 09-04: add Sigra.Workers.AuditCleanup Oban worker and startup warning (a01a25c)
- 10-01: add audit test helpers and section headers to Sigra.Testing (d891e2b)
- 10-02: add scenario fixtures to AuthFixtures template (24ecd7c)
- 10-03: add :cookie_domain config + Sigra.MFA.Trust.cookie_opts/1 (080fd4f)
- 10-03: runtime remember_me_options in UserAuth + MFA trust cookie + boot warning (4aa7030)
- 10-05: add pure helpers + doctests to Config/Auth/Testing (fa57f1e)
- 10-06: scaffold test/example Phoenix app with Sigra installed (2f1790e)
- 10.1.1-03: unify example app on Sigra canonical user_sessions store (B6, D-06/D-07) (ddf7b94)
- 10.1.1-05: flip installer default to binary_id (uuid) PKs (D-10) (d1d2c40)
- 10.1.1-06: add --yes non-interactive flag to sigra.install (2b15e81)
- 10.1.1-06: add install_smoke + example_http_smoke CI jobs (ae37e78)
- 10.1.1-06: add install-smoke.sh and http-smoke.sh CI drivers (c082ab3)
- 10.1.1-07: add data-testid hook to MFA TOTP secret (7dd8e25)
- 10.1.1-07: scaffold Playwright golden-path browser smoke harness (24e8c7c)
- 41: TOTP-gated backup code rotation and GA-01 regression (e5f399e)
- 43-02: atomic auth.register.success audit via register_user_multi (d2e6efb)
- 43-03: atomic magic-link and password-reset request audits via Multi (149ab89)
- 43-04: atomic auth.login.success audit with lockout Multi (3bc7811)
- 49-01: add mix ci.audit_45 alias for AUD-08 merge gate (3adb5fe)
- 50-01: add mix ci.install_golden alias for install golden tests (ba8ca30)
- audit: add audit_multi_step for multi-row Multi audits (a642496)
- mfa: atomic audit Multis for AUD-06 (MFA) (3d5abf1)
- uat: add Docker UAT environment + runbook for milestone v1.0 manual gates (812eca0)
Bug Fixes
- 05: enforce sudo mode on link_provider and unlink_provider (T-05-12) (802b2da)
- 05: WR-04 remove dead code branch in detect_context_name (77f61b5)
- 05: WR-05 document encrypted_* field naming convention in get_tokens (fa53680)
- 06: add Code.ensure_loaded! to function_exported? tests for isolation safety (61826f8)
- 06: add settings_url binding to email template test for MFA emails (86f9759)
- 06: correct struct syntax for Ecto.Changeset.cast in MFA enrollment (b968a86)
- 06: CR-01 use Ecto cast to trigger cloak_ecto encryption for TOTP secrets (3c74dc8)
- 06: CR-02 eliminate modulo bias in backup code and confirmation code generation (66f1d3b)
- 06: WR-01 wrap MFA enrollment and cleanup in Ecto.Multi transactions (41b3899)
- 06: WR-02 combine lockout increment and lock into single atomic query (59f6d78)
- 06: WR-03 align MFA pending state checks between controller, LiveView, and library plugs (84fd485)
- 06: WR-04 add missing settings_url binding for mfa_disabled_email template (a73c46a)
- 06: WR-05 pass required options to setup_totp and simulate_mfa_lockout in fixtures (d8bf183)
- 06: WR-06 handle trailing slashes in RequireMFA path comparison (c1f5e89)
- 07: revise plans based on checker feedback (2fd57a5)
- 08-05: update migration test to match partial unique index from Plan 04 (6037d26)
- 08: CR-01 add missing callback fns to email change request and cancel flows (befa404)
- 08: CR-02 add missing callback fns to email change confirm flow (d8f7d08)
- 08: CR-03 add missing validate_password_fn to password change flow (9903b78)
- 08: WR-01 execute hook multi instead of discarding it (4152725)
- 08: WR-02 document TTL-based cleanup for orphaned email change tokens (5285e68)
- 08: WR-03 include email and hashed_password in deletion_changeset for anonymize strategy (6b775d0)
- 08: WR-04 validate deletion strategy against known values with safe default (debe7fc)
- 09: CR-01 harden validate_metadata_size against non-map and unencodable metadata (58120a9)
- 09: WR-02 raise in Sigra.Audit.stream/2 when repo.stream/1 is unavailable (78a3474)
- 09: WR-06 WR-07 honor configured retention and batch cleanup deletes (065076f)
- 09: WR-08 WR-01 sanitize log_safe error telemetry + surface missing repo (41ec4a0)
- 10-review: CR-01 guard Mix.env() in generated UserAuth remember_me_options (7a922e7)
- 10-review: WR-01 correct MFA guide function references (fc43f52)
- 10-review: WR-02 preserve false/nil in assert_audit_event metadata lookup (138777c)
- 10-review: WR-03 make Sigra.MFA.Trust.cookie_opts/0 raise to prevent silent cookie_domain drop (009d424)
- 10-review: WR-04 oauth_enabled? requires at least one configured provider (1aae029)
- 10.1 IN-01,IN-02: robust migration timestamp offsets and pad/1 cleanup (8d031be)
- 10.1 IN-03: route password reset through Sigra.Auth.reset_password/4 (90d7adb)
- 10.1 IN-05: stop passing :secret_key_base to verify_confirmation_code/3 (7eef6d8)
- 10.1 IN-06 follow-up: move helper after handle_event clauses to satisfy --warnings-as-errors (d64177f)
- 10.1-01: build proper UserToken structs in request_password_reset and request_magic_link (10c7cf9)
- 10.1-02: backport installer template fixes #1-8 (0ab0d04)
- 10.1-02: backport installer template fixes #9-16 (b19bdf3)
- 10.1-03: eliminate mix docs --warnings-as-errors @doc reference warnings (b1f49d3)
- 10.1-05: scenario/2 raises ArgumentError with valid atoms on unknown scenarios (95987e2)
- 10.1-06: delete aspirational cursor_portability_test (182edbf)
- 10.1-06: generator_reset_test stale alias assertion (81d66fd)
- 10.1-06: sigra.install_test bindings — stale after plan 10.1-02 (32dbae1)
- 10.1.1-02: fix /users/sudo KeyError on render (B7, D-08) (388856f)
- 10.1.1-02: wire confirmation email in RegistrationLive (B5, D-05) (fbdc743)
- 10.1.1-04: replace LoginLive with plain SessionController + SessionHTML (B9/D-12) (ba66d76)
- 10.1.1-05: flip test/example to uuid PKs end-to-end (B8 root fix) (949f182)
- 10: revise plans per checker iteration 1 feedback (c70ec28)
- 44: document APIToken.revoke/2 changeset error in typespec (8df3957)
- 49-01: scope ci.audit_45 to one multi-path mix test (c658a74)
- docs: include Nyquist matrix extra for ExDoc link validation (cac5a01)
- example: JS bundle + endpoint socket + router auth pipeline (58b7122)
- mfa: correct Ecto.Multi.merge arity for lockout audit Multis (09e2263)
- MFA: handle cleanup Multi errors in disable flows (2e1d309)
Unreleased
- Chore: Root
.formatter.exsno longer scanstest/example/_build(and other generated trees) where Hex-copied*.exinstall templates are not valid Elixir — restores reliablemix format --check-formattedfor contributors. - Human GA (v1.4): see .planning/v1.4-GA-UAT.md
- AUD-04: Auth
log_safe→Ecto.Multimigration inventory forSigra.Auth(prioritizedAUD-05batches B1–B3, exclusions, grep evidence) in43-AUD-04-INVENTORY.md(tag snapshot). - AUD-04 (continuation): MFA + Account + API token inventory (AUD-04-020+,
AUD-06/AUD-07batches) in44-AUD-04-INVENTORY.md(tag snapshot). - AUD-08 / Phase 45: OAuth + ops + worker AUD-04 slice (AUD-04-050+) in
45-AUD-04-INVENTORY.md(tag snapshot). - AUD-05 (Auth): When
:audit_schemais configured, success audits forauth.register.success, magic-link and password-reset request/verify flows, and confirmed-passwordauth.login.success(including lockout reset and optional hash upgrade) are written in the sameRepotransaction as the associated data changes viaEcto.MultiandSigra.Audit.log_multi_safe/3.
Roadmap traceability
Planning milestone v1.4 (GA readiness & audit trail completeness; not a Hex version): shipped 2026-04-22 per .planning/MILESTONES.md — see .planning/milestones/v1.4-ROADMAP.md, .planning/milestones/v1.4-REQUIREMENTS.md, .planning/milestones/v1.4-MILESTONE-AUDIT.md, and the GA matrix framing in .planning/v1.4-GA-UAT.md (Executed / Waived language; do not duplicate the matrix here).
0.2.0 - 2026-04-19
Roadmap traceability
Planning milestone v1.3 (cleanup & hardening tranche; not a Hex version): shipped 2026-04-19 per .planning/MILESTONES.md — see .planning/milestones/v1.3-ROADMAP.md, .planning/milestones/v1.3-REQUIREMENTS.md, and .planning/milestones/v1.3-MILESTONE-AUDIT.md.
Added
docs/NEXT-STEPS-MANUAL.md— short post-merge checklist (PR merge, Hex, GitHub Release) for maintainers.docs/audit-semantics.md— public note onlog/log_multi/log_safe, C-1 hybrid status, and pointers to testing helpers (linked from README).Sigra.Audit.Assertions— orderedlatest_audit_event/3+assert_audit_fields/3for tests; seeguides/recipes/testing.md.- Atomic
api.token_createaudit viaEcto.Multi/Sigra.Audit.log_multi_safe/3inSigra.APIToken(telemetry fromemit_telemetry_from_changes/1on successful commit only). - Example app smoke tests assert login and MFA enrollment audit rows; host
get_user_by_email_and_password/2now delegates toSigra.Auth.authenticate/2with fullSigra.Configsoauth.login.*audit runs. - Human GA matrix in
v1.3-HUMAN-UAT.mdclosed via machine substitutes; see.planning/uat-evidence/v1.3.0/INDEX.mdfor CI anchors and per-item evidence. - GA UAT shift-left:
docs/uat-ci-coverage.mdmaps SEED-001 items to CI and documents residual human checks;test/example/priv/playwright/tests/ga-uat-shift-left.spec.tscovers invitation email-lock and MFA regenerate UI reachability; example app gainsEmailsLifecycleHtmlTest;scripts/ci/getting-started-contract.shplusgetting_started_uat_contractCI job validate getting-started links/commands. - Generated and example
MFASettingsLiveregenerate form uses an explicittype="submit"on the regenerate button so LiveViewphx-submitfires reliably. - Published to Hex.pm as 0.2.0 (initial package listing).
0.1.0 - 2026-04-17
First library version line with Hex-oriented mix.exs packaging; upgrade to 0.2.0 for the Hex listing and additions above.
Roadmap traceability
Planning milestone v1.2 (admin dashboard tranche; not a Hex version): shipped 2026-04-17 per .planning/MILESTONES.md — see .planning/milestones/v1.2-ROADMAP.md, .planning/milestones/v1.2-REQUIREMENTS.md, and .planning/milestones/v1.2-MILESTONE-AUDIT.md.
Changed
- BREAKING (behavior):
session.createaudit now fires AFTERselect_active_organizationduring login, so the very first audit event of a successful login carries the realorganization_idrather than anilone. Previously,session.createfired before the active-org selection step and always had a null org, meaning the v1.2 impersonation anchor would have no tenant to pin against. If you were relying on the old ordering (e.g. a log scraper keyed on null-org events for login detection), update your consumers to match the new ordering. - BREAKING (API):
Sigra.Audit.Query.build/2now raisesArgumentErroron unknown filter keys instead of silently ignoring them. If your host app was passing an unknown key (e.g.actor:instead ofactor_id:) the query previously returned unfiltered results — now it fails loudly. Rationale: silent-ignore on an audit query is a security-adjacent bug; audit systems must be loud about misconfiguration. - BREAKING (installer):
Sigra.Workers.AccountDeletionjob args now require five additional stringified keys at enqueue time:"organization_id","actor_id","scope_module","organization_schema", and"audit_schema". Host apps that use the Sigra installer to generate the account-deletion Oban enqueue site should regenerate that site (or manually add the new args). The worker validates presence of all five viafetch_arg!/2up front BEFORE anyModule.safe_concatcall so theKeyErrorsurfaces with the actual missing key.
Fixed
- Hex package
fileslist includespriv/(installer, upgrade, and OAuth generator templates) somix sigra.install/mix sigra.upgradework when the dependency is pulled from Hex.
Added
Sigra.Audit.log_safe/3accepts a scope as the second positional argument. The scope is duck-typed on%{user, active_organization, impersonating_from}; passnilexplicitly for pre-authentication or truly anonymous call sites.log_safe/2remains as a thin shim that delegates tolog_safe/3with anilscope.Sigra.Audit.Querysupports:organization_id,:effective_user_id, and:organization_scopefilters.:organization_scopeaccepts{:only, org_id}or{:including_global, org_id}tagged tuples. The composite index(organization_id, inserted_at)is created onaudit_eventsby the new alter migration to keep org-scoped queries off seq-scan plans at scale.Sigra.Scope.build/3library constructor for the host-app%Scope{}struct, used by login-time scope synthesis and by Sigra-aware workers. Also addsSigra.Scope.from_opts/2andSigra.Scope.from_config/2convenience constructors.Sigra.Workersbehaviour — single@callback perform(scope, args)contract for Oban workers requiring tenant context.Sigra.Workers.new/3fails fast when required"organization_id"/"actor_id"arg keys are absent;Sigra.Workers.fetch_arg!/2is a belt+suspenders helper for workerperform/1implementations.Sigra.Workers.AccountDeletionis the reference implementation — it reconstructs the scope insideperform/1and delegates toperform/2with a real%Scope{}.Sigra.Testing.assert_audit_logged/2helper — a thin alias forassert_audit_event/2with the REQ DX-02 naming convention. Signature is(map, keyword)to matchassert_audit_event/2exactly.- Custom Credo check
Sigra.Credo.NoLogSafe2InLibthat forbids arity-2Sigra.Audit.log_safecalls inlib/sigra/**(with an exception for the shim definition itself and fortest/**). Registered in.credo.exsvia therequires:field so host apps pulling Sigra as a dep are not forced to take a Credo dependency. - New migration
alter_audit_events_add_org_columns.exsaddsorganization_id :binary_id(nullable, FK withon_delete: :nilify_allso historical rows survive organization deletion) andeffective_user_id :binary_id(nullable, v1.2 impersonation anchor) columns toaudit_events, plus the composite index(organization_id, inserted_at). On Postgres, the migration uses@disable_ddl_transaction true+create index(..., concurrently: true)for zero-downtime deploy on production audit tables. On SQLite/MySQL, a plainchange/0migration emits the same shape non-concurrently.