add_auth 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33de30a9b51e6aff4236af059703155e8eeed6692497df9657c2958d37d21536
4
- data.tar.gz: a3dd63d2b854c69f4f17af73d067f7dc5b9c5fd3105ce9b45cd2d1aec8eb943f
3
+ metadata.gz: fb4c1fc11f2a73f54a42c1bc5379f328d63e4e3cf4124f83ceaa87187ee04ed8
4
+ data.tar.gz: bb0c1cf6c79e629cf3257a161c867dc0ea722596ccebe6a9b4dd609881e2be6a
5
5
  SHA512:
6
- metadata.gz: ac89ed45158b07a68a94fba2c832781b1f5a38f732217f29992865dc0b0f532ae6e0e70f79c746b1a962f07cad4f7ec0cadff71485d79d1c569af07ef2c3887c
7
- data.tar.gz: 99459566fa90408261c16d2cd3453c168e3800a913cdbe48b44ebc4b64dd13a2cddda3661097b01d12f39cc89415b395158fb0c50b6fa335412fa5544a91f022
6
+ metadata.gz: b9cf550a17e5736ac23be86f151571b6434949c137295c9e12489cead2ba5393d26bb2652c50469eb40775dcb85e8b937bbf1a0fbe5d2359b9d07172efa94fa3
7
+ data.tar.gz: 76d3b435c7f3f6994f639a9d397cba861d1e25071a6143a121d596549c85e9736c5d4a0a54caff1bf7f05e77a8b168915e909002aef847aaaf41d406547de308
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.2 — 2026-09-08
4
+
5
+ - Reject Solid Cache as an authentication rate-limit store: simultaneous first
6
+ increments can be lost. Runtime fails closed and doctor explains how to
7
+ configure a separate atomic store. Solid Queue and ordinary application
8
+ caching remain independent choices. No schema, cookie or job-format change.
9
+ - Add checksum-pinned upgrades from the published 0.2.1 package to the candidate
10
+ and back, including persisted authority, pending delivery and customized
11
+ ejections; run this acceptance on every supported Ruby/Rails CI combination.
12
+ - Verify Solid Queue with a separate queue database, demonstrate Solid Cache
13
+ counter unsuitability on PostgreSQL, and measure bounded maintenance.
14
+ - Refresh immutable checkout action pins to 7.0.1 and add upgrade/compatibility
15
+ guidance. See the upgrade guide before changing a deployed bundle.
16
+
3
17
  ## 0.2.1 — 2026-09-07
4
18
 
5
19
  - Install release dependencies into RubyGems' normal gem path so the attestation
data/README.md CHANGED
@@ -101,12 +101,18 @@ generators again later -- they won't overwrite changes you've already made.
101
101
  AddAuth.configure do |config|
102
102
  config.base_url = "https://accounts.example.com"
103
103
  config.mail_from = "Accounts <sign-in@example.com>"
104
- config.rate_limit_store = Rails.cache
104
+ config.rate_limit_store = ActiveSupport::Cache::RedisCacheStore.new(
105
+ url: ENV.fetch("AUTH_REDIS_URL"), namespace: "add_auth"
106
+ )
105
107
  # Only let certain accounts sign in, e.g. skip unconfirmed or banned users:
106
108
  # config.eligible = ->(user) { user.confirmed? && !user.disabled? }
107
109
  end
