rails-ai-bridge 3.5.2 → 3.6.1

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: 87f66a2c3254515e628ba04cac7fcda527bda86254df738f3384f28ccad5fcdf
4
- data.tar.gz: 6bc9b66810b8c5bedd1526a3683b13530a46c1c5b61ba7db89288544d61bce20
3
+ metadata.gz: ecc139c0066902b92342f732a9e9344b5aa5468153f6193708fa95815bbe0535
4
+ data.tar.gz: 05fe2c9d0ada4aa7a836b1dea1ec70f60ad75a94f87c4b4ff5b29e6c4fe9ca81
5
5
  SHA512:
6
- metadata.gz: ae624883e2d08b61bd76d178b52d7067aefd611a1fc6e6f760b7f07361b7acbe877b2ce3f5984b2b6c9d0c74b7376c522cc8065fdf25a8cc8c78660a95583c18
7
- data.tar.gz: 8cc300bb5f6e4d9669e8de9313eca2c4e5cd0c4a7ce336c2cec7bd5c69665df2580d3864536aef092cc22c16ca775909d26c40c372b5bc065577f567836dc149
6
+ metadata.gz: 73de5c66876b8b4ca8e7a50e3bdaaf8700984f23f884f492d7ebc880aee3fd3345efd847c4d4252012ac920c8e5450877767e79e48ecdc141f74b0d0d5dc5dd8
7
+ data.tar.gz: '08b0c68f5f5af762af8c87e937ba5360f5fa6732f07b3543d24bb000e118f5dad55ca4228984f7f88dc471ea70b8f3a75f8ae4b3a3dbd4eacbef205be1683cfa'
data/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [3.6.1] - 2026-08-07
11
+
12
+ ### Security
13
+
14
+ - **Skill-pack git URL scheme allowlist** (#105/#110) — `DefaultGitRunner#clone_repo` accepts only `https://`, SCP-style `git@host:path`, and `ssh://`. Rejects `file://`, plain `http://`, and empty URLs. Validation `ArgumentError`s do not interpolate the raw URL, so credentials in userinfo cannot leak via exception messages.
15
+ - **SECURITY.md supported-versions table** (#106/#112) — documents 3.6.x / 3.5.x as supported, best-effort for older 3.x, and end-of-life for 1.x / 2.x.
16
+ - **Residual MCP HTTP risk checklist** (#107/#113) — operator checklist in `docs/mcp-security.md` (open HTTP default, CORS `*`, in-memory rate limit) with an install-generator pointer.
17
+
18
+ ### Changed
19
+
20
+ - **`rubydex` bumped to `~> 0.3.0`** (#103/#111) — was `~> 0.2.9`. Run `bundle update rubydex` in host apps.
21
+ - **Dependency audit (2026-08)** (#99) — `bundle-audit` clean; official `mcp` remains on **0.25.x** (`< 1.0`). Migration to `mcp` 1.x remains open in #104.
22
+
23
+ ## [3.6.0]
24
+
25
+ ### Changed
26
+
27
+ - **`mcp` minimum version raised to 0.25** (#92) — the gemspec lower bound is now `>= 0.25` (was `>= 0.10`), matching the minimum version the codebase actually requires. The upper bound remains `< 1.0`.
28
+ - **`rubydex` constraint tightened to `~> 0.2.9`** (#92) — was `~> 0.2.4`. This is a **minor breaking change** for users pinned to rubydex 0.2.4–0.2.8; update your lockfile with `bundle update rubydex`.
29
+ - **`simplecov` bumped to 1.0** (#92) — development dependency only; does not affect gem consumers. The test suite filter was migrated from `add_filter '/spec/'` to `skip 'spec'` per the simplecov 1.0 migration guide (`SourceFile#project_filename` no longer includes a leading separator).
30
+
31
+ ### Fixed
32
+
33
+ - **`Style/ArrayIntersect` lint offense** (#91/#92) — pre-existing rubocop offense in `context_summary.rb` autocorrected to use `Array#intersect?`. No behavior change.
34
+
35
+ ### Added
36
+
37
+ - **PathResolver architectural documentation** (#90/#91) — class-level docblock documents PathResolver's intentional role as a shared utility (11 introspector callers, high betweenness centrality). Prevents false "god class" flags from future graph analyses.
38
+ - **PathResolver edge-case tests** (#90/#91) — 6 new specs covering the private `SafeRelativePath` (backslash normalization, Windows path rejection, empty path rejection) and `SafeJoin` (valid joins, traversal escape prevention) helper classes.
39
+
8
40
  ## [3.5.2]
9
41
 
10
42
  ### Security
data/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
  [![CI](https://github.com/igmarin/rails-ai-bridge/actions/workflows/ci.yml/badge.svg)](https://github.com/igmarin/rails-ai-bridge/actions)
11
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
12
12
  ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/igmarin/rails-ai-bridge?utm_source=oss&utm_medium=github&utm_campaign=igmarin%2Frails-ai-bridge&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
13
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/igmarin/rails-ai-bridge)
13
14
 
14
15
  ---
15
16
 
@@ -780,7 +781,7 @@ Bug reports and pull requests: [github.com/igmarin/rails-ai-bridge/issues](https
780
781
 
781
782
  ## Acknowledgments & Origins
782
783
 
783
- This gem ships as **rails-ai-bridge** (Ruby **`RailsAiBridge`**, version **3.1.0**). Earlier iterations of the same codebase were distributed as `rails-ai-context`.
784
+ This gem ships as **rails-ai-bridge** (Ruby **`RailsAiBridge`**, version **3.6.1**). Earlier iterations of the same codebase were distributed as `rails-ai-context`.
784
785
 
785
786
  RailsMCP evolved from
786
787
  [crisnahine/rails-ai-context](https://github.com/crisnahine/rails-ai-context),
data/SECURITY.md CHANGED
@@ -4,10 +4,12 @@
4
4
 
5
5
  | Version | Supported |
6
6
  |---------|--------------------|
7
- | 3.0.x | :white_check_mark: |
8
- | 2.x | :white_check_mark: |
9
- | 1.x | :white_check_mark: |
10
- | < 1.0 | :x: |
7
+ | 3.6.x | :white_check_mark: |
8
+ | 3.5.x | :white_check_mark: |
9
+ | 3.0.x–3.4.x | :white_check_mark: (security fixes best-effort) |
10
+ | 2.x | :x: (end of life — upgrade to 3.x) |
11
+ | 1.x | :x: |
12
+ | < 1.0 | :x: |
11
13
 
12
14
  ## Reporting a Vulnerability
13
15
 
data/UPGRADING.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Upgrading rails-ai-bridge
2
2
 
3
+ ## Upgrading from 3.6.0 to 3.6.1
4
+
5
+ **One action required if you are pinned to `rubydex` 0.2.x:**
6
+
7
+ The `rubydex` gem constraint moved from `~> 0.2.9` to `~> 0.3.0`. After upgrading
8
+ rails-ai-bridge:
9
+
10
+ ```bash
11
+ bundle update rubydex
12
+ ```
13
+
14
+ No configuration or application code changes are required for the security and
15
+ documentation updates in 3.6.1. Skill-pack git sources must use `https://`,
16
+ SCP-style `git@host:path`, or `ssh://` (plain `http://` and `file://` are rejected).
17
+
18
+ ---
19
+
20
+
21
+ ## Upgrading from 3.5.x to 3.6.0
22
+
23
+ **One action required if you are pinned to an older `rubydex`:**
24
+
25
+ The `rubydex` gem constraint was tightened from `~> 0.2.4` to `~> 0.2.9`. If your
26
+ lockfile resolves to rubydex 0.2.4–0.2.8, update it after upgrading:
27
+
28
+ ```bash
29
+ bundle update rubydex
30
+ ```
31
+
32
+ No other configuration or code changes are required. The `mcp` lower bound also
33
+ moved from `>= 0.10` to `>= 0.25`, but if you were already on a recent version
34
+ (no earlier than 0.25) this is a no-op.
35
+
36
+ ---
37
+
3
38
  ## Upgrading from 1.x to 2.x
4
39
 
5
40
  **No configuration changes required.** Every `config.*` attribute from 1.x is still available — `Configuration` now delegates to focused sub-objects but exposes the same flat DSL. See `CHANGELOG.md` for the full list of internal changes.
data/docs/mcp-security.md CHANGED
@@ -72,3 +72,16 @@ The stdio MCP server has no Bearer layer; anyone who can run the process can use
72
72
 
73
73
  - [SECURITY.md](../SECURITY.md) — reporting vulnerabilities and design summary
74
74
  - [docs/GUIDE.md](GUIDE.md) — full configuration and MCP tool reference
75
+
76
+ ## Residual risk checklist (operators)
77
+
78
+ Use this before exposing HTTP MCP beyond a single-developer machine:
79
+
80
+ | Risk | Default | Mitigation |
81
+ |------|---------|------------|
82
+ | Unauthenticated HTTP when no token/resolver/JWT is configured | Open access (local DX) | Set `RAILS_AI_BRIDGE_MCP_TOKEN` or `config.http_mcp_token`, and/or `config.require_http_auth = true` |
83
+ | `cors_origins` includes `*` | CORS disabled unless configured | Prefer exact origins; never combine `*` with browsers on untrusted networks |
84
+ | In-memory rate limit | Per-process only | Use `config.mcp.rate_limiter` / reverse proxy / WAF for multi-worker or multi-host |
85
+ | Information disclosure via tools | Read-only tools still reveal schema/routes/code | Prefer stdio; bind HTTP to `127.0.0.1`; use exclusions/presets for regulated data |
86
+
87
+ See also [SECURITY.md](../SECURITY.md) for production `auto_mount` requirements and private vulnerability reporting.
@@ -189,6 +189,7 @@ module RailsAiBridge
189
189
  # return 401 unless one of the auth mechanisms above is configured.
190
190
  # Default is false for backward compatibility with local development.
191
191
  # config.mcp.require_http_auth = true
192
+ # See docs/mcp-security.md — Residual risk checklist (operators).
192
193
  #
193
194
  # Timing-safe token comparison is built in, but add rate limiting too
194
195
  # (e.g. Rack::Attack throttle on config.http_path) to prevent brute-force.
@@ -3,6 +3,27 @@
3
3
  module RailsAiBridge
4
4
  # Resolves configured Rails logical paths to filesystem paths without leaking
5
5
  # machine-specific absolute paths into generated assistant context.
6
+ #
7
+ # == Architectural role: intentional shared utility
8
+ #
9
+ # PathResolver is deliberately used by every introspector that needs to
10
+ # locate files on disk (controller, model, view, stimulus, turbo, auth,
11
+ # api, config, action_text, activeStorage, nonArModels — 11 callers as of
12
+ # v3.6.1). It is NOT a god class despite high betweenness centrality in
13
+ # graph analyses: a foundational path-resolution utility is expected to
14
+ # sit at the centre of the introspector graph. Splitting it would spread
15
+ # path-safety logic (traversal guards, safe joins) across multiple files
16
+ # and weaken the single responsibility it currently holds.
17
+ #
18
+ # The three private helper classes — SafeRelativePath, SafeJoin, and
19
+ # ConfiguredPathsError — are kept nested and private_constant so they
20
+ # cannot leak into the public API or be referenced by callers. This
21
+ # keeps the safety surface area small and auditable in one file.
22
+ #
23
+ # If a future graph analysis flags this class again, check the
24
+ # betweenness centrality against the caller count before proposing a
25
+ # split: a utility with many callers and a single responsibility is
26
+ # healthy, not smelly.
6
27
  class PathResolver
7
28
  # Validates user-provided relative paths before filesystem operations.
8
29
  class SafeRelativePath
@@ -69,11 +69,22 @@ module RailsAiBridge
69
69
  #
70
70
  # @param url [String] git repository URL
71
71
  # @param dest [String] destination directory path
72
+ # @raise [ArgumentError] if the URL or destination is unsafe or not allowlisted
72
73
  # @raise [RuntimeError] if git clone command fails, returns non-zero, or times out
73
74
  # @return [void]
75
+ # @note Skill-pack clones accept only +https://+, SCP-style
76
+ # +git@host:path+, and +ssh://+ remote URLs.
77
+ ALLOWED_GIT_URL_PATTERN = %r{\A(?:https://|ssh://|git@[A-Za-z0-9._-]+:)}
78
+
74
79
  def clone_repo(url, dest)
75
- raise ArgumentError, "Invalid git URL #{url.inspect}: URLs must not start with '-'" if url.start_with?('-')
76
- raise ArgumentError, "Invalid destination #{dest.inspect}: paths must not start with '-'" if dest.to_s.start_with?('-')
80
+ url = url.to_s
81
+ # Avoid interpolating +url+ into errors: userinfo may contain credentials.
82
+ raise ArgumentError, "Invalid git URL: URLs must not start with '-'" if url.start_with?('-')
83
+ raise ArgumentError, "Invalid destination: paths must not start with '-'" if dest.to_s.start_with?('-')
84
+ unless url.match?(ALLOWED_GIT_URL_PATTERN)
85
+ raise ArgumentError,
86
+ 'Invalid git URL: scheme is not allowlisted (use https://, git@host:path, or ssh://)'
87
+ end
77
88
 
78
89
  with_timeout('git clone') do
79
90
  _stdout, stderr, status = Open3.capture3('git', 'clone', '--', url, dest)
@@ -459,7 +459,7 @@ module RailsAiBridge
459
459
  private_class_method :sensitive_config_basename?
460
460
 
461
461
  def sensitive_config_path_segment?(path)
462
- path.split('/').any? { |segment| SENSITIVE_CONFIG_SEGMENTS.include?(segment) }
462
+ path.split('/').intersect?(SENSITIVE_CONFIG_SEGMENTS)
463
463
  end
464
464
  module_function :sensitive_config_path_segment?
465
465
  private_class_method :sensitive_config_path_segment?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsAiBridge
4
- VERSION = '3.5.2'
4
+ VERSION = '3.6.1'
5
5
  end
@@ -50,11 +50,11 @@ Gem::Specification.new do |spec|
50
50
  spec.require_paths = ['lib']
51
51
 
52
52
  # Core dependencies
53
- spec.add_dependency 'mcp', '>= 0.10', '< 1.0' # Official MCP Ruby SDK
53
+ spec.add_dependency 'mcp', '>= 0.25', '< 1.0' # Official MCP Ruby SDK
54
54
  spec.add_dependency 'railties', '>= 7.1', '< 10.0'
55
55
  spec.add_dependency 'thor', '>= 1.0', '< 3.0'
56
56
  spec.add_dependency 'zeitwerk', '~> 2.6' # Autoloading
57
57
 
58
58
  # Semantic code analysis via Shopify's rubydex
59
- spec.add_dependency 'rubydex', '~> 0.2.4'
59
+ spec.add_dependency 'rubydex', '~> 0.3.0'
60
60
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-ai-bridge
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.2
4
+ version: 3.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Marin
@@ -15,7 +15,7 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0.10'
18
+ version: '0.25'
19
19
  - - "<"
20
20
  - !ruby/object:Gem::Version
21
21
  version: '1.0'
@@ -25,7 +25,7 @@ dependencies:
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: '0.10'
28
+ version: '0.25'
29
29
  - - "<"
30
30
  - !ruby/object:Gem::Version
31
31
  version: '1.0'
@@ -89,14 +89,14 @@ dependencies:
89
89
  requirements:
90
90
  - - "~>"
91
91
  - !ruby/object:Gem::Version
92
- version: 0.2.4
92
+ version: 0.3.0
93
93
  type: :runtime
94
94
  prerelease: false
95
95
  version_requirements: !ruby/object:Gem::Requirement
96
96
  requirements:
97
97
  - - "~>"
98
98
  - !ruby/object:Gem::Version
99
- version: 0.2.4
99
+ version: 0.3.0
100
100
  description: Rails-AI-Bridge introspects your Rails application and exposes structure
101
101
  to AI assistants via static context files and a live Model Context Protocol (MCP)
102
102
  server. It classifies Active Record models semantically (Core, Join, Supporting),