mirror of
https://github.com/Homebrew/brew.git
synced 2026-08-12 22:29:27 +04:00
Merge pull request #23202 from Homebrew/install-step-04-sandbox-hardening
Sandbox formula install steps
This commit is contained in:
@@ -23,11 +23,10 @@ module Homebrew
|
||||
post_install_steps_defined = f.post_install_steps_defined?
|
||||
post_install_defined = f.post_install_defined?
|
||||
|
||||
f.run_post_install_steps if post_install_steps_defined
|
||||
if post_install_defined
|
||||
if post_install_steps_defined || post_install_defined
|
||||
fi = FormulaInstaller.new(f, **{ debug: args.debug?, quiet: args.quiet?, verbose: args.verbose? }.compact)
|
||||
fi.post_install
|
||||
elsif !post_install_steps_defined
|
||||
else
|
||||
opoo "#{f}: no `post_install` method was defined in the formula!"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1598,6 +1598,7 @@ class Formula
|
||||
def run_post_install_steps
|
||||
return if post_install_steps.empty?
|
||||
|
||||
prefix_returns_versioned_prefix = @prefix_returns_versioned_prefix
|
||||
@prefix_returns_versioned_prefix = T.let(true, T.nilable(T::Boolean))
|
||||
|
||||
begin
|
||||
@@ -1605,7 +1606,7 @@ class Formula
|
||||
Homebrew::InstallSteps::Runner.new(context: self).run(post_install_steps)
|
||||
end
|
||||
ensure
|
||||
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
|
||||
@prefix_returns_versioned_prefix = prefix_returns_versioned_prefix
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1639,7 +1640,8 @@ class Formula
|
||||
ENV.activate_extensions!
|
||||
|
||||
with_logging("post_install") do
|
||||
post_install
|
||||
run_post_install_steps if post_install_steps_defined?
|
||||
post_install if post_install_defined?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1020,8 +1020,7 @@ on_request: installed_on_request?, options:)
|
||||
end
|
||||
else
|
||||
formula.install_etc_var
|
||||
formula.run_post_install_steps if formula.post_install_steps_defined?
|
||||
post_install if formula.post_install_defined?
|
||||
post_install if formula.post_install_steps_defined? || formula.post_install_defined?
|
||||
end
|
||||
|
||||
keg.prepare_debug_symbols if debug_symbols?
|
||||
|
||||
@@ -25,12 +25,12 @@ conversions can peel supported repeated statements out of larger hooks. Runtime
|
||||
handling runs formula steps first and then runs `post_install` last for the
|
||||
remaining Ruby work. Cask `*flight_steps` still replace the matching legacy
|
||||
flight block because cask artifacts already carry replacement semantics and
|
||||
warn when both forms are present. Post-install or postflight steps are not
|
||||
sandboxed for this iteration because they run only Homebrew-owned structured
|
||||
operations. The runner shape leaves room to sandbox future step types that
|
||||
invoke non-Homebrew code. Future cask work should sandbox all `*flight` run
|
||||
scripts from non-Homebrew and non-system sources, for example scripts shipped
|
||||
by upstream artifacts.
|
||||
warn when both forms are present. Formula post-install steps run in the same
|
||||
sandboxed subprocess as the remaining `post_install` hook, preserving its
|
||||
filesystem and network restrictions for structured Ruby operations and any
|
||||
commands they invoke. Future cask work should sandbox all `*flight` run scripts
|
||||
from non-Homebrew and non-system sources, for example scripts shipped by
|
||||
upstream artifacts.
|
||||
|
||||
The final target is not to keep legacy hooks and structured steps side by side.
|
||||
Once `homebrew/core` and `homebrew/cask` have been converted, all
|
||||
@@ -345,6 +345,12 @@ is stripped during metadata serialisation.
|
||||
non-Homebrew code and should be ready for future sandboxing. Land RuboCop
|
||||
autocorrection and tap-wide conversions in a separate follow-up after the
|
||||
new DSL methods are available in a stable Homebrew release.
|
||||
- [x] PR 4.1, formula install-step sandboxing.
|
||||
Commit: `Sandbox formula install steps`.
|
||||
Scope: run structured formula steps inside the existing post-install child
|
||||
process so macOS Seatbelt and Linux Bubblewrap apply the same filesystem and
|
||||
network policy as legacy `post_install` hooks. This must land before any tap
|
||||
migrations use filesystem-mutating steps.
|
||||
- PR 5, default config and template writes (four-PR workflow above).
|
||||
Estimated existing formulae/casks affected: about `112` formulae write or
|
||||
patch default configuration/data files, and a subset of the `68` file-prep
|
||||
|
||||
@@ -7,14 +7,14 @@ require "cmd/shared_examples/args_parse"
|
||||
RSpec.describe Homebrew::Cmd::Postinstall do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "runs post-install steps before the remaining `post_install` hook" do
|
||||
it "runs post-install steps through `FormulaInstaller`" do
|
||||
cmd = described_class.new(["foo"])
|
||||
formula = instance_double(Formula, install_etc_var: nil, post_install_steps_defined?: true,
|
||||
post_install_defined?: true, to_s: "foo")
|
||||
post_install_defined?: false, to_s: "foo")
|
||||
installer = instance_double(FormulaInstaller)
|
||||
|
||||
allow(cmd.args.named).to receive(:to_resolved_formulae).and_return([formula])
|
||||
expect(formula).to receive(:run_post_install_steps).ordered
|
||||
expect(formula).not_to receive(:run_post_install_steps)
|
||||
expect(FormulaInstaller).to receive(:new)
|
||||
.with(formula, debug: false, quiet: false, verbose: false)
|
||||
.ordered
|
||||
|
||||
@@ -103,7 +103,7 @@ RSpec.describe FormulaInstaller do
|
||||
end
|
||||
|
||||
describe "#finish" do
|
||||
it "runs post-install steps before the remaining `post_install` hook" do
|
||||
it "runs structured post-install work through the post-install subprocess" do
|
||||
formula = formula "finish-install-steps" do
|
||||
T.bind(self, T.class_of(Formula))
|
||||
url "foo-1.0"
|
||||
@@ -128,7 +128,7 @@ RSpec.describe FormulaInstaller do
|
||||
summary: "summary",
|
||||
verbose?: false,
|
||||
)
|
||||
allow(formula).to receive_messages(post_install_steps_defined?: true, post_install_defined?: true,
|
||||
allow(formula).to receive_messages(post_install_steps_defined?: true, post_install_defined?: false,
|
||||
runtime_dependencies: [])
|
||||
allow(CacheStoreDatabase).to receive(:use).with(:linkage)
|
||||
allow(Homebrew::EnvConfig).to receive(:sbom?).and_return(false)
|
||||
@@ -138,7 +138,7 @@ RSpec.describe FormulaInstaller do
|
||||
allow(tab).to receive(:write)
|
||||
|
||||
expect(formula).to receive(:install_etc_var).ordered
|
||||
expect(formula).to receive(:run_post_install_steps).ordered
|
||||
expect(formula).not_to receive(:run_post_install_steps)
|
||||
expect(installer).to receive(:post_install).ordered
|
||||
|
||||
installer.finish
|
||||
|
||||
@@ -1153,6 +1153,20 @@ RSpec.describe Formula do
|
||||
)
|
||||
end
|
||||
|
||||
specify "#run_post_install runs install steps before the remaining hook" do
|
||||
f = formula do
|
||||
T.bind(self, T.class_of(Formula))
|
||||
url "foo-1.0"
|
||||
end
|
||||
|
||||
allow(Tab).to receive(:for_formula).with(f).and_return(f.build)
|
||||
allow(f).to receive_messages(post_install_steps_defined?: true, post_install_defined?: true)
|
||||
expect(f).to receive(:run_post_install_steps).ordered
|
||||
expect(f).to receive(:post_install).ordered
|
||||
|
||||
f.run_post_install
|
||||
end
|
||||
|
||||
specify "#post_install_steps" do
|
||||
f = formula do
|
||||
T.bind(self, T.class_of(Formula))
|
||||
|
||||
@@ -1166,7 +1166,7 @@ end
|
||||
|
||||
Any initialization steps that aren't necessarily part of the install process can be located in a `post_install` block, such as setup commands or data directory creation. This block can be re-run separately with `brew postinstall <formula>`.
|
||||
|
||||
For simple file preparation, prefer [`post_install_steps`](/rubydoc/Formula.html#post_install_steps-class_method). These steps are stored in the JSON API and do not require evaluating formula Ruby. A `post_install_steps` block may only contain the supported step calls with literal arguments. It cannot call the wider formula DSL or arbitrary Ruby code.
|
||||
For simple file preparation, prefer [`post_install_steps`](/rubydoc/Formula.html#post_install_steps-class_method). These steps are stored in the JSON API and do not require evaluating formula Ruby. A `post_install_steps` block may only contain the supported step calls with literal arguments. It cannot call the wider formula DSL or arbitrary Ruby code. Homebrew executes the steps with the same sandbox policy as `post_install`.
|
||||
|
||||
```ruby
|
||||
class Foo < Formula
|
||||
|
||||
Reference in New Issue
Block a user