gemvault 0.2.0 → 0.2.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 +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +31 -0
- data/CLAUDE.md +65 -7
- data/Dockerfile.test +57 -12
- data/Rakefile +17 -2
- data/_claude/archives/issue-13-root-cause.md +197 -0
- data/docs/Rakefile.vault_example +76 -0
- data/issues.rec +91 -15
- data/lib/gemvault/version.rb +1 -1
- metadata +23 -8
- data/LICENSE +0 -21
- /data/{ASSESSMENT.md → _claude/archives/ASSESSMENT.md} +0 -0
- /data/{MACROPLAN.md → _claude/archives/MACROPLAN.md} +0 -0
- /data/{docs/superpowers → _claude/archives}/plans/2026-04-16-container-integration-tests.md +0 -0
- /data/{docs → _claude/archives}/tarvault-findings.md +0 -0
- /data/{docs → _claude/archives}/tarvault.md +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6a1d5d0c990e232ac54514f5837db4224d92b127175f370a3443c8d15d44099f
|
|
4
|
+
data.tar.gz: ab40029793c2dd05206b9812e27da8921eb7fc478164f71fa7485296d5455f15
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 916b9a114590c9eb5fa3a377d59e9639c33a28e948429b8bac18399473eba0dcacf6711a9808106e3f91348945d71ebd051c1f65fe05239f9804289f56fcf859
|
|
7
|
+
data.tar.gz: 9ea36ee67195ca7f7a8bafd7ebc8658e000b72bcbf72356e3a2266c2f8d2679e0d8f5212f0b977a36a36c95441152f2dabae8ada78c5831770c0cd3498c4253d
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -36,6 +36,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
36
36
|
- Vault gems whose versions carry a non-numeric suffix (e.g. `0.2.1.patch1`)
|
|
37
37
|
install from a vault with `gem install --pre`, matching RubyGems' prerelease
|
|
38
38
|
semantics (issue #6).
|
|
39
|
+
- Repeated `bundle install` no longer fails with `cannot load such file --
|
|
40
|
+
bundler/plugin/vault_source` on machines that have gemvault installed
|
|
41
|
+
system-wide. Bundler skips installing a plugin dependency already present on
|
|
42
|
+
the ambient GEM_PATH, so the plugin root holds only the shim; once the app
|
|
43
|
+
bundle is populated Bundler restricts GEM_PATH to it and the ambient copy
|
|
44
|
+
falls out of scope. The shim now locates gemvault's `lib` across every root
|
|
45
|
+
that can hold it — `Gem.default_path` above all, which is what RubyGems knows
|
|
46
|
+
about its own gem roots and therefore covers rubies from rbenv, asdf, chruby,
|
|
47
|
+
Homebrew and distros, none of which export `GEM_HOME` or `GEM_PATH` — and
|
|
48
|
+
loads it via `$LOAD_PATH` rather than gem activation (issue #13).
|
|
49
|
+
- The vault source registers correctly when Bundler evaluates the plugin more
|
|
50
|
+
than once in a process; gemvault is resolved and required only on the first
|
|
51
|
+
evaluation, so `Gemvault::GemEntry` can no longer be defined twice from two
|
|
52
|
+
different gem roots (issue #13).
|
|
53
|
+
- `gemvault new` no longer raises `cannot load such file -- json` on a stock
|
|
54
|
+
distro ruby. json backs the tarball vault's manifest, so every current-format
|
|
55
|
+
vault needs it; it is a default gem upstream but a separate package on
|
|
56
|
+
distros, where `dnf install ruby` leaves it absent. It is now a declared
|
|
57
|
+
runtime dependency.
|
|
58
|
+
- Reading a vault through the Bundler source no longer raises `cannot load such
|
|
59
|
+
file -- json` either. Loading gemvault off `$LOAD_PATH` skips activation, and
|
|
60
|
+
therefore skips its dependencies, so the declared dependency alone did not
|
|
61
|
+
reach the plugin path. The shim now resolves gemvault's declared runtime
|
|
62
|
+
dependencies the same way it resolves gemvault and puts their require paths —
|
|
63
|
+
extension directories included — on `$LOAD_PATH`. A dependency it cannot find
|
|
64
|
+
is skipped rather than fatal, which is what activation could not do.
|
|
65
|
+
- `bundle install` no longer fails with `Could not find 'command_kit' (~> 0.6)`
|
|
66
|
+
when gemvault is installed into the plugin root without its dependencies.
|
|
67
|
+
Loading the vault source no longer activates the gemvault gem, which would
|
|
68
|
+
demand the full runtime dependency set; `vault_source.rb` reaches the rest of
|
|
69
|
+
gemvault through `require_relative` alone (issue #13).
|
|
39
70
|
|
|
40
71
|
### Changed
|
|
41
72
|
- `sqlite3` is no longer a runtime dependency. Gemvault runs dependency-free on
|
data/CLAUDE.md
CHANGED
|
@@ -77,6 +77,15 @@ gem install --source file:///path/to/myvault.gemv foo
|
|
|
77
77
|
- `bundler-source-vault` name exists because Bundler auto-infers plugin name from `type: :vault` → `bundler-source-vault`
|
|
78
78
|
- `file://` URIs stripped to plain paths in `Gem::Source::Vault#initialize`
|
|
79
79
|
- Verbose logging via `Gem::UserInteraction#verbose` for `--verbose` support
|
|
80
|
+
- `shim/plugins.rb` loads gemvault by putting its `lib` on `$LOAD_PATH`, never by
|
|
81
|
+
activating the gem. Bundler skips installing a plugin dependency already
|
|
82
|
+
present on the ambient GEM_PATH, so the plugin root often lacks gemvault, and
|
|
83
|
+
by load time GEM_PATH is restricted to the plugin root and the app bundle. The
|
|
84
|
+
shim therefore searches every root that can hold gemvault, including the ones
|
|
85
|
+
Bundler masked (`Bundler.original_env` GEM_HOME/GEM_PATH). Activation is
|
|
86
|
+
avoided because it demands gemvault's full runtime dependency set (command_kit),
|
|
87
|
+
which Bundler skips for the same reason — `vault_source.rb` reaches the rest of
|
|
88
|
+
gemvault through `require_relative` alone and needs none of it.
|
|
80
89
|
|
|
81
90
|
## Testing
|
|
82
91
|
|
|
@@ -84,17 +93,66 @@ gem install --source file:///path/to/myvault.gemv foo
|
|
|
84
93
|
bundle exec rake test
|
|
85
94
|
```
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- `test/integration_test.rb` — 12 end-to-end bundle install tests
|
|
90
|
-
- `test/cli_test.rb` — 32 CLI tests
|
|
91
|
-
- `test/rubygems_plugin_test.rb` — 28 tests (source, resolver, monkey-patches, gem install integration, file:// URI, verbose logging)
|
|
96
|
+
Minitest covers the library; RSpec covers the CLI and the containerized
|
|
97
|
+
integration suite. `rake` (the default task) runs `test`, `spec` and `rubocop`.
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
```bash
|
|
100
|
+
bundle exec rake test # minitest only
|
|
101
|
+
bundle exec rake spec:core # rspec, no containers
|
|
102
|
+
bundle exec rake spec:integration # rspec, containers (builds the image first)
|
|
103
|
+
bundle exec rake spec:build # rebuild the container image
|
|
104
|
+
bundle exec rake spec:teardown # remove it
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- `test/vault_test.rb` — unit tests for Vault class
|
|
108
|
+
- `test/vault_source_test.rb` — unit tests for Bundler source plugin
|
|
109
|
+
- `test/cli_test.rb` — CLI tests
|
|
110
|
+
- `test/rubygems_plugin_test.rb` — source, resolver, monkey-patches, gem install integration, file:// URI, verbose logging
|
|
111
|
+
- `spec/integration/` — end-to-end specs, each run inside a podman container
|
|
112
|
+
- `spec/support/` — script fragments the integration specs assemble into those containers
|
|
113
|
+
|
|
114
|
+
Integration specs serve the tree's own gems from a local gem index (`GemIndex`)
|
|
115
|
+
to avoid rubygems.org resolution during testing.
|
|
116
|
+
|
|
117
|
+
### Container fidelity — do not undo these
|
|
118
|
+
|
|
119
|
+
The container has to look like a machine a user actually has. The `ruby` base
|
|
120
|
+
image does not, and every way it differs has already hidden a real defect. These
|
|
121
|
+
four are load-bearing; reverting any of them silently makes the suite green
|
|
122
|
+
against something other than the code under test:
|
|
123
|
+
|
|
124
|
+
1. **`bundler-source-vault` is NOT installed system-wide in `Dockerfile.test`.**
|
|
125
|
+
An ambient copy satisfies Bundler's plugin resolution without ever populating
|
|
126
|
+
the plugin root. Specs resolve the shim from the local gem index (`GemIndex`)
|
|
127
|
+
so they exercise the tree's shim. `gemvault` IS installed system-wide on
|
|
128
|
+
purpose — that is a real user's machine and the trigger for issue #13.
|
|
129
|
+
2. **`BUNDLE_APP_CONFIG` is not set in the container.** The `ruby` image sets it
|
|
130
|
+
to `/usr/local/bundle`, which moves `Bundler::Plugin.root` out of the project
|
|
131
|
+
so no spec ever touches a project-local `.bundle/plugin`. Fedora sets it
|
|
132
|
+
nowhere; do not add it, and do not adopt a base image that does.
|
|
133
|
+
3. **`GEM_HOME` and `GEM_PATH` are not exported in the container, and nothing
|
|
134
|
+
pins them.** Gems land in RubyGems' own default dirs. The `ruby` image
|
|
135
|
+
exports `GEM_HOME`; rubies from rbenv, asdf, chruby, Homebrew and distros
|
|
136
|
+
export nothing. Anything that reads gem roots back out of the environment
|
|
137
|
+
finds them on the image and finds nothing on a user's machine — that is what
|
|
138
|
+
made the first fix for issue #13 pass its specs while still failing for the
|
|
139
|
+
reporter. Neither `Dockerfile.test` nor `ContainerHelper#podman_run` should
|
|
140
|
+
grow an `ENV`/`-e` for either variable.
|
|
141
|
+
4. **Bundler is pinned to the version users run, not the image's default gem.**
|
|
142
|
+
The plugin machinery under test is Bundler's own, so a stale default silently
|
|
143
|
+
tests different code.
|
|
144
|
+
|
|
145
|
+
Fidelity is a property of the image, not of a script fragment: integration specs
|
|
146
|
+
run only commands a user would actually type.
|
|
147
|
+
|
|
148
|
+
If a spec fails only after removing a system-installed gem or an exported
|
|
149
|
+
variable, the spec was passing for the wrong reason — fix the spec, not the
|
|
150
|
+
container.
|
|
94
151
|
|
|
95
152
|
## Dependencies
|
|
96
153
|
|
|
97
154
|
- `bundler` — NOT a dependency; the plugin always runs inside an existing Bundler process, and declaring it breaks gem activation under `bundle exec`'s restricted GEM_PATH
|
|
98
155
|
- `command_kit` (~> 0.6) — runtime (CLI)
|
|
156
|
+
- `json` (~> 2.0) — runtime; backs the tarball vault's manifest. A default gem upstream, but distros package it separately, so it is declared. Because the shim loads gemvault off `$LOAD_PATH` without activating it, it has to put json's require paths on `$LOAD_PATH` itself — see `dependency_specs` and `entries` in `shim/gemvault_load_path.rb`.
|
|
99
157
|
- `sqlite3` (~> 2.0) — NOT a runtime dependency; loaded lazily only to read a legacy SQLite (Dbvault) vault. Declared in the Gemfile for development/test.
|
|
100
|
-
- `minitest`, `rake` — development
|
|
158
|
+
- `minitest`, `rspec`, `rake` — development
|
data/Dockerfile.test
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
# A dev machine, not a packaging convenience.
|
|
2
|
+
#
|
|
3
|
+
# The official ruby image is not shaped like anything a user runs: it redirects
|
|
4
|
+
# gems to /usr/local/bundle, exports GEM_HOME and BUNDLE_APP_CONFIG to match,
|
|
5
|
+
# and freezes bundler at whatever shipped. Each of those differences hid a real
|
|
6
|
+
# defect, and patching them one at a time only moved the blind spot. A distro
|
|
7
|
+
# ruby has none of them: gems land in RubyGems' own default dirs, nothing is
|
|
8
|
+
# exported, and bundler is a regular gem rather than a default one -- which is
|
|
9
|
+
# also the shape that broke `bundle exec` in issue #12.
|
|
10
|
+
FROM docker.io/library/fedora:44
|
|
2
11
|
|
|
3
|
-
|
|
12
|
+
# redhat-rpm-config carries the hardening specs Fedora's ruby-devel compiles
|
|
13
|
+
# extensions against; without it every native gem fails in extconf. Any Fedora
|
|
14
|
+
# machine that can build a gem has it.
|
|
15
|
+
RUN dnf -y install --setopt=install_weak_deps=False \
|
|
16
|
+
ruby ruby-devel rubygem-bundler \
|
|
17
|
+
gcc make redhat-rpm-config sqlite-devel tar \
|
|
18
|
+
&& dnf clean all
|
|
4
19
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
&& gem build bundler-source-vault.gemspec \
|
|
10
|
-
&& gem install --no-document bundler-source-vault-*.gem \
|
|
11
|
-
&& rm -rf /tmp/build
|
|
20
|
+
# Keep this in step with the `BUNDLED WITH` line the project's own lockfile
|
|
21
|
+
# carries. The plugin machinery these specs exercise is Bundler's own, so a
|
|
22
|
+
# stale version silently tests different code.
|
|
23
|
+
RUN gem install --no-document bundler -v 4.0.17
|
|
12
24
|
|
|
13
25
|
# sqlite3 is not a gemvault runtime dependency; install it here so the upgrade
|
|
14
26
|
# integration test can read the committed legacy SQLite (Dbvault) fixture it
|
|
@@ -16,10 +28,43 @@ RUN cd /tmp/build \
|
|
|
16
28
|
RUN gem install --no-document sqlite3
|
|
17
29
|
|
|
18
30
|
# Gem files for integration specs that install the plugin from a local gem
|
|
19
|
-
# index at spec runtime, kept for offline use: command_kit
|
|
20
|
-
# runtime
|
|
21
|
-
#
|
|
31
|
+
# index at spec runtime, kept for offline use: command_kit and json are
|
|
32
|
+
# gemvault's runtime dependencies, and `bundle plugin install` resolves them
|
|
33
|
+
# against the Gemfile's sources with GEM_PATH already narrowed to the plugin
|
|
34
|
+
# root, so an ambient copy does not satisfy it -- every declared dependency has
|
|
35
|
+
# to be servable from the index. The bundler gem lets specs reinstall bundler
|
|
36
|
+
# in place.
|
|
22
37
|
RUN mkdir -p /opt/gems \
|
|
23
38
|
&& cd /opt/gems \
|
|
24
39
|
&& gem fetch command_kit -v 0.6.0 \
|
|
40
|
+
&& gem fetch json -v "~> 2.0" \
|
|
25
41
|
&& gem fetch bundler -v "$(ruby -rbundler -e 'print Bundler::VERSION')"
|
|
42
|
+
|
|
43
|
+
# The tree arrives as a bind mount at /src rather than a COPY: the build context
|
|
44
|
+
# lives on a filesystem whose extended-attribute listing podman's copier cannot
|
|
45
|
+
# read. `rake spec:build` supplies both the mount and SOURCE_DIGEST.
|
|
46
|
+
#
|
|
47
|
+
# A bind mount's contents are not part of podman's cache key, so without
|
|
48
|
+
# SOURCE_DIGEST in the command line this layer is reused forever and the image
|
|
49
|
+
# keeps whichever gemvault the tree held the first time it was built -- the
|
|
50
|
+
# suite would then run green against code that is not under test. The digest
|
|
51
|
+
# changes whenever the installed source does, which invalidates the layer. It is
|
|
52
|
+
# last so that editing lib/ does not re-fetch the layers above.
|
|
53
|
+
#
|
|
54
|
+
# gemvault is installed system-wide because integration specs need the CLI to
|
|
55
|
+
# build vault fixtures, and because that is what a real user's machine looks
|
|
56
|
+
# like: `gem install gemvault` puts it on the ambient GEM_PATH. That ambient
|
|
57
|
+
# copy is load-bearing for the plugin root specs -- Bundler skips installing a
|
|
58
|
+
# plugin dependency that is already installed, so the plugin root only gets a
|
|
59
|
+
# complete dependency set if gemvault puts it there itself.
|
|
60
|
+
#
|
|
61
|
+
# bundler-source-vault is deliberately NOT installed system-wide. An ambient
|
|
62
|
+
# copy satisfies Bundler's plugin resolution without ever populating the plugin
|
|
63
|
+
# root, which masks every plugin-root defect the integration specs exist to
|
|
64
|
+
# catch. Specs install it from the local gem index built by GemIndex instead.
|
|
65
|
+
ARG SOURCE_DIGEST=unset
|
|
66
|
+
RUN test "$SOURCE_DIGEST" != unset \
|
|
67
|
+
&& cd /src \
|
|
68
|
+
&& gem build gemvault.gemspec -o /tmp/gemvault.gem \
|
|
69
|
+
&& gem install --no-document /tmp/gemvault.gem \
|
|
70
|
+
&& rm -f /tmp/gemvault.gem
|
data/Rakefile
CHANGED
|
@@ -24,14 +24,29 @@ RuboCop::RakeTask.new
|
|
|
24
24
|
require "gempilot/version_task"
|
|
25
25
|
Gempilot::VersionTask.new
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
require "digest"
|
|
28
|
+
require_relative "spec/support/container_helper"
|
|
29
|
+
|
|
30
|
+
CACHED_IMAGE = ContainerHelper::CACHED_IMAGE
|
|
31
|
+
|
|
32
|
+
# Dockerfile.test reads the tree through a bind mount, whose contents podman
|
|
33
|
+
# does not fold into its layer cache key. Feeding this digest in as a build arg
|
|
34
|
+
# is what makes `rake spec:build` notice that the source changed.
|
|
35
|
+
def image_source_digest
|
|
36
|
+
fingerprints = FileList["lib/**/*", "exe/*", "gemvault.gemspec"]
|
|
37
|
+
.select { |path| File.file?(path) }.sort
|
|
38
|
+
.map { |path| "#{path} #{Digest::SHA256.hexdigest(File.binread(path))}" }
|
|
39
|
+
Digest::SHA256.hexdigest(fingerprints.join("\n"))
|
|
40
|
+
end
|
|
28
41
|
|
|
29
42
|
def cached_image_exists?
|
|
30
43
|
system("podman", "image", "exists", CACHED_IMAGE, out: File::NULL, err: File::NULL)
|
|
31
44
|
end
|
|
32
45
|
|
|
33
46
|
def build_cached_image
|
|
34
|
-
sh "podman", "build", "--network=host", "-
|
|
47
|
+
sh "podman", "build", "--network=host", "-v", "#{__dir__}:/src:ro,z",
|
|
48
|
+
"--build-arg", "SOURCE_DIGEST=#{image_source_digest}",
|
|
49
|
+
"-t", CACHED_IMAGE, "-f", "Dockerfile.test", "."
|
|
35
50
|
end
|
|
36
51
|
|
|
37
52
|
def destroy_cached_image
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Issue #13 — `cannot load such file -- bundler/plugin/vault_source`
|
|
2
|
+
|
|
3
|
+
Line references are to the vendored RubyGems/Bundler checkout in
|
|
4
|
+
`references/rubygems` (`bundler-v4.0.0-1207-gf912ac9b0b`).
|
|
5
|
+
|
|
6
|
+
## Symptom
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
❯ bundle install
|
|
10
|
+
Fetching gem metadata from https://rubygems.org/.......
|
|
11
|
+
Resolving dependencies...
|
|
12
|
+
Installing bundler-source-vault 0.2.0
|
|
13
|
+
|
|
14
|
+
[!] There was an error parsing `Gemfile`: cannot load such file -- bundler/plugin/vault_source. Bundler cannot continue.
|
|
15
|
+
|
|
16
|
+
# from /Users/davidgillis/repos/reversal-store/Gemfile:19
|
|
17
|
+
> source "vendor/vendored.gemv", type: :vault do
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Reported as permanent. `gemvault doctor`, `rm -rf .bundle/plugin`, `rm -f
|
|
21
|
+
Gemfile.lock`, and the two combined all left it unchanged.
|
|
22
|
+
|
|
23
|
+
## Reproduction
|
|
24
|
+
|
|
25
|
+
The reporter's `.bundle` tarball showed a plugin root holding the shim and
|
|
26
|
+
nothing else:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
.bundle/plugin/cache/bundler-source-vault-0.2.0.gem
|
|
30
|
+
.bundle/plugin/gems/bundler-source-vault-0.2.0/plugins.rb
|
|
31
|
+
.bundle/plugin/specifications/bundler-source-vault-0.2.0.gemspec
|
|
32
|
+
.bundle/plugin/index
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No `gemvault` anywhere. Reproduced exactly with: gemvault installed on the
|
|
36
|
+
ambient `GEM_PATH`, the shim not installed, a project-local `.bundle` with a
|
|
37
|
+
configured bundle path, and `bundle install` run **twice**.
|
|
38
|
+
|
|
39
|
+
## Root cause
|
|
40
|
+
|
|
41
|
+
Three independent mechanisms compose. Each is fine alone.
|
|
42
|
+
|
|
43
|
+
### 1. Bundler never puts gemvault in the plugin root
|
|
44
|
+
|
|
45
|
+
`Source::Rubygems#install` (`lib/bundler/source/rubygems.rb:206`) short-circuits:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
if (spec.default_gem? && !cached_built_in_gem(...)) || (installed?(spec) && !options[:force])
|
|
49
|
+
print_using_message "Using #{version_message(spec, options[:previous_spec])}"
|
|
50
|
+
return nil
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`installed?` (`:484`) consults `installed_specs`. On any machine where
|
|
55
|
+
`gem install gemvault` has run — that is, anyone who uses the CLI — the ambient
|
|
56
|
+
copy satisfies it. Bundler prints "Using gemvault" and the plugin root receives
|
|
57
|
+
the shim alone. Nothing is downloaded, so the plugin root's `cache/` has no
|
|
58
|
+
gemvault either, which is exactly what the reporter's tarball showed.
|
|
59
|
+
|
|
60
|
+
### 2. The ambient copy disappears precisely when it is needed
|
|
61
|
+
|
|
62
|
+
`Plugin::Installer#install_all_sources` calls
|
|
63
|
+
`Bundler.configure_gem_home_and_path(Plugin.root)`
|
|
64
|
+
(`lib/bundler/plugin/installer.rb:100`), and `configure_gem_path`
|
|
65
|
+
(`lib/bundler.rb:661`) does:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
unless use_system_gems?
|
|
69
|
+
Bundler::SharedHelpers.set_env "GEM_PATH", ""
|
|
70
|
+
end
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
With a configured bundle path, `use_system_gems?` is false, so `GEM_PATH`
|
|
74
|
+
becomes empty and `Gem.path` collapses to the bundle. The copy that made step 1
|
|
75
|
+
"safe" is now out of scope.
|
|
76
|
+
|
|
77
|
+
This is why the failure is **permanent and why it starts on the second run**.
|
|
78
|
+
The first `bundle install` succeeds because the ambient gemvault is still
|
|
79
|
+
visible. It populates the bundle path. From then on every `bundle install`
|
|
80
|
+
narrows `GEM_PATH`, and every recovery step the reporter tried rebuilds the same
|
|
81
|
+
incomplete plugin root.
|
|
82
|
+
|
|
83
|
+
### 3. Locating gemvault is not sufficient — activation cannot survive here
|
|
84
|
+
|
|
85
|
+
The obvious repair — find gemvault and load it — has a trap. Loading it via
|
|
86
|
+
`$LOAD_PATH` skips activation, and therefore skips its dependencies. gemvault
|
|
87
|
+
reads a vault manifest through `json` (`lib/gemvault/manifest.rb:1`), so the
|
|
88
|
+
plugin dies later, at first vault read, instead of at load.
|
|
89
|
+
|
|
90
|
+
Activating instead does not work, for two separate reasons:
|
|
91
|
+
|
|
92
|
+
- **The path would be stripped one line before it is used.** `Runtime#setup`
|
|
93
|
+
(`lib/bundler/runtime.rb:12-38`) runs `clean_load_path` at line 16 and
|
|
94
|
+
`@definition.specs_for(groups)` at line 18 — and resolution is what asks the
|
|
95
|
+
vault source for specs. `clean_load_path`
|
|
96
|
+
(`lib/bundler/shared_helpers.rb:371-380`) rejects a `$LOAD_PATH` entry only
|
|
97
|
+
when `loaded_gem_paths.delete(p)` is truthy, and `loaded_gem_paths`
|
|
98
|
+
(`lib/bundler/rubygems_integration.rb:132-135`) is built from
|
|
99
|
+
`Gem.loaded_specs` — i.e. **activated gems**. Activating is what would put the
|
|
100
|
+
path on the chopping block. A directory pushed without activation is absent
|
|
101
|
+
from that list, so `delete` returns nil and the entry survives.
|
|
102
|
+
|
|
103
|
+
- **`Gem::Specification` cannot see outside the bundle.** `stub_rubygems`
|
|
104
|
+
(`lib/bundler/rubygems_integration.rb:336-340`) sets
|
|
105
|
+
`Gem::Specification.all = specs` and reapplies it through `Gem.post_reset`, so
|
|
106
|
+
under `bundle exec` `find_by_name` cannot find a gem installed outside the
|
|
107
|
+
bundle, and `Gem::Specification.reset` will not restore it.
|
|
108
|
+
|
|
109
|
+
## Why the test suite could not catch any of this
|
|
110
|
+
|
|
111
|
+
The integration container was the official `ruby` image. It differs from a
|
|
112
|
+
machine anyone develops on in four ways, and each one hid one layer:
|
|
113
|
+
|
|
114
|
+
| Image behaviour | What it hid |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `gemvault` **and** `bundler-source-vault` installed system-wide | `require "bundler/plugin/vault_source"` resolved from `/usr/local/bundle` no matter what the plugin root held |
|
|
117
|
+
| `BUNDLE_APP_CONFIG=/usr/local/bundle` | `Bundler::Plugin.root` was never project-local, so no spec touched a real `.bundle/plugin` |
|
|
118
|
+
| `GEM_HOME` exported | a first repair that read gem roots out of the environment appeared to work |
|
|
119
|
+
| `json` present as a default gem | the undeclared dependency was invisible |
|
|
120
|
+
|
|
121
|
+
The first repair for this issue reconstructed gem roots from
|
|
122
|
+
`Bundler.original_env`, which is a snapshot of environment variables.
|
|
123
|
+
`GEM_HOME`/`GEM_PATH` are only present there if something exported them —
|
|
124
|
+
rbenv, asdf, chruby, Homebrew and distro rubies export neither. The reporter is
|
|
125
|
+
on rbenv (`issues.rec`: `/Users/davidgillis/.rbenv/versions/4.0.1/`,
|
|
126
|
+
`rbenv 1.3.2`), so that repair passed its specs in Docker and still failed on
|
|
127
|
+
their machine.
|
|
128
|
+
|
|
129
|
+
The suite now runs on `fedora:44` with a distro ruby: gems in RubyGems' own
|
|
130
|
+
default dirs, nothing exported, bundler a regular gem. Moving to it immediately
|
|
131
|
+
surfaced two further real defects — the undeclared `json` dependency, and the
|
|
132
|
+
`json/ext/parser` extension path.
|
|
133
|
+
|
|
134
|
+
## The fix
|
|
135
|
+
|
|
136
|
+
`shim/gemvault_load_path.rb` locates gemvault and its declared runtime
|
|
137
|
+
dependencies across every root that could hold them, and pushes their require
|
|
138
|
+
paths onto `$LOAD_PATH`.
|
|
139
|
+
|
|
140
|
+
- **`Gem.default_path` is the load-bearing root.** It is what RubyGems knows
|
|
141
|
+
about its own gem roots, independent of the narrowing in step 2, so it covers
|
|
142
|
+
rubies that export nothing. `Bundler.original_env` is still consulted, for the
|
|
143
|
+
rubies that do export a root outside those defaults, such as RVM.
|
|
144
|
+
- **`$LOAD_PATH`, not activation**, for the reasons in step 3.
|
|
145
|
+
- **Dependencies resolved by hand**, using `full_require_paths`
|
|
146
|
+
(`lib/rubygems/basic_specification.rb:172-183`), which appends `extension_dir`
|
|
147
|
+
when `have_extensions?` — without it `json/ext/parser` is unfindable, since
|
|
148
|
+
json's compiled half lives outside its gem directory.
|
|
149
|
+
- **A dependency that cannot be found is skipped rather than fatal.** That is
|
|
150
|
+
the one thing activation could not do: it would abort on `command_kit`, which
|
|
151
|
+
only the CLI needs.
|
|
152
|
+
- **`json` is now a declared runtime dependency**, so `gemvault new` works on a
|
|
153
|
+
stock distro ruby.
|
|
154
|
+
|
|
155
|
+
## Does the suite actually protect this?
|
|
156
|
+
|
|
157
|
+
Green is not evidence on its own — the whole reason this bug shipped is that a
|
|
158
|
+
green suite was being satisfied by an ambient gem. So the two pieces of the fix
|
|
159
|
+
were checked by mutation:
|
|
160
|
+
|
|
161
|
+
| Mutation | Result |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `Gem.default_path` dropped from the searched roots | 18 examples fail |
|
|
164
|
+
| the shim's pinned gemvault requirement ignored, so the newest wins | both examples of the upgrade-residue scenario fail |
|
|
165
|
+
|
|
166
|
+
Restoring each returns the suite to green.
|
|
167
|
+
|
|
168
|
+
## Platforms verified
|
|
169
|
+
|
|
170
|
+
| Platform | Status |
|
|
171
|
+
|---|---|
|
|
172
|
+
| CRuby 4.0.6, Fedora 44, aarch64 | Full suite, 265 examples |
|
|
173
|
+
| JRuby 10.1.1.0 (the reporter runs 10.1.0.0) | Verified once by hand, **not covered by the suite**: vault create/add/list, `bundle install` twice against a vault source, `bundle exec require`. `json 2.21.1 (java)` installed as a platform gem and resolved, which is the case `full_require_paths` has to get right |
|
|
174
|
+
| macOS `arm64-darwin-24` | **Not verified.** The reporter's own platform. Nothing here can run it |
|
|
175
|
+
|
|
176
|
+
JRuby has no permanent coverage because JRuby caps its own heap from the cgroup
|
|
177
|
+
and the development sandbox is small enough that the cap lands at 148 MB, where
|
|
178
|
+
even a single `gem fetch` dies. The one successful hand-run above happened in a
|
|
179
|
+
lucky memory window and did not reproduce. A JRuby image, rake task and spec
|
|
180
|
+
were written and then reverted rather than shipped unverified: harness code
|
|
181
|
+
nobody has watched pass is the same defect as a spec that cannot fail. On a
|
|
182
|
+
machine with ordinary memory this is worth adding, and it is the highest-value
|
|
183
|
+
gap left, since issue #13 was reported against JRuby as well as CRuby.
|
|
184
|
+
|
|
185
|
+
## Coverage
|
|
186
|
+
|
|
187
|
+
`spec/support/vault_sourced_gemfile_examples.rb` applies "a complete bundle" to
|
|
188
|
+
a vault-sourced Gemfile and then re-applies it after each user action: deleting
|
|
189
|
+
`Gemfile.lock`, deleting `.bundle`, deleting both, removing the vaulted gem,
|
|
190
|
+
adding a gem from rubygems, adding the project's own gemspec (the reporter's
|
|
191
|
+
Gemfile shape), adding another gem from the same vault, and adding one from a
|
|
192
|
+
second vault. `spec/integration/vaulted_project_spec.rb` runs that whole
|
|
193
|
+
group under four bundler configurations — stock, an install path chosen, that
|
|
194
|
+
path undone, and the project's gems cached — and
|
|
195
|
+
`spec/integration/no_ambient_gemvault_spec.rb` covers the machine that has no
|
|
196
|
+
gemvault of its own, where the plugin root has to carry the whole dependency
|
|
197
|
+
set.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "rake/clean"
|
|
2
|
+
require "bundler/gem_tasks"
|
|
3
|
+
require "rspec/core/rake_task"
|
|
4
|
+
require "rubocop/rake_task"
|
|
5
|
+
require "open3"
|
|
6
|
+
|
|
7
|
+
def gemvault_contains?(gemvault_file, gem)
|
|
8
|
+
response, status = Open3.capture2e("gemvault", "list", gemvault_file)
|
|
9
|
+
unless status.success?
|
|
10
|
+
warn "Failed to list gems in vault:"
|
|
11
|
+
warn response
|
|
12
|
+
exit 1
|
|
13
|
+
end
|
|
14
|
+
gems = response.lines(chomp: true)
|
|
15
|
+
gemname_and_version = Pathname(gem).basename.sub_ext("").to_s
|
|
16
|
+
gems.include?(gemname_and_version)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def in_root_dir(&)
|
|
20
|
+
chdir(Bundler.root, &)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def gemvault(*, **)
|
|
24
|
+
sh "gemvault", *, **
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
28
|
+
spec.pattern = FileList["spec/**/*_spec.rb"]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
RuboCop::RakeTask.new
|
|
32
|
+
CLOBBER.include "dist"
|
|
33
|
+
|
|
34
|
+
desc "Generate a new cop with a template"
|
|
35
|
+
task :new_cop, [:cop] do |_task, args|
|
|
36
|
+
require "rubocop"
|
|
37
|
+
|
|
38
|
+
cop_name = args.fetch(:cop) do
|
|
39
|
+
warn "usage: bundle exec rake new_cop[Department/Name]"
|
|
40
|
+
exit!
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
generator = RuboCop::Cop::Generator.new(cop_name)
|
|
44
|
+
generator.write_source
|
|
45
|
+
generator.write_spec
|
|
46
|
+
generator.inject_require(root_file_path: "lib/rubocop/cop/kaizo_cops.rb")
|
|
47
|
+
generator.inject_config(config_file_path: "config/default.yml")
|
|
48
|
+
|
|
49
|
+
puts generator.todo
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
directory "dist" do
|
|
53
|
+
mkdir "dist"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
file "dist/vault.gemv" => "dist" do
|
|
57
|
+
in_root_dir do
|
|
58
|
+
gemvault "new", "dist/vault.gemv"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
ENV["gem_push"] = "0"
|
|
63
|
+
namespace :release do
|
|
64
|
+
desc "release to a vault"
|
|
65
|
+
task vault: ["dist/vault.gemv", :build] do
|
|
66
|
+
FileList["pkg/*.gem"].each do |v|
|
|
67
|
+
in_root_dir do
|
|
68
|
+
gemvault "add", "dist/vault.gemv", v unless gemvault_contains? "dist/vault.gemv", v
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
Rake::Task[:release].enhance ["release:vault"]
|
|
75
|
+
|
|
76
|
+
task default: [:spec, :rubocop]
|
data/issues.rec
CHANGED
|
@@ -57,9 +57,9 @@ Description: Installing bundler-source-vault 0.1.2
|
|
|
57
57
|
+ from /Users/davidgillis/.rbenv/versions/4.0.1/lib/ruby/site_ruby/4.0.0/rubygems.rb:304:in 'Gem.activate_and_load_bin_path'
|
|
58
58
|
+ from /Users/davidgillis/.rbenv/versions/4.0.1/bin/bundle:25:in '<main>'
|
|
59
59
|
+ /Users/davidgillis/.rbenv/versions/4.0.1/lib/ruby/gems/4.0.0/gems/bundler-4.0.8/lib/bundler/source_list.rb:59:in 'Bundler::SourceList#add_plugin_source': undefined method 'new' for nil (NoMethodError)
|
|
60
|
-
+
|
|
60
|
+
+
|
|
61
61
|
+ add_source_to_list Plugin.source(source).new(options), @plugin_sources
|
|
62
|
-
+
|
|
62
|
+
+
|
|
63
63
|
+ RESOLUTION: replicated by spec/integration/bundle_install_spec.rb ("path-installed
|
|
64
64
|
+ bundler plugin's source directory has been renamed"): Bundler's plugin index pins
|
|
65
65
|
+ the absolute path, and `gemvault doctor` clears it and reinstalls. Installing the
|
|
@@ -86,7 +86,7 @@ Description: Steps to replicate:
|
|
|
86
86
|
+ ```
|
|
87
87
|
+
|
|
88
88
|
+ Where vendored.gemv is the name of the old file, and there is still an entry in Gemfile.lock
|
|
89
|
-
+
|
|
89
|
+
+
|
|
90
90
|
+ RESOLUTION: fixed on the tarvault branch; replicated by
|
|
91
91
|
+ spec/integration/bundle_install_spec.rb ("when the .gemv file is renamed and the
|
|
92
92
|
+ Gemfile updated to match"), passing.
|
|
@@ -101,7 +101,7 @@ Description: This vault is in vendor/vendored_gems.gmv, relative to the Gemfile
|
|
|
101
101
|
+ ```
|
|
102
102
|
+ Installing acme 1.0.1 from vault vendored_gems.gemv
|
|
103
103
|
+ ```
|
|
104
|
-
+
|
|
104
|
+
+
|
|
105
105
|
+ RESOLUTION: fixed on the tarvault branch; replicated by
|
|
106
106
|
+ spec/integration/bundle_install_spec.rb ("logs the relative path as written"),
|
|
107
107
|
+ passing.
|
|
@@ -122,7 +122,7 @@ Description: Anytime I run bundle install, I always see:
|
|
|
122
122
|
+ ```
|
|
123
123
|
+
|
|
124
124
|
+ This is unacceptable. these should only need to be installed once
|
|
125
|
-
+
|
|
125
|
+
+
|
|
126
126
|
+ ANALYSIS: upstream Bundler behavior. Bundler::Plugin.gemfile_install runs on
|
|
127
127
|
+ every `bundle install`/`bundle update` (bundler cli/install.rb:41), re-resolves
|
|
128
128
|
+ the inferred plugin definition remotely, and Source::Rubygems#install checks
|
|
@@ -143,7 +143,7 @@ Description: Consider the following:
|
|
|
143
143
|
+ ```
|
|
144
144
|
+
|
|
145
145
|
+ Notice an absolute path was passed to --source, yet it tried to resolve locally
|
|
146
|
-
+
|
|
146
|
+
+
|
|
147
147
|
+ RESOLUTION: fixed on the tarvault branch; replicated by
|
|
148
148
|
+ spec/integration/gem_install_spec.rb ("accepts a vault:// URI with an absolute
|
|
149
149
|
+ path" and the file:// variant), passing. URI stripping now lives in
|
|
@@ -158,7 +158,7 @@ Description: When adding a gem like 'ronin-db-0.2.1.patch1.gem', gemvault succes
|
|
|
158
158
|
+ gemvault add myvault.gemv ronin-db-0.2.1.patch1.gem # success
|
|
159
159
|
+ gem install --debug --verbose --clear-sources --source file://myvault.gemv ronin-db # failure
|
|
160
160
|
+ ```
|
|
161
|
-
+
|
|
161
|
+
+
|
|
162
162
|
+ RESOLUTION: RubyGems semantics, not a vault bug. A version containing letters
|
|
163
163
|
+ (0.2.1.patch1) is a prerelease everywhere in RubyGems, and `gem install`
|
|
164
164
|
+ excludes prereleases unless --pre is passed; with --pre the install from a
|
|
@@ -171,7 +171,7 @@ Id: 7
|
|
|
171
171
|
Updated: Sun, 19 Jul 2026 03:27:39 +0000
|
|
172
172
|
Name: Gemvault pollutes project dir with plugin files in .bundle
|
|
173
173
|
Description: Why is it not using the plugin that is already installed globally?
|
|
174
|
-
+
|
|
174
|
+
+
|
|
175
175
|
+ ANALYSIS: two parts. (1) Global `bundle plugin install bundler-source-vault`
|
|
176
176
|
+ crashed outright (issue #10's bug also hit the global root); that is fixed and
|
|
177
177
|
+ covered by spec/integration/plugin_install_spec.rb ("when run outside any
|
|
@@ -192,7 +192,7 @@ Description: Consider the following:
|
|
|
192
192
|
+ ```
|
|
193
193
|
+
|
|
194
194
|
+ Notice an absolute path was passed to --source, yet it tried to resolve locally
|
|
195
|
-
+
|
|
195
|
+
+
|
|
196
196
|
+ RESOLUTION: duplicate of #5; see its resolution.
|
|
197
197
|
Status: closed
|
|
198
198
|
|
|
@@ -200,7 +200,7 @@ Id: 9
|
|
|
200
200
|
Updated: Sun, 19 Jul 2026 03:27:39 +0000
|
|
201
201
|
Name: Gemvault commands should also be able to accept a uri
|
|
202
202
|
Description: e.g. gemvault list vault:///Users/davidgillis/repos/vault/rubylib/myvault.gemv
|
|
203
|
-
+
|
|
203
|
+
+
|
|
204
204
|
+ RESOLUTION: implemented. Gemvault::VaultPath resolves vault:// and file://
|
|
205
205
|
+ locators (absolute and two-slash relative forms) and every CLI command that
|
|
206
206
|
+ opens a vault goes through it, as does the RubyGems source. Covered by
|
|
@@ -617,7 +617,7 @@ Description:
|
|
|
617
617
|
+ https://github.com/ruby/rubygems/search?q=cannot+load+such+file+--+bundler%2Fplugin%2Fvault_source&type=Issues
|
|
618
618
|
+
|
|
619
619
|
+ If there aren't any reports for this error yet, please fill in the new issue form located at https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md. Make sure to copy and paste the full output of this command under the "What happened instead?" section.
|
|
620
|
-
+
|
|
620
|
+
+
|
|
621
621
|
+ RESOLUTION: two root causes, both fixed. (1) `bundle plugin install` switches
|
|
622
622
|
+ GEM_HOME to the plugin root mid-process, and RubyGems' spec stub cache is
|
|
623
623
|
+ populated during resolution, before gemvault is installed there; the shim's
|
|
@@ -637,14 +637,14 @@ Id: 11
|
|
|
637
637
|
Updated: Sun, 19 Jul 2026 03:56:57 +0000
|
|
638
638
|
Name: CI tests aren't running
|
|
639
639
|
Description: CI tests should be running on all platforms
|
|
640
|
-
+
|
|
640
|
+
+
|
|
641
641
|
+ ANALYSIS: .github/workflows/ci.yml exists (unit tests, specs, rubocop on
|
|
642
642
|
+ push/PR to master). Two likely reasons it cannot go green: (1) `rake rubocop`
|
|
643
643
|
+ exits nonzero on the pre-existing Gemspec/RequiredRubyVersion offenses
|
|
644
644
|
+ (required_ruby_version ">= 3.4.8" vs TargetRubyVersion 4.0 in .rubocop.yml) --
|
|
645
645
|
+ pick one and align; (2) `rake spec` builds/uses a podman image, so the runner
|
|
646
646
|
+ needs podman available. Not replicable as a podman rspec spec (CI infra).
|
|
647
|
-
+
|
|
647
|
+
+
|
|
648
648
|
+ RESOLUTION: three blockers fixed. (1) TargetRubyVersion aligned to 3.4.8, the
|
|
649
649
|
+ gemspec floor, clearing the Gemspec/RequiredRubyVersion offenses; whole
|
|
650
650
|
+ tracked tree is rubocop-clean. (2) The integration job invoked
|
|
@@ -663,14 +663,14 @@ Updated: Sun, 19 Jul 2026 03:27:39 +0000
|
|
|
663
663
|
Name: bundle exec fails after successful bundle install with path vendor
|
|
664
664
|
Description: Reported 2026-07-19 (reversal-store): bundle install succeeds, then
|
|
665
665
|
+ any `bundle exec` fails while parsing the Gemfile:
|
|
666
|
-
+
|
|
666
|
+
+
|
|
667
667
|
+ ```
|
|
668
668
|
+ [!] There was an error parsing `Gemfile`: Could not find 'bundler' (>= 2.0)
|
|
669
669
|
+ among 101 total gem(s)
|
|
670
670
|
+ Checked in 'GEM_PATH=/workspace/vendor/ruby/4.0.0' at:
|
|
671
671
|
+ /workspace/.bundle/plugin/specifications/gemvault-0.1.5.gemspec
|
|
672
672
|
+ ```
|
|
673
|
-
+
|
|
673
|
+
+
|
|
674
674
|
+ RESOLUTION: gemvault declared bundler as a runtime dependency. Under
|
|
675
675
|
+ `bundle exec` with path vendor, GEM_PATH is restricted to the app bundle, and
|
|
676
676
|
+ on rubies where bundler is a regular (non-default) gem its spec is invisible,
|
|
@@ -681,3 +681,79 @@ Description: Reported 2026-07-19 (reversal-store): bundle install succeeds, then
|
|
|
681
681
|
+ reinstalling bundler as a regular gem and deleting its default-gem spec stub;
|
|
682
682
|
+ also covers the system-installed (`gem install gemvault`) flow. Both passing.
|
|
683
683
|
Status: closed
|
|
684
|
+
|
|
685
|
+
Id: 13
|
|
686
|
+
Updated: Sun, 26 Jul 2026 20:33:33 -0400
|
|
687
|
+
Name: bundle install fails, nothing seems to fix it
|
|
688
|
+
Description: bundle install does not complete successfully (ruby 4.0.1 &jruby 10.1.0.0). Tried doing all of these:
|
|
689
|
+
+ 1. gemvault doctor (below, completes successfully, but another bundle install fails)
|
|
690
|
+
+ 2. rm -rf .bundle/plugin && bundle install
|
|
691
|
+
+ 3. rm -f Gemfile.lock && bundle install
|
|
692
|
+
+ 4. 2 & 3 combined before bundle install
|
|
693
|
+
+
|
|
694
|
+
+ ```
|
|
695
|
+
+ jruby -S gemvault doctor
|
|
696
|
+
+ Uninstalled plugin bundler-source-vault
|
|
697
|
+
+ Fetching gem metadata from https://rubygems.org/.......
|
|
698
|
+
+ Resolving dependencies...
|
|
699
|
+
+ Installing bundler-source-vault 0.2.0
|
|
700
|
+
+ Installed plugin bundler-source-vault
|
|
701
|
+
+ Bundle complete! 15 Gemfile dependencies, 50 gems now installed.
|
|
702
|
+
+ Bundled gems are installed into `./vendor`
|
|
703
|
+
+ ❯ bundle install
|
|
704
|
+
+ Fetching gem metadata from https://rubygems.org/.......
|
|
705
|
+
+ Resolving dependencies...
|
|
706
|
+
+ Installing bundler-source-vault 0.2.0
|
|
707
|
+
+
|
|
708
|
+
+ [!] There was an error parsing `Gemfile`: cannot load such file -- bundler/plugin/vault_source. Bundler cannot continue.
|
|
709
|
+
+
|
|
710
|
+
+ # from /Users/davidgillis/repos/reversal-store/Gemfile:19
|
|
711
|
+
+ # -------------------------------------------
|
|
712
|
+
+ #
|
|
713
|
+
+ > source "vendor/vendored.gemv", type: :vault do
|
|
714
|
+
+ # gem 'jarpack', "~> 0.2.1"
|
|
715
|
+
+ # -------------------------------------------
|
|
716
|
+
+ ```
|
|
717
|
+
+
|
|
718
|
+
+ RESOLUTION: the plugin root never held gemvault, and the shim's require had no
|
|
719
|
+
+ way to reach the copy that did exist. Bundler's Source::Rubygems#install
|
|
720
|
+
+ short-circuits on `installed?(spec) && !force`, so a plugin dependency already
|
|
721
|
+
+ present on the ambient GEM_PATH is never downloaded into the plugin root --
|
|
722
|
+
+ which is every machine where `gem install gemvault` has run. That stays hidden
|
|
723
|
+
+ until the app bundle is populated: from the second `bundle install` onward
|
|
724
|
+
+ Bundler restricts GEM_PATH to the bundle, the ambient gemvault falls out of
|
|
725
|
+
+ scope, and nothing is left to resolve. Hence the reported permanence: step 2-4
|
|
726
|
+
+ all rebuild the same incomplete plugin root. shim/plugins.rb now locates
|
|
727
|
+
+ gemvault's lib across every root that can hold it, including the ones Bundler
|
|
728
|
+
+ masked (Bundler.original_env GEM_HOME/GEM_PATH), and puts it on $LOAD_PATH
|
|
729
|
+
+ instead of relying on gem activation. Using $LOAD_PATH also fixes a second
|
|
730
|
+
+ failure found while reproducing this -- `Could not find 'command_kit' (~> 0.6)`
|
|
731
|
+
+ when gemvault does land in the plugin root -- because activation demands the
|
|
732
|
+
+ full runtime dependency set while vault_source.rb reaches the rest of gemvault
|
|
733
|
+
+ through require_relative alone.
|
|
734
|
+
+
|
|
735
|
+
+ The integration suite could not have caught this. Dockerfile.test installed
|
|
736
|
+
+ gemvault AND bundler-source-vault system-wide, so `require
|
|
737
|
+
+ "bundler/plugin/vault_source"` resolved from the ambient GEM_HOME no matter
|
|
738
|
+
+ what the plugin root contained, and the ruby base image's
|
|
739
|
+
+ BUNDLE_APP_CONFIG=/usr/local/bundle moved Bundler::Plugin.root out of the
|
|
740
|
+
+ project so no spec ever exercised a project-local .bundle/plugin. The shim is
|
|
741
|
+
+ no longer installed system-wide (specs resolve it from the local gem index),
|
|
742
|
+
+ BUNDLE_APP_CONFIG is unset in the container, and gemvault stays installed
|
|
743
|
+
+ system-wide on purpose because that is the trigger. Removing the mask turned 13
|
|
744
|
+
+ previously green specs red; all now pass against the tree's shim rather than an
|
|
745
|
+
+ ambient copy. Replicated by spec/integration/plugin_root_deps_spec.rb (repeated
|
|
746
|
+
+ bundle install, and bundle exec under a restricted GEM_PATH).
|
|
747
|
+
Status: closed
|
|
748
|
+
|
|
749
|
+
Id: 14
|
|
750
|
+
Updated: Wed, 29 Jul 2026 16:41:11 -0400
|
|
751
|
+
Name: gemvault doctor fails when bundler/inline is used
|
|
752
|
+
Description: Loudly fails with 2 errors, one of which is "can't find gemfile"
|
|
753
|
+
Status: open
|
|
754
|
+
|
|
755
|
+
Id: 15
|
|
756
|
+
Updated: Wed, 29 Jul 2026 17:39:23 -0400
|
|
757
|
+
Name: gemvault new fails on path/to/gemvault.gemv
|
|
758
|
+
Description: I did it in /tmp, maybe that's why?
|
|
759
|
+
Status: open
|
data/lib/gemvault/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gemvault
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Gillis
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0.6'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: json
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.0'
|
|
26
40
|
description: Portable .gemv archives for bundling and distributing multiple gems as
|
|
27
41
|
a single file, read directly by Bundler and RubyGems
|
|
28
42
|
email:
|
|
@@ -36,18 +50,19 @@ files:
|
|
|
36
50
|
- ".rspec"
|
|
37
51
|
- ".rubocop.yml"
|
|
38
52
|
- ".ruby-version"
|
|
39
|
-
- ASSESSMENT.md
|
|
40
53
|
- CHANGELOG.md
|
|
41
54
|
- CLAUDE.md
|
|
42
55
|
- Dockerfile.test
|
|
43
|
-
- LICENSE
|
|
44
56
|
- LICENSE.txt
|
|
45
|
-
- MACROPLAN.md
|
|
46
57
|
- README.md
|
|
47
58
|
- Rakefile
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
59
|
+
- _claude/archives/ASSESSMENT.md
|
|
60
|
+
- _claude/archives/MACROPLAN.md
|
|
61
|
+
- _claude/archives/issue-13-root-cause.md
|
|
62
|
+
- _claude/archives/plans/2026-04-16-container-integration-tests.md
|
|
63
|
+
- _claude/archives/tarvault-findings.md
|
|
64
|
+
- _claude/archives/tarvault.md
|
|
65
|
+
- docs/Rakefile.vault_example
|
|
51
66
|
- exe/gemvault
|
|
52
67
|
- issues.rec
|
|
53
68
|
- lib/bundler/plugin/vault_source.rb
|
|
@@ -104,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
104
119
|
- !ruby/object:Gem::Version
|
|
105
120
|
version: '0'
|
|
106
121
|
requirements: []
|
|
107
|
-
rubygems_version: 4.0.
|
|
122
|
+
rubygems_version: 4.0.17
|
|
108
123
|
specification_version: 4
|
|
109
124
|
summary: Multi-gem portable archives — a gem server in a file
|
|
110
125
|
test_files: []
|
data/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026
|
|
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.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|