Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .bundler-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Advisories deliberately accepted, with the reason and the exit condition.
# CI reads this file by default (`bundler-audit check --update`), so an entry
# here is applied by the same command a contributor runs locally, and removing
# one shows up in a diff.
#
# Add entries only for an advisory that cannot be fixed by an upgrade, e.g.:
#
# ignore:
# # CVE-2026-00000 — rexml, reached only via rubocop (dev-only, never in a
# # consumer's resolution). Upstream fix pending; revisit after standard 2.x.
# - CVE-2026-00000
#
ignore: []
73 changes: 73 additions & 0 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Advisories

# Separate from main.yml on purpose. Folded into the Ruby workflow, a red
# Monday would be ambiguous between "an advisory landed" and "a spec broke".
# It is still not a one-cause signal: fetching the advisory database and
# evaluating the lockfile are split into two named steps below precisely so
# the step name says which of the two failed.
#
# Do NOT add this job to branch protection as a required status check while
# the `paths:` filter below is in place. A path-filtered workflow that does
# not trigger reports no status at all, so every PR that leaves the
# dependency files alone would sit on "Expected - Waiting for status" and
# never merge. Drop the filter or add a skip-shim job first.
on:
# Only PRs that actually move the resolution. An advisory published on a
# Tuesday should not turn a README PR red.
pull_request:
paths:
- 'Gemfile'
- 'Gemfile.lock'
- '*.gemspec'
- '.github/workflows/audit.yml'

push:
branches:
- main
paths:
- 'Gemfile'
- 'Gemfile.lock'
- '*.gemspec'
- '.github/workflows/audit.yml'

# Catches advisories published against a lockfile nobody touched, which is
# the case no push- or PR-triggered run can see.
schedule:
- cron: '0 6 * * 1'

# For running the sweep on demand. Note that GitHub disables scheduled
# workflows after 60 days of repository inactivity, and only the "Enable
# workflow" control in the Actions tab brings one back.
workflow_dispatch:

permissions:
contents: read

jobs:
audit:
runs-on: ubuntu-latest
name: bundler-audit
timeout-minutes: 10

steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
# Latest stable, not the matrix pin: bundler-audit reads Gemfile.lock
# as text and never loads the gem, so the interpreter is irrelevant
# here and a second hardcoded version would only drift.
ruby-version: 'ruby'
- name: Install bundler-audit
# Deliberately outside the bundle. The scanner has no business inside
# the lockfile it scans, and this keeps the dev bundle's resolution
# independent of the scanner's. Keep the version bound in step with
# CONTRIBUTING.md and MAINTAINING.md.
run: gem install bundler-audit --no-document -v '~> 0.9'
- name: Fetch the advisory database
# Split from the check so a transient clone failure is legible as
# itself rather than as "a gem is vulnerable". One retry, because the
# scheduled run is unattended 52 weeks a year.
run: bundler-audit update || (sleep 15 && bundler-audit update)
- name: Check Gemfile.lock against ruby-advisory-db
run: bundler-audit check
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ Thank you for your interest in contributing to Agentic! This guide will help you
- **Testing**: Use RSpec for tests, aim for >90% coverage on new code
- **Documentation**: Use YARD comments for all public APIs
- **Commit Messages**: Follow [Conventional Commits](https://www.conventionalcommits.org/)
- **Dependencies**: If a change moves `Gemfile.lock` or the gemspec, check it for known advisories first:

```bash
gem install bundler-audit -v '~> 0.9'
bundler-audit check --update
```

If your shell can't find `bundler-audit` after installing it, your gem bindir isn't on `PATH`; `gem exec bundler-audit check --update` works regardless on RubyGems 3.5+.

CI runs the same command on those changes and again every Monday. If it flags an advisory in a gem your change did not touch, say so in the PR rather than bundling an unrelated upgrade into it. An advisory that genuinely cannot be fixed by an upgrade goes in `.bundler-audit.yml` with a reason and an exit condition, where CI honors it and a reviewer can see it.

### Before You Code

Expand Down
4 changes: 2 additions & 2 deletions MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ Before any release:
# Run full test suite
bundle exec rake

# Check for security issues
bundle audit
# Check for security issues (gem install bundler-audit -v '~> 0.9')
bundler-audit check --update
```

2. **Create Release PR**
Expand Down
Loading