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.
- checksums.yaml +7 -0
- data/.ai-reviewer/README.md +182 -0
- data/.ai-reviewer/ai-reviewer.sh +56 -0
- data/.ai-reviewer/build-system-prompt.sh +136 -0
- data/.ai-reviewer/extract-claude-sections.sh +32 -0
- data/.ai-reviewer/test-ai-reviewer.sh +40 -0
- data/.ai-reviewer-config.yml +190 -0
- data/.github/dependabot.yml +12 -0
- data/.github/settings.yml +70 -0
- data/.github/workflows/ai-pr-review-on-comment.yml +384 -0
- data/.github/workflows/ai-pr-review.yml +328 -0
- data/.github/workflows/license-check.yml +78 -0
- data/.github/workflows/lint.yml +79 -0
- data/.github/workflows/security.yml +131 -0
- data/.github/workflows/semgrep.yml +26 -0
- data/.github/workflows/test.yml +44 -0
- data/.gitignore +75 -0
- data/.rubocop.yml +33 -0
- data/.ruby-version +1 -0
- data/.simplecov +14 -0
- data/.stylelintignore +10 -0
- data/.stylelintrc.json +37 -0
- data/AGENTS.md +51 -0
- data/CHANGELOG.md +568 -0
- data/CLAUDE.md +632 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +327 -0
- data/LICENSE +21 -0
- data/README.md +1209 -0
- data/Rakefile +25 -0
- data/app/assets/images/cherry_blossom.svg +1525 -0
- data/app/assets/images/cherry_blossom_tree.png +0 -0
- data/app/assets/images/prysm-icon.png +0 -0
- data/app/assets/stylesheets/base.css +29 -0
- data/app/assets/stylesheets/components.css +1652 -0
- data/app/assets/stylesheets/forms.css +152 -0
- data/app/assets/stylesheets/loading.css +145 -0
- data/app/assets/stylesheets/neon_sakura.css +40 -0
- data/app/assets/stylesheets/pagy-tailwind.css +120 -0
- data/app/assets/stylesheets/theme-default.css +40 -0
- data/app/assets/stylesheets/theme-green.css +84 -0
- data/app/assets/stylesheets/theme-purple.css +94 -0
- data/app/assets/stylesheets/theme-red.css +84 -0
- data/app/assets/stylesheets/utility-borders.css +29 -0
- data/app/assets/stylesheets/utility-colors.css +185 -0
- data/app/assets/stylesheets/utility-effects.css +123 -0
- data/app/assets/stylesheets/utility-gradients.css +158 -0
- data/app/assets/stylesheets/utility-layout.css +132 -0
- data/app/assets/stylesheets/utility-reset.css +13 -0
- data/app/assets/stylesheets/utility-responsive.css +145 -0
- data/app/assets/stylesheets/utility-sizing.css +99 -0
- data/app/assets/stylesheets/utility-spacing.css +174 -0
- data/app/assets/stylesheets/utility-typography.css +97 -0
- data/app/controllers/errors_controller.rb +120 -0
- data/app/controllers/style_guide_controller.rb +117 -0
- data/app/helpers/errors_helper.rb +12 -0
- data/app/helpers/neon_sakura/navbar_helper.rb +43 -0
- data/app/helpers/style_guide_helper.rb +36 -0
- data/app/javascript/neon_sakura/dropdown.js +22 -0
- data/app/javascript/neon_sakura/navbar.js +71 -0
- data/app/javascript/neon_sakura/theme_switcher.js +187 -0
- data/app/views/errors/show.html.erb +105 -0
- data/app/views/layouts/error.html.erb +19 -0
- data/app/views/layouts/mission_control/jobs/_application_selection.html.erb +14 -0
- data/app/views/layouts/mission_control/jobs/_navigation.html.erb +21 -0
- data/app/views/layouts/mission_control/jobs/application.html.erb +453 -0
- data/app/views/layouts/style_guide.html.erb +416 -0
- data/app/views/shared/_file_upload.html.erb +184 -0
- data/app/views/shared/_footer.html.erb +23 -0
- data/app/views/shared/_header.html.erb +42 -0
- data/app/views/shared/_navbar.html.erb +306 -0
- data/app/views/shared/_profile_image_selector.html.erb +165 -0
- data/app/views/shared/_theme_switcher.html.erb +64 -0
- data/app/views/shared/icons/_adjustments.html.erb +10 -0
- data/app/views/shared/icons/_alert_circle.html.erb +3 -0
- data/app/views/shared/icons/_alert_triangle.html.erb +3 -0
- data/app/views/shared/icons/_archive.html.erb +3 -0
- data/app/views/shared/icons/_arrow_down.html.erb +3 -0
- data/app/views/shared/icons/_arrow_left.html.erb +3 -0
- data/app/views/shared/icons/_arrow_up.html.erb +3 -0
- data/app/views/shared/icons/_arrows_pointing_in.html.erb +10 -0
- data/app/views/shared/icons/_arrows_pointing_out.html.erb +10 -0
- data/app/views/shared/icons/_artemis_logo.html.erb +26 -0
- data/app/views/shared/icons/_auth_banner.html.erb +1 -0
- data/app/views/shared/icons/_bars.html.erb +10 -0
- data/app/views/shared/icons/_bell.html.erb +3 -0
- data/app/views/shared/icons/_book.html.erb +3 -0
- data/app/views/shared/icons/_bookmark.html.erb +3 -0
- data/app/views/shared/icons/_box.html.erb +3 -0
- data/app/views/shared/icons/_brain.html.erb +3 -0
- data/app/views/shared/icons/_briefcase.html.erb +3 -0
- data/app/views/shared/icons/_calendar.html.erb +3 -0
- data/app/views/shared/icons/_camera.html.erb +4 -0
- data/app/views/shared/icons/_chart_bar.html.erb +3 -0
- data/app/views/shared/icons/_chart_line.html.erb +10 -0
- data/app/views/shared/icons/_chart_pie.html.erb +11 -0
- data/app/views/shared/icons/_chat.html.erb +3 -0
- data/app/views/shared/icons/_check.html.erb +3 -0
- data/app/views/shared/icons/_check_circle.html.erb +3 -0
- data/app/views/shared/icons/_cherry_blossom.html.erb +1516 -0
- data/app/views/shared/icons/_cherry_blossom_silhouette.html.erb +1016 -0
- data/app/views/shared/icons/_cherry_blossom_single_flower.html.erb +1125 -0
- data/app/views/shared/icons/_cherry_blossom_tree.html.erb +159 -0
- data/app/views/shared/icons/_chevron_down.html.erb +3 -0
- data/app/views/shared/icons/_chevron_right.html.erb +9 -0
- data/app/views/shared/icons/_clipboard.html.erb +3 -0
- data/app/views/shared/icons/_clock.html.erb +3 -0
- data/app/views/shared/icons/_close.html.erb +3 -0
- data/app/views/shared/icons/_cog.html.erb +4 -0
- data/app/views/shared/icons/_crop.html.erb +10 -0
- data/app/views/shared/icons/_crown.html.erb +3 -0
- data/app/views/shared/icons/_disc.html.erb +3 -0
- data/app/views/shared/icons/_download.html.erb +3 -0
- data/app/views/shared/icons/_dragonfly.html.erb +58 -0
- data/app/views/shared/icons/_duplicate.html.erb +4 -0
- data/app/views/shared/icons/_edit.html.erb +3 -0
- data/app/views/shared/icons/_envelope.html.erb +3 -0
- data/app/views/shared/icons/_eraser.html.erb +10 -0
- data/app/views/shared/icons/_external_link.html.erb +3 -0
- data/app/views/shared/icons/_eye.html.erb +4 -0
- data/app/views/shared/icons/_file_csv.html.erb +10 -0
- data/app/views/shared/icons/_file_export.html.erb +10 -0
- data/app/views/shared/icons/_file_image.html.erb +10 -0
- data/app/views/shared/icons/_file_import.html.erb +10 -0
- data/app/views/shared/icons/_file_question.html.erb +6 -0
- data/app/views/shared/icons/_film.html.erb +3 -0
- data/app/views/shared/icons/_filter.html.erb +3 -0
- data/app/views/shared/icons/_folder.html.erb +3 -0
- data/app/views/shared/icons/_folder_open.html.erb +3 -0
- data/app/views/shared/icons/_folder_plus.html.erb +3 -0
- data/app/views/shared/icons/_globe.html.erb +3 -0
- data/app/views/shared/icons/_google.html.erb +11 -0
- data/app/views/shared/icons/_heart.html.erb +3 -0
- data/app/views/shared/icons/_heart_broken.html.erb +11 -0
- data/app/views/shared/icons/_heart_pulse.html.erb +4 -0
- data/app/views/shared/icons/_history.html.erb +11 -0
- data/app/views/shared/icons/_home.html.erb +10 -0
- data/app/views/shared/icons/_image.html.erb +3 -0
- data/app/views/shared/icons/_inbox.html.erb +3 -0
- data/app/views/shared/icons/_info_circle.html.erb +10 -0
- data/app/views/shared/icons/_key.html.erb +3 -0
- data/app/views/shared/icons/_layers.html.erb +10 -0
- data/app/views/shared/icons/_lightbulb.html.erb +10 -0
- data/app/views/shared/icons/_lightning.html.erb +3 -0
- data/app/views/shared/icons/_list.html.erb +3 -0
- data/app/views/shared/icons/_lock.html.erb +3 -0
- data/app/views/shared/icons/_logout.html.erb +3 -0
- data/app/views/shared/icons/_magazine.html.erb +3 -0
- data/app/views/shared/icons/_magic.html.erb +3 -0
- data/app/views/shared/icons/_minus.html.erb +10 -0
- data/app/views/shared/icons/_mobile.html.erb +10 -0
- data/app/views/shared/icons/_moon.html.erb +3 -0
- data/app/views/shared/icons/_network.html.erb +10 -0
- data/app/views/shared/icons/_new_item_banner.html.erb +1 -0
- data/app/views/shared/icons/_ouroboros.html.erb +24 -0
- data/app/views/shared/icons/_package.html.erb +3 -0
- data/app/views/shared/icons/_palette.html.erb +3 -0
- data/app/views/shared/icons/_paper_plane.html.erb +10 -0
- data/app/views/shared/icons/_photo.html.erb +10 -0
- data/app/views/shared/icons/_play.html.erb +4 -0
- data/app/views/shared/icons/_plus.html.erb +3 -0
- data/app/views/shared/icons/_pocket.html.erb +11 -0
- data/app/views/shared/icons/_prysm-icon.html.erb +34 -0
- data/app/views/shared/icons/_prysm.html.erb +13 -0
- data/app/views/shared/icons/_pushbullet-1.html.erb +29 -0
- data/app/views/shared/icons/_pushbullet-2.html.erb +2 -0
- data/app/views/shared/icons/_puzzle.html.erb +10 -0
- data/app/views/shared/icons/_qrcode.html.erb +3 -0
- data/app/views/shared/icons/_question.html.erb +3 -0
- data/app/views/shared/icons/_receipt.html.erb +10 -0
- data/app/views/shared/icons/_redo.html.erb +3 -0
- data/app/views/shared/icons/_refresh.html.erb +3 -0
- data/app/views/shared/icons/_rocket.html.erb +10 -0
- data/app/views/shared/icons/_rss.html.erb +3 -0
- data/app/views/shared/icons/_save.html.erb +3 -0
- data/app/views/shared/icons/_search.html.erb +3 -0
- data/app/views/shared/icons/_search_minus.html.erb +10 -0
- data/app/views/shared/icons/_search_plus.html.erb +10 -0
- data/app/views/shared/icons/_server_error.html.erb +6 -0
- data/app/views/shared/icons/_share.html.erb +3 -0
- data/app/views/shared/icons/_shield_check.html.erb +3 -0
- data/app/views/shared/icons/_sign_in.html.erb +3 -0
- data/app/views/shared/icons/_spinner.html.erb +4 -0
- data/app/views/shared/icons/_star.html.erb +3 -0
- data/app/views/shared/icons/_store.html.erb +10 -0
- data/app/views/shared/icons/_sun.html.erb +3 -0
- data/app/views/shared/icons/_sync.html.erb +3 -0
- data/app/views/shared/icons/_table.html.erb +3 -0
- data/app/views/shared/icons/_tag.html.erb +3 -0
- data/app/views/shared/icons/_tags.html.erb +11 -0
- data/app/views/shared/icons/_tools.html.erb +4 -0
- data/app/views/shared/icons/_trash.html.erb +3 -0
- data/app/views/shared/icons/_undo.html.erb +3 -0
- data/app/views/shared/icons/_unlock.html.erb +3 -0
- data/app/views/shared/icons/_upload.html.erb +3 -0
- data/app/views/shared/icons/_user.html.erb +3 -0
- data/app/views/shared/icons/_user_circle.html.erb +10 -0
- data/app/views/shared/icons/_user_plus.html.erb +10 -0
- data/app/views/shared/icons/_video.html.erb +3 -0
- data/app/views/shared/icons/_wrench.html.erb +11 -0
- data/app/views/style_guide/index.html.erb +77 -0
- data/app/views/style_guide/sections/_alerts.html.erb +114 -0
- data/app/views/style_guide/sections/_badges.html.erb +78 -0
- data/app/views/style_guide/sections/_buttons.html.erb +130 -0
- data/app/views/style_guide/sections/_cards.html.erb +84 -0
- data/app/views/style_guide/sections/_colors.html.erb +106 -0
- data/app/views/style_guide/sections/_file_upload.html.erb +135 -0
- data/app/views/style_guide/sections/_forms.html.erb +129 -0
- data/app/views/style_guide/sections/_gradients.html.erb +253 -0
- data/app/views/style_guide/sections/_header.html.erb +12 -0
- data/app/views/style_guide/sections/_icons.html.erb +55 -0
- data/app/views/style_guide/sections/_images.html.erb +40 -0
- data/app/views/style_guide/sections/_loading.html.erb +242 -0
- data/app/views/style_guide/sections/_pagination.html.erb +212 -0
- data/app/views/style_guide/sections/_profile_components.html.erb +203 -0
- data/app/views/style_guide/sections/_theme_switcher.html.erb +72 -0
- data/app/views/style_guide/sections/_typography.html.erb +65 -0
- data/bin/ai-optimize-claude-md +540 -0
- data/bin/ai-review-local +345 -0
- data/bin/ai-security-review +585 -0
- data/bin/brakeman +9 -0
- data/bin/install-hooks +57 -0
- data/bin/rake +7 -0
- data/bin/rubocop +10 -0
- data/bin/verify_setup.rb +31 -0
- data/config/brakeman.ignore +28 -0
- data/config/initializers/neon_sakura.rb +15 -0
- data/config/license_overrides.yml +13 -0
- data/config/routes.rb +21 -0
- data/config/theme_mappings.yml +61 -0
- data/docs/PRYSM_ASSETS.md +210 -0
- data/docs/plans/extract_ai_reviewer_plan.md +151 -0
- data/docs/plans/neon_sakura_gem_plan.md +138 -0
- data/lib/neon_sakura/configuration.rb +94 -0
- data/lib/neon_sakura/engine.rb +48 -0
- data/lib/neon_sakura/icon_helper.rb +54 -0
- data/lib/neon_sakura/profile_helper.rb +24 -0
- data/lib/neon_sakura/stylesheet_helper.rb +40 -0
- data/lib/neon_sakura/theme_helper.rb +63 -0
- data/lib/neon_sakura/theme_importer.rb +112 -0
- data/lib/neon_sakura/version.rb +5 -0
- data/lib/neon_sakura.rb +13 -0
- data/neon_sakura.gemspec +50 -0
- data/package.json +18 -0
- data/scripts/git-hooks/post-merge +132 -0
- data/scripts/git-hooks/pre-commit +123 -0
- data/scripts/git-hooks/pre-push +127 -0
- data/scripts/license-check.rb +587 -0
- data/settings.local.json +12 -0
- data/yarn.lock +778 -0
- 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
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
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')
|
data/bin/verify_setup.rb
ADDED
|
@@ -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!'
|