Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Library/Homebrew/cask/cask_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def initialize(content, tap: T.unsafe(nil))
def load(config:)
@config = config

ENV.clear_sensitive_environment! do
ENV.clear_sensitive_environment_for_eval! do
instance_eval(content, __FILE__, __LINE__)
end
end
Expand Down Expand Up @@ -190,7 +190,7 @@ def load(config:)
end

begin
ENV.clear_sensitive_environment! do
ENV.clear_sensitive_environment_for_eval! do
instance_eval(content, path.to_s).tap do |cask|
raise CaskUnreadableError.new(token, "'#{path}' does not contain a cask.") unless cask.is_a?(Cask)
end
Expand Down
7 changes: 7 additions & 0 deletions Library/Homebrew/env_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,13 @@ module EnvConfig
description: "If set, do not print any hints about changing Homebrew's behaviour with environment variables.",
boolean: true,
},
HOMEBREW_NO_EVAL_ENV_SCRUBBING: {
# odeprecated: remove in a later release
description: "If set, sensitive environment variables are available while evaluating formulae and casks. " \
"`$HOMEBREW_GITHUB_API_TOKEN` is still available during evaluation when this is unset. " \
"This setting will be removed in a later release.",
boolean: true,
},
HOMEBREW_NO_FORCE_BREW_WRAPPER: {
description: "`Deprecated:` If set, disables `$HOMEBREW_FORCE_BREW_WRAPPER` behaviour, even if set.",
boolean: true,
Expand Down
17 changes: 13 additions & 4 deletions Library/Homebrew/extend/ENV/sensitive.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# typed: strict
# frozen_string_literal: true

require "env_config"

Comment thread
MikeMcQuaid marked this conversation as resolved.
module EnvSensitive
extend T::Helpers

Expand All @@ -16,21 +18,28 @@ def sensitive_environment
select { |key, _| sensitive?(key) }
end

sig { params(block: T.nilable(T.proc.returns(T.untyped))).returns(T.untyped) }
def clear_sensitive_environment!(&block)
sig { params(except: T::Array[String], block: T.nilable(T.proc.returns(T.untyped))).returns(T.untyped) }
def clear_sensitive_environment!(except: [], &block)
unless block
each_key { |key| delete key if sensitive?(key) }
each_key { |key| delete key if sensitive?(key) && except.exclude?(key) }
return
end

old_env = to_hash.dup
begin
clear_sensitive_environment!
clear_sensitive_environment!(except:)
yield
ensure
replace(old_env)
end
end

sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) }
def clear_sensitive_environment_for_eval!(&block)
return yield if Homebrew::EnvConfig.no_eval_env_scrubbing?

clear_sensitive_environment!(except: ["HOMEBREW_GITHUB_API_TOKEN"], &block)
end
end

ENV.extend(EnvSensitive)
2 changes: 1 addition & 1 deletion Library/Homebrew/formulary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def self.load_formula(name, path, contents, namespace, flags:, ignore_errors:)
raise FormulaUnreadableError.new(name, e)
end
end
ENV.clear_sensitive_environment! do
ENV.clear_sensitive_environment_for_eval! do
if ignore_errors
Ignorable.hook_raise(&eval_formula)
else
Expand Down
3 changes: 3 additions & 0 deletions Library/Homebrew/sorbet/rbi/dsl/homebrew/env_config.rbi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Library/Homebrew/test/ENV_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@
expect(subject).not_to include("SECRET_TOKEN")
end

it "preserves excepted sensitive environment variables" do
subject["SECRET_TOKEN"] = "password"
subject.clear_sensitive_environment!(except: ["SECRET_TOKEN"])
expect(subject["SECRET_TOKEN"]).to eq("password")
end

it "leaves non-sensitive environment variables alone" do
subject["FOO"] = "bar"
subject.clear_sensitive_environment!
Expand Down
48 changes: 48 additions & 0 deletions Library/Homebrew/test/cask/cask_loader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,54 @@
end
end

it "allows the GitHub API token while evaluating casks" do
cask_token = "github-token-env"
cask_file = mktmpdir/"#{cask_token}.rb"
cask_file.write <<~RUBY
cask "#{cask_token}" do
version "1.0.0"
sha256 "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

url "https://example.com/app.dmg"
name "GitHub Token Env"
desc ENV.key?("HOMEBREW_GITHUB_API_TOKEN") ? "Token present" : "Token absent"
homepage "https://example.com"

app "App.app"
end
RUBY

with_env(HOMEBREW_GITHUB_API_TOKEN: "github-token") do
cask = Cask::CaskLoader::FromPathLoader.new(cask_file).load(config: nil)

expect(cask.desc).to eq("Token present")
end
end

it "supports temporarily opting out of scrubbing while evaluating casks" do
cask_token = "unscrubbed-env"
cask_file = mktmpdir/"#{cask_token}.rb"
cask_file.write <<~RUBY
cask "#{cask_token}" do
version "1.0.0"
sha256 "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

url "https://example.com/app.dmg"
name "Unscrubbed Env"
desc ENV.key?("SECRET_TOKEN") ? "Secret present" : "Secret absent"
homepage "https://example.com"

app "App.app"
end
RUBY

with_env(HOMEBREW_NO_EVAL_ENV_SCRUBBING: "1", SECRET_TOKEN: "password") do
cask = Cask::CaskLoader::FromPathLoader.new(cask_file).load(config: nil)

expect(cask.desc).to eq("Secret present")
end
end

describe "loading a cask with a removed DSL method" do
let(:tmpdir) { mktmpdir }
let(:cask_token) { "removed-method-cask" }
Expand Down
40 changes: 40 additions & 0 deletions Library/Homebrew/test/formulary_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,46 @@ class SensitiveEnv < Formula
expect(ENV.fetch("SECRET_TOKEN", nil)).to eq("password")
end
end

it "allows the GitHub API token while evaluating formulae" do
with_env(HOMEBREW_GITHUB_API_TOKEN: "github-token") do
formula_class = Formulary.load_formula(
"github-token-env",
mktmpdir/"github-token-env.rb",
<<~RUBY,
class GithubTokenEnv < Formula
GITHUB_TOKEN_PRESENT = ENV.key?("HOMEBREW_GITHUB_API_TOKEN")
url "https://brew.sh/github-token-env-1.0.tar.gz"
end
RUBY
"GithubTokenEnvNamespace",
flags: [],
ignore_errors: false,
)

expect(formula_class::GITHUB_TOKEN_PRESENT).to be(true)
end
end

it "supports temporarily opting out of scrubbing while evaluating formulae" do
with_env(HOMEBREW_NO_EVAL_ENV_SCRUBBING: "1", SECRET_TOKEN: "password") do
formula_class = Formulary.load_formula(
"unscrubbed-env",
mktmpdir/"unscrubbed-env.rb",
<<~RUBY,
class UnscrubbedEnv < Formula
SECRET_TOKEN_PRESENT = ENV.key?("SECRET_TOKEN")
url "https://brew.sh/unscrubbed-env-1.0.tar.gz"
end
RUBY
"UnscrubbedEnvNamespace",
flags: [],
ignore_errors: false,
)

expect(formula_class::SECRET_TOKEN_PRESENT).to be(true)
end
end
end

describe "::factory" do
Expand Down
Loading