bootprint 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 +7 -0
- data/.bootprint.yml.example +37 -0
- data/ARCHITECTURE.md +46 -0
- data/CHANGELOG.md +26 -0
- data/CODE_OF_CONDUCT.md +7 -0
- data/CONTRIBUTING.md +28 -0
- data/LICENSE +21 -0
- data/README.md +422 -0
- data/RELEASE.md +78 -0
- data/ROADMAP.md +15 -0
- data/SECURITY.md +47 -0
- data/assets/branding/README.md +24 -0
- data/assets/branding/bootprint-logo-128.png +0 -0
- data/assets/branding/bootprint-logo-512.png +0 -0
- data/assets/branding/bootprint-logo-64.png +0 -0
- data/assets/branding/bootprint-logo.png +0 -0
- data/docs/capturing.md +9 -0
- data/docs/ci.md +21 -0
- data/docs/comparing.md +22 -0
- data/docs/custom-rules.md +7 -0
- data/docs/docker.md +7 -0
- data/docs/findings.md +7 -0
- data/docs/installation.md +7 -0
- data/docs/maintainer-setup.md +54 -0
- data/docs/plugins.md +7 -0
- data/docs/policy.md +9 -0
- data/docs/privacy.md +7 -0
- data/docs/quick-start.md +9 -0
- data/docs/rails.md +13 -0
- data/docs/snapshot-schema.md +9 -0
- data/docs/troubleshooting.md +8 -0
- data/exe/bootprint +6 -0
- data/lib/bootprint/analysis.rb +13 -0
- data/lib/bootprint/cli.rb +458 -0
- data/lib/bootprint/collectors/environment.rb +21 -0
- data/lib/bootprint/collectors/filesystem.rb +40 -0
- data/lib/bootprint/collectors/gems.rb +96 -0
- data/lib/bootprint/collectors/libraries.rb +75 -0
- data/lib/bootprint/collectors/operating_system.rb +50 -0
- data/lib/bootprint/collectors/rails.rb +97 -0
- data/lib/bootprint/collectors/runtime.rb +34 -0
- data/lib/bootprint/collectors/toolchain.rb +23 -0
- data/lib/bootprint/configuration.rb +38 -0
- data/lib/bootprint/diagnosis.rb +95 -0
- data/lib/bootprint/diff.rb +47 -0
- data/lib/bootprint/docker.rb +149 -0
- data/lib/bootprint/doctor.rb +13 -0
- data/lib/bootprint/errors.rb +9 -0
- data/lib/bootprint/formatters/human.rb +55 -0
- data/lib/bootprint/formatters/json.rb +12 -0
- data/lib/bootprint/formatters/markdown.rb +27 -0
- data/lib/bootprint/formatters/sarif.rb +54 -0
- data/lib/bootprint/formatters.rb +22 -0
- data/lib/bootprint/initializer_profiler.rb +93 -0
- data/lib/bootprint/plugins.rb +90 -0
- data/lib/bootprint/policy.rb +191 -0
- data/lib/bootprint/rails_state.rb +17 -0
- data/lib/bootprint/railtie.rb +36 -0
- data/lib/bootprint/rules/builtin.rb +383 -0
- data/lib/bootprint/rules/finding.rb +40 -0
- data/lib/bootprint/rules/registry.rb +20 -0
- data/lib/bootprint/rules/rule.rb +153 -0
- data/lib/bootprint/rules.rb +58 -0
- data/lib/bootprint/sanitizer.rb +105 -0
- data/lib/bootprint/schema.rb +111 -0
- data/lib/bootprint/security/auditor.rb +63 -0
- data/lib/bootprint/snapshot.rb +122 -0
- data/lib/bootprint/version.rb +5 -0
- data/lib/bootprint.rb +38 -0
- data/lib/tasks/bootprint.rake +18 -0
- metadata +120 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4d4c97b0a32461ce90a144849e6fb9c1416682f0b682039cd5e89cfb2d2ca171
|
|
4
|
+
data.tar.gz: d228014f4dca8d75d8aa03eab9b343e8ee0a9449e5cc8e50220c91549a305803
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ae4e15f6cd2655c988c3f7b845d417240e433b8e1384c5145b984bc0c243fbb0ad10c5fd09fb93cd8c38570b0682538a459e98db931a77c43c16686bf2963d71
|
|
7
|
+
data.tar.gz: 7070a15b2d7a82018cb526c9b0fad201ea8259f87a6daa63641ad5be745fe9eee899348c33f41d1f80879e2a103cb6f3a89444eb65b839ec70660e587b76cc5c
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
mode: permissive
|
|
4
|
+
minimum_severity: warning
|
|
5
|
+
fail_on:
|
|
6
|
+
- error
|
|
7
|
+
- critical
|
|
8
|
+
|
|
9
|
+
ignore:
|
|
10
|
+
- ruby-patch-level-drift
|
|
11
|
+
|
|
12
|
+
expected_platforms:
|
|
13
|
+
- x86_64-linux
|
|
14
|
+
|
|
15
|
+
allow:
|
|
16
|
+
environment_variables:
|
|
17
|
+
- OPTIONAL_ANALYTICS_KEY
|
|
18
|
+
paths:
|
|
19
|
+
- environment.operating_system.processors
|
|
20
|
+
|
|
21
|
+
rules:
|
|
22
|
+
missing-environment-variable:
|
|
23
|
+
severity: critical
|
|
24
|
+
bundler-version-drift:
|
|
25
|
+
severity: warning
|
|
26
|
+
|
|
27
|
+
redaction:
|
|
28
|
+
patterns:
|
|
29
|
+
- TOKEN
|
|
30
|
+
- SECRET
|
|
31
|
+
- PASSWORD
|
|
32
|
+
- PRIVATE_KEY
|
|
33
|
+
safe_list:
|
|
34
|
+
- PUBLIC_TOKEN_NAME
|
|
35
|
+
|
|
36
|
+
plugins:
|
|
37
|
+
strict: false
|
data/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Bootprint is a local-first Ruby gem with no runtime dependencies beyond Ruby standard libraries.
|
|
4
|
+
|
|
5
|
+
## Data flow
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Collectors / plugins
|
|
9
|
+
↓
|
|
10
|
+
recursive sanitization
|
|
11
|
+
↓
|
|
12
|
+
schema-v2 snapshot ──→ deterministic JSON
|
|
13
|
+
↓
|
|
14
|
+
rules + project policy
|
|
15
|
+
↓
|
|
16
|
+
structured findings
|
|
17
|
+
↓
|
|
18
|
+
human / JSON / SARIF / Markdown / CI annotations
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Boundaries
|
|
22
|
+
|
|
23
|
+
- `Bootprint::Snapshot` coordinates collectors, migration, validation, deterministic ordering, and persistence.
|
|
24
|
+
- `Bootprint::Schema` owns the current version and migrates schema v1 in memory while preserving unknown top-level fields under `extensions`.
|
|
25
|
+
- Collectors return JSON-safe hashes and do not perform network requests.
|
|
26
|
+
- `Bootprint::Sanitizer` recursively strips credential-bearing URLs, token-like values, private keys, secret-named fields, and identifying paths.
|
|
27
|
+
- `Bootprint::Rules::Rule` defines detection, explanation, metadata, severity, references, source location, and remediation contracts.
|
|
28
|
+
- `Bootprint::Diagnosis` evaluates rules and produces a stable report independent of presentation.
|
|
29
|
+
- `Bootprint::Policy` validates project control with safe YAML loading and line-aware errors.
|
|
30
|
+
- Formatters contain no detection logic.
|
|
31
|
+
- Docker and security-audit code are lazy-loaded by their CLI commands.
|
|
32
|
+
- Rails hooks load only when `Rails::Railtie` already exists; expensive profiling requires `BOOTPRINT_PROFILE_BOOT=1`.
|
|
33
|
+
|
|
34
|
+
## Plugin contract
|
|
35
|
+
|
|
36
|
+
Plugin API version `1` accepts a collector class responding to `.capture` or `#capture`, and a rules module responding to `.install` or `.register`. Collector output crosses the same recursive-redaction boundary as core data. Exceptions are converted to snapshot warnings unless strict mode is active.
|
|
37
|
+
|
|
38
|
+
Plugins cannot inject executable content into snapshots. Registering a plugin is equivalent to requiring trusted Ruby code and therefore remains an application-level trust decision.
|
|
39
|
+
|
|
40
|
+
## Performance model
|
|
41
|
+
|
|
42
|
+
The standard capture path uses in-process APIs, file metadata, and `PATH` presence checks. It performs no package-manager calls, remote resolution, or Docker inspection. Comparison is an in-memory traversal. Optional Rails and Docker work stays out of ordinary CLI startup.
|
|
43
|
+
|
|
44
|
+
## Exit-code ownership
|
|
45
|
+
|
|
46
|
+
CLI parsing/policy errors use `2`, snapshot/schema errors use `3`, and subsystem/internal failures use `4`. Diagnosis reports determine whether `1` applies from policy `fail_on`; presentation formats do not affect enforcement.
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Bootprint are documented here. The project follows Semantic Versioning before and after 1.0 where practical.
|
|
4
|
+
|
|
5
|
+
## 0.2.0 - 2026-08-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Stable snapshot schema v2 with deterministic output, v1 migration, inspection, validation, and safe migration commands.
|
|
10
|
+
- Formal rule DSL and 39 built-in compatibility rules with cause, impact, evidence, severity, and remediation.
|
|
11
|
+
- `diagnose`, `fix --dry-run`, policy, snapshot, Docker, CI, and security-audit commands.
|
|
12
|
+
- Human, JSON report-schema v1, SARIF 2.1, and Markdown output.
|
|
13
|
+
- Strict/permissive `.bootprint.yml` policies with rule controls, expected platforms, optional variables, and redaction patterns.
|
|
14
|
+
- Expanded Rails configuration inspection, opt-in initializer profiling, and Rails tasks.
|
|
15
|
+
- Read-only, network-disabled Docker image capture.
|
|
16
|
+
- Plugin API v1 with isolated failures.
|
|
17
|
+
- Recursive privacy hardening and strict privacy mode.
|
|
18
|
+
- Cross-platform fixtures, subprocess integration tests, CI matrix, examples, and public contributor documentation.
|
|
19
|
+
- Original Bootprint brand mark, packaged logo assets, README badges, and expanded product and workflow documentation.
|
|
20
|
+
- Release package validation, installed-gem smoke tests, GitHub security automation, and OIDC-based RubyGems trusted publishing.
|
|
21
|
+
- Focused four-job compatibility CI, grouped monthly dependency updates, and a weekly/manual security audit to reduce workflow noise.
|
|
22
|
+
- Presence-only handling for secret-named environment variables across the sanitizer and snapshot schema boundary.
|
|
23
|
+
|
|
24
|
+
## 0.1.0 - 2026-08-02
|
|
25
|
+
|
|
26
|
+
- Added sanitized runtime capture, comparison, initial diagnostics, Rails collection, CI verification, reports, allowed differences, and the first rule DSL.
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
We are committed to a respectful, harassment-free project for everyone. Be constructive, assume good intent while addressing concrete behavior, respect privacy, and avoid publishing another person's sensitive environment data.
|
|
4
|
+
|
|
5
|
+
Unacceptable conduct includes harassment, threats, discriminatory language, deliberate disruption, or disclosure of private information. Maintainers may edit or remove contributions and restrict participation to protect the community.
|
|
6
|
+
|
|
7
|
+
Report conduct concerns privately to `conduct@magnexis.com`. Reports will be reviewed confidentially and fairly.
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for improving Bootprint. Open an issue before large architectural work. Keep the project focused on Ruby runtime reproducibility and local-first diagnosis. By participating, you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
The repository pins the maintainer runtime in `.ruby-version`; the gem itself supports Ruby 3.1 and newer.
|
|
8
|
+
|
|
9
|
+
```console
|
|
10
|
+
bundle install
|
|
11
|
+
bundle exec rake check
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Use a focused branch created from `main`. Keep commits reviewable and do not mix generated snapshots, local package artifacts, or unrelated formatting with a behavior change.
|
|
15
|
+
|
|
16
|
+
## Pull requests
|
|
17
|
+
|
|
18
|
+
Describe the failing environment scenario, the compatibility decision being encoded, and the sanitized evidence used to verify it. Complete the pull-request checklist and call out platform behavior you could not test.
|
|
19
|
+
|
|
20
|
+
Changes to rules require success, no-match, suppression, evidence, and remediation tests. Schema changes require migration and future-schema tests. Security changes require both redaction and false-positive coverage. Docker tests must never inspect unrelated containers or require network access.
|
|
21
|
+
|
|
22
|
+
Do not include real production snapshots, credentials, customer names, or proprietary paths in fixtures. Use the existing synthetic platform fixtures.
|
|
23
|
+
|
|
24
|
+
Pull requests should update documentation and `CHANGELOG.md`, remain compatible with Ruby 3.1+, and avoid new runtime dependencies unless clearly justified.
|
|
25
|
+
|
|
26
|
+
## Releases
|
|
27
|
+
|
|
28
|
+
Maintainers should follow [RELEASE.md](RELEASE.md). Pull requests must not publish gems, create tags, or add long-lived package credentials.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 theworker02
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/branding/bootprint-logo-512.png" alt="Bootprint fingerprint and environment-drift logo" width="180">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Bootprint</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>Reproduce the environment, not just the dependencies.</strong></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/theworker02/bootprint/actions/workflows/test.yml"><img alt="Test status" src="https://github.com/theworker02/bootprint/actions/workflows/test.yml/badge.svg"></a>
|
|
11
|
+
<img alt="Bootprint 0.2.0" src="https://img.shields.io/badge/version-0.2.0-CC342D">
|
|
12
|
+
<img alt="Ruby 3.1 or newer" src="https://img.shields.io/badge/Ruby-%E2%89%A5%203.1-CC342D?logo=ruby&logoColor=white">
|
|
13
|
+
<img alt="Snapshot schema version 2" src="https://img.shields.io/badge/snapshot_schema-v2-3977F6">
|
|
14
|
+
<a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-171A21"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
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.
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
gem install bootprint
|
|
21
|
+
bootprint capture local
|
|
22
|
+
bootprint docker capture myapp:latest
|
|
23
|
+
bootprint diagnose local myapp-latest
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
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.
|
|
27
|
+
|
|
28
|
+
## Contents
|
|
29
|
+
|
|
30
|
+
- [Why Bootprint](#why-bootprint)
|
|
31
|
+
- [What it inspects](#what-it-inspects)
|
|
32
|
+
- [Five-minute start](#five-minute-start)
|
|
33
|
+
- [From capture to diagnosis](#from-capture-to-diagnosis)
|
|
34
|
+
- [Command reference](#command-reference)
|
|
35
|
+
- [Policy enforcement](#policy-enforcement)
|
|
36
|
+
- [Rails inspection](#rails-inspection)
|
|
37
|
+
- [Docker comparison](#docker-comparison)
|
|
38
|
+
- [CI integration](#ci-integration)
|
|
39
|
+
- [Reports and remediation](#reports-and-remediation)
|
|
40
|
+
- [Rules and plugins](#rules-and-plugins)
|
|
41
|
+
- [Privacy and security](#privacy-and-security)
|
|
42
|
+
- [Platform support and performance](#platform-support-and-performance)
|
|
43
|
+
- [Documentation](#documentation)
|
|
44
|
+
- [Development](#development)
|
|
45
|
+
|
|
46
|
+
## Why Bootprint
|
|
47
|
+
|
|
48
|
+
`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.
|
|
49
|
+
|
|
50
|
+
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:
|
|
51
|
+
|
|
52
|
+
1. What changed?
|
|
53
|
+
2. How dangerous is it?
|
|
54
|
+
3. What is the likely impact?
|
|
55
|
+
4. What should the developer do next?
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
CRITICAL Native extension platform mismatch
|
|
59
|
+
nokogiri targets arm64-darwin but production uses x86_64-linux.
|
|
60
|
+
|
|
61
|
+
Recommended fix:
|
|
62
|
+
$ bundle lock --add-platform x86_64-linux
|
|
63
|
+
$ bundle install
|
|
64
|
+
|
|
65
|
+
ERROR Required environment variable is missing
|
|
66
|
+
REDIS_URL is available locally but absent in production.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### At a glance
|
|
70
|
+
|
|
71
|
+
| Capability | Bootprint 0.2 |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Diagnostic knowledge | 39 built-in rules across runtime, dependencies, native libraries, configuration, filesystem, and Rails boot |
|
|
74
|
+
| Severity model | `info`, `warning`, `error`, `critical` |
|
|
75
|
+
| Report formats | Human terminal output, JSON, SARIF 2.1, Markdown |
|
|
76
|
+
| Snapshot contract | Deterministic schema v2 with in-memory v1 migration |
|
|
77
|
+
| Policy | Ignore, enable, disable, override severity, declare optional variables, require platforms |
|
|
78
|
+
| Integrations | Rails, Docker, GitHub Actions, GitLab CI, CircleCI, generic POSIX CI |
|
|
79
|
+
| Runtime dependencies | None |
|
|
80
|
+
| Data flow | Local only; no upload service or telemetry |
|
|
81
|
+
|
|
82
|
+
## What it inspects
|
|
83
|
+
|
|
84
|
+
| Area | Captured metadata |
|
|
85
|
+
|---|---|
|
|
86
|
+
| Ruby runtime | Version, engine, patch level, platform, architecture, build description |
|
|
87
|
+
| Dependency system | Bundler and RubyGems versions, lockfile platforms, resolved gems, sources, checksums, native extensions |
|
|
88
|
+
| Native libraries | OpenSSL, libyaml, SQLite, PostgreSQL, MySQL, libc, compiler and header availability when detectable |
|
|
89
|
+
| Configuration | Environment-variable names and presence, Rails environment, adapters, framework settings |
|
|
90
|
+
| Filesystem | Temporary/log path availability, writability, path separators, case sensitivity, symlink behavior |
|
|
91
|
+
| Rails boot | Framework configuration, autoload/eager-load paths, initializers, and opt-in initializer timings |
|
|
92
|
+
| Docker | Image runtime, platforms, installed package metadata when available, workdir, entrypoint, command, permissions |
|
|
93
|
+
|
|
94
|
+
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.
|
|
95
|
+
|
|
96
|
+
## Five-minute start
|
|
97
|
+
|
|
98
|
+
Add Bootprint to a project:
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
group :development, :test do
|
|
102
|
+
gem "bootprint", require: false
|
|
103
|
+
end
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Install and capture a named local baseline:
|
|
107
|
+
|
|
108
|
+
```console
|
|
109
|
+
bundle install
|
|
110
|
+
bundle exec bootprint capture local
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Capture another environment and diagnose the difference:
|
|
114
|
+
|
|
115
|
+
```console
|
|
116
|
+
bundle exec bootprint capture production
|
|
117
|
+
bundle exec bootprint diagnose local production
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Named captures live at `.bootprint/NAME.json`. An unnamed capture writes `bootprint.lock`:
|
|
121
|
+
|
|
122
|
+
```console
|
|
123
|
+
bundle exec bootprint capture
|
|
124
|
+
bundle exec bootprint verify --against bootprint.lock
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Use strict privacy when a snapshot may be attached to an issue or shared outside the team:
|
|
128
|
+
|
|
129
|
+
```console
|
|
130
|
+
bundle exec bootprint capture support-case --privacy strict
|
|
131
|
+
bundle exec bootprint security audit .bootprint/support-case.json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## From capture to diagnosis
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
Ruby process / Rails app / Docker image
|
|
138
|
+
|
|
|
139
|
+
v
|
|
140
|
+
sanitized collectors
|
|
141
|
+
|
|
|
142
|
+
v
|
|
143
|
+
deterministic schema-v2 snapshot
|
|
144
|
+
|
|
|
145
|
+
source + target
|
|
146
|
+
|
|
|
147
|
+
v
|
|
148
|
+
rules + .bootprint.yml policy
|
|
149
|
+
|
|
|
150
|
+
v
|
|
151
|
+
human | JSON | SARIF | Markdown + stable exit code
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
For example, compare a local macOS Rails environment with a Linux production image:
|
|
155
|
+
|
|
156
|
+
```console
|
|
157
|
+
# macOS development machine
|
|
158
|
+
bundle exec bootprint capture macos-development
|
|
159
|
+
|
|
160
|
+
# Local Docker image; no port or running container is required
|
|
161
|
+
bundle exec bootprint docker capture ghcr.io/example/storefront:latest
|
|
162
|
+
|
|
163
|
+
# Explain only warning-or-higher runtime and dependency findings
|
|
164
|
+
bundle exec bootprint diagnose macos-development storefront-latest \
|
|
165
|
+
--only runtime,dependencies \
|
|
166
|
+
--minimum-severity warning
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Raw `diff` remains available when every changed value matters. `diagnose` is the normal workflow because it applies compatibility knowledge and policy.
|
|
170
|
+
|
|
171
|
+
## Command reference
|
|
172
|
+
|
|
173
|
+
| Command | Purpose |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `bootprint capture [NAME]` | Capture a deterministic, sanitized schema-v2 snapshot |
|
|
176
|
+
| `bootprint diff SOURCE TARGET` | Show every raw environment difference |
|
|
177
|
+
| `bootprint diagnose SOURCE TARGET` | Explain compatibility findings and remediation |
|
|
178
|
+
| `bootprint diagnose --against PATH` | Compare the current process with a reference snapshot |
|
|
179
|
+
| `bootprint doctor` | Diagnose the health of the current environment |
|
|
180
|
+
| `bootprint verify --against PATH` | Enforce policy and return CI-safe exit codes |
|
|
181
|
+
| `bootprint fix --dry-run` | Preview remediation without changing files or running commands |
|
|
182
|
+
| `bootprint docker capture IMAGE` | Inspect a local image in an isolated temporary container |
|
|
183
|
+
| `bootprint docker compare IMAGE` | Show raw drift between the current environment and an image |
|
|
184
|
+
| `bootprint docker diagnose IMAGE` | Diagnose current-environment versus image compatibility |
|
|
185
|
+
| `bootprint ci verify` | Detect CI, emit native annotations, and enforce policy |
|
|
186
|
+
| `bootprint snapshot inspect PATH` | Inspect snapshot metadata safely |
|
|
187
|
+
| `bootprint snapshot validate PATH` | Validate schema and snapshot structure |
|
|
188
|
+
| `bootprint snapshot migrate PATH` | Migrate a legacy snapshot into a new file |
|
|
189
|
+
| `bootprint policy validate` | Validate policy with path and line-aware errors |
|
|
190
|
+
| `bootprint policy explain` | Display the effective merged policy |
|
|
191
|
+
| `bootprint security audit PATH` | Check an existing snapshot for likely sensitive values |
|
|
192
|
+
|
|
193
|
+
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.
|
|
194
|
+
|
|
195
|
+
## Policy enforcement
|
|
196
|
+
|
|
197
|
+
Copy `.bootprint.yml.example` to `.bootprint.yml` and tailor it:
|
|
198
|
+
|
|
199
|
+
```yaml
|
|
200
|
+
version: 1
|
|
201
|
+
mode: permissive
|
|
202
|
+
minimum_severity: warning
|
|
203
|
+
fail_on: [error, critical]
|
|
204
|
+
|
|
205
|
+
expected_platforms: [x86_64-linux]
|
|
206
|
+
ignore: [ruby-patch-level-drift]
|
|
207
|
+
|
|
208
|
+
allow:
|
|
209
|
+
environment_variables: [OPTIONAL_ANALYTICS_KEY]
|
|
210
|
+
|
|
211
|
+
rules:
|
|
212
|
+
missing-environment-variable:
|
|
213
|
+
severity: critical
|
|
214
|
+
|
|
215
|
+
redaction:
|
|
216
|
+
patterns: [TOKEN, SECRET, PASSWORD, PRIVATE_KEY]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
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:
|
|
220
|
+
|
|
221
|
+
```console
|
|
222
|
+
bundle exec bootprint policy validate
|
|
223
|
+
bundle exec bootprint policy explain
|
|
224
|
+
bundle exec bootprint verify --against bootprint.lock
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Exit codes are stable:
|
|
228
|
+
|
|
229
|
+
| Code | Meaning |
|
|
230
|
+
|---:|---|
|
|
231
|
+
| 0 | No blocking findings |
|
|
232
|
+
| 1 | Policy violation |
|
|
233
|
+
| 2 | Invalid command or policy |
|
|
234
|
+
| 3 | Invalid or unsupported snapshot |
|
|
235
|
+
| 4 | Docker, plugin, filesystem, or internal failure |
|
|
236
|
+
|
|
237
|
+
## Rails inspection
|
|
238
|
+
|
|
239
|
+
Bootprint lazily loads Rails integration only after Rails is present. Normal application startup is not profiled unless inspection is explicitly enabled.
|
|
240
|
+
|
|
241
|
+
```console
|
|
242
|
+
BOOTPRINT_INSPECT=1 bin/rails bootprint:capture
|
|
243
|
+
bin/rails bootprint:doctor
|
|
244
|
+
BOOTPRINT_PROFILE_BOOT=1 bundle exec rails runner "Bootprint.capture.write('bootprint.lock')"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
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.
|
|
248
|
+
|
|
249
|
+
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.
|
|
250
|
+
|
|
251
|
+
## Docker comparison
|
|
252
|
+
|
|
253
|
+
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.
|
|
254
|
+
|
|
255
|
+
```console
|
|
256
|
+
bootprint docker capture myapp:latest
|
|
257
|
+
bootprint docker diagnose myapp:latest --against local
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
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.
|
|
261
|
+
|
|
262
|
+
## CI integration
|
|
263
|
+
|
|
264
|
+
Commit a trusted `bootprint.lock` and enforce it in pull requests:
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
name: Bootprint
|
|
268
|
+
|
|
269
|
+
on:
|
|
270
|
+
pull_request:
|
|
271
|
+
push:
|
|
272
|
+
|
|
273
|
+
jobs:
|
|
274
|
+
environment-check:
|
|
275
|
+
runs-on: ubuntu-latest
|
|
276
|
+
steps:
|
|
277
|
+
- uses: actions/checkout@v4
|
|
278
|
+
- uses: ruby/setup-ruby@v1
|
|
279
|
+
with:
|
|
280
|
+
bundler-cache: true
|
|
281
|
+
- run: bundle exec bootprint ci verify --against bootprint.lock
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
`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.
|
|
285
|
+
|
|
286
|
+
## Reports and remediation
|
|
287
|
+
|
|
288
|
+
Machine-readable JSON contains report schema version, source and target metadata, findings, evidence, remediation, suppression state, and execution metadata:
|
|
289
|
+
|
|
290
|
+
```console
|
|
291
|
+
bootprint diagnose local production --format json > bootprint-report.json
|
|
292
|
+
bootprint diagnose local production --format sarif > bootprint.sarif
|
|
293
|
+
bootprint diagnose local production --format markdown > bootprint-report.md
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Every actionable finding can include safe, structured repair guidance:
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"rule_id": "missing-lockfile-platform",
|
|
301
|
+
"severity": "error",
|
|
302
|
+
"evidence": {
|
|
303
|
+
"current_platforms": ["arm64-darwin"],
|
|
304
|
+
"required_platforms": ["x86_64-linux"]
|
|
305
|
+
},
|
|
306
|
+
"remediation": {
|
|
307
|
+
"summary": "Add the deployment platform to the lockfile and rebuild the bundle.",
|
|
308
|
+
"commands": [
|
|
309
|
+
"bundle lock --add-platform <required-platform>",
|
|
310
|
+
"bundle install"
|
|
311
|
+
],
|
|
312
|
+
"files": ["Gemfile.lock"]
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`bootprint fix --dry-run` renders those changes as a preview. Diagnosis and preview never execute remediation commands or modify application files.
|
|
318
|
+
|
|
319
|
+
## Rules and plugins
|
|
320
|
+
|
|
321
|
+
Rules use a structured DSL and load without Rails:
|
|
322
|
+
|
|
323
|
+
```ruby
|
|
324
|
+
Bootprint::Rules.define "redis-client-drift" do
|
|
325
|
+
name "Redis client mismatch"
|
|
326
|
+
category :dependencies
|
|
327
|
+
severity :warning
|
|
328
|
+
|
|
329
|
+
detect do |source, target|
|
|
330
|
+
source.dig("plugins", "redis") != target.dig("plugins", "redis")
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
explain do |_source, _target, evidence|
|
|
334
|
+
{ summary: "Redis clients differ.", evidence: evidence }
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
remediate "Pin the same redis-client release in Gemfile.lock.",
|
|
338
|
+
files: ["Gemfile.lock"]
|
|
339
|
+
end
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Third-party gems can package collectors and rules behind plugin API version 1:
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
Bootprint::Plugin.api_version "1"
|
|
346
|
+
|
|
347
|
+
Bootprint::Plugins.register "sidekiq" do
|
|
348
|
+
collector SidekiqBootprint::Collector
|
|
349
|
+
rules SidekiqBootprint::Rules
|
|
350
|
+
end
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
A broken plugin becomes a warning and does not prevent core capture unless strict policy mode is enabled. See [Writing custom rules](docs/custom-rules.md) and [Creating plugins](docs/plugins.md) for the compatibility contract.
|
|
354
|
+
|
|
355
|
+
## Privacy and security
|
|
356
|
+
|
|
357
|
+
Environment inspection is sensitive, so Bootprint applies defensive handling at collection and serialization boundaries:
|
|
358
|
+
|
|
359
|
+
- Environment variables are represented by name and presence only.
|
|
360
|
+
- Recursive redaction detects secret-like names, credentials in URLs, authorization headers, private keys, JWT-like tokens, database connection strings, and high-entropy values.
|
|
361
|
+
- Home paths are normalized; strict mode removes further host and process identity.
|
|
362
|
+
- Unknown snapshot fields are preserved where practical during migration, then audited like known fields.
|
|
363
|
+
- Standard capture performs no network requests and enables no telemetry.
|
|
364
|
+
- Suggested shell commands remain inert data.
|
|
365
|
+
|
|
366
|
+
Before sharing any snapshot, run:
|
|
367
|
+
|
|
368
|
+
```console
|
|
369
|
+
bootprint security audit bootprint.lock
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Security issues should follow the private reporting process in [SECURITY.md](SECURITY.md), not a public issue containing a snapshot.
|
|
373
|
+
|
|
374
|
+
## Platform support and performance
|
|
375
|
+
|
|
376
|
+
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.
|
|
377
|
+
|
|
378
|
+
Bootprint is designed around these practical limits:
|
|
379
|
+
|
|
380
|
+
| Operation | Target |
|
|
381
|
+
|---|---:|
|
|
382
|
+
| Core CLI startup | Under 250 ms where practical |
|
|
383
|
+
| Standard Ruby snapshot | Under 1 second |
|
|
384
|
+
| Rails inspection | Under 3 seconds, excluding application boot |
|
|
385
|
+
| Ordinary snapshot comparison | Under 500 ms |
|
|
386
|
+
|
|
387
|
+
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.
|
|
388
|
+
|
|
389
|
+
## Documentation
|
|
390
|
+
|
|
391
|
+
- [Installation](docs/installation.md)
|
|
392
|
+
- [Five-minute quick start](docs/quick-start.md)
|
|
393
|
+
- [Capturing environments](docs/capturing.md)
|
|
394
|
+
- [Comparing environments](docs/comparing.md)
|
|
395
|
+
- [Understanding findings](docs/findings.md)
|
|
396
|
+
- [Policy configuration](docs/policy.md)
|
|
397
|
+
- [Rails integration](docs/rails.md)
|
|
398
|
+
- [Docker support](docs/docker.md)
|
|
399
|
+
- [CI integration](docs/ci.md)
|
|
400
|
+
- [Writing custom rules](docs/custom-rules.md)
|
|
401
|
+
- [Creating plugins](docs/plugins.md)
|
|
402
|
+
- [Privacy and redaction](docs/privacy.md)
|
|
403
|
+
- [Snapshot schema](docs/snapshot-schema.md)
|
|
404
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
405
|
+
- [Maintainer setup](docs/maintainer-setup.md)
|
|
406
|
+
|
|
407
|
+
## Development
|
|
408
|
+
|
|
409
|
+
```console
|
|
410
|
+
bundle install
|
|
411
|
+
bundle exec rake test
|
|
412
|
+
bundle exec rubocop lib test exe Rakefile bootprint.gemspec
|
|
413
|
+
gem build bootprint.gemspec
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow, [ARCHITECTURE.md](ARCHITECTURE.md) for system boundaries, and [RELEASE.md](RELEASE.md) for packaging and signed-release instructions.
|
|
417
|
+
|
|
418
|
+
## Status and limitations
|
|
419
|
+
|
|
420
|
+
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.
|
|
421
|
+
|
|
422
|
+
Bootprint is released under the [MIT License](LICENSE).
|
data/RELEASE.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Release process
|
|
2
|
+
|
|
3
|
+
Bootprint releases are built from an immutable `vVERSION` Git tag and published through RubyGems Trusted Publishing. The workflow uses GitHub OIDC to obtain a short-lived, gem-scoped credential; no long-lived RubyGems API key belongs in GitHub secrets.
|
|
4
|
+
|
|
5
|
+
## One-time maintainer setup
|
|
6
|
+
|
|
7
|
+
1. Create the public GitHub repository at `theworker02/bootprint` with `main` as its default branch.
|
|
8
|
+
2. Apply the repository controls in [docs/maintainer-setup.md](docs/maintainer-setup.md).
|
|
9
|
+
3. Create a RubyGems.org account, enable MFA for UI and API operations, and verify the account email.
|
|
10
|
+
4. On RubyGems.org, create a pending trusted publisher for the new `bootprint` gem with:
|
|
11
|
+
- GitHub owner: `theworker02`
|
|
12
|
+
- repository: `bootprint`
|
|
13
|
+
- workflow: `release.yml`
|
|
14
|
+
- environment: `release`
|
|
15
|
+
5. In GitHub, create a protected environment named `release`, restrict it to tags matching `v*`, and require a maintainer review before deployment.
|
|
16
|
+
|
|
17
|
+
RubyGems supports pending trusted publishers for a gem's first release. Recheck that the `bootprint` name is still available immediately before the initial tag is pushed.
|
|
18
|
+
|
|
19
|
+
## Prepare a release
|
|
20
|
+
|
|
21
|
+
1. Update `Bootprint::VERSION` in `lib/bootprint/version.rb`.
|
|
22
|
+
2. Add a dated entry to `CHANGELOG.md` using the exact version.
|
|
23
|
+
3. Update version-specific README text and badges when necessary.
|
|
24
|
+
4. Run the full local gate:
|
|
25
|
+
|
|
26
|
+
```console
|
|
27
|
+
bundle install
|
|
28
|
+
bundle exec rake release_check
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
5. Inspect and smoke-test the generated package:
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
gem specification pkg/bootprint-VERSION.gem
|
|
35
|
+
gem install pkg/bootprint-VERSION.gem --install-dir tmp/gem-home --bindir tmp/gem-bin --no-document
|
|
36
|
+
GEM_HOME="$PWD/tmp/gem-home" GEM_PATH="$PWD/tmp/gem-home" tmp/gem-bin/bootprint --version
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
6. Audit the staged Git diff for credentials, private snapshots, generated packages, absolute user paths, and unrelated files.
|
|
40
|
+
7. Commit the release changes. Do not tag a dirty or unreviewed tree.
|
|
41
|
+
|
|
42
|
+
## Publish
|
|
43
|
+
|
|
44
|
+
Create and push a signed tag only after the `main` branch checks pass:
|
|
45
|
+
|
|
46
|
+
```console
|
|
47
|
+
git tag -s vVERSION -m "Bootprint VERSION"
|
|
48
|
+
git push origin vVERSION
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The tag starts `.github/workflows/release.yml`, which:
|
|
52
|
+
|
|
53
|
+
1. verifies the tag matches `Bootprint::VERSION` and `CHANGELOG.md`;
|
|
54
|
+
2. runs tests and RuboCop;
|
|
55
|
+
3. builds, installs, and smoke-tests a preflight `.gem` from the tagged source;
|
|
56
|
+
4. pauses at the protected `release` environment;
|
|
57
|
+
5. rebuilds and publishes through the official RubyGems OIDC action;
|
|
58
|
+
6. prints the published package's SHA-256 digest; and
|
|
59
|
+
7. creates a GitHub release with that same package attached.
|
|
60
|
+
|
|
61
|
+
For 0.2.0, use the release title `Bootprint 0.2 — From Environment Differences to Actionable Diagnoses` when editing the generated GitHub release notes.
|
|
62
|
+
|
|
63
|
+
## Verify after publication
|
|
64
|
+
|
|
65
|
+
```console
|
|
66
|
+
gem install bootprint -v VERSION
|
|
67
|
+
bootprint --version
|
|
68
|
+
bootprint help
|
|
69
|
+
gem owner bootprint
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Confirm the RubyGems page shows the correct links, MIT license, Ruby requirement, MFA requirement, checksum, owners, and trusted publisher. Confirm the GitHub release attachment has the same SHA-256 digest as the workflow output.
|
|
73
|
+
|
|
74
|
+
## Emergency and manual release policy
|
|
75
|
+
|
|
76
|
+
Prefer rerunning a failed trusted-publishing job. A manual `gem push` is an emergency fallback only and must use an MFA-protected, least-privilege RubyGems API key from an approved maintainer workstation. Never store that key, an OTP, or a signing private key in the repository, workflow variables, shell history, or issue attachments.
|
|
77
|
+
|
|
78
|
+
RubyGems certificate signing is optional and separate from signed Git tags and OIDC publishing. If enabled later, keep the private key offline, commit only the public certificate, configure `spec.cert_chain`, and document how consumers verify it before making signed packages mandatory.
|