ima-claude 2.9.0
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.
- package/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +1064 -0
- package/package.json +49 -0
- package/platforms/claude/adapter.ts +115 -0
- package/platforms/junie/adapter.ts +254 -0
- package/platforms/junie/agents-template.md +113 -0
- package/platforms/junie/hook-translations.md +84 -0
- package/platforms/shared/detector.ts +27 -0
- package/platforms/shared/installer.ts +202 -0
- package/platforms/shared/types.ts +78 -0
- package/plugins/ima-claude/.claude-plugin/plugin.json +25 -0
- package/plugins/ima-claude/agents/explorer.md +30 -0
- package/plugins/ima-claude/agents/implementer.md +30 -0
- package/plugins/ima-claude/agents/memory.md +42 -0
- package/plugins/ima-claude/agents/reviewer.md +53 -0
- package/plugins/ima-claude/agents/tester.md +33 -0
- package/plugins/ima-claude/agents/wp-developer.md +46 -0
- package/plugins/ima-claude/hooks/README.md +145 -0
- package/plugins/ima-claude/hooks/atlassian_prereqs.py +112 -0
- package/plugins/ima-claude/hooks/block_sed_edits.py +59 -0
- package/plugins/ima-claude/hooks/bootstrap.sh +90 -0
- package/plugins/ima-claude/hooks/bootstrap_utility_check.py +94 -0
- package/plugins/ima-claude/hooks/composer_autoload_check.py +70 -0
- package/plugins/ima-claude/hooks/docs_organization.py +104 -0
- package/plugins/ima-claude/hooks/enforce_rg_over_grep.py +56 -0
- package/plugins/ima-claude/hooks/fp_utility_check.py +90 -0
- package/plugins/ima-claude/hooks/hook_logger.py +69 -0
- package/plugins/ima-claude/hooks/hooks.json +239 -0
- package/plugins/ima-claude/hooks/jira_issue_fetch.py +79 -0
- package/plugins/ima-claude/hooks/jquery_in_wordpress.py +92 -0
- package/plugins/ima-claude/hooks/memory_bootstrap.py +79 -0
- package/plugins/ima-claude/hooks/memory_store_reminder.py +75 -0
- package/plugins/ima-claude/hooks/prompt_coach.py +125 -0
- package/plugins/ima-claude/hooks/prompt_coach_digest.md +48 -0
- package/plugins/ima-claude/hooks/prompt_coach_system.md +30 -0
- package/plugins/ima-claude/hooks/sequential_thinking_check.py +81 -0
- package/plugins/ima-claude/hooks/serena_over_grep.py +96 -0
- package/plugins/ima-claude/hooks/serena_over_read.py +66 -0
- package/plugins/ima-claude/hooks/serena_project_check.py +133 -0
- package/plugins/ima-claude/hooks/sql_injection_check.py +73 -0
- package/plugins/ima-claude/hooks/task_master_after_plan.py +31 -0
- package/plugins/ima-claude/hooks/task_master_before_impl.py +93 -0
- package/plugins/ima-claude/hooks/tavily_extract_advanced.py +48 -0
- package/plugins/ima-claude/hooks/vestige_before_external.py +86 -0
- package/plugins/ima-claude/hooks/webfetch_to_tavily.py +42 -0
- package/plugins/ima-claude/hooks/websearch_to_tavily.py +41 -0
- package/plugins/ima-claude/hooks/wp_security_check.py +150 -0
- package/plugins/ima-claude/personalities/README.md +45 -0
- package/plugins/ima-claude/personalities/enable-40k.md +69 -0
- package/plugins/ima-claude/personalities/enable-templars.md +69 -0
- package/plugins/ima-claude/skills/.research-summary.md +340 -0
- package/plugins/ima-claude/skills/architect/SKILL.md +304 -0
- package/plugins/ima-claude/skills/compound-bridge/SKILL.md +200 -0
- package/plugins/ima-claude/skills/discourse/SKILL.md +440 -0
- package/plugins/ima-claude/skills/discourse-admin/SKILL.md +192 -0
- package/plugins/ima-claude/skills/discourse-admin/references/api-endpoints.md +441 -0
- package/plugins/ima-claude/skills/discourse-admin/references/gotchas.md +107 -0
- package/plugins/ima-claude/skills/discourse-admin/references/staging-defaults.md +98 -0
- package/plugins/ima-claude/skills/discourse-admin/scripts/discourse-admin.py +319 -0
- package/plugins/ima-claude/skills/docs-organize/SKILL.md +254 -0
- package/plugins/ima-claude/skills/docs-organize/templates/active-README.md +50 -0
- package/plugins/ima-claude/skills/docs-organize/templates/archive-README.md +57 -0
- package/plugins/ima-claude/skills/docs-organize/templates/docs-README.md +43 -0
- package/plugins/ima-claude/skills/docs-organize/templates/phase-archive-README.md +83 -0
- package/plugins/ima-claude/skills/docs-organize/templates/section-README.md +48 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-README.md +79 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-gitignore +9 -0
- package/plugins/ima-claude/skills/ember-discourse/SKILL.md +496 -0
- package/plugins/ima-claude/skills/functional-programmer/SKILL.md +258 -0
- package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +278 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/bootstrap-patterns.md +356 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +273 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/theme-integration.md +212 -0
- package/plugins/ima-claude/skills/ima-brand/SKILL.md +108 -0
- package/plugins/ima-claude/skills/ima-brand/references/brand-identity.md +140 -0
- package/plugins/ima-claude/skills/ima-brand/references/digital-standards.md +180 -0
- package/plugins/ima-claude/skills/ima-brand/references/visual-system.md +173 -0
- package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +175 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/container-components.md +154 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/examples.md +328 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/field-components.md +298 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/form-factory.md +193 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/quick-reference.md +153 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/validation-engine.md +336 -0
- package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +178 -0
- package/plugins/ima-claude/skills/jquery/SKILL.md +413 -0
- package/plugins/ima-claude/skills/js-fp/SKILL.md +463 -0
- package/plugins/ima-claude/skills/js-fp/core-principles.md +487 -0
- package/plugins/ima-claude/skills/js-fp/examples/pure-functions.js +260 -0
- package/plugins/ima-claude/skills/js-fp/examples/tests/pure-functions.test.js +262 -0
- package/plugins/ima-claude/skills/js-fp/references/anti-patterns.md +120 -0
- package/plugins/ima-claude/skills/js-fp/references/performance-patterns.md +116 -0
- package/plugins/ima-claude/skills/js-fp/references/testing-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/SKILL.md +280 -0
- package/plugins/ima-claude/skills/js-fp-api/examples/crud-endpoint.js +258 -0
- package/plugins/ima-claude/skills/js-fp-api/references/middleware-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/references/security-sql.md +110 -0
- package/plugins/ima-claude/skills/js-fp-api/references/validation-patterns.md +165 -0
- package/plugins/ima-claude/skills/js-fp-react/SKILL.md +447 -0
- package/plugins/ima-claude/skills/js-fp-react/examples/ProductCard.tsx +65 -0
- package/plugins/ima-claude/skills/js-fp-react/references/hooks-advanced.md +136 -0
- package/plugins/ima-claude/skills/js-fp-react/references/performance-patterns.md +175 -0
- package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +322 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/complete-examples.md +397 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/composables-advanced.md +282 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/reactivity-patterns.md +348 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/testing.md +314 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +301 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/ajax-patterns.md +192 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/event-patterns.md +136 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/wp-integration.md +248 -0
- package/plugins/ima-claude/skills/livecanvas/SKILL.md +209 -0
- package/plugins/ima-claude/skills/livecanvas/references/livecanvas-features.md +311 -0
- package/plugins/ima-claude/skills/livecanvas/references/loops-and-logic.md +730 -0
- package/plugins/ima-claude/skills/livecanvas/references/picostrap.md +227 -0
- package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +339 -0
- package/plugins/ima-claude/skills/mcp-context7/SKILL.md +109 -0
- package/plugins/ima-claude/skills/mcp-memory/SKILL.md +182 -0
- package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +233 -0
- package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +149 -0
- package/plugins/ima-claude/skills/mcp-serena/SKILL.md +174 -0
- package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +118 -0
- package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +259 -0
- package/plugins/ima-claude/skills/php-authnet/SKILL.md +275 -0
- package/plugins/ima-claude/skills/php-authnet/references/api-reference.md +624 -0
- package/plugins/ima-claude/skills/php-authnet/references/sandbox-testing.md +424 -0
- package/plugins/ima-claude/skills/php-fp/SKILL.md +333 -0
- package/plugins/ima-claude/skills/php-fp/examples/pure-functions.php +403 -0
- package/plugins/ima-claude/skills/php-fp/examples/tests/PureFunctionsTest.php +515 -0
- package/plugins/ima-claude/skills/php-fp/references/core-principles.md +277 -0
- package/plugins/ima-claude/skills/php-fp/references/testing-patterns.md +374 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +216 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/fp-patterns.md +275 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/plugin-architecture.md +295 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/security-examples.md +203 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/testing-strategy.md +259 -0
- package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +716 -0
- package/plugins/ima-claude/skills/playwright/SKILL.md +434 -0
- package/plugins/ima-claude/skills/playwright/references/accessibility-testing.md +153 -0
- package/plugins/ima-claude/skills/playwright/references/ci-cd.md +268 -0
- package/plugins/ima-claude/skills/playwright/references/network-mocking.md +270 -0
- package/plugins/ima-claude/skills/playwright/references/visual-regression.md +215 -0
- package/plugins/ima-claude/skills/py-fp/SKILL.md +663 -0
- package/plugins/ima-claude/skills/py-fp/examples/pure-functions.py +185 -0
- package/plugins/ima-claude/skills/py-fp/examples/tests/test_pure_functions.py +244 -0
- package/plugins/ima-claude/skills/py-fp/references/core-principles.md +381 -0
- package/plugins/ima-claude/skills/py-fp/references/testing-patterns.md +283 -0
- package/plugins/ima-claude/skills/quasar-fp/SKILL.md +327 -0
- package/plugins/ima-claude/skills/quasar-fp/metadata.json +85 -0
- package/plugins/ima-claude/skills/quasar-fp/references/component-patterns.md +257 -0
- package/plugins/ima-claude/skills/quasar-fp/references/theme-integration.md +233 -0
- package/plugins/ima-claude/skills/quasar-fp/references/utility-classes.md +237 -0
- package/plugins/ima-claude/skills/quickstart/SKILL.md +129 -0
- package/plugins/ima-claude/skills/rails/SKILL.md +359 -0
- package/plugins/ima-claude/skills/resume-session/SKILL.md +68 -0
- package/plugins/ima-claude/skills/rg/SKILL.md +205 -0
- package/plugins/ima-claude/skills/ruby-fp/SKILL.md +336 -0
- package/plugins/ima-claude/skills/save-session/SKILL.md +81 -0
- package/plugins/ima-claude/skills/scorecard/SKILL.md +96 -0
- package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +127 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/advanced-checklist.md +44 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/core-checklist.md +60 -0
- package/plugins/ima-claude/skills/skill-analyzer/scripts/analyze_skill.py +418 -0
- package/plugins/ima-claude/skills/skill-creator/LICENSE.txt +202 -0
- package/plugins/ima-claude/skills/skill-creator/SKILL.md +343 -0
- package/plugins/ima-claude/skills/skill-creator/references/output-patterns.md +82 -0
- package/plugins/ima-claude/skills/skill-creator/references/workflows.md +28 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/plugins/ima-claude/skills/task-master/SKILL.md +51 -0
- package/plugins/ima-claude/skills/task-planner/SKILL.md +228 -0
- package/plugins/ima-claude/skills/task-runner/SKILL.md +192 -0
- package/plugins/ima-claude/skills/unit-testing/SKILL.md +198 -0
- package/plugins/ima-claude/skills/unit-testing/references/mock-patterns.md +181 -0
- package/plugins/ima-claude/skills/unit-testing/references/tdd-workflow.md +177 -0
- package/plugins/ima-claude/skills/unit-testing/references/test-strategy.md +126 -0
- package/plugins/ima-claude/skills/wp-local/SKILL.md +246 -0
- package/plugins/ima-claude/skills/wp-local/references/configuration.md +198 -0
- package/plugins/ima-claude/skills/wp-local/references/wp-cli-reference.md +406 -0
- package/plugins/ima-claude/skills/wp-local/scripts/wp-local.sh +61 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "rails"
|
|
3
|
+
description: "Ruby on Rails conventions + security - strong parameters, ActiveRecord safety, CSRF, auth, secrets management"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rails
|
|
7
|
+
|
|
8
|
+
Convention-over-configuration development on the happy path, with security non-negotiables that prevent the most common Rails vulnerabilities.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
- Building Rails controllers, models, services
|
|
13
|
+
- Reviewing Rails code for security or structure
|
|
14
|
+
- Adding features to an existing Rails application
|
|
15
|
+
- Discourse plugin development (see also `discourse` skill)
|
|
16
|
+
|
|
17
|
+
## Core Philosophy
|
|
18
|
+
|
|
19
|
+
Rails has opinions. Work with them, not against them. The framework gives you:
|
|
20
|
+
- SQL injection protection via ActiveRecord (use it)
|
|
21
|
+
- CSRF protection by default (don't disable it)
|
|
22
|
+
- XSS protection via ERB auto-escaping (use `<%= %>`)
|
|
23
|
+
- Mass assignment protection via Strong Parameters (permit explicitly)
|
|
24
|
+
|
|
25
|
+
**Functional core still applies in Rails.** Business logic in service modules/plain Ruby objects. Keep models and controllers thin.
|
|
26
|
+
|
|
27
|
+
**Foundation**: Reference `../ruby-fp/SKILL.md` for Ruby FP core principles.
|
|
28
|
+
|
|
29
|
+
## The 5 Non-Negotiable Security Practices
|
|
30
|
+
|
|
31
|
+
| Practice | Prevents | Rule |
|
|
32
|
+
|----------|----------|------|
|
|
33
|
+
| **Strong Parameters** | Mass assignment | `params.require(:model).permit(:field, ...)` on ALL controller actions |
|
|
34
|
+
| **Parameterized Queries** | SQL injection | ActiveRecord methods or `?`/named placeholders — NEVER string interpolation |
|
|
35
|
+
| **CSRF Protection** | CSRF | Never disable `protect_from_forgery`; use `form_with` helpers |
|
|
36
|
+
| **Before Actions (Auth)** | Unauthorized access | `before_action :authenticate_user!` or equivalent on ALL sensitive actions |
|
|
37
|
+
| **Secrets via Credentials** | Credential exposure | Rails credentials or ENV — never hardcode secrets in source |
|
|
38
|
+
|
|
39
|
+
### Quick Reference: The Five in Code
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
# 1. Strong Parameters
|
|
43
|
+
def user_params
|
|
44
|
+
params.require(:user).permit(:name, :email, :bio)
|
|
45
|
+
# Never: params[:user] or params.permit!
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# 2. Parameterized Queries — ActiveRecord keeps you safe
|
|
49
|
+
User.where(email: params[:email]) # safe
|
|
50
|
+
User.where("email = ?", params[:email]) # safe
|
|
51
|
+
User.where("email = :email", email: params[:email]) # safe
|
|
52
|
+
User.where("email = '#{params[:email]}'") # NEVER — SQL injection
|
|
53
|
+
|
|
54
|
+
# 3. CSRF — keep default, use form helpers
|
|
55
|
+
class ApplicationController < ActionController::Base
|
|
56
|
+
protect_from_forgery with: :exception # default — keep it
|
|
57
|
+
end
|
|
58
|
+
# form_with and form_for automatically include the token
|
|
59
|
+
|
|
60
|
+
# 4. Before action auth
|
|
61
|
+
class PostsController < ApplicationController
|
|
62
|
+
before_action :authenticate_user! # Devise
|
|
63
|
+
before_action :require_admin, only: [:destroy]
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
def require_admin
|
|
67
|
+
redirect_to root_path unless current_user&.admin?
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# 5. Credentials — never hardcode
|
|
72
|
+
# config/credentials.yml.enc (encrypted)
|
|
73
|
+
# Access: Rails.application.credentials.stripe[:secret_key]
|
|
74
|
+
# ENV fallback: ENV.fetch('STRIPE_SECRET_KEY')
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## ActiveRecord Safety
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
# SAFE — all these use parameterization internally
|
|
81
|
+
User.find(params[:id]) # auto-cast to integer
|
|
82
|
+
User.find_by(email: params[:email])
|
|
83
|
+
User.where(status: params[:status])
|
|
84
|
+
User.where("created_at > ?", 1.week.ago)
|
|
85
|
+
|
|
86
|
+
# SAFE — sanitize_sql_like for LIKE patterns
|
|
87
|
+
query = ActiveRecord::Base.sanitize_sql_like(params[:search])
|
|
88
|
+
User.where("name LIKE ?", "%#{query}%")
|
|
89
|
+
|
|
90
|
+
# UNSAFE — never do these
|
|
91
|
+
User.where("id = #{params[:id]}") # SQL injection
|
|
92
|
+
User.where("name LIKE '%#{params[:q]}%'") # SQL injection
|
|
93
|
+
User.find_by("email = '#{email}'") # SQL injection
|
|
94
|
+
|
|
95
|
+
# Raw SQL when needed — use sanitize or bind params
|
|
96
|
+
User.find_by_sql(["SELECT * FROM users WHERE token = ?", token])
|
|
97
|
+
ActiveRecord::Base.connection.execute(
|
|
98
|
+
ActiveRecord::Base.sanitize_sql(["UPDATE users SET x = ? WHERE id = ?", val, id])
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Mass Assignment
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
# BAD — never permit all, never skip permit
|
|
106
|
+
User.new(params[:user]) # bypasses strong params
|
|
107
|
+
User.update(params.permit!) # permits everything — dangerous
|
|
108
|
+
|
|
109
|
+
# GOOD — explicit whitelist
|
|
110
|
+
def user_params
|
|
111
|
+
params.require(:user).permit(:name, :email, :bio)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Nested params
|
|
115
|
+
def post_params
|
|
116
|
+
params.require(:post).permit(:title, :body, tags: [], author: [:name, :email])
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Never permit sensitive fields
|
|
120
|
+
# role, admin, password_digest, confirmed_at — set these explicitly in code
|
|
121
|
+
def promote_to_admin
|
|
122
|
+
@user.update!(role: 'admin') # explicit, not from params
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## XSS in Views
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
# ERB auto-escaping — always use <%= %> for user content
|
|
130
|
+
<%= user.name %> # safe — HTML-escaped
|
|
131
|
+
<%== user.name %> # UNSAFE — raw output, HTML injection risk
|
|
132
|
+
<%= raw user.name %> # UNSAFE — same as above
|
|
133
|
+
<%= user.name.html_safe %> # UNSAFE — marking untrusted content safe
|
|
134
|
+
|
|
135
|
+
# When you need to render HTML you control
|
|
136
|
+
<%= sanitize user.bio, tags: %w[b i em strong p] %>
|
|
137
|
+
|
|
138
|
+
# JavaScript context — never interpolate directly
|
|
139
|
+
<script>var name = "<%= user.name %>"</script> # UNSAFE — XSS via JS
|
|
140
|
+
# GOOD
|
|
141
|
+
<script>var data = <%= user.to_json.html_safe %></script> # if you control the data
|
|
142
|
+
# BEST — pass via data attributes
|
|
143
|
+
<div data-user-name="<%= user.name %>"></div>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Authentication & Authorization Pattern
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
# Authentication — Devise is the Rails default
|
|
150
|
+
# Before action guards all sensitive routes
|
|
151
|
+
class ApplicationController < ActionController::Base
|
|
152
|
+
before_action :authenticate_user!
|
|
153
|
+
|
|
154
|
+
# Override to allow public actions
|
|
155
|
+
skip_before_action :authenticate_user!, only: [:index, :show]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Authorization — policy objects (Pundit pattern or manual)
|
|
159
|
+
class PostPolicy
|
|
160
|
+
def initialize(user, post)
|
|
161
|
+
@user = user
|
|
162
|
+
@post = post
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def update?
|
|
166
|
+
@user.admin? || @post.user_id == @user.id
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# In controller
|
|
171
|
+
def update
|
|
172
|
+
@post = Post.find(params[:id])
|
|
173
|
+
policy = PostPolicy.new(current_user, @post)
|
|
174
|
+
return head :forbidden unless policy.update?
|
|
175
|
+
# ... update logic
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# NEVER rely on hidden fields or client-side checks alone
|
|
179
|
+
# Always enforce auth server-side
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Secrets Management
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# config/credentials.yml.enc (encrypted, safe to commit)
|
|
186
|
+
# Edit with: rails credentials:edit
|
|
187
|
+
# Access:
|
|
188
|
+
Rails.application.credentials.database[:password]
|
|
189
|
+
Rails.application.credentials.dig(:aws, :access_key_id)
|
|
190
|
+
|
|
191
|
+
# ENV for 12-factor apps (Heroku, Docker, etc.)
|
|
192
|
+
# Always use fetch to fail loudly if missing
|
|
193
|
+
DB_PASSWORD = ENV.fetch('DB_PASSWORD') # raises KeyError if missing
|
|
194
|
+
DB_PASSWORD = ENV.fetch('DB_PASSWORD') { raise "DB_PASSWORD not set" }
|
|
195
|
+
|
|
196
|
+
# Never in source code
|
|
197
|
+
config.secret_key_base = "abc123hardcoded" # NEVER
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Controller Pattern
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
class UsersController < ApplicationController
|
|
204
|
+
before_action :authenticate_user!
|
|
205
|
+
before_action :set_user, only: [:show, :update, :destroy]
|
|
206
|
+
before_action :authorize_user!, only: [:update, :destroy]
|
|
207
|
+
|
|
208
|
+
def show
|
|
209
|
+
render json: @user.as_json(only: [:id, :name, :email])
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def update
|
|
213
|
+
if @user.update(user_params)
|
|
214
|
+
render json: @user
|
|
215
|
+
else
|
|
216
|
+
render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
private
|
|
221
|
+
|
|
222
|
+
def set_user
|
|
223
|
+
@user = User.find(params[:id])
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def authorize_user!
|
|
227
|
+
head :forbidden unless current_user.admin? || @user == current_user
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def user_params
|
|
231
|
+
params.require(:user).permit(:name, :email, :bio)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Model: Thin, Validated, No Business Logic
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
class User < ApplicationRecord
|
|
240
|
+
# Validations
|
|
241
|
+
validates :email, presence: true, uniqueness: { case_sensitive: false },
|
|
242
|
+
format: { with: URI::MailTo::EMAIL_REGEXP }
|
|
243
|
+
validates :name, presence: true, length: { maximum: 100 }
|
|
244
|
+
|
|
245
|
+
# Scopes — declarative query building
|
|
246
|
+
scope :active, -> { where(active: true) }
|
|
247
|
+
scope :recent, -> { order(created_at: :desc) }
|
|
248
|
+
scope :admins, -> { where(role: 'admin') }
|
|
249
|
+
|
|
250
|
+
# Callbacks — use sparingly, only for model lifecycle concerns
|
|
251
|
+
before_save :normalize_email
|
|
252
|
+
|
|
253
|
+
# Associations
|
|
254
|
+
has_many :posts, dependent: :destroy
|
|
255
|
+
belongs_to :organization
|
|
256
|
+
|
|
257
|
+
private
|
|
258
|
+
|
|
259
|
+
def normalize_email
|
|
260
|
+
self.email = email.to_s.strip.downcase
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Business logic lives in service objects, NOT the model
|
|
265
|
+
# UserRegistrationService, UserImportService, etc.
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Service Objects (Functional Core in Rails)
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
# app/services/user_registration_service.rb
|
|
272
|
+
class UserRegistrationService
|
|
273
|
+
Result = Data.define(:success, :user, :errors)
|
|
274
|
+
|
|
275
|
+
def self.call(attrs)
|
|
276
|
+
new(attrs).call
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def initialize(attrs)
|
|
280
|
+
@attrs = attrs
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def call
|
|
284
|
+
user = User.new(normalized_attrs)
|
|
285
|
+
if user.save
|
|
286
|
+
send_welcome_email(user)
|
|
287
|
+
Result.new(success: true, user: user, errors: [])
|
|
288
|
+
else
|
|
289
|
+
Result.new(success: false, user: nil, errors: user.errors.full_messages)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
private
|
|
294
|
+
|
|
295
|
+
def normalized_attrs
|
|
296
|
+
@attrs.slice(:name, :email, :password).merge(
|
|
297
|
+
email: @attrs[:email].to_s.strip.downcase,
|
|
298
|
+
name: @attrs[:name].to_s.strip
|
|
299
|
+
)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def send_welcome_email(user)
|
|
303
|
+
WelcomeMailer.with(user: user).welcome_email.deliver_later
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Usage in controller
|
|
308
|
+
result = UserRegistrationService.call(user_params)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## File Organization
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
app/
|
|
315
|
+
├── controllers/
|
|
316
|
+
│ └── users_controller.rb # Thin — delegate to services
|
|
317
|
+
├── models/
|
|
318
|
+
│ └── user.rb # Validations, scopes, associations only
|
|
319
|
+
├── services/
|
|
320
|
+
│ └── user_registration_service.rb # Business logic
|
|
321
|
+
├── policies/
|
|
322
|
+
│ └── user_policy.rb # Authorization rules
|
|
323
|
+
└── views/
|
|
324
|
+
└── users/ # Only <%= %> — never <%== %>
|
|
325
|
+
config/
|
|
326
|
+
└── credentials.yml.enc # Secrets (encrypted)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Security Checklist
|
|
330
|
+
|
|
331
|
+
- [ ] Strong Parameters on all mutating actions
|
|
332
|
+
- [ ] No string interpolation in SQL queries
|
|
333
|
+
- [ ] `protect_from_forgery` enabled (default — don't remove)
|
|
334
|
+
- [ ] `before_action` auth guard on all sensitive routes
|
|
335
|
+
- [ ] No secrets in source code — credentials or ENV.fetch
|
|
336
|
+
- [ ] ERB uses `<%= %>` not `<%== %>` for user content
|
|
337
|
+
- [ ] `sanitize` used when rendering user-supplied HTML
|
|
338
|
+
- [ ] Dependency audit: `bundle exec bundler-audit check --update`
|
|
339
|
+
|
|
340
|
+
## When to Load Reference Files
|
|
341
|
+
|
|
342
|
+
### Security Deep Dive
|
|
343
|
+
**File**: [`references/security.md`](references/security.md)
|
|
344
|
+
**Load when**: Need vulnerable vs. safe comparisons, injection examples, CSRF details
|
|
345
|
+
**Contains**: Full attack examples, all Rails security helpers, CSP configuration
|
|
346
|
+
|
|
347
|
+
### ActiveRecord Patterns
|
|
348
|
+
**File**: [`references/activerecord.md`](references/activerecord.md)
|
|
349
|
+
**Load when**: Complex queries, raw SQL needs, migration patterns, performance
|
|
350
|
+
**Contains**: Query interface, raw SQL safety, N+1 prevention, index strategy
|
|
351
|
+
|
|
352
|
+
### Testing Strategy
|
|
353
|
+
**File**: [`references/testing.md`](references/testing.md)
|
|
354
|
+
**Load when**: Writing request specs, model specs, service object tests
|
|
355
|
+
**Contains**: RSpec patterns, factory patterns, security test examples
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
**Evidence Base**: OWASP Top 10 (2021), Rails Security Guide, RailsFactory/Corgea security research (2024–2025).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "resume-session"
|
|
3
|
+
description: "Resume previous session from Serena MCP memory. Use when: resume session, restore session, load session, continue session, resume from save."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# resume-session
|
|
7
|
+
|
|
8
|
+
Resume a previously saved session from Serena MCP memory.
|
|
9
|
+
|
|
10
|
+
## Trigger Phrases
|
|
11
|
+
|
|
12
|
+
- "resume session"
|
|
13
|
+
- "restore session"
|
|
14
|
+
- "load session"
|
|
15
|
+
- "continue session"
|
|
16
|
+
- "resume from save"
|
|
17
|
+
|
|
18
|
+
## Instructions
|
|
19
|
+
|
|
20
|
+
1. Use `mcp__serena__read_memory` with memory name `session-state`
|
|
21
|
+
2. Search Vestige for project context: `mcp__vestige__search query: "{project-name}" limit: 5`
|
|
22
|
+
3. Check for pending intentions: `mcp__vestige__intention action: "check"`
|
|
23
|
+
4. Parse the content and provide a brief status summary
|
|
24
|
+
5. Wait for user direction before taking action
|
|
25
|
+
|
|
26
|
+
## Output Format
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
## Session Resumed
|
|
30
|
+
|
|
31
|
+
**Task**: {current task from memory}
|
|
32
|
+
**Last saved**: {date from memory}
|
|
33
|
+
|
|
34
|
+
### Status
|
|
35
|
+
- {bullet 1: what was in progress}
|
|
36
|
+
- {bullet 2: key decision or context}
|
|
37
|
+
- {bullet 3: main outstanding item}
|
|
38
|
+
|
|
39
|
+
### Suggested Next Step
|
|
40
|
+
{The "Resume Hint" from memory, or first outstanding item}
|
|
41
|
+
|
|
42
|
+
Ready to continue. What would you like to focus on?
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Rules
|
|
46
|
+
|
|
47
|
+
- **Do not** take any actions beyond reading and summarizing
|
|
48
|
+
- **Do not** start working on outstanding items automatically
|
|
49
|
+
- **Do not** re-read files mentioned unless user asks
|
|
50
|
+
- **Do** present the state clearly and wait for direction
|
|
51
|
+
|
|
52
|
+
## If Memory Not Found
|
|
53
|
+
|
|
54
|
+
Respond with:
|
|
55
|
+
```
|
|
56
|
+
No session memory found.
|
|
57
|
+
|
|
58
|
+
To save a session, use: /ima-claude:save-session
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You can also check available memories with `mcp__serena__list_memories` if helpful.
|
|
62
|
+
|
|
63
|
+
## Technical Notes
|
|
64
|
+
|
|
65
|
+
- Uses Serena MCP `read_memory` tool (no file path confusion)
|
|
66
|
+
- Memory persists across Claude sessions in project context
|
|
67
|
+
- Project-specific storage (sessions are project-bound)
|
|
68
|
+
- Single checkpoint model (latest session-state only)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "rg"
|
|
3
|
+
description: "Ripgrep (rg) - fast recursive search tool. Prefer over grep/find for code search. Respects .gitignore, searches recursively, supports regex. Use for file content search, file listing, pattern matching. Triggers on: ripgrep, rg, search files, find in files, grep, search code, find pattern."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Ripgrep (rg) - Preferred Search Tool
|
|
7
|
+
|
|
8
|
+
**Always use `rg` instead of `grep` or `find -name`** - it's faster, has better defaults, and respects `.gitignore`.
|
|
9
|
+
|
|
10
|
+
## Quick Reference
|
|
11
|
+
|
|
12
|
+
### Basic Search
|
|
13
|
+
```bash
|
|
14
|
+
# Search for pattern in current directory (recursive)
|
|
15
|
+
rg "pattern"
|
|
16
|
+
|
|
17
|
+
# Search specific file or directory
|
|
18
|
+
rg "pattern" src/
|
|
19
|
+
rg "pattern" file.ts
|
|
20
|
+
|
|
21
|
+
# Case-insensitive search
|
|
22
|
+
rg -i "pattern"
|
|
23
|
+
|
|
24
|
+
# Word boundary match (whole words only)
|
|
25
|
+
rg -w "function"
|
|
26
|
+
|
|
27
|
+
# Fixed string (not regex)
|
|
28
|
+
rg -F "exact.string.match"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Output Control
|
|
32
|
+
```bash
|
|
33
|
+
# Show N lines of context (before and after)
|
|
34
|
+
rg -C 3 "pattern"
|
|
35
|
+
|
|
36
|
+
# Lines before (-B) or after (-A) only
|
|
37
|
+
rg -B 2 -A 5 "pattern"
|
|
38
|
+
|
|
39
|
+
# Count matches per file
|
|
40
|
+
rg -c "pattern"
|
|
41
|
+
|
|
42
|
+
# List files with matches only (no content)
|
|
43
|
+
rg -l "pattern"
|
|
44
|
+
rg --files-with-matches "pattern"
|
|
45
|
+
|
|
46
|
+
# List files WITHOUT matches
|
|
47
|
+
rg --files-without-match "pattern"
|
|
48
|
+
|
|
49
|
+
# Show only the matched text (not full line)
|
|
50
|
+
rg -o "pattern"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### File Filtering
|
|
54
|
+
```bash
|
|
55
|
+
# By file type (built-in types)
|
|
56
|
+
rg -t ts "pattern" # TypeScript only
|
|
57
|
+
rg -t py "pattern" # Python only
|
|
58
|
+
rg -t js "pattern" # JavaScript only
|
|
59
|
+
rg -t rust "pattern" # Rust only
|
|
60
|
+
|
|
61
|
+
# Exclude file type
|
|
62
|
+
rg -T js "pattern" # Exclude JavaScript
|
|
63
|
+
|
|
64
|
+
# By glob pattern
|
|
65
|
+
rg -g "*.vue" "pattern" # Only .vue files
|
|
66
|
+
rg -g "!*.test.ts" "pattern" # Exclude test files
|
|
67
|
+
rg -g "src/**/*.ts" "pattern" # TypeScript in src/
|
|
68
|
+
|
|
69
|
+
# Multiple globs
|
|
70
|
+
rg -g "*.ts" -g "*.vue" "pattern"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### List Files (No Search)
|
|
74
|
+
```bash
|
|
75
|
+
# List all files that would be searched
|
|
76
|
+
rg --files
|
|
77
|
+
|
|
78
|
+
# List files matching glob
|
|
79
|
+
rg --files -g "*.ts"
|
|
80
|
+
|
|
81
|
+
# List files in specific directory
|
|
82
|
+
rg --files src/components/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Bypass Filters
|
|
86
|
+
```bash
|
|
87
|
+
# -u levels (unrestricted):
|
|
88
|
+
rg -u "pattern" # Ignore .gitignore
|
|
89
|
+
rg -uu "pattern" # + search hidden files
|
|
90
|
+
rg -uuu "pattern" # + search binary files
|
|
91
|
+
|
|
92
|
+
# Specific overrides
|
|
93
|
+
rg --hidden "pattern" # Include hidden files
|
|
94
|
+
rg --no-ignore "pattern" # Ignore all ignore files
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Advanced Patterns
|
|
98
|
+
```bash
|
|
99
|
+
# Multiline search
|
|
100
|
+
rg -U "start.*\n.*end"
|
|
101
|
+
|
|
102
|
+
# PCRE2 regex (lookahead/lookbehind)
|
|
103
|
+
rg -P "(?<=prefix)pattern(?=suffix)"
|
|
104
|
+
|
|
105
|
+
# Replace in output (preview, doesn't modify files)
|
|
106
|
+
rg "old" -r "new"
|
|
107
|
+
|
|
108
|
+
# With capture groups
|
|
109
|
+
rg "fn (\w+)" -r "function $1"
|
|
110
|
+
|
|
111
|
+
# JSON output (for scripting)
|
|
112
|
+
rg --json "pattern"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Common Recipes
|
|
116
|
+
|
|
117
|
+
### Find Function/Class Definitions
|
|
118
|
+
```bash
|
|
119
|
+
# JavaScript/TypeScript
|
|
120
|
+
rg "^(export )?(async )?(function|const|class) \w+"
|
|
121
|
+
rg "^export (default )?(function|class)"
|
|
122
|
+
|
|
123
|
+
# Python
|
|
124
|
+
rg "^(async )?def \w+|^class \w+"
|
|
125
|
+
|
|
126
|
+
# PHP
|
|
127
|
+
rg "^(public |private |protected )?(static )?(function) \w+"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Find Imports/Requires
|
|
131
|
+
```bash
|
|
132
|
+
rg "^import .+ from"
|
|
133
|
+
rg "require\(['\"]"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Find TODOs/FIXMEs
|
|
137
|
+
```bash
|
|
138
|
+
rg "TODO|FIXME|HACK|XXX" -g "!node_modules"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Find Files by Extension
|
|
142
|
+
```bash
|
|
143
|
+
rg --files -g "*.tsx" # All TSX files
|
|
144
|
+
rg --files -g "*.{ts,tsx}" # TS and TSX
|
|
145
|
+
rg --files -g "!*.test.*" # Exclude test files
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Search and Replace Preview
|
|
149
|
+
```bash
|
|
150
|
+
# See what would change (doesn't modify files)
|
|
151
|
+
rg "oldFunction" -r "newFunction" --passthru
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## vs grep/find
|
|
155
|
+
|
|
156
|
+
| Task | grep/find (avoid) | rg (prefer) |
|
|
157
|
+
|------|-------------------|-------------|
|
|
158
|
+
| Search text | `grep -r "pattern" .` | `rg "pattern"` |
|
|
159
|
+
| Find files | `find . -name "*.ts"` | `rg --files -g "*.ts"` |
|
|
160
|
+
| Case insensitive | `grep -ri "pattern" .` | `rg -i "pattern"` |
|
|
161
|
+
| Whole word | `grep -rw "word" .` | `rg -w "word"` |
|
|
162
|
+
| Show context | `grep -r -C 3 "pattern" .` | `rg -C 3 "pattern"` |
|
|
163
|
+
| List files only | `grep -rl "pattern" .` | `rg -l "pattern"` |
|
|
164
|
+
|
|
165
|
+
## Key Advantages
|
|
166
|
+
|
|
167
|
+
1. **Speed**: 2-10x faster than grep on large codebases
|
|
168
|
+
2. **Smart defaults**: Respects `.gitignore`, skips binary/hidden files
|
|
169
|
+
3. **Recursive by default**: No `-r` flag needed
|
|
170
|
+
4. **Better regex**: Rust regex engine, optional PCRE2
|
|
171
|
+
5. **Built-in file types**: `-t ts`, `-t py`, etc.
|
|
172
|
+
6. **Colored output**: Easy to read in terminal
|
|
173
|
+
|
|
174
|
+
## Configuration
|
|
175
|
+
|
|
176
|
+
Create `~/.ripgreprc` for persistent settings:
|
|
177
|
+
```shell
|
|
178
|
+
# Smart case (case-insensitive unless uppercase used)
|
|
179
|
+
--smart-case
|
|
180
|
+
|
|
181
|
+
# Max line length for display
|
|
182
|
+
--max-columns=150
|
|
183
|
+
--max-columns-preview
|
|
184
|
+
|
|
185
|
+
# Include hidden files by default
|
|
186
|
+
# --hidden
|
|
187
|
+
|
|
188
|
+
# Custom file type
|
|
189
|
+
--type-add
|
|
190
|
+
web:*.{html,css,js,ts,vue}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Set the config file path:
|
|
194
|
+
```bash
|
|
195
|
+
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Type List
|
|
199
|
+
|
|
200
|
+
View all built-in types:
|
|
201
|
+
```bash
|
|
202
|
+
rg --type-list
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Common types: `ts`, `js`, `py`, `rust`, `go`, `java`, `php`, `ruby`, `css`, `html`, `json`, `yaml`, `md`, `sh`
|