enola 0.4.4.1 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84ee668ecfaed2e6d8ebc55fe5054e1635300502f762887f2d7b96660beb908f
4
- data.tar.gz: 2905c89cad26afb7f6226515c7b3620ed6e089c16ff5886398f4043deda50360
3
+ metadata.gz: 35717854ffb165b2d79fe06be0998d847a25a0ce10a2907ab155a39fd3119a75
4
+ data.tar.gz: 8940517eabb47871b5321fd23ed4f369cc7f31486f2f486096fdf78cd8e6cbcc
5
5
  SHA512:
6
- metadata.gz: e8b8a19a54c9f13be8b2dd6a1d62b5cb999d14a7ff959f0771ca25cfc63b6fac3822bc31ccd676cc44c60e4106401c626f9fc1e7b2802a68d3f5f68a0c23c322
7
- data.tar.gz: 42a9119e1b7d33d1a20b3e3d9f7a79f2c8199de3599365f6d13674db19a968aba0a749180014b061bb413940a17ae8212ebf63181ee40302acdcae20952c1bb5
6
+ metadata.gz: cd181d1618ba05ebea4a77136ed6fc5d3afd197978c955576e1c8554d374b7558c3b4b0bd12b87e14f4c88642ff55faa6a5e8ef35bf12e33963fe7345418a778
7
+ data.tar.gz: 89206de715d8b08d9b7138cf4400df93b9385cf8b45c94bb08aa7de7b90f01267398e4d5da1f1ed3a4e87cd58ad33cf1e5f7492a6480ccee647a9129806ec142
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## enola 0.5.1 (2026-08-23)
2
+
3
+ The resolver no longer probes its own binstub. It read a candidate's first 512
4
+ bytes looking for the marker RubyGems writes, and a real binstub carries a
5
+ `/bin/sh` + `ruby -x` preamble holding the interpreter's absolute path, which puts
6
+ that marker around byte 580 — outside the window. So the guard missed every
7
+ RubyGems-generated binstub, the wrapper ran itself, and running itself has no
8
+ bottom: `enola --version` on a cold cache spawned Ruby processes until it was
9
+ killed. The whole file is read now, capped at 64 KiB so a released binary is never
10
+ slurped only to be rejected, and `Gem.bin_path` is recognised beside
11
+ `Gem.activate_bin_path`. A probe also marks its child's environment, and a resolver
12
+ that sees the marker declines to look at PATH at all, so the recursion is bounded
13
+ by construction rather than by how well a heuristic reads a file.
14
+
15
+ The marker is written where it is spawned: every probe passes it into the child,
16
+ so a wrapper reached under another name leaves PATH alone instead of probing in
17
+ turn. That bound is what covers the wrappers the content check cannot see, a
18
+ version manager's shim among them, which carries none of the markers a binstub
19
+ does. Reported and fixed by dejo1307 in #1.
20
+
1
21
  ## munola 0.4.4.2 and munola-rb 0.4.4.2 (2026-08-23)
2
22
 
3
23
  munola follows the channel it drives. Its binary is now cut from the stable
data/LICENSE CHANGED
@@ -187,7 +187,7 @@ APPENDIX: How to apply the Apache License to your work.
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright (c) 2026 Dejan Menges
190
+ Copyright (c) 2026 Muhamed Isabegovic
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -11,8 +11,9 @@ once, in `enola-rb`, and the munola gems add only what is munola's own.
11
11
 
12
12
  ## `enola`
13
13
 
14
- The wrapper of the released enola. Its version is the upstream release it
15
- drives: `enola 0.4.4` runs enola-labs' v0.4.4.
14
+ The wrapper of the released enola. The gem versions itself; the release it
15
+ drives is `Enola::UPSTREAM_VERSION`, v0.4.4 as of `enola 0.5.0`, and every
16
+ gemspec summary names it.
16
17
 
