feat: grow blog_demo

This commit is contained in:
dualfroz committed 2026-09-01 21:06:03 +02:00
1 parent 889030db77
commit 8a31d9de17
1 file changed
+89
+89
View File
@@ -1894,7 +1894,96 @@ Net::HTTP.start('127.0.0.1', port) do |http|
'user[email]' => 'writer@example.com', 'user[password]' => 'wrong password', 'authenticity_token' => token
)
# Three POST /session slots are already spent before this loop starts:
# device A's own sign-in plus devices B and C from the multi-device
# remember-me scene above (each a real POST /session.json, all from the
# same IP). So the throttle (limit: 5) trips two attempts earlier here
# than it would against a completely fresh IP. Attempt 1 goes through
# .json instead of the usual form post - same slot either way (the
# discriminator strips the extension), but it doubles as the
# JSON-format proof that a rejected login is a 401 with a JSON:API
# error, not the HTML branch's 422.
6.times do |i|
path = i.zero? ? '/session.json' : '/session'
attempt = http.post(path, login_attempt_body, 'Content-Type' => 'application/x-www-form-urlencoded',
'Cookie' => cookie)
expected = if i.zero? then '401'
elsif i == 1 then '422'
else '429'
end
puts " attempt #{i + 1}: POST #{path} -> #{attempt.code} (expected #{expected})"
raise "login attempt #{i + 1}: expected #{expected}, got #{attempt.code}" unless attempt.code == expected
if i.zero?
error = JSON.parse(attempt.body)['errors'].first
raise 'expected the JSON login rejection to point at the password attribute' unless error['source']['pointer'] == '/data/attributes/password'
end
raise 'the blocked attempt should carry a Retry-After header' if i == 2 && attempt['retry-after'].nil?
end
puts '-' * 40
puts 'hammering POST /users to exercise the signup throttle (limit 3/60s per IP)'
signup_attempt_body = URI.encode_www_form(
'user[email]' => 'writer@example.com', 'user[password]' => 'irrelevant',
'user[password_confirmation]' => 'irrelevant', 'authenticity_token' => token
)
# The demo user and the ownership-check user above each cost one of the
# 3 POST /users slots, so the throttle trips one attempt earlier here
# than it would against a completely fresh IP. Attempt 1 goes through
# .json to prove the duplicate-email rejection is a normal render_errors
# 422 (same shape a JSON client already gets from posts.json), not a
# special case just because it happens to come from a throttled action.
2.times do |i|
path = i.zero? ? '/users.json' : '/users'
attempt = http.post(path, signup_attempt_body, 'Content-Type' => 'application/x-www-form-urlencoded',
'Cookie' => cookie)
expected = i.zero? ? '422' : '429'
puts " attempt #{i + 1}: POST #{path} -> #{attempt.code} (expected #{expected})"
raise "signup attempt #{i + 1}: expected #{expected}, got #{attempt.code}" unless attempt.code == expected
if i.zero?
error = JSON.parse(attempt.body)['errors'].first
raise 'expected the JSON signup rejection to point at the email attribute' unless error['source']['pointer'] == '/data/attributes/email'
end
raise 'the blocked attempt should carry a Retry-After header' if i == 1 && attempt['retry-after'].nil?
end
end
puts '-' * 40
puts "checking that add_index :users, :email, unique: true (db/migrate/20260907000002_add_index_on_users_email.rb) is a REAL storage-level constraint, not just the app-level validates :email, uniqueness: true above"
existing_writer = User.find_by(email: 'writer@example.com')
raise 'expected the writer@example.com user created earlier in this demo to still exist' unless existing_writer
users_count_before_bypass = User.count
# Model#save always calls #valid? first, which is exactly what the app-level
# uniqueness validator above already covers - so the only way to prove the
# INDEX (not the validator) is what actually stops a duplicate is to skip
# the model layer entirely and hit Store#insert directly, the way a future
# admin script, a data migration, or a second process racing past the
# validator's own SELECT before either commits, all would.
begin
User.store.insert(User.table_name, 'email' => existing_writer[:email])
raise 'expected the unique index on users.email to reject a duplicate row inserted directly through Store#insert, bypassing Model#valid? entirely'
rescue Prism::Orm::Store::UniqueConstraintViolation => e
puts " Store#insert with a duplicate encrypted email, bypassing Model validation entirely -> #{e.class}: #{e.message}"
end
raise 'the rejected bypass insert must not have left a phantom row behind' unless User.count == users_count_before_bypass
puts '-' * 40
puts 'checking examples/blog/log/development.log for real Instrumentation::LogSubscriber output'
new_log_lines = File.read(log_path)[log_offset_before_requests..].to_s
%w[sql.prism render_template.prism process_action.prism perform_job.prism deliver_mail.prism].each do |event_name|
raise "expected at least one #{event_name} line in #{log_path}" unless new_log_lines.include?(" #{event_name} (")
end
unless new_log_lines.include?('table="posts"')
raise "expected a sql.prism line touching the posts table in #{log_path}"
end
unless new_log_lines.include?('path="/"')
raise "expected a process_action.prism line for the homepage in #{log_path}"
end
unless new_log_lines.include?('job_class="Prism::Mailer::DeliveryJob"')
raise "expected a perform_job.prism line for the mailer delivery job in #{log_path}"
end
unless new_log_lines.include?('deliver_mail.prism') && new_log_lines.include?('delivery_method=:test')
raise "expected a deliver_mail.prism line for the notification email in #{log_path}"
end
puts " log grew by #{new_log_lines.lines.count} lines, sql/render/process_action/perform_job/deliver_mail all present"
server.stop
puts '-' * 40