Skip to content

Publish only a whitelist of files in the gem - #5

Merged
Fivell merged 5 commits into
masterfrom
chore/exclude-specs-from-gem
Oct 1, 2026
Merged

Fivell merged 5 commits into
masterfrom
chore/exclude-specs-from-gem

Conversation

@Fivell

@Fivell Fivell commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

What

files is now an explicit whitelist, instead of publishing everything tracked minus whatever someone remembered to exclude.

s.files         = `git ls-files -z -- lib app vendor config db exe bin README.md LICENSE`.split("\x0")

A reject list only removes what someone named. That is how 2 README images ended up in the published gem — each needed its own pattern, and none was added until an audit went looking. A whitelist inverts the default: a new directory does not reach consumers until it is listed.

Every root Rails::Engine loads from is listed, present in this repo or not — app, lib, config, db, vendor per rails/engine/configuration.rb. A whitelist fails quietly — git ls-files -- config against a tree with no config/ exits 0 and prints nothing — so the day someone adds config/initializers/foo.rb the gem would install, boot, and never run it. Naming the roots up front costs nothing (git ls-files on a missing path is a no-op) and removes that trapdoor.

Selected through git ls-files rather than Dir[...] so the artifact stays tracked-only — an untracked or generated file under lib/ cannot leak into a release — and so files carries no directory entries.

Verified

$ gem build active_admin_filters_visibility.gemspec
11 files / 1.3M   ->   5 files / 12K

All 5 files that remain. Nothing is added, and the entire runtime payload — the 3 files under app/, lib/ — is unchanged:

LICENSE
README.md
app/assets/javascripts/active_admin_filters_visibility.js
lib/active_admin_filters_visibility.rb
lib/active_admin_filters_visibility/version.rb

All 6 files that leave the package:

Gemfile
Rakefile
active_admin_filters_visibility.gemspec
package.json
screen/example_aa_filters_ordering.gif
screen/example_aa_filters_visibility.gif

The 4 root files leave on purpose — nothing under lib/ or app/ reads any of them. Gemfile and Rakefile drive the development bundle and bundler/gem_tasks from a git checkout. package.json is the npm manifest; it publishes src/**/*, which prepublishOnly generates from app/assets/javascripts/, also in a checkout. And the full spec is already in the package's own metadata.gz, so the .gemspec file inside data.tar.gz was a duplicate of it.

`git ls-files` with no filter published everything tracked, so the gem
is 1.3 MB of which ~12 KB is the actual library. The bulk is two README
demo gifs:

  screen/example_aa_filters_ordering.gif     722 KB
  screen/example_aa_filters_visibility.gif   656 KB

98% of every download, for images referenced from README.md as
repo-relative paths — GitHub renders them out of the repo and nothing
ever reads them from the package.

The test/spec/features part of the filter is prophylactic: master has
no spec/ today, but without a filter the first suite added ships to
consumers automatically.

Drops `s.test_files` while here: RubyGems deprecated it, and it pointed
at paths that do not exist on master.

Packaged: 11 files / 1.3 MB -> 9 files / 12 KB.
@Fivell
Fivell force-pushed the chore/exclude-specs-from-gem branch from 39e6cfc to 48911bd Compare September 30, 2026 10:51
@Fivell Fivell changed the title Keep specs and README gifs out of the packaged gem (1.33 MB -> 12 KB) Keep README gifs out of the packaged gem (1.3 MB -> 12 KB) Sep 30, 2026
The reject list only removes directories someone remembered to name.
That is how spec/, .github/, screen/ and img/ got published in the
first place — each needed a new pattern, and none was added until an
audit went looking.

A whitelist inverts the default: a new directory in the repo does not
reach consumers until it is listed. Same shape the sibling gems
activeadmin-oidc and credit_card_validations already use.

Drops the remaining dev-only files the reject form kept:

  active_admin_filters_visibility.gemspec Gemfile package.json Rakefile

Packaged: 9 -> 5 files. The runtime payload — everything
under lib/, app/, vendor/, config/ and exe/ — is byte-identical to
before, verified by diffing the built .gem both ways.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The whitelist omits files that the PR says will remain in the package.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

This PR narrows the gem’s packaged files to keep README demo GIFs out of downloads.

Changes:

  • Replaces the git ls-files package list with a whitelist.
  • Removes the deprecated s.test_files setting.
File Description
active_admin_filters_visibility.gemspec Changes the packaged-file list and removes test-file metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread active_admin_filters_visibility.gemspec Outdated
`Dir[...]` globs the working tree, so any untracked or generated file
under lib/, app/ or vendor/ would be published in a release — the build
artifact depended on the releaser's local checkout. The reject form it
replaced was tracked-only; this restores that property while keeping
the whitelist.

`git ls-files -- <paths>` also returns files only, where `Dir["**/*"]`
returns directory entries too, so `files` no longer carries entries
RubyGems just ignores.

Built .gem is byte-for-byte the same file list as the Dir[] version.
@Fivell Fivell changed the title Keep README gifs out of the packaged gem (1.3 MB -> 12 KB) Publish only a whitelist of files in the gem Sep 30, 2026
A whitelist fails quietly: `git ls-files -- config` against a tree with
no config/ exits 0 and prints nothing, so the day someone adds
`config/initializers/foo.rb` the gem installs, boots, and the
initializer never runs. Nothing in `gem build` warns.

That is not hypothetical for this family of gems —
active_admin_datetimepicker's Ransack predicates live in exactly such
an initializer, and its filters return no results without them.

So list every root Rails::Engine loads from (lib app vendor config exe
bin) in all of them, present or not, instead of only the ones that
happen to exist today. No package changes: the built .gem is identical
in every gem.
The whitelist names every root a Rails::Engine loads from so the list does
not silently lose a directory the day one is added. db was missing:
railties-8.1.4 lib/rails/engine/configuration.rb registers

    paths.add "db"
    paths.add "db/migrate"
    paths.add "db/seeds.rb"

as engine roots, and `rake <engine>:install:migrations` copies out of
db/migrate — so a migration added later would have installed with the gem
and been invisible. public/ is deliberately not added: it is registered by
Rails::Application, not Rails::Engine.

No change to the current artifact. `gem build` before and after produces
the same 5 files:

    LICENSE
    README.md
    app/assets/javascripts/active_admin_filters_visibility.js
    lib/active_admin_filters_visibility.rb
    lib/active_admin_filters_visibility/version.rb

`git ls-files -- db` against a tree with no db/ exits 0 and prints nothing.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The whitelist preserves the complete runtime payload while intentionally excluding development-only and media files.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@Fivell
Fivell merged commit de2e975 into master Oct 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants