hotcell-client 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62be0a0a7b86a0273cfdfbe7ed7cd04460e536aeb3af1a03b08b944930c18082
4
- data.tar.gz: cf6ffc9e65616d8cb89219f57e8273ecd8a7f8d47b5fc85db74f6014ff1e61bd
3
+ metadata.gz: c907b155be1d28cc8ca37320ac22f71689f581390e6aa45e77a5a7e31bce04f3
4
+ data.tar.gz: cb676888f838068d7b6671df95fc869a9bd5736d04556e0f2b0c9a8352e7e300
5
5
  SHA512:
6
- metadata.gz: 93e74a6462bf95bed04585d87588df0916eaadb4eaab24b37966c8c7266f0051a5a9c8de6c825a542c54a0481ae885799bf56b892f7d184eaf99ee83895ff6ee
7
- data.tar.gz: 99571523cc72ad1845a95dcab86dab7f9de917673543832d7abf591e182ec927dd77c542640fe9b94777eb39fcdbf8e7746e147f6fd41571b3f00251870d0646
6
+ metadata.gz: d436910383ab67af5a826efd3854441c1c90d28bd792657bd6598c27940e7fffa80b1eb50c421eaba737152b4c93a1dd2d2f29243bb9529762ba25bf699bb26b
7
+ data.tar.gz: e3e71a17d0f2e152fb8a504c6966a9fcb1addf63dc3e383cfa021e402d9c322221c02545bfea92fa9f467952dd492e0bc8b3bc945bc787853df38c491b2b3998
data/lib/hot_cell/cell.rb CHANGED
@@ -66,14 +66,13 @@ module HotCell
66
66
  @on_contract_skew&.call error, self
67
67
  end
68
68
 
69
- # Static, and called once at boot. The cheapest way to catch a client pointed at a cell that does not
70
- # carry the operation it wants, which is otherwise an `unsupported` on the first real request.
69
+ # Static, and called once at boot.
71
70
  #
72
71
  # Boot must not fail when a cell does not answer. A cell that is down at app boot is a degraded
73
72
  # deployment rather than a broken one, and an application that refuses to start because its thumbnail
74
73
  # cell is restarting is worse than one that serves placeholders. So this warns and carries on.
75
74
  #
76
- # Nor when a cell answers something this client cannot read. The three warnings below reach into the
75
+ # Nor when a cell answers something this client cannot read. The two warnings below reach into the
77
76
  # description without checking types, so a cell that sends the wrong ones raises here — and the README
78
77
  # calls `describe_cells` from `after_initialize`, where that is not a failed check but an application
79
78
  # that does not boot. The process that wrote the description is the one that runs untrusted content.
@@ -86,7 +85,6 @@ module HotCell
86
85
 
87
86
  response.result.tap do |described|
88
87
  warn_about_timeout described
89
- warn_about_missing_operations described
90
88
  warn_about_group_skew described
91
89
  end
92
90
  rescue StandardError => error
@@ -164,16 +162,6 @@ module HotCell
164
162
  "every operation that gives a tool a filename will fail with EACCES."
165
163
  end
166
164
 
167
- def warn_about_missing_operations(described)
168
- carried = Array(described[:operations])
169
- wanted = HotCell.clients.select { |client| client.hotcell == name }
170
-
171
- wanted.reject { |client| carried.include?(client.operation) }.each do |client|
172
- HotCell.logger.warn "hotcell #{name}: #{client} wants #{client.operation.inspect} and this cell " \
173
- "carries #{carried.inspect}"
174
- end
175
- end
176
-
177
165
  # A `nil` timeout reaches `Transport::Socket#receive` as `deadline: nil`, and reading with no deadline
178
166
  # blocks: a cell that accepts the connection and then never answers holds this caller for good. At
179
167
  # boot that is an application that never finishes starting, with no exception and nothing to rescue.
@@ -60,13 +60,6 @@ module HotCell
60
60
  cells.key?(name.to_s)
61
61
  end
62
62
 
63
- # Every HotCell::Client subclass, so a boot check can tell which cell is expected to carry what. This
64
- # records what the process has loaded rather than what it has configured, so resetting registrations
65
- # leaves it alone: the classes are still defined either way.
66
- def clients
67
- @clients ||= []
68
- end
69
-
70
63
  # Call once at boot, after registering. Warns and carries on; see Cell#describe.
71
64
  def describe_cells
72
65
  warn_about_group
@@ -3,6 +3,6 @@
3
3
  module HotCell
4
4
  # A class and not a module: this file loads before hot_cell/client.rb opens the same name.
5
5
  class Client
6
- VERSION = "0.2.0"
6
+ VERSION = "0.3.0"
7
7
  end
8
8
  end
@@ -40,11 +40,6 @@ module HotCell
40
40
  class << self
41
41
  include Declarations
42
42
 
43
- def inherited(subclass)
44
- super
45
- HotCell.clients << subclass
46
- end
47
-
48
43
  def hotcell(name = nil)
49
44
  return inherited_value(:@cell_name) if name.nil?
50
45
 
@@ -4,9 +4,21 @@
4
4
  # A cell carries a Ruby runtime and every gem in its loaded graph, all inside the blast radius, so treat
5
5
  # this file as a budget rather than an inventory. Which tools it holds is what decides its blast radius.
6
6
 
