Skip to content

Commit 32a1d20

Browse files
gem
0 parents  commit 32a1d20

22 files changed

Lines changed: 517 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Ruby gem
2+
3+
on:
4+
push:
5+
branches:
6+
- "*"
7+
tags:
8+
- v*
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
ruby_version: ["2.5", "2.6", "2.7"]
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
20+
- name: Set up Ruby versions
21+
uses: actions/setup-ruby@v1
22+
with:
23+
ruby-version: ${{ matrix.ruby_version }}
24+
25+
- name: Build
26+
run: |
27+
gem install bundler --version 1.16.6
28+
bundle install --jobs 4 --retry 3
29+
gem install rspec
30+
- name: Test
31+
run: |
32+
rspec
33+
deploy:
34+
if: contains(github.ref, 'refs/tags/v')
35+
needs: test
36+
runs-on: ubuntu-latest
37+
38+
steps:
39+
- uses: actions/checkout@v2
40+
41+
- name: Set up Ruby 2.5
42+
uses: actions/setup-ruby@v1
43+
with:
44+
ruby-version: 2.5
45+
46+
- name: Build
47+
run: |
48+
gem install bundler --version 1.16.6
49+
bundle install --jobs 4 --retry 3
50+
51+
- name: Publish to RubyGems
52+
uses: devmasx/publish-rubygems-action@master
53+
env:
54+
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
55+
RELEASE_COMMAND: rake release

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/.bundle/
2+
/.yardoc
3+
/_yardoc/
4+
/coverage/
5+
/doc/
6+
/pkg/
7+
/spec/reports/
8+
/tmp/
9+
*.gem
10+
.env

.rubocop.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
AllCops:
2+
NewCops: enable
3+
TargetRubyVersion: 3.0
4+
Exclude:
5+
- "active-admin-vpn-auto-login.gemspec"
6+
7+
Style/StringLiterals:
8+
EnforcedStyle: double_quotes
9+
10+
Style/FrozenStringLiteralComment:
11+
Enabled: true

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
## [Unreleased]
6+
7+
## [0.1.0] - 2026-04-17
8+
- Initial release

Gemfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
source "https://rubygems.org"
4+
5+
gemspec
6+
7+
gem "rake", "~> 13.0"
8+
gem "rspec", "~> 3.0"
9+
gem "rubocop", "~> 1.21"
10+
gem "rubocop-rspec", require: false

