boxcars 0.2.3 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea9c5df0584f588d618c22fc44f8bba2638c0946ba32cea8487429ad6df694f5
4
- data.tar.gz: a7cd6609da5d63c1b41763fc7c6e8b4e1c8df41992fd133d0bf359b28d50dd0c
3
+ metadata.gz: a3593a9df2d9d8a867729e0b6081b300125933566923ca905e2eefb16a933394
4
+ data.tar.gz: 90c03ea9b328b8cff10f828f8b9bf4375cce0fd574dd8a26c690776e58a58c1b
5
5
  SHA512:
6
- metadata.gz: aac8bd34e6ddca629d26ff0cb892e46de30e1f20db188b56477422e5526e03c80a22e1b06ab7d8263e8db067db6ec1966f34450ab63e98cea3e857aa7eb27286
7
- data.tar.gz: 10ce3be58a020a5de80c27fdf46cbd7811afc45ac28e0712479b113eb6a34ca6a2f7043711659bb4b0a152e0981ded5a8f76fe0704f1a89751b3c8ec0a843ea8
6
+ metadata.gz: 5de41be1f154b2c21fcd6602159a6428d8702dc318904e6e03db9de1b0ed1788b03aa10365203557b39fe268f04b4594cf6915faa941b2c64e475cd6cbb55d09
7
+ data.tar.gz: 2ad84e5f416b19759807d658d739d1abb8405ba6ded3b38bdf5ce9406efeadccbc2102b7b477a90df67beaa287a9810b09e59b5843090fbe4619b03500d0a4f4
data/CHANGELOG.md CHANGED
@@ -1,8 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased](https://github.com/BoxcarsAI/boxcars/tree/HEAD)
3
+ ## [v0.2.4](https://github.com/BoxcarsAI/boxcars/tree/v0.2.4) (2023-03-28)
4
4
 
5
- [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.2...HEAD)
5
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.3...v0.2.4)
6
+
7
+ **Closed issues:**
8
+
9
+ - security [\#40](https://github.com/BoxcarsAI/boxcars/issues/40)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Fix regex action input [\#41](https://github.com/BoxcarsAI/boxcars/pull/41) ([makevoid](https://github.com/makevoid))
14
+
15
+ ## [v0.2.3](https://github.com/BoxcarsAI/boxcars/tree/v0.2.3) (2023-03-20)
16
+
17
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.2...v0.2.3)
6
18
 
7
19
  **Merged pull requests:**
8
20
 
data/Gemfile.lock CHANGED
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.2.3)
4
+ boxcars (0.2.5)
5
5
  google_search_results (~> 2.2)