17
18
  ```ruby
18
19
  gem "enola"
@@ -44,7 +45,7 @@ This gem is not an enola-labs release; it runs theirs.
44
45
 
45
46
  ## `enola-rb`
46
47
 
47
- The Rails layer over `enola`. It depends on `enola` at the same version and on
48
+ The Rails layer over `enola`. It depends on `enola` at the same minor and on
48
49
  [enola-guides](https://github.com/misabegovic/enola-guides), and adds nothing
49
50
  to the binary's surface.
50
51
 
@@ -73,10 +74,10 @@ remedy.
73
74
 
74
75
  One person's taste on top of enola: the same wrapper over another channel,
75
76
  the builds cut from [a fork of enola](https://github.com/misabegovic/enola),
76
- versioned as the upstream they are built on plus a fourth segment
77
- (`0.4.4.1` drives a build on v0.4.4), each release naming what differs from
78
- that upstream. It is offered upstream where it fits and is not positioned
79
- against it. What it adds is the channel and the catalogue.
77
+ each release naming what differs from that upstream. The gem versions itself;
78
+ the channel release it fetches is `Munola::CHANNEL_VERSION`, which carries the
79
+ upstream it is built on plus a segment of its own (`0.4.4.2` on v0.4.4). It is
80
+ offered upstream where it fits and is not positioned against it. What it adds is the channel and the catalogue.
80
81
 
81
82
  ```ruby
82
83
  gem "munola"
@@ -99,18 +100,19 @@ inflection table; it writes `mcp-arch.yaml` with both Ruby providers on by
99
100
  default, Prism through the script the `enola` gem carries and Rubydex built
100
101
  into the binary, and fetches the Rubydex library, a failed fetch reported as a
101
102
  named skip. It never asks a question. `munola --version` names the munola
102
- version, the upstream it is built on and which binary answered.
103
+ version, the channel release and upstream it is built on, and which binary
104
+ answered.
103
105
 
104
106
  The binary comes from the fork's releases the way `enola`'s comes from
105
107
  upstream's, fetched on first use and verified against the sha256 the release
106
108
  publishes; `MUNOLA_BINARY=/path/to/enola` names one to drive instead, and
107
- every command says which answered. `munola` depends on `enola` at its upstream
108
- version and on `enola-guides` 0.3.1 or later; requiring it loads no Rails.
109
+ every command says which answered. `munola` depends on `enola` at the same
110
+ minor and on `enola-guides` 0.3.1 or later; requiring it loads no Rails.
109
111
 
110
112
  ## `munola-rb`
111
113
 
112
114
  The Rails layer over `munola`, what `enola-rb` is to `enola`. It depends on
113
- both at their own versions and adds one generator.
115
+ both at the same minor and adds one generator.
114
116
 
