Commit f6d1a695 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Pass variables matching the scopes

parent ff6864b8
......@@ -206,7 +206,7 @@ module Ci
variables += project.deployment_variables if has_environment?
variables += yaml_variables
variables += user_variables
variables += project.secret_variables_for(ref).map(&:to_runner_variable)
variables += secret_variables
variables += trigger_request.user_variables if trigger_request
variables
end
......@@ -391,6 +391,12 @@ module Ci
]
end
def secret_variables
project.secret_variables_for(
ref: ref, environment: persisted_environment)
.map(&:to_runner_variable)
end
def steps
[Gitlab::Ci::Build::Step.from_commands(self),
Gitlab::Ci::Build::Step.from_after_script(self)].compact
......
......@@ -6,7 +6,7 @@ module Ci
validates :key,
presence: true,
uniqueness: { scope: :project_id },
uniqueness: { scope: %i[project_id scope] },
length: { maximum: 255 },
format: { with: /\A[a-zA-Z0-9_]+\z/,
message: "can contain only letters, digits and '_'." }
......
......@@ -77,8 +77,26 @@ module EE
end
end
def secret_variables_for(ref)
super.where(scope: '*')
def secret_variables_for(ref:, environment:)
query = super
# Full wildcard has the least priority
variables = query.where(scope: '*').to_a
if environment
# Partial wildcard sits in the middle
variables.concat(
query.where("? LIKE REPLACE(scope, ?, ?)",
environment.name, '*', '%')
.where.not(scope: '*')
.where.not(scope: environment.name)
)
# Exactly match has the highest priority
variables.concat(query.where(scope: environment.name))
end
variables
end
private
......
......@@ -1503,7 +1503,8 @@ class Project < ActiveRecord::Base
variables
end
def secret_variables_for(ref)
def secret_variables_for(ref:, environment: nil)
# EE would use the environment
if protected_for?(ref)
variables
else
......
......@@ -6,12 +6,17 @@ describe Ci::Variable, models: true do
let(:secret_value) { 'secret' }
it { is_expected.to validate_presence_of(:key) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id) }
it { is_expected.to validate_length_of(:key).is_at_most(255) }
it { is_expected.to allow_value('foo').for(:key) }
it { is_expected.not_to allow_value('foo bar').for(:key) }
it { is_expected.not_to allow_value('foo/bar').for(:key) }
if described_class.column_names.include?('scope')
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :scope) }
else
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id) }
end
describe '.unprotected' do
subject { described_class.unprotected }
......
......@@ -2238,7 +2238,12 @@ describe Project, models: true do
create(:ci_variable, :protected, value: 'protected', project: project)
end
subject { project.secret_variables_for('ref') }
subject { project.secret_variables_for(ref: 'ref') }
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
shared_examples 'ref is protected' do
it 'contains all the variables' do
......@@ -2247,11 +2252,6 @@ describe Project, models: true do
end
context 'when the ref is not protected' do
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
it 'contains only the secret variables' do
is_expected.to contain_exactly(secret_variable)
end
......@@ -2272,6 +2272,70 @@ describe Project, models: true do
it_behaves_like 'ref is protected'
end
# EE
context 'when environment is specified' do
let(:environment) { create(:environment, name: 'review/name') }
subject do
project.secret_variables_for(ref: 'ref', environment: environment)
end
context 'when scope is exactly matched' do
before do
secret_variable.update(scope: 'review/name')
end
it 'contains the secret variable' do
is_expected.to contain_exactly(secret_variable)
end
end
context 'when scope is matched by wildcard' do
before do
secret_variable.update(scope: 'review/*')
end
it 'contains the secret variable' do
is_expected.to contain_exactly(secret_variable)
end
end
context 'when scope does not match' do
before do
secret_variable.update(scope: 'review/*/special')
end
it 'does not contain the secret variable' do
is_expected.not_to contain_exactly(secret_variable)
end
end
context 'when variables with the same name have different scopes' do
let!(:partially_matched_variable) do
create(:ci_variable,
key: secret_variable.key,
value: 'partial',
scope: 'review/*',
project: project)
end
let!(:perfectly_matched_variable) do
create(:ci_variable,
key: secret_variable.key,
value: 'prefect',
scope: 'review/name',
project: project)
end
it 'puts variables matching scope more in the end' do
is_expected.to eq(
[secret_variable,
partially_matched_variable,
perfectly_matched_variable])
end
end
end
end
describe '#protected_for?' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment