rails_maint 0.1.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2b1b8a1904b4d02c2f73d2274afdef2bd999883d326e1c12308802454b97c22
4
- data.tar.gz: 5772a26f65a8c5bd00d76ed7b155fb6bb34fd4f20e524a337d0da1b2471c663c
3
+ metadata.gz: 644b76b9127a7f3d676d57ac465b5d4a0e51c182ed7e688255521c525c04b8ff
4
+ data.tar.gz: 93a468bdd47373347f2b4da22b471fb3b3792b403e394a24aa7fb3106d5f9767
5
5
  SHA512:
6
- metadata.gz: fef32a839d45b57beed5f2bb3937a41b00ec546557c5117d061c6104bdd55d35576ce35634cef15c421ed10261d1dbfcd4992856c4afce23d07c021c0c14144a
7
- data.tar.gz: 7315dcadd5a482c59c85a301e157b2fd786459d6f15c75434992f6498c0ac6da27acd346854754b923afa9b4e7139c3643c1c2e9e15122cb0b6be294518dfe54
6
+ metadata.gz: d9f1558562c106f2acb1e6cdcce18bbd2d4c7d12af5e199d985f313f488e375562aaf086433c0d4faa33e9dca946c6c65e2913424284b31248bddcf5f32c5171
7
+ data.tar.gz: a1e1ff3f2d802c22d37c41306f0e0fe41b4c0a5c9983852c08f7284563753f0155851407f78df86cd817d022cc9df0a03881dd34695f4287449b3316212460e4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
- ## [0.1.1] - 2024-03-XX
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0] - 2026-02-28
9
+
2
10
  ### Added
3
- - New feature
11
+ - **Configuration DSL** — `RailsMaint.configure { |c| c.retry_after = 1800 }` for programmatic configuration
12
+ - **Railtie** — Middleware is now auto-registered in Rails apps (no manual `config.middleware.use` needed)
13
+ - **Rails Generator** — `rails generate rails_maint:install` creates config, locale, and initializer files
14
+ - **Retry-After header** — 503 responses include a `Retry-After` header (default: 3600s, configurable)
15
+ - **Route-based maintenance** — `bypass_paths` (always accessible) and `maintenance_paths` (only these paths show maintenance)
16
+ - **Custom maintenance page** — Serve a custom HTML file instead of the default template
17
+ - **Scheduled maintenance** — `rails_maint enable --start="..." --end="..."` for time-windowed maintenance
18
+ - **CLI `status` command** — `rails_maint status` shows current maintenance state and configuration
19
+ - **Webhook notifications** — POST JSON to a configured URL on enable/disable events
20
+ - **ConfigLoader module** — Shared YAML config loading extracted from middleware and CLI
21
+ - **Rails.logger integration** — All log output goes through `RailsMaint.logger` (auto-wired to `Rails.logger` via Railtie)
22
+ - **ActiveSupport::Notifications** — Instrumentation events: `request_blocked.rails_maint`, `enabled.rails_maint`, `disabled.rails_maint`
23
+ - **Custom error classes** — `InvalidConfigurationError`, `InvalidLocaleError`, `ScheduleError`, `WebhookError`
24
+ - **Configuration validation** — `validate!` checks locale format, retry_after, and webhook_url on `RailsMaint.configure`
25
+ - **SimpleCov code coverage** — 99%+ line coverage with branch coverage tracking
26
+ - **README badges** — Gem version, CI status, Codecov, RuboCop style, MIT license
27
+ - **Schedule module** — Parses scheduled maintenance windows with backward-compatible flag file format
28
+ - `remaining_time` translation key added to en.yml and tr.yml
29
+
30
+ ### Security
31
+ - Fix IP spoofing vulnerability via X-Forwarded-For header
32
+ - Fix XSS vulnerability in maintenance page template
33
+ - Fix YAML deserialization vulnerability (switched to safe_load)
34
+ - Fix path traversal vulnerability in locale handling
35
+ - Path traversal protection for custom maintenance page
36
+
4
37
  ### Fixed
