mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 22:34:47 +00:00
* Add LLM prompt for API endpoint consistency (fixes #944) - Add .cursor/rules/api-endpoint-consistency.mdc: checklist that applies when editing app/controllers/api/v1, spec/requests/api/v1, or test/controllers/api/v1. Enforces (1) Minitest-only behavioral coverage for new endpoints, (2) rswag docs-only (no expect/assert), (3) same API key auth pattern in all rswag specs. - Reference the rule in AGENTS.md under API Development Guidelines. * Add tests for API endpoint consistency implementation - Minitest: test/api_endpoint_consistency_rule_test.rb checks rule file exists, globs, and all three sections (Minitest, rswag docs-only, API key auth) plus AGENTS.md reference. - Standalone: test/support/verify_api_endpoint_consistency.rb runs same checks without loading Rails (use when app fails to boot). - Rule: add mdc: links for Cursor, note valuations_spec OAuth outlier. * Address review: add --compliance check, CLAUDE.md section - Verification script: --compliance scans current APIs and reports rswag OAuth vs API key, missing Minitest for controllers, expect/assert. - CLAUDE.md: add Post-commit API consistency subsection under API Development Guidelines (links to rule, documents script + --compliance). --------- Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
113 lines
4.9 KiB
Ruby
113 lines
4.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Standalone verification of the API endpoint consistency implementation (issue #944).
|
|
# Run without loading Rails: ruby test/support/verify_api_endpoint_consistency.rb
|
|
# Or with bundle: bundle exec ruby test/support/verify_api_endpoint_consistency.rb
|
|
#
|
|
# Option: pass --compliance to also scan the current API codebase and report violations
|
|
# (rswag specs using OAuth instead of API key, missing Minitest for API controllers,
|
|
# rswag specs with expect/assert).
|
|
|
|
def project_root
|
|
dir = File.dirname(File.expand_path(__FILE__))
|
|
loop do
|
|
return dir if File.exist?(File.join(dir, "AGENTS.md")) && File.directory?(File.join(dir, ".cursor", "rules"))
|
|
parent = File.dirname(dir)
|
|
raise "Could not find project root (AGENTS.md + .cursor/rules)" if parent == dir
|
|
dir = parent
|
|
end
|
|
end
|
|
|
|
def assert(condition, message)
|
|
raise "FAIL: #{message}" unless condition
|
|
end
|
|
|
|
def assert_includes(content, substring, message)
|
|
assert content.include?(substring), "#{message} (missing: #{substring.inspect})"
|
|
end
|
|
|
|
root = project_root
|
|
rule_path = File.join(root, ".cursor", "rules", "api-endpoint-consistency.mdc")
|
|
agents_path = File.join(root, "AGENTS.md")
|
|
|
|
assert File.exist?(rule_path), "Rule file should exist at #{rule_path}"
|
|
rule_content = File.read(rule_path)
|
|
|
|
assert_includes rule_content, "app/controllers/api/v1", "Rule must have glob for app/controllers/api/v1"
|
|
assert_includes rule_content, "spec/requests/api/v1", "Rule must have glob for spec/requests/api/v1"
|
|
assert_includes rule_content, "test/controllers/api/v1", "Rule must have glob for test/controllers/api/v1"
|
|
assert_includes rule_content, "Minitest behavioral coverage", "Rule must include Minitest section"
|
|
assert_includes rule_content, "test/controllers/api/v1/{resource}_controller_test.rb", "Rule must specify Minitest location"
|
|
assert_includes rule_content, "api_headers", "Rule must mention api_headers"
|
|
assert_includes rule_content, "X-Api-Key", "Rule must mention X-Api-Key"
|
|
assert_includes rule_content, "rswag is docs-only", "Rule must include rswag docs-only section"
|
|
assert_includes rule_content, "run_test!", "Rule must mention run_test!"
|
|
assert_includes rule_content, "rswag:specs:swaggerize", "Rule must mention swaggerize task"
|
|
assert_includes rule_content, "Same API key auth", "Rule must include API key auth section"
|
|
assert_includes rule_content, "ApiKey.generate_secure_key", "Rule must show API key pattern"
|
|
assert_includes rule_content, "plain_key", "Rule must mention plain_key"
|
|
assert_includes rule_content, "Doorkeeper", "Rule must mention Doorkeeper (to avoid OAuth in specs)"
|
|
|
|
assert File.exist?(agents_path), "AGENTS.md should exist"
|
|
agents_content = File.read(agents_path)
|
|
assert_includes agents_content, "Post-commit API consistency", "AGENTS.md must reference post-commit checklist"
|
|
assert_includes agents_content, "api-endpoint-consistency.mdc", "AGENTS.md must link to rule file"
|
|
assert_includes agents_content, "Minitest", "AGENTS.md must mention Minitest"
|
|
assert_includes agents_content, "rswag", "AGENTS.md must mention rswag"
|
|
assert_includes agents_content, "X-Api-Key", "AGENTS.md must mention X-Api-Key"
|
|
|
|
puts "OK: API endpoint consistency implementation verified (rule + AGENTS.md)."
|
|
|
|
if ARGV.include?("--compliance")
|
|
puts "\n--- Compliance check (current APIs) ---"
|
|
spec_dir = File.join(root, "spec", "requests", "api", "v1")
|
|
test_dir = File.join(root, "test", "controllers", "api", "v1")
|
|
app_controllers_dir = File.join(root, "app", "controllers", "api", "v1")
|
|
|
|
rswag_oauth = []
|
|
rswag_assertions = []
|
|
missing_minitest = []
|
|
|
|
if File.directory?(spec_dir)
|
|
Dir.glob(File.join(spec_dir, "*_spec.rb")).each do |path|
|
|
basename = File.basename(path, "_spec.rb")
|
|
next if basename == "auth"
|
|
content = File.read(path)
|
|
if content.include?("Doorkeeper") || content.include?("Bearer") || content.include?("access_token")
|
|
rswag_oauth << "#{basename}_spec.rb"
|
|
end
|
|
rswag_assertions << "#{basename}_spec.rb" if content.include?("expect(") || content.include?("assert_")
|
|
end
|
|
end
|
|
|
|
skip_controllers = %w[base_controller test_controller]
|
|
if File.directory?(app_controllers_dir)
|
|
Dir.glob(File.join(app_controllers_dir, "*_controller.rb")).each do |path|
|
|
basename = File.basename(path, ".rb")
|
|
next if skip_controllers.include?(basename)
|
|
test_path = File.join(test_dir, "#{basename}_test.rb")
|
|
missing_minitest << basename unless File.exist?(test_path)
|
|
end
|
|
end
|
|
|
|
if rswag_oauth.any?
|
|
puts "rswag using OAuth (should use API key per rule): #{rswag_oauth.join(", ")}"
|
|
else
|
|
puts "rswag auth: all specs use API key."
|
|
end
|
|
|
|
if rswag_assertions.any?
|
|
puts "rswag with expect/assert (should be docs-only): #{rswag_assertions.join(", ")}"
|
|
else
|
|
puts "rswag: no expect/assert found (docs-only)."
|
|
end
|
|
|
|
if missing_minitest.any?
|
|
puts "API v1 controllers missing Minitest: #{missing_minitest.join(", ")}"
|
|
else
|
|
puts "Minitest: all API v1 controllers have a test file."
|
|
end
|
|
|
|
puts "---"
|
|
end
|