7
+ # The base image. This tag is mutable: `ruby:3.4-slim` moves as Debian and Ruby publish patches, so a
8
+ # clean build is only as reproducible and as patched as the tag on the day it runs. Build with
9
+ # `docker build --pull` to always take the newest patched base. If you also need to name the exact image
10
+ # you shipped, pin a digest (`FROM ruby:${RUBY_VERSION}-slim@sha256:…`) and refresh it on a schedule; the
11
+ # image scan in CI is what catches a base that has drifted into known-vulnerable either way.
7
12
  ARG RUBY_VERSION=3.4
8
13
  FROM ruby:${RUBY_VERSION}-slim
9
14
 
15
+ # Apply Debian's pending security patches. `--pull` takes the newest base tag, and the tag can still be
16
+ # behind an advisory that is already in `trixie-security`, because only a rebuild by docker-library/ruby
17
+ # moves it. Upgrading here makes the image's patch level its own rather than upstream's release cadence,
18
+ # and it is what keeps the image scan in CI passing on a fixable vulnerability the base has not picked up
19
+ # yet. It costs a layer and a little build time on every build.
20
+ RUN apt-get update && apt-get upgrade -y --no-install-recommends && rm -rf /var/lib/apt/lists/*
21
+
10
22
  # Install the tools and libraries your operations run — and nothing else. For example:
11
23
  #
12
24
  # RUN apt-get update && \
@@ -25,14 +37,28 @@ RUN mkdir -p /run/hotcell/cell /hotcell/operations && chown -R hotcell:hotcell /
25
37
 
26
38
  # HOME is /tmp because the cell's user has no home directory, and bundler wants one. A worker replaces
27
39
  # it with its slot's home before it serves anything.
40
+ #
41
+ # OpenMP sizes its thread pool from the host's core count, and a `cpus:` quota does not lower it, so an
42
+ # unbounded libvips or ImageMagick asks a 98-core host for 98 threads, each with an 8MB stack.
43
+ # `RLIMIT_DATA` charges those stacks, and libgomp calls `exit(1)` on the first `pthread_create` it cannot satisfy. Match
44
+ # OMP_NUM_THREADS to the container's `cpus:`: the number follows the allocation rather than being 2.
45
+ # OMP_THREAD_LIMIT bounds a library that raises the count itself, which is what ImageMagick does.
28
46
  ENV HOME=/tmp \
29
47
  BUNDLE_PATH=/hotcell/bundle \
30
48
  BUNDLE_WITHOUT=development \
49
+ OMP_NUM_THREADS=2 \
50
+ OMP_THREAD_LIMIT=8 \
31
51
  HOTCELL_OPERATIONS=/hotcell/operations \
32
52
  HOTCELL_DIR=/run/hotcell/cell
33
53
 
34
54
  WORKDIR /hotcell
35
55
 
56
+ # For a reproducible dependency graph, commit a Gemfile.lock next to the Gemfile so a clean build resolves
57
+ # the exact gems the lockfile names rather than whatever the sources offer that day. Generate it for the
58
+ # platform you deploy on — e.g. from a macOS checkout, `bundle lock --add-platform x86_64-linux` so the
59
+ # Linux image accepts it — and build frozen (`bundle install --frozen`, or set `BUNDLE_FROZEN=true`) to
60
+ # refuse a Gemfile that has drifted from the lockfile. Left off by default so a freshly installed scaffold
61
+ # builds before you have generated a lockfile.
36
62
  COPY --chown=hotcell:hotcell Gemfile* ./
37
63
  USER hotcell
38
64
  RUN bundle install
@@ -46,6 +72,13 @@ COPY operations/ /hotcell/operations/
46
72
  # root once the build is done. `read-only: true` covers this as well, and this holds without it.
47
73
  USER root
48
74
  RUN chown -R root:root /hotcell && chmod -R go-w /hotcell
75
+
76
+ # Strip the setuid and setgid bits off every binary the image carries (mount, umount, su, … from the base,
77
+ # plus anything a RUN above installed). The cell runs as an unprivileged user under `--cap-drop ALL` and
78
+ # `--security-opt no-new-privileges`, which already make these gadgets inert; removing the bits keeps a
79
+ # security image from shipping escalation tools it never uses. As the last root step it covers everything
80
+ # built above it. `-xdev` stays on the image's own filesystem; `chmod a-s` clears both bits.
81
+ RUN find / -xdev -type f -perm /06000 -exec chmod a-s {} +
49
82
  USER hotcell
50
83
 
51
84
  # Probes the supervisor's control socket from inside the container, where network: none does not apply.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hotcell-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dalessio
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.0
18
+ version: 0.3.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.2.0
25
+ version: 0.3.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activesupport
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -67,8 +67,8 @@ licenses:
67
67
  - MIT
68
68
  metadata:
69
69
  homepage_uri: https://github.com/basecamp/hotcell
70
- source_code_uri: https://github.com/basecamp/hotcell/tree/v0.2.0/hotcell-client
71
- changelog_uri: https://github.com/basecamp/hotcell/blob/v0.2.0/CHANGELOG.md
70
+ source_code_uri: https://github.com/basecamp/hotcell/tree/v0.3.0/hotcell-client
71
+ changelog_uri: https://github.com/basecamp/hotcell/blob/v0.3.0/CHANGELOG.md
72
72
  bug_tracker_uri: https://github.com/basecamp/hotcell/issues
73
73
  rubygems_mfa_required: 'true'
74
74
  rdoc_options: []