108
110
  ```
109
111
 
112
+ For this example, add `gem "redis", "~> 5.4"` to the host Gemfile, run
113
+ `bundle install`, and configure `AUTH_REDIS_URL` for every web/worker/scheduler
114
+ process. Keep their namespace identical.
115
+
110
116
  Before real users touch this, make sure of three things:
111
117
 
112
118
  - **Email actually sends.** Configure Action Mailer's SMTP settings for
@@ -115,9 +121,11 @@ Before real users touch this, make sure of three things:
115
121
  background job, so use a real Active Job backend like Sidekiq or Solid
116
122
  Queue -- not Rails' default in-memory one, which forgets everything on
117
123
  deploy.
118
- - **Your cache is shared across servers**, e.g. Redis, Memcached or Solid
119
- Cache -- not each server's own memory. Otherwise sign-in rate limits only
120
- apply per-server instead of across your whole app.
124
+ - **Abuse counters are shared and atomic**, including the first increment and
125
+ expiry under concurrent requests. RedisCacheStore has local acceptance. Solid
126
+ Cache is unsuitable: its absent-row increment can lose concurrent requests.
127
+ Keep application caching separate from `rate_limit_store`; local MemoryStore
128
+ is for a single-process trial. Other adapters require their own atomic/TTL proof.
121
129
 
122
130
  Then schedule this to run at least once a minute, however you run scheduled
123
131
  jobs (cron, `whenever`, your platform's scheduler):
@@ -478,6 +486,13 @@ Selenium in the host test bundle. AddAuth itself uses RSpec.
478
486
 
479
487
  ## Operations and rollback
480
488
 
489
+ See the [persisted-host upgrade guide](https://addauthgem.com/upgrading/) and
490
+ [integration boundaries](https://addauthgem.com/compatibility/) before changing
491
+ a deployed bundle. The published 0.2.1 doctor cannot detect Solid Cache's
492
+ concurrent-initialization race; 0.2.2 rejects that known
493
+ incompatible adapter at runtime and reports a separate-store remedy in doctor.
494
+
495
+
481
496
  Run doctor after migrations and template upgrades. Expand schemas before enabling
482
497
  features; generators preserve existing sessions and credentials. Keep the new
483
498
  reader during rollback while browser-bound proofs or strict accounts exist.
data/ROADMAP.md CHANGED
@@ -1,244 +1,213 @@
1
1
  # Roadmap
2
2
 
3
- AddAuth extends Rails 8's `bin/rails generate authentication` with email-link
4
- sign-in, passkeys, purpose-bound reauthentication, session hardening and pluggable
5
- captcha. It reuses the host's accounts and Session model.
6
-
7
- The canonical design lives in the companion **private** planning workspace:
8
- [scope](https://github.com/taimoorq/add_auth-workspace/blob/main/docs/authentication-gem-plan.md#14-scope-decision-and-roadmap)
9
- and [user journeys, contracts and test plan](https://github.com/taimoorq/add_auth-workspace/blob/main/docs/authentication-gem-plan.md#16-integrated-user-journeys-and-implementation-plan).
10
- Those links require workspace access. This public checklist stands on its own as
11
- progress tracking; it does not duplicate the private design. Engineering guidance
12
- stays only in that workspace's `AGENTS.md`.
13
-
14
- Reviewed 2026-09-07. The 0.2.1 source implements the v1
15
- strategy features: password/email/passkey sign-in, hardened sessions, reauthentication,
16
- credential management, default recovery and strict policy, security notifications,
17
- challenge adapters and fingerprinted ejection. Core policy, session finalization
18
- and leased mail delivery are shared by engine and ejected flows.
19
-
20
- The 0.2 release gate uses local real-database, generated-host, browser and
21
- SMTP/queue/cache acceptance. The final supported matrix is recorded in the
22
- [canonical evidence ledger](https://github.com/taimoorq/add_auth-workspace/blob/main/docs/authentication-gem-plan.md#20-release-020-execution--2026-09-07).
23
- Checked feature items mean passing relevant local specs. GitHub's required
24
- merge/release controls still apply. Hosts verify their own live providers,
25
- physical authenticators and deployment operations; those checks do not block
26
- the gem's 0.2 release. Email themes and branding are optional host presentation.
27
-
28
- Generated pages use shared HTML/Turbo partials. Password/email paths support
29
- ordinary no-JS navigation when permitted by policy; passkeys require browser
30
- JavaScript, and a configured captcha may also require it. Strict policy must never
31
- be weakened to simulate no-JS parity.
32
-
33
- ## 0. Project foundations
34
-
35
- - [x] Gemspec with a capability-derived Rails floor (`>= 8.0`, the release
36
- that shipped the authentication generator) and a security-patch-derived
37
- Ruby floor (`>= 3.3.0`), not just whatever the newest Rails tolerates.
38
- - [x] MIT license, Code of Conduct, Security policy (`SECURITY.md`).
39
- - [x] RSpec test setup (`.rspec`, `spec/spec_helper.rb`).
40
- - [x] `standard` for formatting/linting.
41
- - [x] CI (GitHub Actions): RSpec + Standard across the Ruby support matrix,
42
- plus a `bundler-audit` job.
43
- - [x] Dependabot, grouped by ecosystem, with the Rails family grouped
44
- together the concrete mechanism behind the "stay current" mandate in
45
- the workspace's `AGENTS.md`.
46
- - [x] RubyGems release workflow configured for [Trusted
47
- Publishing](https://guides.rubygems.org/trusted-publishing/) (OIDC from
48
- GitHub Actions) instead of a long-lived API key, gated behind
49
- `rubygems_mfa_required` and `allowed_push_host`.
50
- - [x] `bin/setup` / `bin/console` dev scripts.
51
- - [ ] First successful tagged release published via the Trusted Publishing
52
- workflow, to lock in the gem name on RubyGems.
53
-
54
- ## 1. Core primitives
55
-
56
- - [x] `AddAuth::Result` — closed success/failure type for auth outcomes.
57
- - [x] `AddAuth::Configuration` / `AddAuth.configure`.
58
- - [x] Challenge adapter contract (`AddAuth::Core::Challenge::Base`) with the
59
- three-state result (success / rejected / unavailable).
60
- - [x] `Challenge::Null` (default, always succeeds) and `Challenge::Test`
61
- (configurable, for specs) adapters.
62
- - [x] Purpose-separated HMAC digests with explicit strong key material,
63
- real Rails key derivation, override tests and a framework-free Core check.
64
-
65
- ## 2. Shared contracts and a real host harness slices A1/A2
66
-
67
- - [x] One Core policy for eligibility, purpose, proof strength and freshness;
68
- one session finalizer and public result presenter across all methods.
69
- - [x] Ordinary email-token store and encrypted delivery-intent contracts,
70
- shared examples against fake and real SQLite/PostgreSQL adapters, with clock/digest
71
- injection, replay/race/rollback/address-binding coverage.
72
- - [x] Passkey/recovery proof and host lifecycle contracts, with actual WebAuthn
73
- cryptography, rollback and concurrency on SQLite and PostgreSQL.
74
- - [x] Boot `spec/dummy` through RSpec; replace generated test stubs with
75
- password sign-in/reset/sign-out requests and real database coverage.
76
- - [x] Generate and boot Rails 8.0/8.1 hosts; exercise the persistence
77
- generator and preserve host customizations. CI covers both Rails lines
78
- on Ruby 3.3, 3.4 and 4.0. Commands are in CONTRIBUTING.md.
79
- - [x] Browser/virtual-authenticator harness with the passkey slice.
80
-
81
- ## 3. Adopt the host's sessions and password flow slice B, U1/U8
82
-
83
- - [x] Inert `add_auth:install` configuration plus additive `session_upgrade`
84
- migration and shared lifecycle hooks; repeat generation preserves edits.
85
- - [x] Bounded signed-ID cookie transition to random digested bearers, with
86
- real signature/tamper, race, cutoff and revocation tests.
87
- - [x] Password/reset normalization and routes preserved; password/address
88
- invalidation and account deletion integrated. Hosts supply eligibility.
89
- - [x] Absolute/idle expiry, protected cookies, fresh session IDs and safe local
90
- return destinations for implemented password/email flows.
91
- - [x] Current-session sign-out revokes its bearer and clears browser state.
92
- - [x] Session list and revoke-one, including next-request rejection in another
93
- browser and cache/back-safe authenticated-page handling.
94
- - [x] Sign-out-everywhere, guarded by fresh allowed proof and covering every
95
- active browser, with old bearers rejected on their next request.
96
- - [x] Account-scoped cursor pages and bounded maintenance, with optional history
97
- retention, active-lease protection and completed-pass counts.
98
- - [x] Explicit passwordless mode, guarded stock entry routes and authenticated
99
- account-management pages in hosts that also serve public pages.
100
-
101
- ## 4. Complete email-link sign-in slice C, U2
102
-
103
- - [x] Internal `EmailLink#issue`/`#consume` lifecycle: atomic replacement and
104
- session persistence, one-use proof, account/address eligibility rechecks,
105
- expiring encrypted delivery handoff and tested concurrent use.
106
- - [x] Wire the lifecycle to the hardened session finalizer and uniform
107
- asynchronous/rate-limited public intake.
108
- - [x] Additive token model/store generator and protected pending-delivery
109
- payload, cleared on consumption/revocation; no Session schema changes.
110
- - [x] Encrypted request jobs, idempotent issuance, leased mail delivery,
111
- retry/cleanup sweep and delivered-link-to-browser integration.
112
- - [x] Durable security notifications share the delivery lease/retry/cancellation
113
- contract and recover interrupted queue handoffs.
114
- - [x] Local SMTP, durable queue restart/retry and cross-process shared-cache
115
- acceptance. Live transport and monitoring validation belongs to each host.
116
- - [x] Shared IP + keyed identifier rate policy, normalization and generic
117
- request/resend responses for unknown, disabled and throttled accounts.
118
- - [x] Request check-email inert GET confirmation explicit POST consume
119
- session; masked account confirmation and deliberate account switching.
120
- - [x] Resend limits, newest-link guidance, expired/used-link recovery and
121
- cross-device sign-in by default.
122
- - [x] Optional same-browser binding, including delivered links, wrong-browser denial,
123
- Turbo/no-JS browsers and generated/ejected hosts.
124
- - [x] Real DB concurrency and delivered-mail-to-session specs, plus HTML,
125
- Turbo and no-JS request/system coverage for the complete flow.
126
-
127
- - [x] Basic scoped CSS, semantic class overrides for host Bootstrap/Tailwind
128
- builds, stylesheet opt-out and view ejection with custom-file preservation.
129
-
130
- ## 5. Reauthentication and recovery policy slice D, U6/U7
131
-
132
- - [x] Core purpose/freshness evaluator with account/session binding, generic
133
- elevation failures and passkey UV requirements.
134
- - [x] Additive session elevation metadata and bearer-rotation finalizer for a
135
- previously authorized grant, now wired to public reauthentication routes.
136
- - [x] Host reauthentication adapters persist purpose-bound grants and rotate the
137
- existing session's bearer after password/email/passkey verification.
138
- - [x] Password/email reauthentication adapters share policy and presentation;
139
- email step-up is bound to the initiating browser/session/purpose.
140
- - [x] Sensitive-action return goes to a safe confirmation page; final mutation
141
- rechecks authorization/grant/target and never automatically replays a POST.
142
- - [x] Default email recovery with explicit recovery purpose, replacement grant,
143
- security notifications and post-recovery session/proof invalidation.
144
- - [x] Stricter opt-in policy enforced across sign-in, fallback, credential
145
- management, password reset and policy changes; no hidden weaker route.
146
- - [x] Tests for fresh-but-insufficient proof, wrong account/session/purpose,
147
- expiry, lost response, cancellation and attempted policy bypass.
148
-
149
- ## 6. Complete passkeys and credential management slice E, U3–U7
150
-
151
- - [x] Registration with discoverable credentials, server-enforced user
152
- verification and transaction binding to an existing account.
153
- - [x] Discoverable sign-in with credential/userHandle ownership checks;
154
- explicit and conditional-autofill UI share the same verification path.
155
- - [x] Native browser support for another device/security key, neutral cancel,
156
- understandable retry/fallback and strict-policy unavailable states.
157
- - [x] First-passkey bootstrap and additional-passkey enrollment require
158
- appropriate fresh proof. The optional post-login invitation is a host product
159
- choice; v1 supplies the authenticated `/passkeys` entry point.
160
- - [x] Credential list, rename, remove, notifications and atomic last-usable-method
161
- checks; default/strict recovery works with enrollment and lost-device flows.
162
- - [x] Correct sign-counter anomaly/backup-flag handling, with atomic counter
163
- updates and tests for zero, equal, increasing and decreasing counters.
164
- - [x] Exact origin/RP policy, single-use server transactions, one shared codec,
165
- payload bounds and cleanup of pending browser ceremonies.
166
- - [x] Virtual-authenticator and real-store coverage of success, UV/signature/
167
- origin/ownership failures, replay, races, management and recovery.
168
-
169
- ## 7. Challenge adapters and accessible failure paths — slice F, U9
170
-
171
- - [x] Turnstile adapter with hostname/action checks, provider-owned lifetime,
172
- bounded HTTPS timeouts and safe no-retry handling for single-use tokens.
173
- - [x] reCAPTCHA v2/v3 adapters respecting their different verification fields
174
- and configured score/action requirements where applicable.
175
- - [x] Shared success/rejected/unavailable behavior, fail-closed default and
176
- observable explicit fail-open policy; no implicit bypass without JS.
177
- - [x] Retry/outage messages, preserved input, provider protocol fixtures and no
178
- live-provider dependency in routine specs.
179
- - [x] Local keyboard/focus/status, virtual-authenticator and provider-contract
180
- browser coverage in bundled and ejected UI. Broader browser/device and
181
- assistive-technology verification remains a host deployment responsibility.
182
-
183
- ## 8. Generators, ejection and integrated acceptance — slice G
184
-
185
- - [x] `add_auth:install` writes inert configuration; session/email feature
186
- generators add reviewable wiring and preserve edits on repeat runs.
187
- - [x] `add_auth:views`, `add_auth:controllers`, `add_auth:javascript` and
188
- `add_auth:mailer_views` reuse the same Core policy, presenter and templates.
189
- - [x] `add_auth:challenge` writes environment-keyed Turnstile/reCAPTCHA config,
190
- adds the fixed challenge route and preserves an existing initializer.
191
- - [x] `add_auth:doctor` checks deployment origins, cookies/session metadata,
192
- delivery, migrations and challenge policy/routes.
193
- - [x] `add_auth:doctor` checks recovery policy and generated-file drift.
194
- - [x] Every generated flow exercised before and after ejection, with Turbo
195
- Drive/Frames/Streams, ordinary HTML, no-JS alternatives and strict denial.
196
- - [x] Auth-page cache/referrer protections, redacted app/job telemetry,
197
- CSRF, safe redirects and correct success/failure HTTP contracts.
198
- - [x] RSpec strategy/store shared examples and host-facing test helpers,
199
- including virtual authenticator lifecycle and delivered-link extraction.
200
- - [x] Full RSpec, Standard and dependency audit pass on supported local matrices;
201
- README/roadmap distinguish working development APIs from release gates.
202
- - [ ] Exact-commit remote CI/CodeQL and required repository security checks;
203
- refresh deployed public documentation when the gem is released.
204
-
205
- ## 9. Release readiness
206
-
207
- - [x] README rewritten from skeleton status to verified usage and migration
208
- instructions, linking to maintained public API docs as they ship.
209
- - [x] Security policy updated for shipped strategies, recovery limits and
210
- supported versions; redacted events and incident/rollback guidance documented.
211
- - [ ] CHANGELOG entries and successful Trusted Publishing release; a tag or
212
- configured workflow alone does not prove the gem was published.
213
- - [x] Local enabled-journey, delivery-retry/restart, expiry and transaction rollback
214
- evidence. Record 0.2 operational defaults and host deployment responsibilities.
215
- - [x] Audit adopter-requested changes against stock Rails behavior; keep app roles,
216
- invitations, authorization and email themes in the host.
217
- - [ ] `v1.0.0` only after the integrated acceptance gates pass.
218
-
219
- ## v2 — reassess after v1 usage
220
-
221
- - [ ] AddAuth-owned password registration/reset, confirmation, lockout and
222
- password policy. Existing host password integration is part of v1.
223
- - [ ] Password-hashing adapter seam, following the canonical cryptography
224
- policy and Rails support available at implementation time.
225
- - [ ] Recovery codes; they are not an implied fallback for v1 strict policy.
226
- - [ ] Multiple realms/routing scopes.
227
-
228
- ## Decisions before they become dependencies
229
-
230
- Owner and deadline details remain in the canonical plan's section 16.
231
-
232
- - [x] Review the 0.2 configuration and public integration contract. The runtime
233
- uses Rails-generator User/Session conventions; authentication models must
234
- share one database connection pool and cross-pool writes are rejected.
235
- - [x] Review lifetime/resend/legacy-bridge defaults and local failure evidence;
236
- retention is opt-in, and key changes require a host deployment plan.
237
- - [x] Framework-neutral mail and virtual-authenticator helpers; no
238
- Minitest-specific integration DSL. AddAuth's own suite stays RSpec.
239
- - [ ] Revisit API/token authentication after v1; outside current scope.
240
-
241
- ## Potential standalone libraries
242
-
243
- - [ ] Virtual-authenticator test helpers.
244
- - [ ] Challenge adapter contract and its three-state result.
3
+ AddAuth extends Rails 8's authentication generator with email-link sign-in,
4
+ passkeys, purpose-bound reauthentication, hardened sessions and pluggable captcha.
5
+ It reuses the host's accounts and Session model.
6
+
7
+ **Reviewed 2026-09-07: 0.2.1 is published, and the planned v1 strategy features
8
+ have shipped.** The next work makes adoption, upgrades and the future 1.0 support
9
+ commitment clearer. Milestones below describe priorities, not promised dates or
10
+ versions. See [release status](https://addauthgem.com/release-status/),
11
+ [the changelog](CHANGELOG.md) and [the manual](https://addauthgem.com/).
12
+
13
+ **0.2.2 is prepared locally, not published.** It contains the counter-store
14
+ correction and upgrade/operations coverage described below. The owner selected
15
+ this patch before accepting the proposed 1.0 commitment.
16
+
17
+ An unchecked item is remaining work; deferred candidates need a scope decision
18
+ before implementation. Checked features have passing relevant acceptance specs.
19
+ Other completed work requires its applicable verification evidence. Checkmarks
20
+ can describe tested local work; release/publication remains a separate gate. Detailed
21
+ design and decision records remain in the companion private planning workspace;
22
+ this public checklist is derived from its section 14 and stands on its own.
23
+
24
+ ## Now maintain 0.2 and learn from adoption
25
+
26
+ - [ ] **R1 · Resolve the outstanding dependency update.** Review
27
+ [actions/checkout PR #1](https://github.com/taimoorq/add_auth/pull/1) against
28
+ current master. Its old failed Ruby checks need current evidence; retain
29
+ immutable action pins and all merge/release protections. Record a merge,
30
+ replacement or reasoned deferral.
31
+ - [x] **R1 · Complete the 2026-09-07 currency review.** Review Rails/Ruby support,
32
+ authentication APIs, WebAuthn, advisories and the competitive landscape
33
+ before the next version bump; repeat the standing review at least quarterly.
34
+ Floors remain Ruby 3.3 / Rails 8.0; current audits are clear. Follow Rails-
35
+ native password hashing when the supported API permits it. Future reviews
36
+ remain an ongoing maintenance responsibility.
37
+ - [x] **R2 · Complete a bounded first-adopter feedback review.** Official-package
38
+ local integration already passes. Collect installation, sign-in/recovery,
39
+ customization and operational friction; give each finding a gem fix,
40
+ documentation improvement, host-owned resolution or explicit deferral.
41
+ The review dispositions existing passwordless/management fixes, host-owned
42
+ onboarding/roles/mail branding and the new upgrade/operations guidance.
43
+ Stock and synthetic host regressions remain required for reusable changes.
44
+ - [x] **R2 · Improve onboarding from observed friction.** Update existing
45
+ quickstart, doctor and troubleshooting guidance with exact prerequisites,
46
+ observable success and recovery steps. Keep the public manual tied to the
47
+ published package. Upgrade, compatibility, cache and ejection guidance is
48
+ prepared locally; build and browser checks pass. Publication is pending.
49
+
50
+ The current master CI and CodeQL runs pass. The post-publication
51
+ passwordless-fixture isolation failure is fixed in
52
+ [PR #8](https://github.com/taimoorq/add_auth/pull/8); it is not an open runtime
53
+ defect or a reason by itself to republish 0.2.1.
54
+
55
+ ## Next — prove upgrades, plan migrations and define the 1.0 contract
56
+
57
+ - [x] **R3 · Rehearse an upgrade from published 0.2.1.** Start with a populated
58
+ host, active sessions, passkeys, strict accounts, pending mail and customized
59
+ ejected files. Upgrade to the candidate and verify data/policy preservation,
60
+ migration repeatability, doctor diffs, reviewed baseline acceptance,
61
+ worker compatibility and safe rollback or explicit revocation. Keep
62
+ fresh-install and before/after-ejection coverage. The checksum-pinned
63
+ baseline/candidate/rollback test passes on all six Ruby/Rails combinations;
64
+ CI now includes the same rehearsal.
65
+ - [x] **R4 · Validate the Rails-default operations path.** Exercise Solid Queue
66
+ restart/enqueue failure and same-intent mail retry locally. Determine
67
+ whether Solid Cache meets atomic rate-limit increment/TTL requirements;
68
+ document a tested separate store if needed. Publish only verified adapter
69
+ support. Solid Queue 1.7.0 passes with a separate queue database. Solid
70
+ Cache 1.0.10 loses concurrent first increments on PostgreSQL; the pending
71
+ fix rejects it for abuse counters and documents a separate Redis store.
72
+ - [x] **R4 · Measure bounded maintenance and recovery.** Record workload,
73
+ query counts, backlog drain and latency for session pages, outbox retries
74
+ and cleanup. Use those measurements to explain batch sizing, retention,
75
+ alerts and recovery procedures. SQLite/PostgreSQL rehearsals retain 5,000
76
+ live sessions while draining 1,200 expired rows in twelve batches of 100;
77
+ session listing uses two SELECTs and at most 52 loaded Session records.
78
+ - [x] **R5 · Inventory the proposed stable public surface.** Name supported configuration,
79
+ Core/host hooks and Results, routes, generators/ejection metadata, testing
80
+ helpers and redacted events. Distinguish internal APIs and document
81
+ compatibility, deprecation and migration rules. The current integration
82
+ reference and proposed contract are prepared; owner acceptance of the
83
+ 1.0 commitment remains the separate item below.
84
+ - [ ] **R5 · Set the 1.0 support policy.** Specify supported runtime/database
85
+ combinations and security-supported release lines. Publish an upgrade
86
+ guide and evidence-backed troubleshooting updates before the candidate
87
+ freezes. The current latest-0.x policy remains in
88
+ [SECURITY.md](SECURITY.md).
89
+ - [ ] **R8 · Define Devise migration readiness.** Inventory source versions,
90
+ modules, extensions and customizations; provide a read-only preflight with
91
+ supported mappings, prerequisites and actionable blockers. Running Rails 8
92
+ alone does not establish the authentication contracts AddAuth needs.
93
+ - [ ] **R8 · Provide a path for Rails-aligned Devise apps.** Reuse verified
94
+ account/session contracts and preserve host customizations while replacing
95
+ remaining Devise authentication wiring. Prove password compatibility,
96
+ account restrictions, session/token revocation and safe cutover/rollback.
97
+ - [ ] **R8 · Provide a path for standard or customized Devise apps.** Guide an
98
+ additive conversion from existing models, identifiers, password storage
99
+ and controllers to the supported Rails contracts. Preserve account IDs and
100
+ associations; resolve incompatible hashes, identifier collisions and
101
+ unsupported module policies before cutover. Include older-runtime
102
+ prerequisites and host-owned lifecycle replacements where needed.
103
+ - [ ] **R8 · Rehearse and document both migration paths.** Test populated Devise
104
+ hosts before and after migration, including custom schema, peppered
105
+ passwords, denied accounts, interrupted conversion and rollback. Verify
106
+ supported database/runtime and Turbo/no-JS journeys, publish step-by-step
107
+ guides and prove the destination works with Devise removed.
108
+
109
+ Each change owns its tests and keeps intermediate releases usable. R3/R4 findings
110
+ feed R5. A patch may address compatible corrections; another 0.x minor is possible
111
+ if integration contracts change. A 0.3 release is not a prerequisite for 1.0.
112
+ R8 is planned after the prepared 0.2.2 correction; its supported source profiles
113
+ and delivery version will be decided during discovery, with public API impact
114
+ resolved before R5 freezes. Devise migration support is not available yet.
115
+
116
+ ## Delivery 0.2.2 first, then the proposed 1.0 gate
117
+
118
+ - [ ] **R6 · Deliver the prepared 0.2.2 correction.** Commit and review the
119
+ tested changes, pass current required GitHub checks, publish through
120
+ protected OIDC, verify the registry package in a fresh host and publish
121
+ the matching manual. Preserve the existing latest-0.x support policy.
122
+
123
+ - [ ] **R6 · Finish the adoption and compatibility review.** R1–R5 findings are
124
+ completed or explicitly dispositioned, the supported API is accepted, and
125
+ the published-package upgrade and documented operations profile pass.
126
+ - [ ] **R6 · Verify the exact candidate.** Preserve the complete local
127
+ Ruby/Rails, SQLite/PostgreSQL, generated/ejected browser and operations
128
+ acceptance; resolve release-blocking security and upgrade findings.
129
+ Recheck dependency currency and pass required GitHub CI/CodeQL controls.
130
+ - [ ] **R6 · Publish and verify 1.0.** Release notes, migration/support guidance,
131
+ protected OIDC publication, registry checksum/package verification, fresh
132
+ installation and the public manual all identify the same accepted release.
133
+
134
+ The owner accepted local testing as the gem release gate. Production migration,
135
+ a fixed number of adopters, live captcha accounts, physical devices and branded
136
+ emails are not additional gem release requirements. Hosts remain responsible for
137
+ their actual providers, proxy/TLS, trusted recovery addresses and support process.
138
+
139
+ ## Ongoing broader compatibility evidence
140
+
141
+ - [ ] **R7 · Record browser, device and accessibility results as available.**
142
+ Track exact Safari/Firefox/mobile/hybrid authenticator and
143
+ assistive-technology environments. Add local regressions for reproducible
144
+ defects and document limits.
145
+ - [ ] **R7 · Record deployment-provider results as available.** Capture actual
146
+ provider and failure/recovery evidence without treating local protocol
147
+ fixtures as live-service certification.
148
+
149
+ These broaden host deployment confidence; they do not reopen completed 0.2
150
+ acceptance or silently add hardware/service gates to 1.0.
151
+
152
+ ## Later evaluate demand before adding scope
153
+
154
+ These are candidates, not promised features or a committed “v2” release. A
155
+ compatible extension could ship in 1.x after an explicit scope decision.
156
+
157
+ - [ ] **F1 · Recovery codes.** First expansion candidate to assess when adopters
158
+ need recovery beyond trusted email or strict host support. Design single
159
+ use, regeneration/revocation, abuse controls and the recovery-policy boundary
160
+ before implementation; codes must not silently satisfy passkey-only purposes.
161
+ - [ ] **F2 · Rails-native password hashing integration.** Recheck available Rails
162
+ support and real adopter needs before adding an adapter or changing a default.
163
+ - [ ] **F3 · Account lifecycle helpers.** Evaluate registration, confirmation,
164
+ reset, lockout and password policy individually against repeated needs.
165
+ Current host password integration already ships.
166
+ - [ ] **F4 · Multiple realms.** Require a concrete identity/session-isolation need
167
+ and migration design before adding models, cookies or routing APIs.
168
+ - [ ] **F4 · API/token authentication.** Decide separately from browser sessions
169
+ and realms; require a real non-browser client use case.
170
+ - [ ] **F5 · Standalone test helpers or challenge adapters.** Extract only if
171
+ independent demand and maintenance capacity justify another package;
172
+ retain one implementation per concern.
173
+
174
+ Social/OIDC, SMS/TOTP and enterprise or cross-origin WebAuthn are outside the
175
+ current roadmap. Account roles, invitations, authorization and email branding
176
+ stay with the host.
177
+
178
+ ## Shipped 0.2.1 baseline
179
+
180
+ - [x] Host password integration and explicit passwordless mode; one Core policy,
181
+ result presenter and atomic session finalizer.
182
+ - [x] Random digested session bearers, bounded Rails signed-ID session adoption,
183
+ expiry, device listing/pagination, revoke-one/all and host lifecycle invalidation.
184
+ - [x] Email links with inert GET/explicit POST confirmation, generic intake,
185
+ resend/replay protection and optional same-browser binding.
186
+ - [x] Discoverable passkeys, conditional sign-in, UV/origin enforcement,
187
+ credential management, counter checks and atomic last-method protection.
188
+ - [x] Purpose-bound password/email/passkey reauthentication, trusted-address
189
+ recovery, strict opt-in policy and protected host mutations.
190
+ - [x] Durable encrypted mail/notification intents, leases, retries,
191
+ cancellation and bounded maintenance with optional retention.
192
+ - [x] Turnstile and reCAPTCHA v2/v3 with distinct rejected/unavailable outcomes,
193
+ bounded verification and explicit outage policy.
194
+ - [x] Additive generators, fingerprinted view/controller/JavaScript/mail ejection,
195
+ drift diagnostics, doctor and framework-neutral testing helpers.
196
+ - [x] Shared HTML/Turbo pages, permitted no-JS alternatives, browser
197
+ capability detection and cache/CSRF/privacy protections.
198
+ - [x] Local supported Ruby 3.3/3.4/4.0 × Rails 8.0/8.1 matrix, SQLite/PostgreSQL
199
+ concurrency, generated/ejected browser and SMTP/queue/cache acceptance.
200
+ - [x] RSpec, Standard, dependency audit, CodeQL, protected repository controls
201
+ and pinned-action Trusted Publishing.
202
+ - [x] [Published 0.2.1](https://rubygems.org/gems/add_auth/versions/0.2.1),
203
+ verified registry installation and the maintained public manual.
204
+
205
+ Passkeys require JavaScript and a capable browser. Configured captcha may also
206
+ require JavaScript; strict policy is never weakened to imitate no-JS parity.
207
+ The immutable 0.1.0/0.2.0 tags did not publish packages; 0.2.1 is the first
208
+ successful package release. Historical details remain in the changelog and
209
+ release records.
210
+
211
+ For application setup, start with the [quickstart](https://addauthgem.com/quickstart/).
212
+ Report bugs or adoption feedback through [public issues](https://github.com/taimoorq/add_auth/issues);
213
+ use [private vulnerability reporting](SECURITY.md) for security concerns.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "add_auth/rails/ejection"
4
+ require "add_auth/rails/rate_limit_cache"
4
5
 
5
6
  module AddAuth
6
7
  module Rails
@@ -45,7 +46,9 @@ module AddAuth
45
46
  end
46
47
  check("Configure valid session timeouts and digest adapters") { Runtime.sessions }
47
48
  cache = config.rate_limit_store || ::Rails.cache
49
+ check(RateLimitCache::INCOMPATIBLE) { RateLimitCache.validate!(cache) }
48
50
  check("Configure an atomic rate-limit cache") do
51
+ RateLimitCache.validate!(cache)
49
52
  key = "add_auth:doctor:#{SecureRandom.hex(16)}"
50
53
  begin
51
54
  cache.increment(key, 1, expires_in: 30, initial: 0) == 1 && cache.increment(key, 1, expires_in: 30, initial: 0) == 2
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AddAuth
4
+ module Rails
5
+ # Adapter compatibility only; window and admission policy live in Core.
6
+ module RateLimitCache
7
+ INCOMPATIBLE = "Solid Cache cannot provide atomic rate-limit counters; configure rate_limit_store with a separate atomic store"
8
+
9
+ def self.validate!(cache)
10
+ if defined?(::SolidCache::Store) && cache.is_a?(::SolidCache::Store)
11
+ raise AddAuth::Error, INCOMPATIBLE
12
+ end
13
+ cache
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "add_auth/rails/rate_limit_cache"
4
+
3
5
  require "uri"
4
6
  require "add_auth/rails/stores/sessions"
5
7
  require "add_auth/rails/stores/email_tokens"
@@ -186,7 +188,7 @@ module AddAuth
186
188
  raise AddAuth::Error, "rate limit store unavailable", cause: nil
187
189
  end
188
190
 
189
- def rate_limit_cache = config.rate_limit_store || ::Rails.cache
191
+ def rate_limit_cache = RateLimitCache.validate!(config.rate_limit_store || ::Rails.cache)
190
192
 
191
193
  def maintenance_cache_key = "add_auth:maintenance:v1:#{config.sign_in_token_digest.digest("last-success")}"
192
194
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AddAuth
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.2"
5
5
  end
@@ -21,7 +21,9 @@ AddAuth.configure do |config|
21
21
  # config.base_url = "https://your-app.example"
22
22
  # config.mail_from = "Your app <sign-in@your-app.example>"
23
23
  # Configure a durable Active Job adapter and schedule add_auth:deliver_pending.
24
- # config.rate_limit_store = Rails.cache # shared, atomic increment in production
24
+ # Rails.cache is suitable only with shared atomic increments and expiry.
25
+ # Solid Cache is not suitable; configure a separate counter store:
26
+ # https://addauthgem.com/production/#rate-limits
25
27
  # Each maintenance pass handles at most this many rows per operation/model:
26
28
  # config.maintenance.batch_size = 100 # 1..1000
27
29
  # History is retained until the host chooses a retention period (seconds):
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: add_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taimoor Qureshi
@@ -284,6 +284,7 @@ files:
284
284
  - lib/add_auth/rails/elevation.rb
285
285
  - lib/add_auth/rails/engine.rb
286
286
  - lib/add_auth/rails/password_entry.rb
287
+ - lib/add_auth/rails/rate_limit_cache.rb
287
288
  - lib/add_auth/rails/runtime.rb
288
289
  - lib/add_auth/rails/stores/account_lock.rb
289
290
  - lib/add_auth/rails/stores/delivery_state.rb