115
117
  ```ruby
116
118
  gem "munola-rb"
data/lib/enola/probe.rb CHANGED
@@ -6,12 +6,18 @@ module Enola
6
6
  class Probe
7
7
  SURFACES = %w[constraints providers check plan hook].freeze
8
8
 
9
+ # A probed binary may be this wrapper wearing another name. The marker
10
+ # travels into the child, where the resolver reads it and leaves PATH
11
+ # alone, so a probe cannot start another one.
12
+ PROBE_ENV = "ENOLA_RESOLVER_PROBE"
13
+ CHILD_ENV = {PROBE_ENV => "1"}.freeze
14
+
9
15
  def initialize(binary)
10
16
  @binary = binary
11
17
  end
12
18
 
13
19
  def version
14
- out, status = Open3.capture2e(@binary, "--version")
20
+ out, status = Open3.capture2e(CHILD_ENV, @binary, "--version")
15
21
  return nil unless status.success?
16
22
 
17
23
  out[/\d+\.\d+\.\d+(?:[.-][\w.]+)?/]
@@ -23,7 +29,7 @@ module Enola
23
29
  # for --help); one it lacks is refused by the top-level dispatch by name.
24
30
  def capabilities
25
31
  SURFACES.to_h do |surface|
26
- out, = Open3.capture2e(@binary, surface, "--help")
32
+ out, = Open3.capture2e(CHILD_ENV, @binary, surface, "--help")
27
33
  [surface.to_sym, !out.include?("unknown command \"#{surface}\"")]
28
34
  rescue SystemCallError
29
35
  [surface.to_sym, false]
@@ -25,9 +25,19 @@ module Enola
25
25
 
26
26
  EXECUTABLE = File.expand_path("../../exe/enola", __dir__)
27
27
 
28
+ # A binstub is a script; the released binary is megabytes. The cap keeps the
29
+ # whole-file read cheap and means a real binary is never slurped to be rejected.
30
+ MAX_SCRIPT_BYTES = 64 * 1024
31
+
28
32
  private
29
33
 
30
34
  def matching_path_binary
35
+ # A probe runs the candidate, and the candidate may be this wrapper wearing
36
+ # another name. The marker travels into that child, and a resolver that finds
37
+ # it declines to look at PATH — so the recursion is bounded by construction
38
+ # rather than by how well the check below reads a file.
39
+ return [nil, nil] if ENV[Probe::PROBE_ENV]
40
+
31
41
  candidate = @path.split(File::PATH_SEPARATOR).map { |dir| File.join(dir, "enola") }
32
42
  .find { |bin| File.executable?(bin) && !wrapper?(bin) }
33
43
  return [nil, nil] unless candidate
@@ -39,11 +49,18 @@ module Enola
39
49
  # Bundler puts this gem's own exe on PATH, and a rubygems binstub for the
40
50
  # gem looks like a binary too; probing either would run the wrapper inside
41
51
  # itself without end.
52
+ #
53
+ # The whole file is read, not a fixed head. RubyGems writes a /bin/sh + `ruby -x`
54
+ # polyglot preamble carrying the interpreter's absolute path, so the marker sits
55
+ # ~580 bytes in — past the 512 this used to read, which made the guard miss every
56
+ # real binstub and the wrapper probe itself without end.
42
57
  def wrapper?(bin)
43
58
  return true if File.realpath(bin) == File.realpath(EXECUTABLE)
59
+ return false if File.size(bin) > MAX_SCRIPT_BYTES
44
60
 
45
- head = File.binread(bin, 512)
46
- head.include?("Gem.activate_bin_path") || head.include?('require "enola"')
61
+ body = File.binread(bin)
62
+ body.include?("Gem.activate_bin_path") || body.include?("Gem.bin_path") ||
63
+ body.include?('require "enola"')
47
64
  rescue SystemCallError
48
65
  true
49
66
  end
data/lib/enola/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enola
4
- # The release this wrapper drives. VERSION carries a patch segment for
5
- # wrapper-only fixes, so what to fetch is stated separately.
4
+ # The gem versions itself. UPSTREAM_VERSION names the enola release it
5
+ # fetches and drives.
6
6
  UPSTREAM_VERSION = "0.4.4"
7
- VERSION = "#{UPSTREAM_VERSION}.1"
7
+ VERSION = "0.5.1"
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enola
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4.1
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muhamed Isabegovic
@@ -26,8 +26,9 @@ dependencies:
26
26
  version: '1.3'
27
27
  description: |
28
28
  A pure-Ruby wrapper around enola, the architecture-graph tool by enola-labs.
29
- The gem's version is the upstream release it drives. The binary is not in
30
- the gem: the first command that needs it downloads the release for your
29
+ The gem versions itself; the enola release it drives is named in its
30
+ UPSTREAM_VERSION, 0.4.4 here. The binary is not in the
31
+ gem: the first command that needs it downloads the release for your
31
32
  platform, verifies it against the checksum the release publishes, and keeps
32
33
  it in a per-user cache. Every command and exit code is forwarded unchanged.
33
34
  This gem is not an enola-labs release.
@@ -79,6 +80,6 @@ requirements: []
79
80
  rubygems_version: 3.5.22
80
81
  signing_key:
81
82
  specification_version: 4
82
- summary: 'Runs the released enola from Ruby: fetched on first use, verified, pinned
83
- to this gem''s version.'
83
+ summary: 'Runs the released enola from Ruby: fetched on first use, verified, cached.
84
+ This release drives enola 0.4.4.'
84
85
  test_files: []