jekyll-client-search 0.3.0 → 0.3.2

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: ed1c7a635cc419d9fb130411ced8e64a473c016e8188e36ddd98ea6922a098f7
4
- data.tar.gz: f320844ded59274df991b1aa3d56fb22560e818105c5a0e682ea6e6a0c67df88
3
+ metadata.gz: d8289b785b9591674a7c171eea4ac3a3500765d79dd6679793a5c693879d7ed1
4
+ data.tar.gz: 2cc203750200af25356f75ca4e272747f39763f7abcfd9bedc9eff2ee9332b24
5
5
  SHA512:
6
- metadata.gz: a12fb0052f9a727baf957735cd23fc9759f46fe7b54977acd16ed63edb14b0d63e2594d3c2bee936c9317541f8810a654acf7a5369746c9d11c39699457cf351
7
- data.tar.gz: 46986b4c1a0107821f6932d8538c1aff0fcc386ddb9e9f787a4890da5f8af3ccd30a8c0b6b9257d928d3b52aa6fe625806136812cfbf781763a0f3a391cf9aa6
6
+ metadata.gz: 9ffd9295cb6e23c001c8c88acbdeb5fa8252a47dd646c58ef5f09b4a0233fe88b026cea4c5f8a4b0cc9b03e2907377e6b070af3066c2b266752ad1e49163beaf
7
+ data.tar.gz: 90261e2e563cf3649913211bcded60669fe55abec5a9e5caf1fa049e4342874d4a33e2ff058b72c35817ed96fed92b88a10c94731c2f7c7467940413f4444211
data/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.2 — 2026-09-10
6
+
7
+ ### Added
8
+ - Semgrep security scan in CI (`semgrep ci` job in `.github/workflows/ci.yml`) — runs on every push and pull request using the `SEMGREP_APP_TOKEN` secret and the Semgrep Pro engine with the organization's full policy (2,900+ rules)
9
+ - `.semgrep.yml` with custom Ruby ReDoS detection rules and usage documentation
10
+ - Semgrep step in pre-commit hook (`bin/install-hooks.sh`)
11
+ - Dependabot configuration for GitHub Actions (`.github/dependabot.yml`) — weekly SHA-pinned action updates
12
+ - CodeFactor and Semgrep badges in README.md
13
+ - Documentation of CodeQL, Semgrep, CodeFactor, and Dependabot in README.md, README.developer.md, and AGENTS.md
14
+ - Semgrep usage guide in README.developer.md (local commands, nosemgrep annotations, SHA pinning)
15
+
16
+ ### Fixed
17
+ - Pin all GitHub Actions to full 40-character commit SHAs with version comments to prevent supply-chain attacks via mutable tag repointing (Semgrep: `github-actions-mutable-action-tag`)
18
+ - Replace `Object.assign({}, entry, ...)` in benchmark with explicit field construction to avoid mass-assignment taint (Semgrep: `insecure-object-assign`)
19
+ - Replace manual arXiv query string with `URI.encode_www_form` for correct URL encoding (Semgrep: `avoid-tainted-http-request`)
20
+
21
+ ### Changed
22
+ - Add `nosemgrep` annotations with justifications for false positives (static ERB template, array-form `Open3.capture2`, fixed-host arXiv request) and acceptable risks (local loopback Ollama HTTP in tests and benchmarks)
23
+
24
+ ## 0.3.1 — 2026-09-09
25
+
26
+ ### Fixed
27
+ - Fix CodeQL `rb/bad-tag-filter` (high) in `DocumentBuilder#clean` — closing tag regex `</script\s*>` only matched whitespace before `>`, missing browser-accepted tags like `</script\t\n bar>`; changed to `</script[^>]*>` and `</style[^>]*>` to match any non-`>` content
28
+ - Fix CodeQL `rb/polynomial-redos` (high) in `RelatedTag` — `\s*` patterns between optional groups in SYNTAX regex caused O(n²) backtracking on input with many spaces; replaced single regex with token-split parser that validates each token individually
29
+
30
+ ### Changed
31
+ - Update `simplecov` 1.1.1 → 1.2.0
32
+ - Update `google-protobuf` 4.36.0 → 4.36.1 (transitive)
33
+ - Update `sass-embedded` 1.103.1 → 1.104.0 (transitive)
34
+ - Update `eslint` 10.9.1 → 10.10.0 (dev)
35
+ - Update `globals` 17.11.0 → 17.12.0 (dev)
36
+
5
37
  ## 0.3.0 — 2026-09-02
6
38
 
7
39
  ### Added
data/README.developer.md CHANGED
@@ -24,9 +24,50 @@ are required for the default test run.
24
24
  ## Quality checks and git hooks
25
25
 
26
26
  The project uses a focused quality stack: RuboCop (style), bundler-audit
