neon_sakura 0.1.4

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.
Files changed (251) hide show
  1. checksums.yaml +7 -0
  2. data/.ai-reviewer/README.md +182 -0
  3. data/.ai-reviewer/ai-reviewer.sh +56 -0
  4. data/.ai-reviewer/build-system-prompt.sh +136 -0
  5. data/.ai-reviewer/extract-claude-sections.sh +32 -0
  6. data/.ai-reviewer/test-ai-reviewer.sh +40 -0
  7. data/.ai-reviewer-config.yml +190 -0
  8. data/.github/dependabot.yml +12 -0
  9. data/.github/settings.yml +70 -0
  10. data/.github/workflows/ai-pr-review-on-comment.yml +384 -0
  11. data/.github/workflows/ai-pr-review.yml +328 -0
  12. data/.github/workflows/license-check.yml +78 -0
  13. data/.github/workflows/lint.yml +79 -0
  14. data/.github/workflows/security.yml +131 -0
  15. data/.github/workflows/semgrep.yml +26 -0
  16. data/.github/workflows/test.yml +44 -0
  17. data/.gitignore +75 -0
  18. data/.rubocop.yml +33 -0
  19. data/.ruby-version +1 -0
  20. data/.simplecov +14 -0
  21. data/.stylelintignore +10 -0
  22. data/.stylelintrc.json +37 -0
  23. data/AGENTS.md +51 -0
  24. data/CHANGELOG.md +568 -0
  25. data/CLAUDE.md +632 -0
  26. data/Gemfile +8 -0
  27. data/Gemfile.lock +327 -0
  28. data/LICENSE +21 -0
  29. data/README.md +1209 -0
  30. data/Rakefile +25 -0
  31. data/app/assets/images/cherry_blossom.svg +1525 -0
  32. data/app/assets/images/cherry_blossom_tree.png +0 -0
  33. data/app/assets/images/prysm-icon.png +0 -0
  34. data/app/assets/stylesheets/base.css +29 -0
  35. data/app/assets/stylesheets/components.css +1652 -0
  36. data/app/assets/stylesheets/forms.css +152 -0
  37. data/app/assets/stylesheets/loading.css +145 -0
  38. data/app/assets/stylesheets/neon_sakura.css +40 -0
  39. data/app/assets/stylesheets/pagy-tailwind.css +120 -0
  40. data/app/assets/stylesheets/theme-default.css +40 -0
  41. data/app/assets/stylesheets/theme-green.css +84 -0
  42. data/app/assets/stylesheets/theme-purple.css +94 -0
  43. data/app/assets/stylesheets/theme-red.css +84 -0
  44. data/app/assets/stylesheets/utility-borders.css +29 -0
  45. data/app/assets/stylesheets/utility-colors.css +185 -0
  46. data/app/assets/stylesheets/utility-effects.css +123 -0
  47. data/app/assets/stylesheets/utility-gradients.css +158 -0
  48. data/app/assets/stylesheets/utility-layout.css +132 -0
  49. data/app/assets/stylesheets/utility-reset.css +13 -0
  50. data/app/assets/stylesheets/utility-responsive.css +145 -0
  51. data/app/assets/stylesheets/utility-sizing.css +99 -0
  52. data/app/assets/stylesheets/utility-spacing.css +174 -0
  53. data/app/assets/stylesheets/utility-typography.css +97 -0
  54. data/app/controllers/errors_controller.rb +120 -0
  55. data/app/controllers/style_guide_controller.rb +117 -0
  56. data/app/helpers/errors_helper.rb +12 -0
  57. data/app/helpers/neon_sakura/navbar_helper.rb +43 -0
  58. data/app/helpers/style_guide_helper.rb +36 -0
  59. data/app/javascript/neon_sakura/dropdown.js +22 -0
  60. data/app/javascript/neon_sakura/navbar.js +71 -0
  61. data/app/javascript/neon_sakura/theme_switcher.js +187 -0
  62. data/app/views/errors/show.html.erb +105 -0
  63. data/app/views/layouts/error.html.erb +19 -0
  64. data/app/views/layouts/mission_control/jobs/_application_selection.html.erb +14 -0
  65. data/app/views/layouts/mission_control/jobs/_navigation.html.erb +21 -0
  66. data/app/views/layouts/mission_control/jobs/application.html.erb +453 -0
  67. data/app/views/layouts/style_guide.html.erb +416 -0
  68. data/app/views/shared/_file_upload.html.erb +184 -0
  69. data/app/views/shared/_footer.html.erb +23 -0
  70. data/app/views/shared/_header.html.erb +42 -0
  71. data/app/views/shared/_navbar.html.erb +306 -0
  72. data/app/views/shared/_profile_image_selector.html.erb +165 -0
  73. data/app/views/shared/_theme_switcher.html.erb +64 -0
  74. data/app/views/shared/icons/_adjustments.html.erb +10 -0
  75. data/app/views/shared/icons/_alert_circle.html.erb +3 -0
  76. data/app/views/shared/icons/_alert_triangle.html.erb +3 -0
  77. data/app/views/shared/icons/_archive.html.erb +3 -0
  78. data/app/views/shared/icons/_arrow_down.html.erb +3 -0
  79. data/app/views/shared/icons/_arrow_left.html.erb +3 -0
  80. data/app/views/shared/icons/_arrow_up.html.erb +3 -0
  81. data/app/views/shared/icons/_arrows_pointing_in.html.erb +10 -0
  82. data/app/views/shared/icons/_arrows_pointing_out.html.erb +10 -0
  83. data/app/views/shared/icons/_artemis_logo.html.erb +26 -0
  84. data/app/views/shared/icons/_auth_banner.html.erb +1 -0
  85. data/app/views/shared/icons/_bars.html.erb +10 -0
  86. data/app/views/shared/icons/_bell.html.erb +3 -0
  87. data/app/views/shared/icons/_book.html.erb +3 -0
  88. data/app/views/shared/icons/_bookmark.html.erb +3 -0
  89. data/app/views/shared/icons/_box.html.erb +3 -0
  90. data/app/views/shared/icons/_brain.html.erb +3 -0
  91. data/app/views/shared/icons/_briefcase.html.erb +3 -0
  92. data/app/views/shared/icons/_calendar.html.erb +3 -0
  93. data/app/views/shared/icons/_camera.html.erb +4 -0
  94. data/app/views/shared/icons/_chart_bar.html.erb +3 -0
  95. data/app/views/shared/icons/_chart_line.html.erb +10 -0
  96. data/app/views/shared/icons/_chart_pie.html.erb +11 -0
  97. data/app/views/shared/icons/_chat.html.erb +3 -0
  98. data/app/views/shared/icons/_check.html.erb +3 -0
  99. data/app/views/shared/icons/_check_circle.html.erb +3 -0
  100. data/app/views/shared/icons/_cherry_blossom.html.erb +1516 -0
  101. data/app/views/shared/icons/_cherry_blossom_silhouette.html.erb +1016 -0
  102. data/app/views/shared/icons/_cherry_blossom_single_flower.html.erb +1125 -0
  103. data/app/views/shared/icons/_cherry_blossom_tree.html.erb +159 -0
  104. data/app/views/shared/icons/_chevron_down.html.erb +3 -0
  105. data/app/views/shared/icons/_chevron_right.html.erb +9 -0
  106. data/app/views/shared/icons/_clipboard.html.erb +3 -0
  107. data/app/views/shared/icons/_clock.html.erb +3 -0
  108. data/app/views/shared/icons/_close.html.erb +3 -0
  109. data/app/views/shared/icons/_cog.html.erb +4 -0
  110. data/app/views/shared/icons/_crop.html.erb +10 -0
  111. data/app/views/shared/icons/_crown.html.erb +3 -0
  112. data/app/views/shared/icons/_disc.html.erb +3 -0
  113. data/app/views/shared/icons/_download.html.erb +3 -0
  114. data/app/views/shared/icons/_dragonfly.html.erb +58 -0
  115. data/app/views/shared/icons/_duplicate.html.erb +4 -0
  116. data/app/views/shared/icons/_edit.html.erb +3 -0
  117. data/app/views/shared/icons/_envelope.html.erb +3 -0
  118. data/app/views/shared/icons/_eraser.html.erb +10 -0
  119. data/app/views/shared/icons/_external_link.html.erb +3 -0
  120. data/app/views/shared/icons/_eye.html.erb +4 -0
  121. data/app/views/shared/icons/_file_csv.html.erb +10 -0
  122. data/app/views/shared/icons/_file_export.html.erb +10 -0
  123. data/app/views/shared/icons/_file_image.html.erb +10 -0
  124. data/app/views/shared/icons/_file_import.html.erb +10 -0
  125. data/app/views/shared/icons/_file_question.html.erb +6 -0
  126. data/app/views/shared/icons/_film.html.erb +3 -0
  127. data/app/views/shared/icons/_filter.html.erb +3 -0
  128. data/app/views/shared/icons/_folder.html.erb +3 -0
  129. data/app/views/shared/icons/_folder_open.html.erb +3 -0
  130. data/app/views/shared/icons/_folder_plus.html.erb +3 -0
  131. data/app/views/shared/icons/_globe.html.erb +3 -0
  132. data/app/views/shared/icons/_google.html.erb +11 -0
  133. data/app/views/shared/icons/_heart.html.erb +3 -0
  134. data/app/views/shared/icons/_heart_broken.html.erb +11 -0
  135. data/app/views/shared/icons/_heart_pulse.html.erb +4 -0
  136. data/app/views/shared/icons/_history.html.erb +11 -0
  137. data/app/views/shared/icons/_home.html.erb +10 -0
  138. data/app/views/shared/icons/_image.html.erb +3 -0
  139. data/app/views/shared/icons/_inbox.html.erb +3 -0
  140. data/app/views/shared/icons/_info_circle.html.erb +10 -0
  141. data/app/views/shared/icons/_key.html.erb +3 -0
  142. data/app/views/shared/icons/_layers.html.erb +10 -0
  143. data/app/views/shared/icons/_lightbulb.html.erb +10 -0
  144. data/app/views/shared/icons/_lightning.html.erb +3 -0
  145. data/app/views/shared/icons/_list.html.erb +3 -0
  146. data/app/views/shared/icons/_lock.html.erb +3 -0
  147. data/app/views/shared/icons/_logout.html.erb +3 -0
  148. data/app/views/shared/icons/_magazine.html.erb +3 -0
  149. data/app/views/shared/icons/_magic.html.erb +3 -0
  150. data/app/views/shared/icons/_minus.html.erb +10 -0
  151. data/app/views/shared/icons/_mobile.html.erb +10 -0
  152. data/app/views/shared/icons/_moon.html.erb +3 -0
  153. data/app/views/shared/icons/_network.html.erb +10 -0
  154. data/app/views/shared/icons/_new_item_banner.html.erb +1 -0
  155. data/app/views/shared/icons/_ouroboros.html.erb +24 -0
  156. data/app/views/shared/icons/_package.html.erb +3 -0
  157. data/app/views/shared/icons/_palette.html.erb +3 -0
  158. data/app/views/shared/icons/_paper_plane.html.erb +10 -0
  159. data/app/views/shared/icons/_photo.html.erb +10 -0
  160. data/app/views/shared/icons/_play.html.erb +4 -0
  161. data/app/views/shared/icons/_plus.html.erb +3 -0
  162. data/app/views/shared/icons/_pocket.html.erb +11 -0
  163. data/app/views/shared/icons/_prysm-icon.html.erb +34 -0
  164. data/app/views/shared/icons/_prysm.html.erb +13 -0
  165. data/app/views/shared/icons/_pushbullet-1.html.erb +29 -0
  166. data/app/views/shared/icons/_pushbullet-2.html.erb +2 -0
  167. data/app/views/shared/icons/_puzzle.html.erb +10 -0
  168. data/app/views/shared/icons/_qrcode.html.erb +3 -0
  169. data/app/views/shared/icons/_question.html.erb +3 -0
  170. data/app/views/shared/icons/_receipt.html.erb +10 -0
  171. data/app/views/shared/icons/_redo.html.erb +3 -0
  172. data/app/views/shared/icons/_refresh.html.erb +3 -0
  173. data/app/views/shared/icons/_rocket.html.erb +10 -0
  174. data/app/views/shared/icons/_rss.html.erb +3 -0
  175. data/app/views/shared/icons/_save.html.erb +3 -0
  176. data/app/views/shared/icons/_search.html.erb +3 -0
  177. data/app/views/shared/icons/_search_minus.html.erb +10 -0
  178. data/app/views/shared/icons/_search_plus.html.erb +10 -0
  179. data/app/views/shared/icons/_server_error.html.erb +6 -0
  180. data/app/views/shared/icons/_share.html.erb +3 -0
  181. data/app/views/shared/icons/_shield_check.html.erb +3 -0
  182. data/app/views/shared/icons/_sign_in.html.erb +3 -0
  183. data/app/views/shared/icons/_spinner.html.erb +4 -0
  184. data/app/views/shared/icons/_star.html.erb +3 -0
  185. data/app/views/shared/icons/_store.html.erb +10 -0
  186. data/app/views/shared/icons/_sun.html.erb +3 -0
  187. data/app/views/shared/icons/_sync.html.erb +3 -0
  188. data/app/views/shared/icons/_table.html.erb +3 -0
  189. data/app/views/shared/icons/_tag.html.erb +3 -0
  190. data/app/views/shared/icons/_tags.html.erb +11 -0
  191. data/app/views/shared/icons/_tools.html.erb +4 -0
  192. data/app/views/shared/icons/_trash.html.erb +3 -0
  193. data/app/views/shared/icons/_undo.html.erb +3 -0
  194. data/app/views/shared/icons/_unlock.html.erb +3 -0
  195. data/app/views/shared/icons/_upload.html.erb +3 -0
  196. data/app/views/shared/icons/_user.html.erb +3 -0
  197. data/app/views/shared/icons/_user_circle.html.erb +10 -0
  198. data/app/views/shared/icons/_user_plus.html.erb +10 -0
  199. data/app/views/shared/icons/_video.html.erb +3 -0
  200. data/app/views/shared/icons/_wrench.html.erb +11 -0
  201. data/app/views/style_guide/index.html.erb +77 -0
  202. data/app/views/style_guide/sections/_alerts.html.erb +114 -0
  203. data/app/views/style_guide/sections/_badges.html.erb +78 -0
  204. data/app/views/style_guide/sections/_buttons.html.erb +130 -0
  205. data/app/views/style_guide/sections/_cards.html.erb +84 -0
  206. data/app/views/style_guide/sections/_colors.html.erb +106 -0
  207. data/app/views/style_guide/sections/_file_upload.html.erb +135 -0
  208. data/app/views/style_guide/sections/_forms.html.erb +129 -0
  209. data/app/views/style_guide/sections/_gradients.html.erb +253 -0
  210. data/app/views/style_guide/sections/_header.html.erb +12 -0
  211. data/app/views/style_guide/sections/_icons.html.erb +55 -0
  212. data/app/views/style_guide/sections/_images.html.erb +40 -0
  213. data/app/views/style_guide/sections/_loading.html.erb +242 -0
  214. data/app/views/style_guide/sections/_pagination.html.erb +212 -0
  215. data/app/views/style_guide/sections/_profile_components.html.erb +203 -0
  216. data/app/views/style_guide/sections/_theme_switcher.html.erb +72 -0
  217. data/app/views/style_guide/sections/_typography.html.erb +65 -0
  218. data/bin/ai-optimize-claude-md +540 -0
  219. data/bin/ai-review-local +345 -0
  220. data/bin/ai-security-review +585 -0
  221. data/bin/brakeman +9 -0
  222. data/bin/install-hooks +57 -0
  223. data/bin/rake +7 -0
  224. data/bin/rubocop +10 -0
  225. data/bin/verify_setup.rb +31 -0
  226. data/config/brakeman.ignore +28 -0
  227. data/config/initializers/neon_sakura.rb +15 -0
  228. data/config/license_overrides.yml +13 -0
  229. data/config/routes.rb +21 -0
  230. data/config/theme_mappings.yml +61 -0
  231. data/docs/PRYSM_ASSETS.md +210 -0
  232. data/docs/plans/extract_ai_reviewer_plan.md +151 -0
  233. data/docs/plans/neon_sakura_gem_plan.md +138 -0
  234. data/lib/neon_sakura/configuration.rb +94 -0
  235. data/lib/neon_sakura/engine.rb +48 -0
  236. data/lib/neon_sakura/icon_helper.rb +54 -0
  237. data/lib/neon_sakura/profile_helper.rb +24 -0
  238. data/lib/neon_sakura/stylesheet_helper.rb +40 -0
  239. data/lib/neon_sakura/theme_helper.rb +63 -0
  240. data/lib/neon_sakura/theme_importer.rb +112 -0
  241. data/lib/neon_sakura/version.rb +5 -0
  242. data/lib/neon_sakura.rb +13 -0
  243. data/neon_sakura.gemspec +50 -0
  244. data/package.json +18 -0
  245. data/scripts/git-hooks/post-merge +132 -0
  246. data/scripts/git-hooks/pre-commit +123 -0
  247. data/scripts/git-hooks/pre-push +127 -0
  248. data/scripts/license-check.rb +587 -0
  249. data/settings.local.json +12 -0
  250. data/yarn.lock +778 -0
  251. metadata +503 -0
