biscuit-rails 0.1.4 → 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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +33 -1
- data/lib/biscuit/version.rb +1 -1
- data/lib/generators/biscuit/install/install_generator.rb +26 -0
- data/lib/generators/biscuit/install/templates/SKILL.md +266 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a99734c304d99da013a29fd797e8d8d9461bdea8811bb87997bddc4a0b1cd100
|
|
4
|
+
data.tar.gz: b93c476239e0e9ee02f5466596b1de11dc3f24fcb3794c7b99497a66073efaf4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 695482883b254ce859513919089eaa30f80947d792f9755cba738db35aff1bfde4bf6472cdbde5860b4e300acf05dda113ba595f26a422f2d6d60ef1833975d1
|
|
7
|
+
data.tar.gz: 197a2f37232f33b7b179fef7418497eaed80a3630016175e75709315e01778b273fdc0fa8347371b07c84884b0d78b0e696b9d6f0093eb930f779d8bc4ed0c6b
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ 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.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-03-31
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `rails generate biscuit:install` generator — installs a Claude Code skill
|
|
13
|
+
into `.claude/skills/biscuit-install/` for AI-assisted setup
|
|
14
|
+
- `biscuit-install` Claude Code skill — guides developers through compatibility
|
|
15
|
+
checks, engine mounting, Stimulus registration, initializer configuration,
|
|
16
|
+
cookie and tracking script audit, integration tests, and optional commit
|
|
17
|
+
- README section documenting the AI-assisted setup workflow
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
8
21
|
## [0.1.4] - 2026-03-29
|
|
9
22
|
|
|
10
23
|
### Fixed
|
data/README.md
CHANGED
|
@@ -21,7 +21,39 @@ default).
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## AI-assisted setup (Claude Code)
|
|
25
|
+
|
|
26
|
+
If you use [Claude Code](https://claude.ai/code), the quickest way to install
|
|
27
|
+
and configure biscuit is via the built-in setup skill.
|
|
28
|
+
|
|
29
|
+
After adding the gem to your Gemfile and running `bundle install`, run the
|
|
30
|
+
generator to install the skill:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
rails generate biscuit:install
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then open Claude Code in your project and run:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
/biscuit-install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The skill will:
|
|
43
|
+
|
|
44
|
+
- Check your app is compatible (Ruby, Rails, Propshaft, Stimulus)
|
|
45
|
+
- Mount the engine and register the Stimulus controller
|
|
46
|
+
- Ask about banner position, cookie categories, and other preferences
|
|
47
|
+
- Generate `config/initializers/biscuit.rb` from your answers
|
|
48
|
+
- Scan your codebase for existing cookies and third-party tracking scripts
|
|
49
|
+
(Google Analytics, GTM, Meta Pixel, etc.) and help you wrap them with
|
|
50
|
+
`biscuit_allowed?` guards
|
|
51
|
+
- Add integration tests and run them
|
|
52
|
+
- Optionally commit everything
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Manual installation
|
|
25
57
|
|
|
26
58
|
Add to your `Gemfile`:
|
|
27
59
|
|
data/lib/biscuit/version.rb
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
|
|
3
|
+
module Biscuit
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Installs the biscuit-rails Claude Code setup skill into .claude/skills/biscuit-install/"
|
|
9
|
+
|
|
10
|
+
def copy_claude_skill
|
|
11
|
+
empty_directory ".claude/skills/biscuit-install"
|
|
12
|
+
copy_file "SKILL.md", ".claude/skills/biscuit-install/SKILL.md"
|
|
13
|
+
|
|
14
|
+
say ""
|
|
15
|
+
say " Claude Code skill installed at .claude/skills/biscuit-install/SKILL.md", :green
|
|
16
|
+
say ""
|
|
17
|
+
say " Open Claude Code in this project and run:", :cyan
|
|
18
|
+
say " /biscuit-install", :cyan
|
|
19
|
+
say ""
|
|
20
|
+
say " The skill will check compatibility, configure the gem, audit your existing", :cyan
|
|
21
|
+
say " cookies and tracking scripts, add tests, and optionally commit.", :cyan
|
|
22
|
+
say ""
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: biscuit-install
|
|
3
|
+
description: Install and configure the biscuit-rails GDPR cookie consent gem. Checks compatibility, installs the gem, configures categories and position, audits existing cookies and tracking scripts, adds integration tests, and optionally commits.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# biscuit-install
|
|
8
|
+
|
|
9
|
+
Complete installation and setup of biscuit-rails in this Rails app. Work through each step in order, confirming with the user before making any changes.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Step 1 — Compatibility check
|
|
14
|
+
|
|
15
|
+
Read `Gemfile`, `Gemfile.lock`, and `.ruby-version` (if present) to check:
|
|
16
|
+
|
|
17
|
+
- **Ruby >= 3.2** — stop with a clear error if not met
|
|
18
|
+
- **Rails >= 8.0** — check `Gemfile.lock` for the rails version; stop if not met
|
|
19
|
+
- **Asset pipeline** — check Gemfile for `propshaft`. If absent, warn that `stylesheet_link_tag "biscuit/biscuit"` may need adjustment
|
|
20
|
+
- **JS setup** — check for `importmap-rails` vs `jsbundling-rails`/`vite_rails`. Note the difference for Step 5
|
|
21
|
+
- **Stimulus** — check for `stimulus-rails` or `hotwire-rails`. Warn if absent — Stimulus must be installed for the banner to work
|
|
22
|
+
- **Conflicts** — check for other cookie consent gems (`eu_cookie_law`, `cookieconsent`, `cookie_law`). Warn if found
|
|
23
|
+
|
|
24
|
+
Report findings before proceeding.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Step 2 — Add gem to Gemfile
|
|
29
|
+
|
|
30
|
+
Check if `biscuit-rails` already appears in the Gemfile. If not:
|
|
31
|
+
|
|
32
|
+
- Add `gem "biscuit-rails"` to the Gemfile
|
|
33
|
+
- Run `bundle install`
|
|
34
|
+
|
|
35
|
+
If already present, skip this step.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 3 — Mount the engine
|
|
40
|
+
|
|
41
|
+
Check `config/routes.rb` for an existing `mount Biscuit::Engine` line. If absent, add it inside the `routes.draw` block:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
mount Biscuit::Engine, at: "/biscuit"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Step 4 — Configure the initializer
|
|
50
|
+
|
|
51
|
+
Ask the user the following questions before writing anything:
|
|
52
|
+
|
|
53
|
+
1. **Banner position** — top or bottom? (default: `bottom`)
|
|
54
|
+
2. **Cookie categories** — which categories beyond `necessary` are needed? Options: `analytics`, `marketing`, `preferences`, or custom names. (default: `analytics` and `marketing`)
|
|
55
|
+
3. **Reload on consent** — should the page reload after the user saves consent, so conditionally-loaded scripts activate immediately? (default: `false`)
|
|
56
|
+
4. **Privacy policy URL** — where does your privacy policy live? (default: `"/privacy"`)
|
|
57
|
+
5. **Cookie lifetime** — how many days should consent last? (default: `365`)
|
|
58
|
+
|
|
59
|
+
Then create `config/initializers/biscuit.rb` based on their answers. Example output:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
Biscuit.configure do |config|
|
|
63
|
+
config.position = :bottom
|
|
64
|
+
config.privacy_policy_url = "/privacy"
|
|
65
|
+
config.cookie_expires_days = 365
|
|
66
|
+
|
|
67
|
+
config.categories = {
|
|
68
|
+
necessary: { required: true },
|
|
69
|
+
analytics: { required: false },
|
|
70
|
+
marketing: { required: false }
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If `config/initializers/biscuit.rb` already exists, show the current content and ask before overwriting.
|
|
76
|
+
|
|
77
|
+
If custom category names are used, remind the user to add matching i18n keys to their locale files — for example:
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
en:
|
|
81
|
+
biscuit:
|
|
82
|
+
categories:
|
|
83
|
+
my_category:
|
|
84
|
+
name: "My Category"
|
|
85
|
+
description: "Used for..."
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step 5 — Register the Stimulus controller
|
|
91
|
+
|
|
92
|
+
### If using importmap
|
|
93
|
+
|
|
94
|
+
Check `app/javascript/controllers/index.js`. If `biscuit/biscuit_controller` is not already imported, add:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
import BiscuitController from "biscuit/biscuit_controller"
|
|
98
|
+
application.register("biscuit", BiscuitController)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Ensure `application` is already imported at the top of that file (it will be in the standard Rails 8 scaffold).
|
|
102
|
+
|
|
103
|
+
### If using esbuild / jsbundling
|
|
104
|
+
|
|
105
|
+
The same import and register lines apply, but inform the user that `@hotwired/stimulus` must be marked as external in their esbuild config so it is not bundled twice:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
// esbuild.config.js
|
|
109
|
+
external: ["@hotwired/stimulus"]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Step 6 — Add stylesheet and banner to layout
|
|
115
|
+
|
|
116
|
+
Check `app/views/layouts/application.html.erb`:
|
|
117
|
+
|
|
118
|
+
- Add `<%= stylesheet_link_tag "biscuit/biscuit" %>` inside `<head>` if not already present
|
|
119
|
+
- Add `<%= biscuit_banner %>` as the first child of `<body>` if not already present
|
|
120
|
+
|
|
121
|
+
If the layout file doesn't exist at that path, ask the user which layout file to modify.
|
|
122
|
+
|
|
123
|
+
If the app uses `reload_on_consent: true` (from Step 4), use:
|
|
124
|
+
|
|
125
|
+
```erb
|
|
126
|
+
<%= biscuit_banner(reload_on_consent: true) %>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Step 7 — Cookie and tracking script audit
|
|
132
|
+
|
|
133
|
+
Scan the codebase for existing cookie and tracking usage that should be gated behind consent. Report all findings before making any changes — let the user decide what to wrap.
|
|
134
|
+
|
|
135
|
+
### Server-side cookies (Ruby)
|
|
136
|
+
|
|
137
|
+
Search `app/` for:
|
|
138
|
+
- `cookies[`, `cookies.permanent[`, `cookies.signed[`, `cookies.encrypted[`
|
|
139
|
+
|
|
140
|
+
For each result, determine whether it is a functional/necessary cookie (session, CSRF, etc.) or a tracking cookie. Non-necessary cookies should be wrapped in the relevant controller:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
if Biscuit::Consent.new(cookies).allowed?(:analytics)
|
|
144
|
+
cookies[:my_tracking_cookie] = { value: "...", expires: 1.year }
|
|
145
|
+
end
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Client-side storage (JavaScript)
|
|
149
|
+
|
|
150
|
+
Search `app/assets/` and `app/javascript/` for:
|
|
151
|
+
- `document.cookie`
|
|
152
|
+
- `localStorage.setItem`
|
|
153
|
+
- `sessionStorage.setItem`
|
|
154
|
+
|
|
155
|
+
Non-necessary writes should check the `biscuit_consent` cookie before setting.
|
|
156
|
+
|
|
157
|
+
### Third-party scripts (layout/views)
|
|
158
|
+
|
|
159
|
+
Search `app/views/layouts/` and `app/views/` for known analytics and marketing patterns:
|
|
160
|
+
|
|
161
|
+
| Pattern | Category |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `gtag(`, `googletagmanager.com`, `_gaq`, `ga(` | analytics |
|
|
164
|
+
| `GTM-` | analytics |
|
|
165
|
+
| `fbq(`, `connect.facebook.net` | marketing |
|
|
166
|
+
| `intercomSettings`, `widget.intercom.io` | marketing |
|
|
167
|
+
| `hj(`, `static.hotjar.com` | analytics |
|
|
168
|
+
| `hs-script-loader` | marketing |
|
|
169
|
+
| `_linkedin_data_partner_id` | marketing |
|
|
170
|
+
|
|
171
|
+
For each match, show the file, line number, and suggested wrapping:
|
|
172
|
+
|
|
173
|
+
```erb
|
|
174
|
+
<% if biscuit_allowed?(:analytics) %>
|
|
175
|
+
<!-- existing script -->
|
|
176
|
+
<% end %>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Ask the user to confirm each wrapping before applying it.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Step 8 — Add integration tests
|
|
184
|
+
|
|
185
|
+
Check whether the app uses Minitest (`test/`) or RSpec (`spec/`).
|
|
186
|
+
|
|
187
|
+
### Minitest
|
|
188
|
+
|
|
189
|
+
If `test/integration/biscuit_consent_test.rb` does not exist, create it:
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
require "test_helper"
|
|
193
|
+
|
|
194
|
+
class BiscuitConsentTest < ActionDispatch::IntegrationTest
|
|
195
|
+
test "banner is shown on first visit" do
|
|
196
|
+
get "/"
|
|
197
|
+
assert_response :success
|
|
198
|
+
assert_select "[data-controller='biscuit']"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
test "biscuit_allowed? returns false before consent" do
|
|
202
|
+
get "/"
|
|
203
|
+
assert_equal false, Biscuit::Consent.new(cookies).allowed?(:analytics)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
test "biscuit_allowed? for necessary always returns true" do
|
|
207
|
+
get "/"
|
|
208
|
+
assert_equal true, Biscuit::Consent.new(cookies).allowed?(:necessary)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
test "accept all sets consent cookie" do
|
|
212
|
+
post "/biscuit/consent", params: {},
|
|
213
|
+
headers: { "Content-Type" => "application/json" },
|
|
214
|
+
as: :json,
|
|
215
|
+
body: { categories: { analytics: true, marketing: true } }.to_json
|
|
216
|
+
assert_response :success
|
|
217
|
+
assert Biscuit::Consent.new(cookies).given?
|
|
218
|
+
assert Biscuit::Consent.new(cookies).allowed?(:analytics)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
test "reject all sets non-required categories to false" do
|
|
222
|
+
post "/biscuit/consent", params: {},
|
|
223
|
+
headers: { "Content-Type" => "application/json" },
|
|
224
|
+
as: :json,
|
|
225
|
+
body: { categories: { analytics: false, marketing: false } }.to_json
|
|
226
|
+
assert_response :success
|
|
227
|
+
assert Biscuit::Consent.new(cookies).given?
|
|
228
|
+
assert_equal false, Biscuit::Consent.new(cookies).allowed?(:analytics)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Adjust category names to match the categories configured in Step 4.
|
|
234
|
+
|
|
235
|
+
### RSpec
|
|
236
|
+
|
|
237
|
+
If `spec/requests/biscuit_consent_spec.rb` does not exist, create an equivalent using RSpec/Rails request spec syntax.
|
|
238
|
+
|
|
239
|
+
Run the new tests and confirm they pass before continuing.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Step 9 — Optional commit
|
|
244
|
+
|
|
245
|
+
Ask the user: "Would you like to commit these changes?"
|
|
246
|
+
|
|
247
|
+
If yes, stage only the files that were created or modified during this setup and commit:
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
git add config/routes.rb config/initializers/biscuit.rb \
|
|
251
|
+
app/views/layouts/application.html.erb \
|
|
252
|
+
app/javascript/controllers/index.js \
|
|
253
|
+
test/integration/biscuit_consent_test.rb
|
|
254
|
+
git commit -m "Install biscuit-rails cookie consent"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Do not use `git add -A` — only stage biscuit-related files.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Summary
|
|
262
|
+
|
|
263
|
+
After all steps complete, print a summary of:
|
|
264
|
+
- What was installed and configured
|
|
265
|
+
- Which tracking scripts were wrapped (if any)
|
|
266
|
+
- Any manual steps remaining (custom i18n keys, esbuild config, layouts other than `application.html.erb`)
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: biscuit-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gareth James
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-03-
|
|
10
|
+
date: 2026-03-31 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rails
|
|
@@ -51,6 +51,8 @@ files:
|
|
|
51
51
|
- lib/biscuit/engine.rb
|
|
52
52
|
- lib/biscuit/rails.rb
|
|
53
53
|
- lib/biscuit/version.rb
|
|
54
|
+
- lib/generators/biscuit/install/install_generator.rb
|
|
55
|
+
- lib/generators/biscuit/install/templates/SKILL.md
|
|
54
56
|
homepage: https://github.com/garethfr/biscuit-rails
|
|
55
57
|
licenses:
|
|
56
58
|
- MIT
|