LICENSE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2026 Your Name
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# ActiveAdminVpn
2+
3+
Restrict access to [ActiveAdmin](https://activeadmin.info/) to requests coming from
4+
configured VPN IP ranges. Optionally auto-login VPN users so they skip the login form.
5+
6+
## Installation
7+
8+
Add to your Gemfile:
9+
10+
```ruby
11+
gem "active_admin_vpn"
12+
```
13+
14+
Then run:
15+
16+
```bash
17+
bundle install
18+
rails generate active_admin_vpn:install
19+
```
20+
21+
This creates `config/initializers/active_admin_vpn.rb`.
22+
23+
---
24+
25+
## Configuration
26+
27+
### Option 1 — Environment variable (recommended)
28+
29+
Set `VPN_IP_RANGE` in your environment (`.env`, Heroku config vars, etc.):
30+
31+
```bash
32+
VPN_IP_RANGE="10.0.0.0/8,192.168.1.0/24"
33+
```
34+
35+
The gem reads this automatically — no extra code needed.
36+
37+
### Option 2 — Initializer
38+
39+
```ruby
40+
# config/initializers/active_admin_vpn.rb
41+
ActiveAdminVpn.configure do |config|
42+
config.ip_ranges = "10.0.0.0/8,192.168.1.0/24"
43+
end
44+
```
45+
46+
---
47+
48+
## Auto-login (skip login form on VPN)
49+
50+
```ruby
51+
ActiveAdminVpn.configure do |config|
52+
config.ip_ranges = ENV["VPN_IP_RANGE"]
53+
config.auto_login = true
54+
config.auto_login_email = "admin@yourcompany.com"
55+
end
56+
```
57+
58+
When `auto_login` is `true`, any request from a VPN IP is automatically signed in
59+
as the given `AdminUser` — no username/password required.
60+
61+
> **Security note:** Keep the standard login enabled for non-VPN users. Auto-login
62+
> only applies when the request IP is inside a configured VPN range.
63+
64+
---
65+
66+
## Route constraint (optional)
67+
68+
If you prefer to block at the routing layer instead of the controller layer:
69+
70+
```ruby
71+
# config/routes.rb
72+
constraints(ActiveAdminVpn::VpnConstraint) do
73+
ActiveAdmin.routes(self)
74+
end
75+
```
76+
77+
---
78+
79+
## Trusted proxies
80+
81+
If your app runs behind a load balancer or reverse proxy, make sure Rails trusts
82+
the forwarded IP headers so `request.remote_ip` reflects the real client IP:
83+
84+
```ruby
85+
# config/application.rb
86+
config.action_dispatch.trusted_proxies = [
87+
"127.0.0.1",
88+
"::1",
89+
IPAddr.new("10.0.0.0/8"),
90+
IPAddr.new("172.16.0.0/12"),
91+
IPAddr.new("192.168.0.0/16")
92+
]
93+
```
94+
95+
---
96+
97+
## All configuration options
98+
99+
| Option | Default | Description |
100+
|--------------------|-------------|------------------------------------------------------|
101+
| `ip_ranges` | `VPN_IP_RANGE` env | Comma-separated CIDR ranges |
102+
| `auto_login` | `false` | Skip login form for VPN users |
103+
| `auto_login_email` | `nil` | AdminUser email used for auto-login |
104+
| `forbidden_status` | `:forbidden`| HTTP status for blocked requests (403) |
105+
| `forbidden_message`| `"Access denied..."` | Body text for blocked requests |
106+
107+
---
108+
109+
## License
110+
111+
MIT

Rakefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
require "bundler/gem_tasks"
4+
require "rspec/core/rake_task"
5+
require "rubocop/rake_task"
6+
7+
RSpec::RakeTask.new(:spec)
8+
RuboCop::RakeTask.new
9+
10+
task default: %i[spec rubocop]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "lib/active_admin/vpn_auto_login/version"
4+
5+
Gem::Specification.new do |spec|
6+
spec.name = "active-admin-vpn-auto-login"
7+
spec.version = ActiveAdmin::VpnAutoLogin::VERSION
8+
spec.authors = ["Your Name"]
9+
spec.email = ["your.email@example.com"]
10+
11+
spec.summary = "A Rails gem that limits access to ActiveAdmin to requests coming from configured VPN IP ranges (CIDR). Supports optional auto-login for VPN users so they skip the login form entirely."
12+
spec.description = "A Rails gem that limits access to ActiveAdmin to requests coming from configured VPN IP ranges (CIDR). Supports optional auto-login for VPN users so they skip the login form entirely."
13+
spec.homepage = "https://github.com/yourusername/active-admin-vpn-auto-login"
14+
spec.license = "MIT"
15+
spec.required_ruby_version = ">= 3.0.0"
16+
17+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
18+
spec.metadata["homepage_uri"] = spec.homepage
19+
spec.metadata["source_code_uri"] = spec.homepage
20+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
21+
22+
gemspec = File.basename(__FILE__)
23+
spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
24+
ls.readlines("\x0", chomp: true).reject do |f|
25+
(f == gemspec) ||
26+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
27+
end
28+
end
29+
30+
spec.require_paths = ["lib"]
31+
32+
spec.add_dependency "rails", ">= 6.0"
33+
spec.add_dependency "activeadmin", ">= 2.0"
34+
end

active_admin_vpn.gemspec

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require_relative "lib/active_admin_vpn/version"
2+
3+
Gem::Specification.new do |spec|
4+
spec.name = "active_admin_vpn"
5+
spec.version = ActiveAdminVpn::VERSION
6+
spec.authors = ["Your Name"]
7+
spec.email = ["you@example.com"]
8+
9+
spec.summary = "Restrict ActiveAdmin access to VPN IP ranges"
10+
spec.description = <<~DESC
11+
A Rails gem that limits access to ActiveAdmin to requests coming from
12+
configured VPN IP ranges (CIDR). Supports optional auto-login for VPN
13+
users so they skip the login form entirely.
14+
DESC
15+
spec.homepage = "https://github.com/yourname/active_admin_vpn"
16+
spec.license = "MIT"
17+
18+
spec.required_ruby_version = ">= 2.7.0"
19+
20+
spec.files = Dir[
21+
"lib/**/*",
22+
"README.md",
23+
"LICENSE.txt",
24+
"active_admin_vpn.gemspec"
25+
]
26+
27+
spec.require_paths = ["lib"]
28+
29+
spec.add_dependency "rails", ">= 6.0"
30+
spec.add_dependency "activeadmin", ">= 2.0"
31+
32+
spec.add_development_dependency "rspec-rails"
33+
spec.add_development_dependency "devise"
34+
end

0 commit comments

Comments
 (0)