27
- (security), RSpec (Ruby tests), and `npm test` (JavaScript tests). This
28
- covers the actionable ground without the maintenance burden of additional
29
- code-smell tools on a small focused gem.
27
+ (security), RSpec (Ruby tests), `npm test` (JavaScript tests), and Semgrep
28
+ (security scanning). This covers the actionable ground without the
29
+ maintenance burden of additional code-smell tools on a small focused gem.
30
+
31
+ External automated code review services:
32
+ - [CodeQL](https://codeql.github.com) — GitHub native security scanning
33
+ (Ruby + JavaScript), runs on every push.
34
+ - [Semgrep](https://semgrep.dev) — CI security scan using the Semgrep Pro
35
+ engine with the organization's full policy (2,900+ rules). Runs as a CI
36
+ job (`semgrep ci`) and in the pre-commit hook (custom rules only). See
37
+ `.semgrep.yml` for local configuration and usage instructions.
38
+ - [CodeFactor](https://www.codefactor.io/repository/github/gundestrup/jekyll-client-search) —
39
+ automated code review (RuboCop, Brakeman, bundler-audit, duplication).
40
+ - [Dependabot](https://docs.github.com/en/code-security/dependabot) — weekly
41
+ GitHub Actions version updates (SHA-pinned actions updated automatically).
42
+
43
+ ### Semgrep usage
44
+
45
+ The project uses two Semgrep scanning modes:
46
+
47
+ 1. **Pre-commit hook** — runs `semgrep scan --config .semgrep.yml` with only
48
+ the custom ReDoS rules defined in `.semgrep.yml`. Fast (~3s).
49
+ 2. **CI job** — runs `semgrep ci` with the full organization policy from the
50
+ Semgrep AppSec Platform, including Pro engine rules. Findings are uploaded
51
+ to the dashboard for triage.
52
+
53
+ Local commands:
54
+
55
+ ```bash
56
+ semgrep scan --config .semgrep.yml --error lib/ assets/ # custom rules only
57
+ semgrep ci --dry-run # full org policy, no upload
58
+ semgrep ci # full org policy, upload to dashboard
59
+ ```
60
+
61
+ To suppress a false positive or acceptable risk, add an inline annotation
62
+ with the full rule ID and a justification:
63
+
64
+ ```ruby
65
+ # nosemgrep: problem-based-packs.insecure-transport.ruby-stdlib.net-http-request.net-http-request
66
+ # Acceptable risk: local loopback Ollama test endpoint.
67
+ ```
68
+
69
+ All GitHub Actions are pinned to full 40-character commit SHAs with version
70
+ comments. Dependabot updates the SHAs and version comments automatically.
30
71
 
31
72
  ### Rake tasks
32
73
 
@@ -55,12 +96,12 @@ This installs two hooks:
55
96
 
56
97
  | Hook | What it runs | When |
57
98
  | --- | --- | --- |
58
- | `pre-commit` | `rubocop` only (~2s) | Before each commit |
99
+ | `pre-commit` | `rubocop + semgrep` (~5s) | Before each commit |
59
100
  | `pre-push` | `rubocop + rspec` (~15s) | Before each push |
60
101
 
61
- The pre-commit hook is intentionally fast (style only) to avoid bypassing
62
- with `--no-verify`. The full test suite runs on pre-push and in CI. Skip
63
- either with `git commit --no-verify` or `git push --no-verify`.
102
+ The pre-commit hook is intentionally fast (style + security) to avoid
103
+ bypassing with `--no-verify`. The full test suite runs on pre-push and in
104
+ CI. Skip either with `git commit --no-verify` or `git push --no-verify`.
64
105
 
65
106
  ### CI checks
66
107
 
@@ -71,6 +112,7 @@ request across Ruby 3.2/3.3/3.4 and Node 22/24:
71
112
  - `bundle exec bundle-audit check --update` (Ruby dependency security)
72
113
  - `npm audit --audit-level=high` (JavaScript dependency security)
73
114
  - `npm outdated` (non-blocking — warns about outdated npm packages)
115
+ - `semgrep ci` (security scan with custom rules from `.semgrep.yml`)
74
116
 
75
117
  ## Build-time related articles
76
118
 
data/README.md CHANGED
@@ -8,6 +8,8 @@
8
8
  [![License: AGPL v3](https://img.shields.io/badge/license-AGPL--3.0--or--later-blue.svg)](LICENSE)
9
9
  [![DeepWiki](https://img.shields.io/badge/DeepWiki-docs-7B68EE.svg)](https://deepwiki.com/gundestrup/jekyll-client-search)
10
10
  [![Coverage](https://img.shields.io/badge/coverage-100%25%20branches-brightgreen.svg)](#testing-strategy)
11
+ [![Semgrep](https://img.shields.io/badge/semgrep-scanning-brightgreen.svg)](https://semgrep.dev)
12
+ [![CodeFactor](https://www.codefactor.io/repository/github/gundestrup/jekyll-client-search/badge)](https://www.codefactor.io/repository/github/gundestrup/jekyll-client-search)
11
13
 
12
14
  A Jekyll plugin that generates a JSON document index for client-side search.
13
15
  Supports lexical search ([MiniSearch](https://lucaong.github.io/minisearch/),
@@ -1140,10 +1142,30 @@ bundle exec rake ci
1140
1142
 
1141
1143
  GitHub Actions are configured in `.github/workflows/`:
1142
1144
 
1143
- - `ci.yml` runs the test and gem build checks on pushes and pull requests.
1145
+ - `ci.yml` runs the test and gem build checks on pushes and pull requests,
1146
+ plus a Semgrep security scan job.
1144
1147
  - `release.yml` runs on `v*` tags or manual dispatch, verifies the gem, and
1145
1148
  publishes it using RubyGems trusted publishing.
1146
1149
 
1150
+ Additional automated code quality and security services:
1151
+
1152
+ - [CodeQL](https://codeql.github.com) — GitHub native code scanning for
1153
+ security vulnerabilities (Ruby + JavaScript).
1154
+ - [Semgrep](https://semgrep.dev) — CI security scan using the Semgrep Pro
1155
+ engine with the organization's full policy (2,900+ rules). Custom ReDoS
1156
+ detection rules are defined in `.semgrep.yml`. Findings are triaged on the
1157
+ [Semgrep AppSec Platform](https://semgrep.dev) dashboard. False positives
1158
+ and acceptable risks are annotated inline with `# nosemgrep: rule.id`.
1159
+ - [CodeFactor](https://www.codefactor.io/repository/github/gundestrup/jekyll-client-search) —
1160
+ automated code review with RuboCop, Brakeman, bundler-audit, and duplication
1161
+ checks.
1162
+ - [Dependabot](https://docs.github.com/en/code-security/dependabot) — weekly
1163
+ checks for GitHub Actions version updates (SHA-pinned actions are kept
1164
+ up to date automatically).
1165
+
1166
+ All GitHub Actions are pinned to full 40-character commit SHAs with version
1167
+ comments to prevent supply-chain attacks via mutable tag repointing.
1168
+
1147
1169
  Before enabling releases:
1148
1170
 
1149
1171
  1. Configure the GitHub repository as a RubyGems trusted publisher.
@@ -67,8 +67,8 @@ module Jekyll
67
67
 
68
68
  def clean(value)
69
69
  cleaned = value.to_s
70
- .gsub(%r{<script\b[^>]*>.*?</script\s*>}mi, " ")
71
- .gsub(%r{<style\b[^>]*>.*?</style\s*>}mi, " ")
70
+ .gsub(%r{<script\b[^>]*>.*?</script[^>]*>}mi, " ")
71
+ .gsub(%r{<style\b[^>]*>.*?</style[^>]*>}mi, " ")
72
72
  .gsub(/\{%.*?%\}/m, " ")
73
73
  .gsub(/\{\{.*?\}\}/m, " ")
74
74
  .gsub(/!\[[^\]]*\]\([^)]*\)/, " ")
@@ -14,23 +14,39 @@ module Jekyll
14
14
  # When +related.enabled+ is false the tag renders nothing, so it is safe
15
15
  # to leave in a layout even when the feature is off.
16
16
  class RelatedTag < Liquid::Tag
17
- SYNTAX = /\A(sort:(\w+))?\s*(max:(\d+))?\s*(no_scripts)?\z/
17
+ TOKEN_SYNTAX = /\A(sort:\w+|max:\d+|no_scripts)\z/
18
18
 
19
19
  def initialize(tag_name, markup, tokens)
20
20
  super
21
21
  @markup = markup.to_s.strip
22
- unless (match = @markup.match(SYNTAX))
23
- raise Liquid::SyntaxError,
24
- "related_articles: invalid syntax. Use {% related_articles %}, " \
25
- "{% related_articles sort:date %}, {% related_articles max:3 %}, " \
26
- "or {% related_articles no_scripts %}"
27
- end
22
+ parse_tokens(@markup)
23
+ end
24
+
25
+ def parse_tokens(markup)
26
+ @sort = nil
27
+ @max_items = nil
28
+ @include_scripts = true
29
+ return if markup.empty?
30
+
31
+ markup.split(/\s+/).each { |token| apply_token(token) }
32
+ end
33
+
34
+ def apply_token(token)
35
+ raise Liquid::SyntaxError, syntax_error_msg unless token.match(TOKEN_SYNTAX)
28
36
 
29
- @sort = match[2] if match[2]
30
- @max_items = match[4].to_i if match[4]
31
- raise Liquid::SyntaxError, "related_articles: max must be greater than zero" if @max_items && @max_items < 1
37
+ case token
38
+ when /\Asort:(\w+)\z/ then @sort = Regexp.last_match(1)
39
+ when /\Amax:(\d+)\z/
40
+ @max_items = Regexp.last_match(1).to_i
41
+ raise Liquid::SyntaxError, "related_articles: max must be greater than zero" if @max_items < 1
42
+ when "no_scripts" then @include_scripts = false
43
+ end
44
+ end
32
45
 
33
- @include_scripts = match[5].nil?
46
+ def syntax_error_msg
47
+ "related_articles: invalid syntax. Use {% related_articles %}, " \
48
+ "{% related_articles sort:date %}, {% related_articles max:3 %}, " \
49
+ "or {% related_articles no_scripts %}"
34
50
  end
35
51
 
36
52
  def render(context)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module ClientSearch
5
- VERSION = "0.3.0"
5
+ VERSION = "0.3.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-client-search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Svend Gundestrup