Bootprint
Reproduce the environment, not just the dependencies.
Bootprint is a local-first Ruby runtime fingerprint and compatibility diagnostic. It captures a sanitized description of an application environment, compares that description with CI, Docker, staging, or production, and turns raw drift into explanations, severity, evidence, remediation, and enforceable policy.
gem install bootprint
bootprint capture local
bootprint docker capture myapp:latest
bootprint diagnose local myapp-latest
Bootprint 0.2 combines a dependency compatibility analyzer, Rails boot inspector, environment-drift detector, and CI policy engine. Ordinary capture performs no network requests, suggested commands never execute automatically, and environment-variable values are never recorded.
Contents
- Why Bootprint
- What it inspects
- Five-minute start
- From capture to diagnosis
- Command reference
- Policy enforcement
- Rails inspection
- Docker comparison
- CI integration
- Reports and remediation
- Rules and plugins
- Privacy and security
- Platform support and performance
- Documentation
- Development
Why Bootprint
Gemfile.lock captures dependency resolution, but not the complete runtime contract. Ruby engine and patch level, native clients, libc, CPU architecture, Rails adapters, required configuration, filesystem behavior, and initializer ordering can all change application behavior.
Bootprint records those facts as deterministic schema-v2 JSON and evaluates them with 39 independently testable built-in rules. A finding answers four questions that a plain diff cannot:
- What changed?
- How dangerous is it?
- What is the likely impact?
- What should the developer do next?
CRITICAL Native extension platform mismatch
nokogiri targets arm64-darwin but production uses x86_64-linux.
Recommended fix:
$ bundle lock --add-platform x86_64-linux
$ bundle install
ERROR Required environment variable is missing
REDIS_URL is available locally but absent in production.
At a glance
| Capability | Bootprint 0.2 |
|---|---|
| Diagnostic knowledge | 39 built-in rules across runtime, dependencies, native libraries, configuration, filesystem, and Rails boot |
| Severity model | info, warning, error, critical |
| Report formats | Human terminal output, JSON, SARIF 2.1, Markdown |
| Snapshot contract | Deterministic schema v2 with in-memory v1 migration |
| Policy | Ignore, enable, disable, override severity, declare optional variables, require platforms |
| Integrations | Rails, Docker, GitHub Actions, GitLab CI, CircleCI, generic POSIX CI |
| Runtime dependencies | None |
| Data flow | Local only; no upload service or telemetry |
What it inspects
| Area | Captured metadata |
|---|---|
| Ruby runtime | Version, engine, patch level, platform, architecture, build description |
| Dependency system | Bundler and RubyGems versions, lockfile platforms, resolved gems, sources, checksums, native extensions |
| Native libraries | OpenSSL, libyaml, SQLite, PostgreSQL, MySQL, libc, compiler and header availability when detectable |
| Configuration | Environment-variable names and presence, Rails environment, adapters, framework settings |
| Filesystem | Temporary/log path availability, writability, path separators, case sensitivity, symlink behavior |
| Rails boot | Framework configuration, autoload/eager-load paths, initializers, and opt-in initializer timings |
| Docker | Image runtime, platforms, installed package metadata when available, workdir, entrypoint, command, permissions |
Bootprint deliberately does not collect credential values, database passwords, API tokens, cookies, session contents, full connection URLs, user data, or application source. Strict privacy mode additionally omits or normalizes hostnames, usernames, home paths, and process identifiers.
Five-minute start
Add Bootprint to a project:
group :development, :test do
gem "bootprint", require: false
end
Install and capture a named local baseline:
bundle install
bundle exec bootprint capture local
Capture another environment and diagnose the difference:
bundle exec bootprint capture production
bundle exec bootprint diagnose local production
Named captures live at .bootprint/NAME.json. An unnamed capture writes bootprint.lock:
bundle exec bootprint capture
bundle exec bootprint verify --against bootprint.lock
Use strict privacy when a snapshot may be attached to an issue or shared outside the team:
bundle exec bootprint capture support-case --privacy strict
bundle exec bootprint security audit .bootprint/support-case.json
From capture to diagnosis
Ruby process / Rails app / Docker image
|
v
sanitized collectors
|
v
deterministic schema-v2 snapshot
|
source + target
|
v
rules + .bootprint.yml policy
|
v
human | JSON | SARIF | Markdown + stable exit code
For example, compare a local macOS Rails environment with a Linux production image:
# macOS development machine
bundle exec bootprint capture macos-development
# Local Docker image; no port or running container is required
bundle exec bootprint docker capture ghcr.io/example/storefront:latest
# Explain only warning-or-higher runtime and dependency findings
bundle exec bootprint diagnose macos-development storefront-latest \
--only runtime,dependencies \
--minimum-severity warning
Raw diff remains available when every changed value matters. diagnose is the normal workflow because it applies compatibility knowledge and policy.
Command reference
| Command | Purpose |
|---|---|
bootprint capture [NAME] |
Capture a deterministic, sanitized schema-v2 snapshot |
bootprint diff SOURCE TARGET |
Show every raw environment difference |
bootprint diagnose SOURCE TARGET |
Explain compatibility findings and remediation |
bootprint diagnose --against PATH |
Compare the current process with a reference snapshot |
bootprint doctor |
Diagnose the health of the current environment |
bootprint verify --against PATH |
Enforce policy and return CI-safe exit codes |
bootprint fix --dry-run |
Preview remediation without changing files or running commands |
bootprint docker capture IMAGE |
Inspect a local image in an isolated temporary container |
bootprint docker compare IMAGE |
Show raw drift between the current environment and an image |
bootprint docker diagnose IMAGE |
Diagnose current-environment versus image compatibility |
bootprint ci verify |
Detect CI, emit native annotations, and enforce policy |
bootprint snapshot inspect PATH |
Inspect snapshot metadata safely |
bootprint snapshot validate PATH |
Validate schema and snapshot structure |
bootprint snapshot migrate PATH |
Migrate a legacy snapshot into a new file |
bootprint policy validate |
Validate policy with path and line-aware errors |
bootprint policy explain |
Display the effective merged policy |
bootprint security audit PATH |
Check an existing snapshot for likely sensitive values |
Diagnosis supports --format human|json|sarif|markdown, --only CATEGORY,..., and --minimum-severity LEVEL. Color is disabled when output is redirected or NO_COLOR is set.
Policy enforcement
Copy .bootprint.yml.example to .bootprint.yml and tailor it:
version: 1
mode: permissive
minimum_severity: warning
fail_on: [error, critical]
expected_platforms: [x86_64-linux]
ignore: [ruby-patch-level-drift]
allow:
environment_variables: [OPTIONAL_ANALYTICS_KEY]
rules:
missing-environment-variable:
severity: critical
redaction:
patterns: [TOKEN, SECRET, PASSWORD, PRIVATE_KEY]
Policies can disable rules, override severity, acknowledge known differences, declare optional environment variables, define deployment platforms and redaction patterns, and select strict or permissive behavior. Validate before CI enforcement:
bundle exec bootprint policy validate
bundle exec bootprint policy explain
bundle exec bootprint verify --against bootprint.lock
Exit codes are stable:
| Code | Meaning |
|---|---|
| 0 | No blocking findings |
| 1 | Policy violation |
| 2 | Invalid command or policy |
| 3 | Invalid or unsupported snapshot |
| 4 | Docker, plugin, filesystem, or internal failure |
Rails inspection
Bootprint lazily loads Rails integration only after Rails is present. Normal application startup is not profiled unless inspection is explicitly enabled.
BOOTPRINT_INSPECT=1 bin/rails bootprint:capture
bin/rails bootprint:doctor
BOOTPRINT_PROFILE_BOOT=1 bundle exec rails runner "Bootprint.capture.write('bootprint.lock')"
Rails capture includes the version and environment, framework defaults, eager loading, cache classes, paths, database/queue/cache/session adapters, Active Storage, Action Cable, mail delivery, time zone, logging, public-file serving, assets, and initializer order.
Opt-in profiling records initializer start and completion order, duration, exception metadata, newly loaded constant names, and a conservative network-operation heuristic. It never captures credentials, connection URLs, cookie contents, session contents, or user data.
Docker comparison
Docker inspection requires a local image containing Ruby. Bootprint checks that the image already exists, then runs a read-only, network-disabled --rm container with a fixed inspection script.
bootprint docker capture myapp:latest
bootprint docker diagnose myapp:latest --against local
Bootprint does not pull images, expose ports, persist temporary containers, inspect unrelated running containers, or upload captured data. If Docker is missing or unavailable, the CLI reports that condition with exit code 4.
CI integration
Commit a trusted bootprint.lock and enforce it in pull requests:
name: Bootprint
on:
pull_request:
push:
jobs:
environment-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- run: bundle exec bootprint ci verify --against bootprint.lock
bootprint ci verify detects GitHub Actions, GitLab CI, CircleCI, and generic POSIX CI environments. GitHub output includes workflow annotations and a Markdown job summary; SARIF output can be consumed by GitHub code scanning without inventing file locations.
Reports and remediation
Machine-readable JSON contains report schema version, source and target metadata, findings, evidence, remediation, suppression state, and execution metadata:
bootprint diagnose local production --format json > bootprint-report.json
bootprint diagnose local production --format sarif > bootprint.sarif
bootprint diagnose local production --format markdown > bootprint-report.md
Every actionable finding can include safe, structured repair guidance:
{
"rule_id": "missing-lockfile-platform",
"severity": "error",
"evidence": {
"current_platforms": ["arm64-darwin"],
"required_platforms": ["x86_64-linux"]
},
"remediation": {
"summary": "Add the deployment platform to the lockfile and rebuild the bundle.",
"commands": [
"bundle lock --add-platform <required-platform>",
"bundle install"
],
"files": ["Gemfile.lock"]
}
}
bootprint fix --dry-run renders those changes as a preview. Diagnosis and preview never execute remediation commands or modify application files.
Rules and plugins
Rules use a structured DSL and load without Rails:
Bootprint::Rules.define "redis-client-drift" do
name "Redis client mismatch"
category :dependencies
severity :warning
detect do |source, target|
source.dig("plugins", "redis") != target.dig("plugins", "redis")
end
explain do |_source, _target, evidence|
{ summary: "Redis clients differ.", evidence: evidence }
end
remediate "Pin the same redis-client release in Gemfile.lock.",
files: ["Gemfile.lock"]
end
Third-party gems can package collectors and rules behind plugin API version 1:
Bootprint::Plugin.api_version "1"
Bootprint::Plugins.register "sidekiq" do
collector SidekiqBootprint::Collector
rules SidekiqBootprint::Rules
end
A broken plugin becomes a warning and does not prevent core capture unless strict policy mode is enabled. See Writing custom rules and Creating plugins for the compatibility contract.
Privacy and security
Environment inspection is sensitive, so Bootprint applies defensive handling at collection and serialization boundaries:
- Environment variables are represented by name and presence only.
- Recursive redaction detects secret-like names, credentials in URLs, authorization headers, private keys, JWT-like tokens, database connection strings, and high-entropy values.
- Home paths are normalized; strict mode removes further host and process identity.
- Unknown snapshot fields are preserved where practical during migration, then audited like known fields.
- Standard capture performs no network requests and enables no telemetry.
- Suggested shell commands remain inert data.
Before sharing any snapshot, run:
bootprint security audit bootprint.lock
Security issues should follow the private reporting process in SECURITY.md, not a public issue containing a snapshot.
Platform support and performance
The focused automated matrix covers the oldest supported MRI release on Linux and Ruby 3.4 on Linux, macOS, and Windows. Fixture coverage includes macOS development, Linux CI, Docker production, Windows development, ARM64 development, x86-64 deployment, Rails, and plain Ruby projects.
Bootprint is designed around these practical limits:
| Operation | Target |
|---|---|
| Core CLI startup | Under 250 ms where practical |
| Standard Ruby snapshot | Under 1 second |
| Rails inspection | Under 3 seconds, excluding application boot |
| Ordinary snapshot comparison | Under 500 ms |
Rails, Docker, SARIF, and plugin code are lazy-loaded so basic CLI use does not pay for integrations it does not invoke. Performance varies with Ruby, filesystem, dependency count, and host load.
Documentation
- Installation
- Five-minute quick start
- Capturing environments
- Comparing environments
- Understanding findings
- Policy configuration
- Rails integration
- Docker support
- CI integration
- Writing custom rules
- Creating plugins
- Privacy and redaction
- Snapshot schema
- Troubleshooting
- Maintainer setup
Development
bundle install
bundle exec rake test
bundle exec rubocop lib test exe Rakefile bootprint.gemspec
gem build bootprint.gemspec
Read CONTRIBUTING.md for the development workflow, ARCHITECTURE.md for system boundaries, and RELEASE.md for packaging and signed-release instructions.
Status and limitations
Bootprint 0.2 is local-first and pre-1.0. It diagnoses captured facts; it does not guarantee perfect binary compatibility, query remote gem indexes during capture, execute suggested repairs, or provide malware isolation. Yanked-gem detection uses metadata supplied by snapshots or trusted plugins because standard capture deliberately avoids network access.
Bootprint is released under the MIT License.