5
- - Bug fix
38
+ - Remove debug puts statement from production code path
39
+ - Add missing require statements in middleware
40
+ - Fix uninstall command to dynamically find locale files
41
+ - Add locale validation for install command
42
+ - Ensure tmp/ directory exists before writing maintenance file
43
+
44
+ ### Changed
45
+ - Minimum Ruby version updated to 3.0+
46
+ - Migrated CI from Travis CI to GitHub Actions
47
+ - Improved error handling throughout
48
+ - Installation reduced from 4 steps to 2 steps (`bundle add` + `rails generate`)
49
+ - Middleware refactored to use Configuration DSL with YAML precedence
50
+ - CLI `uninstall` now also removes the initializer file
51
+
52
+ ### Removed
53
+ - Remove unused create_maintenance_page method
54
+ - Remove obsolete .travis.yml
55
+
56
+ ## [0.1.1] - 2024-03-28
57
+
58
+ ### Added
59
+ - Multi-language support (English, Turkish)
60
+ - IP whitelist support with proxy header detection
61
+ - CLI commands (install, enable, disable, uninstall)
62
+ - Rack middleware integration
63
+ - Customizable maintenance page with modern design
64
+
65
+ ## [0.1.0] - 2024-03-20
66
+
67
+ ### Added
68
+ - Initial release
69
+ - Basic maintenance mode functionality
70
+ - Simple CLI interface
data/README.md CHANGED
@@ -1,129 +1,259 @@
1
1
  # RailsMaint
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rails_maint.svg)](https://badge.fury.io/rb/rails_maint)
4
+ [![Build Status](https://github.com/codescaptain/rails_maint/workflows/CI/badge.svg)](https://github.com/codescaptain/rails_maint/actions)
5
+ [![codecov](https://codecov.io/gh/codescaptain/rails_maint/branch/main/graph/badge.svg)](https://codecov.io/gh/codescaptain/rails_maint)
6
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ <img src="https://github.com/user-attachments/assets/4daa45fe-833b-48c5-9f69-457424769804" width="500" height="500" alt="rails_maint">
10
+
11
+
3
12
  RailsMaint is a simple and customizable maintenance mode gem for Rails applications. It allows you to display a sleek maintenance page to your users during maintenance work.
4
13
 
5
14
  ## Features
6
15
 
7
- - 🚀 Easy setup and usage
8
- - 🎨 Customizable, modern maintenance page design
9
- - 🌍 Multi-language support (English and Turkish)
10
- - 🔒 IP whitelist support
11
- - 💻 Simple CLI commands
12
- - 🎯 Rails Middleware integration
16
+ - Easy setup just 2 commands to install
17
+ - Automatic middleware registration via Railtie
18
+ - Configuration DSL and YAML config support
19
+ - Retry-After HTTP header for SEO-friendly 503 responses
20
+ - Route-based maintenance with bypass paths
21
+ - Scheduled maintenance windows with auto-deactivation
22
+ - Custom maintenance page support
23
+ - Multi-language support (English and Turkish)
24
+ - IP whitelist support
25
+ - CLI commands (install, enable, disable, status, uninstall)
26
+ - Webhook notifications on enable/disable events
27
+ - Rails Generator for quick setup
13
28
 
14
29
  ## Installation
15
30
 
16
- 1. Add this line to your application's Gemfile:
31
+ ### Rails Apps (Recommended)
17
32
 
33
+ ```bash
34
+ bundle add rails_maint
35
+ rails generate rails_maint:install
18
36
  ```
37
+
38
+ That's it! The Railtie automatically registers the middleware. The generator creates:
39
+ - `config/rails_maint.yml` — Configuration file
40
+ - `config/locales/rails_maint.en.yml` — Language file
41
+ - `config/initializers/rails_maint.rb` — Initializer with DSL configuration
42
+
43
+ ### Manual Setup
44
+
45
+ 1. Add to your Gemfile:
46
+
47
+ ```ruby
19
48
  gem 'rails_maint'
20
49
  ```
21
50
 
22
- 2. Execute:
51
+ 2. Run:
23
52
 
24
- ```
53
+ ```bash
25
54
  bundle install
55
+ rails_maint install
26
56
  ```
27
57
 
28
- 3. Add the middleware to your Rails application's `config/application.rb`:
58
+ 3. If you need manual middleware registration (the Railtie handles this automatically):
29
59
 
30
- ```
60
+ ```ruby
61
+ # config/application.rb
31
62
  config.middleware.use RailsMaint::Middleware
32
63
  ```
33
64
 
34
65
  ## Usage
35
66
 
36
- ### Installing the Gem
37
-
38
- ```
39
- # For English (default)
40
- rails_maint install
41
-
42
- # For Turkish
43
- rails_maint install --locale=tr
44
- ```
45
-
46
- This command creates the following files:
47
- - `config/rails_maint.yml` - Configuration file
48
- - `config/locales/rails_maint.{locale}.yml` - Language file
49
-
50
67
  ### Managing Maintenance Mode
51
68
 
52
- ```
53
- # To enable maintenance mode
69
+ ```bash
70
+ # Enable maintenance mode
54
71
  rails_maint enable
55
72
 
56
- # To disable maintenance mode
73
+ # Enable with scheduled window
74
+ rails_maint enable --start="2024-06-01 10:00" --end="2024-06-01 12:00"
75
+
76
+ # Disable maintenance mode
57
77
  rails_maint disable
58
78
 
59
- # To remove all files
79
+ # Check current status
80
+ rails_maint status
81
+
82
+ # Remove all RailsMaint files
60
83
  rails_maint uninstall
61
84
  ```
62
85
 
86
+ ### Status Command
87
+
88
+ ```bash
89
+ $ rails_maint status
90
+ Status: ENABLED
91
+ Enabled at: 2024-06-01 10:00:00 +0000
92
+ Start time: 2024-06-01 10:00:00 +0000
93
+ End time: 2024-06-01 12:00:00 +0000
94
+ Remaining: 3542s
95
+
96
+ Locale: en
97
+ Whitelisted IPs: 127.0.0.1, ::1
98
+ Bypass paths: /health, /up
99
+ Retry-After: 3600s
100
+ Custom page: none
101
+ Webhook URL: none
102
+ ```
103
+
63
104
  ## Configuration
64
105
 
65
- You can customize your settings in `config/rails_maint.yml`:
106
+ ### YAML Configuration
66
107
 
67
- ```
108
+ Customize your settings in `config/rails_maint.yml`:
109
+
110
+ ```yaml
68
111
  # Default language setting
69
112
  locale: en
70
113
 
71
- # IP addresses allowed to access
114
+ # IP addresses allowed to access during maintenance
72
115
  white_listed_ips:
73
- - 127.0.0.1
74
- - ::1
75
- # Add your IPs
76
- # - 192.168.1.1
116
+ - 127.0.0.1
117
+ - "::1"
118
+
119
+ # Retry-After header value in seconds (default: 3600)
120
+ retry_after: 3600
121
+
122
+ # Paths that bypass maintenance mode (always accessible)
123
+ bypass_paths:
124
+ - /health
125
+ - /up
126
+ - /api/status
127
+
128
+ # Only apply maintenance to specific paths (empty = all paths)
129
+ # maintenance_paths:
130
+ # - /api/*
131
+
132
+ # Custom maintenance page (relative to app root)
133
+ # custom_page: public/maintenance.html
134
+
135
+ # Webhook URL for maintenance notifications
136
+ # webhook_url: https://hooks.slack.com/services/...
77
137
  ```
78
138
 
79
- ## Language Support
139
+ ### DSL Configuration
80
140
 
81
- Language files are stored in the `config/locales` directory. You can customize existing translations or add new languages:
141
+ Configure programmatically in `config/initializers/rails_maint.rb`:
82
142
 
143
+ ```ruby
144
+ RailsMaint.configure do |config|
145
+ config.locale = 'en'
146
+ config.white_listed_ips = ['127.0.0.1', '::1']
147
+ config.retry_after = 3600
148
+ config.bypass_paths = ['/health', '/up']
149
+ config.maintenance_paths = []
150
+ config.custom_page_path = 'public/maintenance.html'
151
+ config.webhook_url = 'https://hooks.slack.com/services/...'
152
+ end
83
153
  ```
84
- # config/locales/rails_maint.en.yml
85
- en:
86
- rails_maint:
87
- title: "System Maintenance"
88
- description: "Our system is currently being updated..."
89
- estimated_time: "Estimated time: 1 hour"
154
+
155
+ **Precedence:** YAML config > DSL config > defaults
156
+
157
+ ## Route-Based Maintenance
158
+
159
+ ### Bypass Paths
160
+
161
+ Keep certain endpoints accessible during maintenance:
162
+
163
+ ```yaml
164
+ bypass_paths:
165
+ - /health
166
+ - /up
167
+ - /api/status
168
+ ```
169
+
170
+ ### Maintenance Paths
171
+
172
+ Only show maintenance for specific paths (all others pass through):
173
+
174
+ ```yaml
175
+ maintenance_paths:
176
+ - /api/*
90
177
  ```
91
178
 
179
+ Wildcard matching is supported with `/*` suffix for prefix matching. When both are configured, `bypass_paths` takes precedence.
180
+
181
+ ## Scheduled Maintenance
182
+
183
+ Schedule a maintenance window that auto-deactivates:
184
+
185
+ ```bash
186
+ rails_maint enable --start="2024-06-01 10:00" --end="2024-06-01 12:00"
92
187
  ```
93
- # config/locales/rails_maint.tr.yml
94
- tr:
95
- rails_maint:
96
- title: "Sistem Bakımda"
97
- description: "Sistemimiz şu anda güncelleniyor..."
98
- estimated_time: "Tahmini süre: 1 saat"
188
+
189
+ - Before `start_time`: requests pass through normally
190
+ - Between `start_time` and `end_time`: maintenance page is shown
191
+ - After `end_time`: requests pass through again
192
+ - The `Retry-After` header is automatically computed from the remaining time
193
+
194
+ ## Custom Maintenance Page
195
+
196
+ Serve your own HTML file instead of the default template:
197
+
198
+ ```yaml
199
+ custom_page: public/maintenance.html
200
+ ```
201
+
202
+ The file path is validated against path traversal attacks. If the file doesn't exist, the default template is used as a fallback.
203
+
204
+ ## Webhook Notifications
205
+
206
+ Get notified when maintenance mode changes:
207
+
208
+ ```yaml
209
+ webhook_url: https://hooks.slack.com/services/T00/B00/xxx
210
+ ```
211
+
212
+ The gem sends a POST request with a JSON payload:
213
+
214
+ ```json
215
+ {
216
+ "event": "maintenance.enabled",
217
+ "timestamp": "2024-06-01T10:00:00+00:00",
218
+ "gem": "rails_maint",
219
+ "version": "0.1.1"
220
+ }
221
+ ```
222
+
223
+ Events: `maintenance.enabled`, `maintenance.disabled`
224
+
225
+ ## Language Support
226
+
227
+ Language files are stored in the `config/locales` directory. You can customize existing translations or add new languages:
228
+
229
+ ```yaml
230
+ # config/locales/rails_maint.en.yml
231
+ en:
232
+ rails_maint:
233
+ title: "System Maintenance"
234
+ description: "Our system is currently being updated..."
235
+ estimated_time: "Estimated time: 1 hour"
236
+ remaining_time: "Estimated remaining time: %{time}"
99
237
  ```
100
238
 
101
239
  ## How IP Whitelist Works
102
240
 
103
241
  - When maintenance mode is active, IPs in the whitelist can access the site normally
104
242
  - All other IPs will see the maintenance page
105
- - If behind a proxy, the gem checks the X-Forwarded-For header
106
- - Each IP should be added to the configuration file
243
+ - The gem uses `REMOTE_ADDR` for IP checking (not `X-Forwarded-For`, to prevent spoofing)
244
+ - IPs can be configured via both YAML and DSL (merged from both sources)
245
+
246
+ ## Requirements
247
+
248
+ - Rails 6.0 or higher
249
+ - Ruby 3.0 or higher
107
250
 
108
251
  ## Development
109
252
 
110
253
  1. Clone the repository
111
254
  2. Install dependencies: `bundle install`
112
255
  3. Run tests: `bundle exec rspec`
113
-
114
- ## Customizing the Maintenance Page
115
-
116
- The maintenance page template can be customized by creating your own version in `public/maintenance.html`. The default template includes:
117
-
118
- - Responsive design
119
- - Animated maintenance icon
120
- - Clean and modern layout
121
- - Estimated time display
122
-
123
- ## Rails Version Support
124
-
125
- - Rails 6.0 or higher
126
- - Ruby 2.6 or higher
256
+ 4. Run linter: `bundle exec rubocop`
127
257
 
128
258
  ## Contributing
129
259
 
@@ -133,32 +263,13 @@ The maintenance page template can be customized by creating your own version in
133
263
  4. Push to the branch (`git push origin feature/amazing_feature`)
134
264
  5. Create a Pull Request
135
265
 
136
- ## Best Practices
137
-
138
- - Always test your changes
139
- - Follow the Ruby Style Guide
140
- - Write meaningful commit messages
141
- - Add tests for new features
142
- - Update documentation when needed
143
-
144
- ## Common Issues
145
-
146
- ### IP Whitelist Not Working
147
-
148
- Make sure your IP is correctly added to the configuration file and you're not behind an unexpected proxy.
149
-
150
- ### Language Not Changing
151
-
152
- Verify that:
153
- 1. The locale file exists
154
- 2. The locale is correctly set in the configuration
155
- 3. The Rails server was restarted after changes
156
-
157
266
  ## Security
158
267
 
159
- - The gem uses Rails' built-in security features
160
- - IP validation is performed securely
161
- - No sensitive information is exposed
268
+ - Uses `REMOTE_ADDR` for IP validation (prevents spoofing via `X-Forwarded-For`)
269
+ - HTML-escapes all translation values to prevent XSS
270
+ - Uses `YAML.safe_load_file` for safe deserialization
271
+ - Validates locale format with strict regex pattern
272
+ - Path traversal protection for custom maintenance pages and locale files
162
273
 
163
274
  ## License
164
275
 
@@ -175,4 +286,4 @@ Developed and maintained by [CodesCaptain](https://github.com/codescaptain)
175
286
 
176
287
  ## Changelog
177
288
 
178
- See [CHANGELOG.md](CHANGELOG.md) for a list of changes.
289
+ See [CHANGELOG.md](CHANGELOG.md) for a list of changes.
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+
5
+ module RailsMaint
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path('templates', __dir__)
9
+
10
+ class_option :locale, type: :string, default: 'en',
11
+ desc: 'Set the language for maintenance page (e.g., en, tr)'
12
+
13
+ desc 'Installs RailsMaint configuration, locale, and initializer files'
14
+
15
+ def create_config_file
16
+ template 'rails_maint.yml.tt', 'config/rails_maint.yml'
17
+ end
18
+
19
+ def copy_locale_file
20
+ locale = options[:locale]
21
+ source = gem_locale_path(locale)
22
+
23
+ unless File.exist?(source)
24
+ say "Locale '#{locale}' is not supported. Falling back to 'en'.", :red
25
+ locale = 'en'
26
+ source = gem_locale_path(locale)
27
+ end
28
+
29
+ create_file "config/locales/rails_maint.#{locale}.yml", File.read(source)
30
+ end
31
+
32
+ def create_initializer
33
+ template 'initializer.rb.tt', 'config/initializers/rails_maint.rb'
34
+ end
35
+
36
+ def show_post_install_message
37
+ say ''
38
+ say 'RailsMaint installed successfully!', :green
39
+ say ''
40
+ say 'Usage:'
41
+ say ' rails_maint enable # Enable maintenance mode'
42
+ say ' rails_maint disable # Disable maintenance mode'
43
+ say ' rails_maint status # Show maintenance status'
44
+ say ''
45
+ say 'Configuration: config/rails_maint.yml'
46
+ say 'Initializer: config/initializers/rails_maint.rb'
47
+ say ''
48
+ end
49
+
50
+ private
51
+
52
+ def gem_locale_path(locale)
53
+ File.expand_path("../../../rails_maint/assets/locales/#{locale}.yml", __dir__)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RailsMaint Configuration
4
+ # Middleware is automatically registered via Railtie.
5
+ # Settings here override defaults; YAML config (config/rails_maint.yml) takes precedence.
6
+
7
+ RailsMaint.configure do |config|
8
+ # Locale for the maintenance page (default: 'en')
9
+ # config.locale = '<%= options[:locale] %>'
10
+
11
+ # IP addresses that bypass maintenance mode
12
+ # config.white_listed_ips = ['127.0.0.1', '::1']
13
+
14
+ # Path to the maintenance flag file
15
+ # config.maintenance_file_path = 'tmp/maintenance_mode.txt'
16
+
17
+ # Retry-After header value in seconds
18
+ # config.retry_after = 3600
19
+
20
+ # Paths that always bypass maintenance mode
21
+ # config.bypass_paths = ['/health', '/up']
22
+
23
+ # Only apply maintenance to specific paths (empty = all paths)
24
+ # config.maintenance_paths = []
25
+
26
+ # Custom maintenance page path (relative to app root)
27
+ # config.custom_page_path = 'public/maintenance.html'
28
+
29
+ # Webhook URL for maintenance event notifications
30
+ # config.webhook_url = 'https://hooks.slack.com/services/...'
31
+ end
@@ -0,0 +1,32 @@
1
+ # RailsMaint Configuration
2
+ # -----------------------
3
+
4
+ # Default locale for maintenance page
5
+ locale: <%= options[:locale] %>
6
+
7
+ # IP addresses that can access the application during maintenance
8
+ white_listed_ips:
9
+ - 127.0.0.1
10
+ - "::1"
11
+ # Add more IPs below
12
+ # - 192.168.1.1
13
+
14
+ # Retry-After header value in seconds (default: 3600)
15
+ # retry_after: 3600
16
+
17
+ # Paths that bypass maintenance mode (always accessible)
18
+ # bypass_paths:
19
+ # - /health
20
+ # - /up
21
+ # - /api/status
22
+
23
+ # Paths that are affected by maintenance mode (all others pass through)
24
+ # When empty, all paths are affected
25
+ # maintenance_paths:
26
+ # - /api/*
27
+
28
+ # Custom maintenance page (relative to app root)
29
+ # custom_page: public/maintenance.html
30
+
31
+ # Webhook URL for maintenance notifications (e.g., Slack incoming webhook)
32
+ # webhook_url: https://hooks.slack.com/services/...
@@ -2,4 +2,5 @@ en:
2
2
  rails_maint:
3
3
  title: "System Maintenance"
4
4
  description: "Our system is currently being updated..."
5
- estimated_time: "Estimated time: 1 hour"
5
+ estimated_time: "Estimated time: 1 hour"
6
+ remaining_time: "Estimated remaining time: %{time}"
@@ -2,4 +2,5 @@ tr:
2
2
  rails_maint:
3
3
  title: "Sistem Bakımda"
4
4
  description: "Sistemimiz şu anda güncelleniyor..."
5
- estimated_time: "Tahmini süre: 1 saat"
5
+ estimated_time: "Tahmini süre: 1 saat"
6
+ remaining_time: "Tahmini kalan süre: %{time}"
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMaint
4
+ class StatusPrinter
5
+ def print
6
+ config = ConfigLoader.load
7
+ print_maintenance_status
8
+ puts ''
9
+ print_config_status(config)
10
+ end
11
+
12
+ private
13
+
14
+ def print_maintenance_status
15
+ maintenance_file = 'tmp/maintenance_mode.txt'
16
+
17
+ unless File.exist?(maintenance_file)
18
+ puts 'Status: DISABLED'
19
+ return
20
+ end
21
+
22
+ schedule = RailsMaint::Schedule.load(maintenance_file)
23
+ puts schedule.active? ? 'Status: ENABLED' : 'Status: ENABLED (not currently active — outside scheduled window)'
24
+ print_schedule_details(schedule)
25
+ end
26
+
27
+ def print_schedule_details(schedule)
28
+ puts " Enabled at: #{schedule.enabled_at}" if schedule.enabled_at
29
+ puts " Start time: #{schedule.start_time}" if schedule.start_time
30
+ puts " End time: #{schedule.end_time}" if schedule.end_time
31
+
32
+ return unless schedule.end_time
33
+
34
+ remaining = schedule.seconds_until_end
35
+ puts " Remaining: #{remaining}s" if remaining
36
+ end
37
+
38
+ def print_config_status(config)
39
+ puts "Locale: #{config['locale'] || 'en'}"
40
+ print_list('Whitelisted IPs', config['white_listed_ips'])
41
+ print_list('Bypass paths', config['bypass_paths'])
42
+ puts "Retry-After: #{config['retry_after'] || 3600}s"
43
+ puts "Custom page: #{config['custom_page'] || 'none'}"
44
+ puts "Webhook URL: #{config['webhook_url'] || 'none'}"
45
+ end
46
+
47
+ def print_list(label, items)
48
+ items ||= []
49
+ puts "#{label}: #{items.empty? ? 'none' : items.join(', ')}"
50
+ end
51
+ end
52
+ end