6
6
  ruby-openai (~> 3.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (7.0.4.2)
12
- activesupport (= 7.0.4.2)
13
- activerecord (7.0.4.2)
14
- activemodel (= 7.0.4.2)
15
- activesupport (= 7.0.4.2)
16
- activesupport (7.0.4.2)
11
+ activemodel (7.0.4.3)
12
+ activesupport (= 7.0.4.3)
13
+ activerecord (7.0.4.3)
14
+ activemodel (= 7.0.4.3)
15
+ activesupport (= 7.0.4.3)
16
+ activesupport (7.0.4.3)
17
17
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
18
  i18n (>= 1.6, < 2)
19
19
  minitest (>= 5.1)
@@ -21,7 +21,7 @@ GEM
21
21
  addressable (2.8.1)
22
22
  public_suffix (>= 2.0.2, < 6.0)
23
23
  ast (2.4.2)
24
- async (1.30.3)
24
+ async (1.31.0)
25
25
  console (~> 1.10)
26
26
  nio4r (~> 2.3)
27
27
  timers (~> 4.1)
@@ -38,14 +38,14 @@ GEM
38
38
  faraday
39
39
  async-io (1.34.3)
40
40
  async
41
- async-pool (0.3.12)
41
+ async-pool (0.4.0)
42
42
  async (>= 1.25)
43
- concurrent-ruby (1.2.0)
43
+ concurrent-ruby (1.2.2)
44
44
  console (1.16.2)
45
45
  fiber-local
46
46
  crack (0.4.5)
47
47
  rexml
48
- debug (1.7.1)
48
+ debug (1.7.2)
49
49
  irb (>= 1.5.0)
50
50
  reline (>= 0.3.1)
51
51
  diff-lcs (1.5.0)
@@ -56,7 +56,7 @@ GEM
56
56
  faraday-http-cache (2.4.1)
57
57
  faraday (>= 0.8)
58
58
  faraday-net_http (3.0.2)
59
- faraday-retry (2.0.0)
59
+ faraday-retry (2.1.0)
60
60
  faraday (~> 2.0)
61
61
  fiber-local (1.0.0)
62
62
  github_changelog_generator (1.16.4)
@@ -77,13 +77,13 @@ GEM
77
77
  concurrent-ruby (~> 1.0)
78
78
  io-console (0.6.0)
79
79
  io-console (0.6.0-java)
80
- irb (1.6.2)
80
+ irb (1.6.3)
81
81
  reline (>= 0.3.0)
82
82
  json (2.6.3)
83
83
  json (2.6.3-java)
84
84
  mini_mime (1.1.2)
85
85
  mini_portile2 (2.8.1)
86
- minitest (5.17.0)
86
+ minitest (5.18.0)
87
87
  multi_json (1.15.0)
88
88
  multi_xml (0.6.0)
89
89
  nio4r (2.5.8)
@@ -92,7 +92,7 @@ GEM
92
92
  faraday (>= 1, < 3)
93
93
  sawyer (~> 0.9)
94
94
  parallel (1.22.1)
95
- parser (3.2.1.0)
95
+ parser (3.2.1.1)
96
96
  ast (~> 2.4.1)
97
97
  protocol-hpack (1.4.2)
98
98
  protocol-http (0.24.1)
@@ -105,7 +105,7 @@ GEM
105
105
  rainbow (3.1.1)
106
106
  rake (13.0.6)
107
107
  regexp_parser (2.7.0)
108
- reline (0.3.2)
108
+ reline (0.3.3)
109
109
  io-console (~> 0.5)
110
110
  rexml (3.2.5)
111
111
  rspec (3.12.0)
@@ -117,42 +117,42 @@ GEM
117
117
  rspec-expectations (3.12.2)
118
118
  diff-lcs (>= 1.2.0, < 2.0)
119
119
  rspec-support (~> 3.12.0)
120
- rspec-mocks (3.12.3)
120
+ rspec-mocks (3.12.5)
121
121
  diff-lcs (>= 1.2.0, < 2.0)
122
122
  rspec-support (~> 3.12.0)
123
123
  rspec-support (3.12.0)
124
- rubocop (1.45.1)
124
+ rubocop (1.48.1)
125
125
  json (~> 2.3)
126
126
  parallel (~> 1.10)
127
127
  parser (>= 3.2.0.0)
128
128
  rainbow (>= 2.2.2, < 4.0)
129
129
  regexp_parser (>= 1.8, < 3.0)
130
130
  rexml (>= 3.2.5, < 4.0)
131
- rubocop-ast (>= 1.24.1, < 2.0)
131
+ rubocop-ast (>= 1.26.0, < 2.0)
132
132
  ruby-progressbar (~> 1.7)
133
133
  unicode-display_width (>= 2.4.0, < 3.0)
134
- rubocop-ast (1.26.0)
134
+ rubocop-ast (1.28.0)
135
135
  parser (>= 3.2.1.0)
136
136
  rubocop-capybara (2.17.1)
137
137
  rubocop (~> 1.41)
138
138
  rubocop-rake (0.6.0)
139
139
  rubocop (~> 1.0)
140
- rubocop-rspec (2.18.1)
140
+ rubocop-rspec (2.19.0)
141
141
  rubocop (~> 1.33)
142
142
  rubocop-capybara (~> 2.17)
143
- ruby-openai (3.5.0)
143
+ ruby-openai (3.7.0)
144
144
  httparty (>= 0.18.1)
145
- ruby-progressbar (1.11.0)
145
+ ruby-progressbar (1.13.0)
146
146
  ruby2_keywords (0.0.5)
147
147
  sawyer (0.9.2)
148
148
  addressable (>= 2.3.5)
149
149
  faraday (>= 0.17.3, < 3)
150
- sqlite3 (1.6.0)
150
+ sqlite3 (1.6.2)
151
151
  mini_portile2 (~> 2.8.0)
152
- sqlite3 (1.6.0-x86_64-darwin)
153
- sqlite3 (1.6.0-x86_64-linux)
152
+ sqlite3 (1.6.2-x86_64-darwin)
153
+ sqlite3 (1.6.2-x86_64-linux)
154
154
  timers (4.3.5)
155
- traces (0.8.0)
155
+ traces (0.9.1)
156
156
  tzinfo (2.0.6)
157
157
  concurrent-ruby (~> 1.0)
158
158
  unicode-display_width (2.4.2)
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  <a href="https://github.com/BoxcarsAI/boxcars/blob/main/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
12
12
  </p>
13
13
 
14
- Boxcars is a gem that enables you to create new systems with AI composability, using various concepts such as OpenAI, Search, SQL, Rails Active Record and more. This can even be extended with your concepts as well.(including your concepts).
14
+ Boxcars is a gem that enables you to create new systems with AI composability, using various concepts such as OpenAI, Search, SQL, Rails Active Record and more. This can even be extended with your concepts as well (including your concepts).
15
15
 
16
16
  This gem was inspired by the popular Python library Langchain. However, we wanted to give it a Ruby spin and make it more user-friendly for beginners to get started.
17
17
 
@@ -23,6 +23,11 @@ All of these concepts are in a module named Boxcars:
23
23
  - Prompt - used by an Engine to generate text results. Most of the Boxcars have built-in prompts, so you only need to worry about these if you are extending the system.
24
24
  - Engine - an entity that generates text from a Prompt. OpenAI's LLM text generator is the default Engine if no other is specified.
25
25
 
26
+ ## Security
27
+ Currently, our system is designed for individuals who already possess administrative privileges for their project. It is likely possible to manipulate the system's prompts to carry out malicious actions, but if you already have administrative access, you can perform such actions without requiring boxcars in the first place.
28
+
29
+ *Note:* We are actively seeking ways to improve our system's ability to identify and prevent any nefarious attempts from occurring. If you have any suggestions or recommendations, please feel free to share them with us by either finding an existing issue or creating a new one and providing us with your feedback.
30
+
26
31
  ## Installation
27
32
 
28
33
  Add this line to your application's Gemfile:
@@ -66,10 +71,10 @@ Produces:
66
71
  ```text
67
72
  > Entering Calculator#run
68
73
  what is pi to the forth power divided by 22.1?
69
- RubyREPL: puts(Math::PI**4 / 22.1)
74
+ RubyREPL: puts (Math::PI**4)/22.1
70
75
  Answer: 4.407651178009159
71
76
 
72
- 4.407651178009159
77
+ {"status":"ok","answer":"4.407651178009159","explanation":"Answer: 4.407651178009159","code":"puts (Math::PI**4)/22.1"}
73
78
  < Exiting Calculator#run
74
79
  4.407651178009159
75
80
  ```
@@ -94,27 +99,34 @@ Here is what we have so far, but please put up a PR with your new ideas.
94
99
  # run a Train for a calculator, and search using default Engine
95
100
  boxcars = [Boxcars::Calculator.new, Boxcars::Serp.new]
96
101
  train = Boxcars.train.new(boxcars: boxcars)
97
- puts train.run "What is pi times the square root of the average temperature in Austin TX in January?"
102
+ train.run "What is pi times the square root of the average temperature in Austin TX in January?"
98
103
  ```
99
104
  Produces:
100
105
  ```text
101
106
  > Entering Zero Shot#run
102
107
  What is pi times the square root of the average temperature in Austin TX in January?
108
+ Thought: We need to find the average temperature in Austin TX in January and then multiply it by pi and the square root of that value. We can use a search engine to find the average temperature and a calculator to perform the multiplication.
103
109
  Question: Average temperature in Austin TX in January
104
110
  Answer: increase from 62°F to 64°F
105
- #Observation: increase from 62°F to 64°F
111
+ Observation: increase from 62°F to 64°F
112
+ Thought: The average temperature in Austin TX in January is around 63°F.
106
113
  > Entering Calculator#run
107
- 64°F x pi
108
- RubyREPL: puts (64 * Math::PI).round(2)
109
- Answer: 201.06
114
+ pi * sqrt(63)
115
+ RubyREPL: puts(Math::PI * Math.sqrt(63))
116
+ Answer: 24.935618646198247
110
117
 
111
- 201.06
118
+ {"status":"ok","answer":"24.935618646198247","explanation":"Answer: 24.935618646198247","code":"puts(Math::PI * Math.sqrt(63))"}
112
119
  < Exiting Calculator#run
113
- #Observation: 201.06
114
- I now know the final answer
115
- Final Answer: 201.06
120
+ Observation: 24.935618646198247
121
+ The result of pi times the square root of the average temperature in Austin TX in January is approximately 24.94.
122
+
123
+ Final Answer: 24.94
124
+
125
+ Next Actions:
126
+ 1. What is the average temperature in Austin TX in July?
127
+ 2. What is the formula for calculating the area of a circle?
128
+ 3. What is the value of pi to 10 decimal places?
116
129
  < Exiting Zero Shot#run
117
- 201.06
118
130
  ```
119
131
  ### More Examples
120
132
  See [this](https://github.com/BoxcarsAI/boxcars/blob/main/notebooks/boxcars_examples.ipynb) Jupyter Notebook for more examples.
@@ -76,7 +76,7 @@ module Boxcars
76
76
  ::ActiveRecord::Base.transaction do
77
77
  begin
78
78
  result = yield
79
- rescue ::NameError, ::Error => e
79
+ rescue SecurityError, ::NameError, ::Error => e
80
80
  Boxcars.error("Error while running code: #{e.message[0..60]} ...", :red)
81
81
  runtime_exception = e
82
82
  end
@@ -93,13 +93,20 @@ module Boxcars
93
93
  bad_words = %w[commit drop_constraint drop_constraint! drop_extension drop_extension! drop_foreign_key drop_foreign_key! \
94
94
  drop_index drop_index! drop_join_table drop_join_table! drop_materialized_view drop_materialized_view! \
95
95
  drop_partition drop_partition! drop_schema drop_schema! drop_table drop_table! drop_trigger drop_trigger! \
96
- drop_view drop_view! eval execute reset revoke rollback truncate].freeze
96
+ drop_view drop_view! eval instance_eval send system execute reset revoke rollback truncate \
97
+ encrypted_password].freeze
97
98
  without_strings = code.gsub(/('([^'\\]*(\\.[^'\\]*)*)'|"([^"\\]*(\\.[^"\\]*)*"))/, 'XX')
98
- word_list = without_strings.split(/[.,()]/)
99
+
100
+ if without_strings.include?("`")
101
+ Boxcars.info "code included possibly destructive backticks #{code}", :red
102
+ return false
103
+ end
104
+
105
+ word_list = without_strings.split(/[.,() :\[\]]/)
99
106
 
100
107
  bad_words.each do |w|
101
108
  if word_list.include?(w)
102
- Boxcars.info "code included destructive instruction: #{w} #{code}", :red
109
+ Boxcars.info "code included possibly destructive instruction: '#{w}' in #{code}", :red
103
110
  return false
104
111
  end
105
112
  end
@@ -107,12 +114,24 @@ module Boxcars
107
114
  true
108
115
  end
109
116
 
117
+ # run the code in a safe environment
118
+ # @param code [String] The code to run
119
+ # @return [Object] The result of the code
120
+ def eval_safe_wrapper(code)
121
+ # if the code used ActiveRecord, we need to add :: in front of it to escape the module
122
+ new_code = code.gsub(/(\W)ActiveRecord::/, '\1::ActiveRecord::')
123
+ proc do
124
+ $SAFE = 4
125
+ # rubocop:disable Security/Eval
126
+ eval new_code
127
+ # rubocop:enable Security/Eval
128
+ end.call
129
+ end
130
+
110
131
  def evaluate_input(code)
111
132
  raise SecurityError, "Found unsafe code while evaluating: #{code}" unless safe_to_run?(code)
112
133
 
113
- # rubocop:disable Security/Eval
114
- eval code
115
- # rubocop:enable Security/Eval
134
+ eval_safe_wrapper code
116
135
  end
117
136
 
118
137
  def change_count(changes_code)
@@ -176,7 +195,7 @@ module Boxcars
176
195
  have_approval = false
177
196
  begin
178
197
  have_approval = approved?(changes_code, code)
179
- rescue NameError, ::Error => e
198
+ rescue NameError, Error => e
180
199
  return Result.new(status: :error, explanation: error_message(e, "ARChanges"), changes_code: changes_code)
181
200
  end
182
201
 
@@ -185,7 +204,9 @@ module Boxcars
185
204
  begin
186
205
  output = clean_up_output(run_active_record_code(code))
187
206
  Result.new(status: :ok, answer: output, explanation: "Answer: #{output.to_json}", code: code)
188
- rescue NameError, ::Error => e
207
+ rescue SecurityError => e
208
+ raise e
209
+ rescue ::StandardError => e
189
210
  Result.new(status: :error, answer: nil, explanation: error_message(e, "ARCode"), code: code)
190
211
  end
191
212
  end
@@ -220,7 +241,8 @@ module Boxcars
220
241
  "Only use the following Active Record models: %<model_info>s\n",
221
242
  "Pay attention to use only the attribute names that you can see in the model description.\n",
222
243
  "Do not make up variable or attribute names, and do not share variables between the code in ARChanges and ARCode\n",
223
- "Be careful to not query for attributes that do not exist, and to use the format specified above.\n"
244
+ "Be careful to not query for attributes that do not exist, and to use the format specified above.\n",
245
+ "Finally, do not use print or puts in your code."
224
246
  ),
