Curated library of atomic AI agent skills for Hanami, dry-rb, and ROM Ruby development. Covers actions, slices, repositories, relations, changesets, providers, DI, operations, TDD, CLI, views, routing, and validation. Shared Ruby process skills have moved to ruby-core-skills. Uses Markdown + Front-matter architecture.
92
94%
Does it follow best practices?
Impact
92%
1.33xAverage score across 35 eval scenarios
Passed
No known issues
Use this skill when reviewing Hanami 2.x code for security concerns.
Core principle: Security is layered. Validate at the boundary, authenticate explicitly, and never trust input.
Follow this sequence when performing a security review:
params block. Grep: grep -rn 'request.params' app/actions/ | grep -v 'params do'config.actions.csrf_protection = true in config/app.rb for HTML apps.before :authenticate! or equivalent. Grep: grep -rn 'def handle' app/actions/ and cross-check with grep -rn 'authenticate'grep -rn 'secret\|password\|api_key\|token' app/ config/ --include='*.rb' | grep -v 'settings\|ENV'grep -rn 'logger' app/ | grep 'password\|token\|secret'grep -rn 'where("' app/ to find potential string interpolation in queries.grep -rn 'raw ' app/ to find unescaped output.config.sessions has a secret from settings, not hardcoded.| Concern | Red Flag |
|---|---|
| Param validation | request.params used directly in business logic |
| CSRF protection | Missing csrf_protection = true for HTML endpoints |
| Authentication | Auth assumed by convention, not explicit check |
| Authorization | Only authn, no authz |
| Error messages | Messages like "User not found" or "Password incorrect" |
| Logging | params[:password] or tokens in log calls |
| Secrets | Hardcoded strings for keys/secrets in source files |
| SQL injection | String interpolation in where("...") |
| XSS | raw or html_safe on user input |
| Session management | No secret, no expiration, or hardcoded secret |
Validate all params via the Params DSL:
# GOOD
params do
required(:email).value(:string, format?: /\A.+@.+\z/)
required(:password).value(:string, min_size?: 8)
end
# BAD — mass assignment risk
user_repo.create(request.params)Enable CSRF protection for HTML endpoints:
# config/app.rb
config.actions.csrf_protection = trueAuthenticate in Actions using injected services:
include Deps["authentication"]
before :authenticate!
def authenticate!(request, response)
halt 401 unless authentication.valid?(request)
endNever log sensitive data:
# GOOD
logger.info("Login attempt: #{params[:email]}")
# BAD
logger.info("Login: #{params[:email]}, password: #{params[:password]}")Store secrets in settings, never in code:
# config/settings.rb
setting :session_secret, constructor: Types::String# .env
SESSION_SECRET=your-secret-herePrevent SQL injection using ROM's query interface:
# GOOD
users.where(email: params[:email]).one
# BAD
users.where("email = '#{params[:email]}'")Escape output in templates to prevent XSS:
<!-- GOOD -->
<p><%= user.bio %></p>
<!-- BAD -->
<p><%= raw user.bio %></p>Use secure session configuration:
config.sessions = :cookie, {
key: "my_app.session",
secret: settings.session_secret,
expire_after: 60 * 60 * 24 * 7
}Return generic error messages for auth failures:
# GOOD
halt 401, { error: "Invalid credentials" }.to_json
# BAD — reveals account existence
halt 401, { error: "User not found" }.to_json| Related Skill | When to chain |
|---|---|
| validate-params | All params must be validated before use. |
| handle-errors | Error responses must not leak sensitive information. |
| settings | Secrets and configuration must use Settings, not hardcoded values. |
| code-review | Security review is part of every code review. |
| setup-authentication | For implementing auth strategies. |
| security-review-process (from ruby-core-skills) | OWASP checklist, Ruby-level security concerns. |
| Rails | Hanami 2.x |
|---|---|
protect_from_forgery | config.actions.csrf_protection = true |
before_action :authenticate_user! | Explicit before :authenticate! in each Action |
strong_parameters | Params DSL with type coercion and constraints |
Rails.application.credentials | Settings with environment variables |
html_safe / raw | ERB auto-escapes; avoid raw on user input |
config.session_store | config.sessions = :cookie, { ... } in config/app.rb |
docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
scenario-27
scenario-28
scenario-29
scenario-30
scenario-31
scenario-32
scenario-33
scenario-34
scenario-35
skills
actions
build-json-api
create-action
handle-errors
validate-params
context
load-context
db
create-changeset
create-repository
define-relation
write-migration
dry-monads
handle-result-pattern
dry-rb
create-operation
create-validation-contract
providers
configure-providers
implement-di
review-security
routing
define-routes
slices
configure-slice
create-slice
extract-slice
review-slice-boundaries
test-slice