@@ -0,0 +1,585 @@
1
+ #!/usr/bin/env bash
2
+ # AI-powered security analysis for Rails applications
3
+ # Analyzes routes, security scans, controller architecture, and API security
4
+ #
5
+ # Usage:
6
+ # bin/ai-security-review [OPTIONS] [BASE_BRANCH] [OLLAMA_URL]
7
+ # bin/ai-security-review --help | -h
8
+ #
9
+ # Options:
10
+ # -m, --model MODEL Specify the model to use (default: codestral:latest)
11
+ # -i, --interactive Interactively select model from available models
12
+ # -f, --full-review Review current state (no comparison)
13
+ # --help, -h Show this help message
14
+ #
15
+ # Arguments:
16
+ # BASE_BRANCH - Branch to compare against (default: main or master, ignored with -f)
17
+ # OLLAMA_URL - Ollama server URL (default: $OLLAMA_URL env var or http://localhost:11434)
18
+ #
19
+ # Examples:
20
+ # bin/ai-security-review # Compare security changes vs main
21
+ # bin/ai-security-review -f # Full security review (current state)
22
+ # bin/ai-security-review develop # Compare vs develop branch
23
+ # bin/ai-security-review -i # Interactively select model
24
+ # bin/ai-security-review -m llama3:latest # Use specific model
25
+ # bin/ai-security-review main http://server # Use remote Ollama server
26
+
27
+ # Load shared library
28
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
+ if [ -f "$SCRIPT_DIR/../lib/ai-script-base.sh" ]; then
30
+ # shellcheck source=../lib/ai-script-base.sh
31
+ source "$SCRIPT_DIR/../lib/ai-script-base.sh"
32
+ else
33
+ echo "Error: Shared library not found at $SCRIPT_DIR/../lib/ai-script-base.sh"
34
+ exit 1
35
+ fi
36
+
37
+ # Show help
38
+ show_help() {
39
+ cat << EOF
40
+ AI Security Review - Comprehensive security analysis using Ollama
41
+
42
+ USAGE:
43
+ bin/ai-security-review [OPTIONS] [BASE_BRANCH] [OLLAMA_URL]
44
+ bin/ai-security-review --help | -h
45
+
46
+ OPTIONS:
47
+ -m, --model MODEL Specify the model to use (default: codestral:latest)
48
+ -i, --interactive Interactively select model from available models
49
+ -f, --full-review Review current state (no branch comparison)
50
+ --help, -h Show this help message
51
+
52
+ ARGUMENTS:
53
+ BASE_BRANCH Branch to compare against (default: auto-detect main/master)
54
+ Ignored when using -f/--full-review
55
+ OLLAMA_URL Ollama server URL (default: \$OLLAMA_URL env var or http://localhost:11434)
56
+
57
+ EXAMPLES:
58
+ # Compare security changes vs main
59
+ bin/ai-security-review
60
+
61
+ # Full security review of current state
62
+ bin/ai-security-review -f
63
+
64
+ # Compare vs develop branch
65
+ bin/ai-security-review develop
66
+
67
+ # Interactively select model
68
+ bin/ai-security-review -i
69
+
70
+ # Use specific model
71
+ bin/ai-security-review -m llama3:latest
72
+
73
+ # Use remote Ollama server
74
+ bin/ai-security-review main http://server:11434
75
+
76
+ # Combine options
77
+ bin/ai-security-review -f -m llama3:latest
78
+
79
+ WHAT IT ANALYZES:
80
+ - Routes and API endpoints (config/routes.rb)
81
+ - Brakeman security scanner results
82
+ - Bundle Audit gem vulnerabilities
83
+ - Controller architecture and authentication patterns
84
+ - User management implementation
85
+ - API security (JWT, authentication, authorization)
86
+ - Secret detection (optional, requires trufflehog)
87
+
88
+ REQUIREMENTS:
89
+ - Ollama installed and running (https://ollama.ai)
90
+ - At least one model pulled (e.g., ollama pull codestral:latest)
91
+ - Rails application with standard structure
92
+
93
+ ENVIRONMENT VARIABLES:
94
+ OLLAMA_URL Ollama server URL (overridden by command line argument)
95
+ Example: export OLLAMA_URL=http://192.168.1.100:11434
96
+
97
+ OUTPUT:
98
+ Reviews are saved to: docs/ai-reviews/ai-security-review-YYYYMMDD-HHMMSS.md
99
+
100
+ MORE INFO:
101
+ See docs/AI_PR_REVIEWER.md for full documentation
102
+ EOF
103
+ exit 0
104
+ }
105
+
106
+ # Parse options
107
+ INTERACTIVE_MODE=false
108
+ FULL_REVIEW=false
109
+ MODEL_NAME="codestral:latest"
110
+ BASE_BRANCH=""
111
+ OLLAMA_URL=""
112
+
113
+ while [[ $# -gt 0 ]]; do
114
+ case $1 in
115
+ --help|-h)
116
+ show_help
117
+ ;;
118
+ -i|--interactive)
119
+ INTERACTIVE_MODE=true
120
+ shift
121
+ ;;
122
+ -f|--full-review)
123
+ FULL_REVIEW=true
124
+ shift
125
+ ;;
126
+ -m|--model)
127
+ if [ -z "${2:-}" ]; then
128
+ log_error "Option -m/--model requires a model name"
129
+ exit 1
130
+ fi
131
+ MODEL_NAME="$2"
132
+ shift 2
133
+ ;;
134
+ *)
135
+ # Positional arguments
136
+ if [ -z "$BASE_BRANCH" ]; then
137
+ BASE_BRANCH="$1"
138
+ elif [ -z "$OLLAMA_URL" ]; then
139
+ OLLAMA_URL="$1"
140
+ else
141
+ log_error "Unknown argument: $1"
142
+ echo "Run 'bin/ai-security-review --help' for usage information"
143
+ exit 1
144
+ fi
145
+ shift
146
+ ;;
147
+ esac
148
+ done
149
+
150
+ # Set defaults
151
+ OLLAMA_URL=$(get_ollama_url "$OLLAMA_URL")
152
+ if [ "$FULL_REVIEW" = false ]; then
153
+ BASE_BRANCH=$(determine_base_branch "$BASE_BRANCH")
154
+ fi
155
+
156
+ # Create temp directory
157
+ TEMP_DIR=$(create_temp_dir)
158
+
159
+ log_info "Starting AI security review..."
160
+ if [ "$FULL_REVIEW" = true ]; then
161
+ log_info "Mode: ${CYAN}Full review (current state)${NC}"
162
+ else
163
+ log_info "Mode: ${CYAN}Branch comparison${NC}"
164
+ log_info "Base branch: ${CYAN}$BASE_BRANCH${NC}"
165
+ fi
166
+ log_info "Ollama server: ${CYAN}$OLLAMA_URL${NC}"
167
+ echo ""
168
+
169
+ # Check if Ollama is accessible
170
+ check_ollama_server "$OLLAMA_URL" || exit 1
171
+ echo ""
172
+
173
+ # Interactive model selection if requested
174
+ if [ "$INTERACTIVE_MODE" = true ]; then
175
+ MODEL_NAME=$(select_ollama_model "$OLLAMA_URL" "$MODEL_NAME")
176
+ echo ""
177
+ log_info "Selected model: ${CYAN}$MODEL_NAME${NC}"
178
+ echo ""
179
+ fi
180
+
181
+ # Ensure model is available
182
+ ensure_ollama_model "$OLLAMA_URL" "$MODEL_NAME" || exit 1
183
+ echo ""
184
+
185
+ # ============================================================================
186
+ # Gather Security Information
187
+ # ============================================================================
188
+
189
+ log_section "📊 Gathering Security Information"
190
+
191
+ # Get current branch and changes if in comparison mode
192
+ if [ "$FULL_REVIEW" = false ]; then
193
+ CURRENT_BRANCH=$(get_current_branch)
194
+ log_info "Current branch: ${CYAN}$CURRENT_BRANCH${NC}"
195
+
196
+ # Get changed files
197
+ log_info "Getting changed files..."
198
+ CHANGED_FILES=$(get_changed_files "$BASE_BRANCH")
199
+ CHANGED_FILES_COUNT=$(echo "$CHANGED_FILES" | wc -l | tr -d ' ')
200
+ log_success "Found $CHANGED_FILES_COUNT changed files"
201
+ echo ""
202
+
203
+ # Get diff for security-relevant files
204
+ log_info "Extracting security-relevant changes..."
205
+ SECURITY_DIFF=$(git diff "$BASE_BRANCH...HEAD" -- \
206
+ 'config/routes.rb' \
207
+ 'app/controllers/**/*.rb' \
208
+ 'app/models/user.rb' \
209
+ 'app/models/account.rb' \
210
+ 'config/application.rb' \
211
+ 'Gemfile' \
212
+ 'Gemfile.lock' 2>/dev/null || echo "")
213
+
214
+ if [ -n "$SECURITY_DIFF" ]; then
215
+ SECURITY_DIFF=$(echo "$SECURITY_DIFF" | head -c 5000)
216
+ log_success "Security changes extracted"
217
+ else
218
+ log_info "No security-relevant file changes detected"
219
+ fi
220
+ echo ""
221
+ fi
222
+
223
+ # 1. Routes
224
+ log_info "Extracting routes..."
225
+ if [ -f "config/routes.rb" ]; then
226
+ ROUTES=$(cat config/routes.rb)
227
+ log_success "Routes extracted (${#ROUTES} chars)"
228
+ else
229
+ ROUTES="Routes file not found"
230
+ log_warning "Routes file not found at config/routes.rb"
231
+ fi
232
+
233
+ # 2. Run Brakeman
234
+ log_info "Running Brakeman security scanner..."
235
+ if command -v brakeman &> /dev/null; then
236
+ BRAKEMAN_OUTPUT=$(brakeman -q -f text --no-pager 2>&1 || true)
237
+ if [ -z "$BRAKEMAN_OUTPUT" ]; then
238
+ BRAKEMAN_OUTPUT="No security warnings found"
239
+ fi
240
+ log_success "Brakeman scan complete"
241
+ else
242
+ BRAKEMAN_OUTPUT="Brakeman not installed. Install with: gem install brakeman"
243
+ log_warning "Brakeman not found"
244
+ fi
245
+
246
+ # 3. Bundle Audit
247
+ log_info "Running Bundle Audit..."
248
+ if command -v bundle-audit &> /dev/null; then
249
+ bundle-audit update > /dev/null 2>&1 || true
250
+ BUNDLE_AUDIT_OUTPUT=$(bundle-audit check 2>&1 || true)
251
+ if echo "$BUNDLE_AUDIT_OUTPUT" | grep -q "No vulnerabilities found"; then
252
+ BUNDLE_AUDIT_OUTPUT="No gem vulnerabilities found"
253
+ fi
254
+ log_success "Bundle Audit complete"
255
+ else
256
+ BUNDLE_AUDIT_OUTPUT="Bundle Audit not installed. Install with: gem install bundler-audit"
257
+ log_warning "Bundle Audit not found"
258
+ fi
259
+
260
+ # 4. Trufflehog (optional - secret detection)
261
+ log_info "Checking for secrets with Trufflehog..."
262
+ if command -v trufflehog &> /dev/null; then
263
+ TRUFFLEHOG_OUTPUT=$(trufflehog filesystem . --json --no-update 2>&1 | head -20 || true)
264
+ if [ -z "$TRUFFLEHOG_OUTPUT" ]; then
265
+ TRUFFLEHOG_OUTPUT="No secrets detected"
266
+ else
267
+ TRUFFLEHOG_OUTPUT="Potential secrets found (first 20 lines):
268
+ $TRUFFLEHOG_OUTPUT"
269
+ fi
270
+ log_success "Trufflehog scan complete"
271
+ else
272
+ TRUFFLEHOG_OUTPUT="Trufflehog not installed (optional). See: https://github.com/trufflesecurity/trufflehog"
273
+ log_info "Trufflehog not found (optional)"
274
+ fi
275
+
276
+ # 5. Controller Architecture
277
+ log_info "Analyzing controller architecture..."
278
+ CONTROLLERS_LIST=""
279
+ if [ -d "app/controllers" ]; then
280
+ CONTROLLERS_LIST=$(find app/controllers -name "*.rb" -type f | head -20)
281
+ CONTROLLER_COUNT=$(echo "$CONTROLLERS_LIST" | wc -l | tr -d ' ')
282
+ log_success "Found $CONTROLLER_COUNT controllers"
283
+ else
284
+ log_warning "Controllers directory not found"
285
+ fi
286
+
287
+ # 6. Authentication Implementation (ApplicationController)
288
+ log_info "Extracting authentication patterns..."
289
+ AUTH_PATTERNS=""
290
+ if [ -f "app/controllers/application_controller.rb" ]; then
291
+ AUTH_PATTERNS=$(cat app/controllers/application_controller.rb)
292
+ log_success "ApplicationController extracted"
293
+ else
294
+ AUTH_PATTERNS="ApplicationController not found"
295
+ log_warning "ApplicationController not found"
296
+ fi
297
+
298
+ # 7. API Security (JWT, API controllers)
299
+ log_info "Analyzing API security..."
300
+ API_SECURITY=""
301
+ if [ -d "app/controllers/api" ]; then
302
+ API_CONTROLLERS=$(find app/controllers/api -name "*.rb" -type f | head -10)
303
+ API_SECURITY="API Controllers found:
304
+ $API_CONTROLLERS
305
+
306
+ "
307
+ for controller in $API_CONTROLLERS; do
308
+ if [ -f "$controller" ]; then
309
+ API_SECURITY+="
310
+ === $(basename "$controller") ===
311
+ $(head -50 "$controller")
312
+ "
313
+ fi
314
+ done
315
+ log_success "API controllers analyzed"
316
+ else
317
+ API_SECURITY="No API controllers found"
318
+ log_info "No API directory found"
319
+ fi
320
+
321
+ # 8. User Model (if exists)
322
+ log_info "Checking user management..."
323
+ USER_MODEL=""
324
+ if [ -f "app/models/user.rb" ]; then
325
+ USER_MODEL=$(cat app/models/user.rb | head -100)
326
+ log_success "User model extracted"
327
+ elif [ -f "app/models/account.rb" ]; then
328
+ USER_MODEL=$(cat app/models/account.rb | head -100)
329
+ log_success "Account model extracted"
330
+ else
331
+ USER_MODEL="No user/account model found"
332
+ log_info "No user model found"
333
+ fi
334
+
335
+ # 9. Security Headers (config/application.rb)
336
+ log_info "Checking security headers..."
337
+ SECURITY_CONFIG=""
338
+ if [ -f "config/application.rb" ]; then
339
+ SECURITY_CONFIG=$(grep -A 5 -B 5 "security\|headers\|force_ssl\|cookies" config/application.rb || echo "No explicit security config found")
340
+ log_success "Security config extracted"
341
+ else
342
+ SECURITY_CONFIG="Application config not found"
343
+ log_warning "Application config not found"
344
+ fi
345
+
346
+ echo ""
347
+
348
+ # ============================================================================
349
+ # Build Security-Focused System Prompt
350
+ # ============================================================================
351
+
352
+ log_info "Building security-focused system prompt..."
353
+
354
+ SYSTEM_PROMPT=$(cat <<'SYSEND'
355
+ You are an expert security analyst specializing in Ruby on Rails applications.
356
+
357
+ **Your Task:**
358
+ Perform a comprehensive security analysis of the Rails application based on the provided information.
359
+
360
+ **Analysis Areas:**
361
+
362
+ 1. **Authentication & Authorization:**
363
+ - Review authentication implementation (sessions, tokens, JWT)
364
+ - Check authorization patterns (before_action, pundit, cancancan, etc.)
365
+ - Verify password handling and secure storage
366
+ - Check for insecure direct object references (IDOR)
367
+ - Review session management and cookie security
368
+
369
+ 2. **API Security:**
370
+ - JWT implementation and token validation
371
+ - API authentication mechanisms
372
+ - Rate limiting and throttling
373
+ - CORS configuration
374
+ - API versioning and deprecation
375
+
376
+ 3. **Input Validation & Sanitization:**
377
+ - SQL injection vulnerabilities
378
+ - Cross-Site Scripting (XSS) risks
379
+ - Mass assignment vulnerabilities
380
+ - File upload security
381
+ - Path traversal attacks
382
+
383
+ 4. **Routes & Endpoints:**
384
+ - Publicly accessible endpoints without authentication
385
+ - Admin routes and their protection
386
+ - API endpoints and versioning
387
+ - Unnecessary or dangerous routes
388
+ - HTTP method restrictions
389
+
390
+ 5. **Dependency Security:**
391
+ - Vulnerable gems (from Bundle Audit)
392
+ - Outdated dependencies
393
+ - Security patches needed
394
+
395
+ 6. **Secret Management:**
396
+ - Exposed secrets or credentials
397
+ - Hardcoded passwords or API keys
398
+ - Environment variable usage
399
+ - Secret rotation practices
400
+
401
+ 7. **Security Headers & HTTPS:**
402
+ - Content Security Policy (CSP)
403
+ - X-Frame-Options
404
+ - X-Content-Type-Options
405
+ - Strict-Transport-Security (HSTS)
406
+ - force_ssl configuration
407
+
408
+ 8. **OWASP Top 10 Coverage:**
409
+ - Broken Access Control
410
+ - Cryptographic Failures
411
+ - Injection
412
+ - Insecure Design
413
+ - Security Misconfiguration
414
+ - Vulnerable Components
415
+ - Authentication Failures
416
+ - Software and Data Integrity Failures
417
+ - Security Logging and Monitoring Failures
418
+ - Server-Side Request Forgery (SSRF)
419
+
420
+ **Output Format:**
421
+
422
+ ## Executive Summary
423
+ [2-3 sentences on overall security posture]
424
+
425
+ ## Critical Security Issues
426
+ [ONLY list critical vulnerabilities that need immediate attention]
427
+ [Use format: `Category - Description - Location`]
428
+ [If none, write "No critical issues found"]
429
+
430
+ ## High Priority Issues
431
+ [List important security concerns - MAX 10]
432
+ [Use format: `Category - Description - Location`]
433
+ [If none, write "Security posture is good"]
434
+
435
+ ## Medium Priority Issues
436
+ [List moderate security improvements - MAX 10]
437
+ [Use format: `Category - Description`]
438
+ [If none, write "No medium priority issues"]
439
+
440
+ ## Security Best Practices Observed
441
+ [List 3-5 things the application does well]
442
+
443
+ ## Recommendations
444
+ [Top 5 actionable recommendations, prioritized]
445
+
446
+ ## Compliance Notes
447
+ [Notes on OWASP Top 10 coverage, if relevant]
448
+
449
+ **Review Guidelines:**
450
+ - Be SPECIFIC with file paths and line numbers when possible
451
+ - Focus on EXPLOITABLE vulnerabilities, not theoretical risks
452
+ - Provide ACTIONABLE recommendations
453
+ - Distinguish between critical, high, and medium priority
454
+ - Consider Rails version and modern security practices
455
+ - Do not report false positives from scanners without verification
456
+ SYSEND
457
+ )
458
+
459
+ log_success "System prompt built"
460
+ echo ""
461
+
462
+ # ============================================================================
463
+ # Build User Prompt with Gathered Information
464
+ # ============================================================================
465
+
466
+ log_info "Building analysis prompt..."
467
+
468
+ if [ "$FULL_REVIEW" = true ]; then
469
+ MODE_INFO="**Analysis Mode:** Full security review of current state"
470
+ else
471
+ MODE_INFO="**Analysis Mode:** Security changes comparison
472
+ **Branch:** $CURRENT_BRANCH vs $BASE_BRANCH
473
+ **Changed Files:** $CHANGED_FILES_COUNT
474
+
475
+ ## Security-Relevant Changes
476
+ \`\`\`diff
477
+ ${SECURITY_DIFF:-No security-relevant file changes}
478
+ \`\`\`
479
+
480
+ ## Changed Files
481
+ \`\`\`
482
+ $CHANGED_FILES
483
+ \`\`\`
484
+ "
485
+ fi
486
+
487
+ USER_PROMPT=$(cat <<USEREND
488
+ # Security Analysis Request
489
+
490
+ $MODE_INFO
491
+
492
+ ## Routes (config/routes.rb)
493
+ \`\`\`ruby
494
+ ${ROUTES:0:3000}
495
+ \`\`\`
496
+
497
+ ## Brakeman Security Scan
498
+ \`\`\`
499
+ ${BRAKEMAN_OUTPUT:0:2000}
500
+ \`\`\`
501
+
502
+ ## Bundle Audit (Gem Vulnerabilities)
503
+ \`\`\`
504
+ ${BUNDLE_AUDIT_OUTPUT:0:1500}
505
+ \`\`\`
506
+
507
+ ## Secret Detection (Trufflehog)
508
+ \`\`\`
509
+ ${TRUFFLEHOG_OUTPUT:0:1500}
510
+ \`\`\`
511
+
512
+ ## Controller Architecture
513
+ Controllers found:
514
+ \`\`\`
515
+ ${CONTROLLERS_LIST}
516
+ \`\`\`
517
+
518
+ ## Authentication Implementation (ApplicationController)
519
+ \`\`\`ruby
520
+ ${AUTH_PATTERNS:0:2000}
521
+ \`\`\`
522
+
523
+ ## API Security
524
+ \`\`\`ruby
525
+ ${API_SECURITY:0:3000}
526
+ \`\`\`
527
+
528
+ ## User Management
529
+ \`\`\`ruby
530
+ ${USER_MODEL:0:1500}
531
+ \`\`\`
532
+
533
+ ## Security Configuration
534
+ \`\`\`ruby
535
+ ${SECURITY_CONFIG:0:1000}
536
+ \`\`\`
537
+
538
+ Please perform a comprehensive security analysis based on the above information.
539
+ USEREND
540
+ )
541
+
542
+ log_success "Analysis prompt built"
543
+ echo ""
544
+
545
+ # ============================================================================
546
+ # Call Ollama API for Security Analysis
547
+ # ============================================================================
548
+
549
+ log_info "Calling Ollama API for security analysis..."
550
+ echo -e "${CYAN}This may take a few minutes...${NC}"
551
+ echo ""
552
+
553
+ REVIEW=$(call_ollama_chat "$OLLAMA_URL" "$MODEL_NAME" "$SYSTEM_PROMPT" "$USER_PROMPT")
554
+
555
+ # No deduplication needed for security reviews (different context)
556
+ # Just truncate if too long
557
+ REVIEW=$(truncate_review "$REVIEW" 150)
558
+
559
+ # Display the review
560
+ if [ "$FULL_REVIEW" = true ]; then
561
+ ADDITIONAL_INFO="${CYAN}Mode:${NC} Full review (current state)
562
+ ${CYAN}Analysis:${NC} Routes, Brakeman, Bundle Audit, Controllers, API, User Management
563
+ ${CYAN}Tools Used:${NC} Brakeman, Bundle Audit, Trufflehog (optional)"
564
+ else
565
+ ADDITIONAL_INFO="${CYAN}Mode:${NC} Branch comparison ($CURRENT_BRANCH vs $BASE_BRANCH)
566
+ ${CYAN}Changed files:${NC} $CHANGED_FILES_COUNT
567
+ ${CYAN}Analysis:${NC} Routes, Brakeman, Bundle Audit, Controllers, API, User Management, Changes
568
+ ${CYAN}Tools Used:${NC} Brakeman, Bundle Audit, Trufflehog (optional)"
569
+ fi
570
+
571
+ display_review "$REVIEW" "AI Security Review" "$MODEL_NAME" "$ADDITIONAL_INFO"
572
+
573
+ # Save review to file
574
+ REVIEW_FILE=$(save_review "$REVIEW" "docs/ai-reviews" "ai-security-review")
575
+ log_success "Security review saved to: ${CYAN}$REVIEW_FILE${NC}"
576
+ echo ""
577
+
578
+ # Check for critical issues
579
+ if echo "$REVIEW" | grep -qi "CRITICAL SECURITY\|CRITICAL.*ISSUE\|IMMEDIATE.*ATTENTION"; then
580
+ log_error "Critical security issues found! Review the report above."
581
+ exit 1
582
+ else
583
+ log_success "Security review complete!"
584
+ exit 0
585
+ fi
data/bin/brakeman ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+
7
+ ARGV.unshift('--ensure-latest')
8
+
9
+ load Gem.bin_path('brakeman', 'brakeman')
data/bin/install-hooks ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Install git hooks for Neon Sakura project
4
+ # This script creates symlinks from .git/hooks to scripts/git-hooks
5
+
6
+ set -e
7
+
8
+ # Colors for output
9
+ RED='\033[0;31m'
10
+ GREEN='\033[0;32m'
11
+ YELLOW='\033[1;33m'
12
+ NC='\033[0m' # No Color
13
+
14
+ echo "🔧 Installing git hooks for Neon Sakura..."
15
+
16
+ # Check if we're in a git repository
17
+ if [ ! -d ".git" ]; then
18
+ echo -e "${RED}❌ Not a git repository${NC}"
19
+ exit 1
20
+ fi
21
+
22
+ # Create hooks directory if it doesn't exist
23
+ mkdir -p .git/hooks
24
+
25
+ # Install each hook
26
+ hooks=("pre-commit" "pre-push" "post-merge")
27
+ installed_count=0
28
+
29
+ for hook in "${hooks[@]}"; do
30
+ source_hook="scripts/git-hooks/$hook"
31
+ target_hook=".git/hooks/$hook"
32
+
33
+ if [ ! -f "$source_hook" ]; then
34
+ echo -e "${YELLOW}⚠️ Source hook not found: $source_hook${NC}"
35
+ continue
36
+ fi
37
+
38
+ # Remove existing hook or symlink
39
+ if [ -e "$target_hook" ] || [ -L "$target_hook" ]; then
40
+ rm -f "$target_hook"
41
+ fi
42
+
43
+ # Create symlink
44
+ ln -s "../../$source_hook" "$target_hook"
45
+ echo -e "${GREEN}✅ Installed $hook hook${NC}"
46
+ installed_count=$((installed_count + 1))
47
+ done
48
+
49
+ echo ""
50
+ echo -e "${GREEN}🎉 Installed $installed_count git hook(s)${NC}"
51
+ echo ""
52
+ echo "Installed hooks:"
53
+ echo " - pre-commit: Runs Rubocop, Stylelint, Brakeman, Bundle Audit, and secrets detection"
54
+ echo " - pre-push: Checks database schema consistency and asset compilation"
55
+ echo " - post-merge: Auto-runs bundle install and migrations after merges"
56
+ echo ""
57
+ echo "To skip hooks when committing/pushing, use --no-verify flag"
data/bin/rake ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+
7
+ load Gem.bin_path('rake', 'rake')
data/bin/rubocop ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+
7
+ # Explicit RuboCop config increases performance slightly while avoiding config confusion.
8
+ ARGV.unshift('--config', File.expand_path('../.rubocop.yml', __dir__))
9
+
10
+ load Gem.bin_path('rubocop', 'rubocop')
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Simple script to check that our gem setup is working correctly
5
+ require 'bundler/setup'
6
+ require 'minitest/autorun'
7
+
8
+ puts 'Testing neon_sakura gem setup...'
9
+ puts "Version: #{NeonSakura::VERSION}"
10
+
11
+ # Test basic functionality
12
+ puts '✓ Version test passed'
13
+
14
+ # Check if files exist
15
+ required_files = [
16
+ 'lib/neon_sakura/version.rb',
17
+ 'lib/neon_sakura/engine.rb',
18
+ 'app/assets/stylesheets/application.css',
19
+ 'app/assets/stylesheets/base.css',
20
+ 'app/views/layouts/mission_control/jobs/application.html.erb'
21
+ ]
22
+
23
+ required_files.each do |file|
24
+ if File.exist?(file)
25
+ puts "✓ #{file} exists"
26
+ else
27
+ puts "✗ #{file} missing"
28
+ end
29
+ end
30
+
31
+ puts 'Gem setup verification complete!'