225
247
  user("Question: %<question>s")
226
248
  ].freeze
@@ -100,7 +100,7 @@ module Boxcars
100
100
  end
101
101
  Boxcars.error answer.to_json, :red
102
102
  { output_key => "Error: #{answer}" }
103
- rescue Boxcars::ConfigurationError => e
103
+ rescue Boxcars::ConfigurationError, Boxcars::SecurityError => e
104
104
  raise e
105
105
  rescue Boxcars::Error => e
106
106
  Boxcars.error e.message, :red
@@ -49,8 +49,8 @@ module Boxcars
49
49
  [:answer_box, :snippet_highlighted_words, 0],
50
50
  %i[sports_results game_spotlight],
51
51
  %i[knowledge_graph description],
52
- [:organic_results, 0, :snippet_highlighted_words, 0],
53
- [:organic_results, 0, :snippet]
52
+ [:organic_results, 0, :snippet],
53
+ [:organic_results, 0, :snippet_highlighted_words, 0]
54
54
  ].freeze
55
55
 
56
56
  def find_answer(res)
@@ -50,7 +50,7 @@ module Boxcars
50
50
  # the thought should be the frist line here if it doesn't start with "Action:"
51
51
  thought = engine_output.split(/\n+/).reject(&:empty?).first
52
52
  Boxcars.debug("Thought: #{thought}", :yellow)
53
- regex = /Action: (?<action>.*)\n+Action Input: (?<action_input>.*)/
53
+ regex = /Action(?<extra>[\s\d]*): (?<action>.+?)\n+Action Input:(?<action_input>.+)/m
54
54
  match = regex.match(engine_output)
55
55
 
56
56
  # we have an unexpected output from the engine
data/lib/boxcars/train.rb CHANGED
@@ -196,6 +196,8 @@ module Boxcars
196
196
  begin
197
197
  observation = boxcar.run(output.boxcar_input)
198
198
  return_direct = boxcar.return_direct
199
+ rescue Boxcars::ConfigurationError, Boxcars::SecurityError => e
200
+ raise e
199
201
  rescue StandardError => e
200
202
  Boxcars.error "Error in #{boxcar.name} boxcar#call: #{e}", :red
201
203
  observation = "Error - #{e}, correct and try again."
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.2.3"
5
+ VERSION = "0.2.5"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxcars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francis Sullivan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-03-20 00:00:00.000000000 Z
12
+ date: 2023-03-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug