Commit 0ca58f91 authored by Brian Williams's avatar Brian Williams

Add `container_policy` to policies controller

For MVC, we would like for the policies controller to be able to
return both `scan_execution_policy` and `container_policy`
types. Until the container runtime policies are migrated to use
a security policy project, we will call out to the
NetworkPolicies::FindResourceService as a workaround, using some of the
same logic as the ThreatMonitoringController. The
ThreatMonitoringController will be deleted when all of the functionality
in this controller is completed.
parent 4280e2f3
...@@ -21,24 +21,20 @@ module Projects ...@@ -21,24 +21,20 @@ module Projects
def edit def edit
@policy_name = URI.decode_www_form_component(params[:id]) @policy_name = URI.decode_www_form_component(params[:id])
@policy_type = params[:type] @policy = policy
result = ::Security::SecurityOrchestrationPolicies::FetchPolicyService render_404 if @policy.nil?
.new(policy_configuration: policy_configuration, name: @policy_name, type: @policy_type.to_sym)
.execute
@policy = result[:policy]
return render_404 if @policy.blank?
render :edit
end end
private private
def validate_policy_configuration def validate_policy_configuration
type = params[:type] @policy_type = params[:type].presence&.to_sym
result = ::Security::SecurityOrchestrationPolicies::PolicyConfigurationValidationService result = ::Security::SecurityOrchestrationPolicies::PolicyConfigurationValidationService.new(
.new(policy_configuration: policy_configuration, type: (type.to_sym if type)).execute policy_configuration: policy_configuration,
type: @policy_type,
environment_id: params[:environment_id].presence
).execute
if result[:status] == :error if result[:status] == :error
case result[:invalid_component] case result[:invalid_component]
...@@ -62,6 +58,39 @@ module Projects ...@@ -62,6 +58,39 @@ module Projects
end end
end end
def policy
if @policy_type == :container_policy
# Currently, container policies are stored as active record objects and other policies
# are stored in a policy management project. When we have a unified approach for
# storing the security policies, we can remove this conditional and retrieve all of
# the policies using the FetchPolicyService.
container_policy
else
default_policy
end
end
def container_policy
@environment = project.environments.find(params[:environment_id])
result = NetworkPolicies::FindResourceService.new(
resource_name: @policy_name,
environment: @environment,
kind: params[:kind].presence || Gitlab::Kubernetes::CiliumNetworkPolicy::KIND
).execute
result.payload if result.success?
end
def default_policy
result = ::Security::SecurityOrchestrationPolicies::FetchPolicyService.new(
policy_configuration: policy_configuration,
name: @policy_name,
type: @policy_type
).execute
result[:policy].presence
end
def policy_configuration def policy_configuration
@policy_configuration ||= project.security_orchestration_policy_configuration @policy_configuration ||= project.security_orchestration_policy_configuration
end end
......
...@@ -14,4 +14,21 @@ module Projects::Security::PoliciesHelper ...@@ -14,4 +14,21 @@ module Projects::Security::PoliciesHelper
branch: security_policy_management_project.default_branch_or_main branch: security_policy_management_project.default_branch_or_main
} }
end end
def orchestration_policy_data(project, policy_type, policy, environment = nil)
return unless project && policy
{
network_policies_endpoint: project_security_network_policies_path(project),
configure_agent_help_path: help_page_url('user/clusters/agent/repository.html'),
create_agent_help_path: help_page_url('user/clusters/agent/index.md', anchor: 'create-an-agent-record-in-gitlab'),
environments_endpoint: project_environments_path(project),
environment_id: environment&.id,
project_path: project.full_path,
project_id: project.id,
policy: policy.to_json,
policy_type: policy_type,
threat_monitoring_path: project_threat_monitoring_path(project)
}
end
end end
...@@ -5,14 +5,16 @@ module Security ...@@ -5,14 +5,16 @@ module Security
class PolicyConfigurationValidationService class PolicyConfigurationValidationService
include BaseServiceUtility include BaseServiceUtility
def initialize(policy_configuration:, type:) def initialize(policy_configuration:, type:, environment_id:)
@policy_configuration = policy_configuration @policy_configuration = policy_configuration
@type = type @type = type
@environment_id = environment_id
end end
def execute def execute
return error_response(_('type parameter is missing and is required'), :parameter) unless @type return error_response(_('type parameter is missing and is required'), :parameter) unless @type
return error_response(_('Invalid policy type'), :parameter) unless valid_type? return error_response(_('Invalid policy type'), :parameter) unless valid_type?
return error_response(_('environment_id parameter is required when type is container_policy'), :parameter) if container_policy? && !@environment_id
return error_response(_('Project does not have a policy configuration'), :policy_configuration) if policy_configuration.nil? return error_response(_('Project does not have a policy configuration'), :policy_configuration) if policy_configuration.nil?
unless policy_configuration.policy_configuration_exists? unless policy_configuration.policy_configuration_exists?
...@@ -39,8 +41,13 @@ module Security ...@@ -39,8 +41,13 @@ module Security
error(message, pass_back: { invalid_component: invalid_component }) error(message, pass_back: { invalid_component: invalid_component })
end end
def container_policy?
type == :container_policy
end
def valid_type? def valid_type?
Security::OrchestrationPolicyConfiguration::AVAILABLE_POLICY_TYPES.include?(type) # :container_policy has yet to be migrated to OrchestrationPolicyConfiguration
Security::OrchestrationPolicyConfiguration::AVAILABLE_POLICY_TYPES.include?(type) || container_policy?
end end
end end
end end
......
- add_to_breadcrumbs s_("SecurityOrchestration|Policies"), project_security_policy_path(@project) - add_to_breadcrumbs s_("SecurityOrchestration|Policies"), project_security_policy_path(@project)
- breadcrumb_title s_("SecurityOrchestration|Edit policy") - breadcrumb_title s_("SecurityOrchestration|Edit policy")
- page_title s_("SecurityOrchestration|Edit policy") - page_title s_("SecurityOrchestration|Edit policy")
- data = orchestration_policy_data(@project, @policy_type, @policy, @environment)
#js-policy-builder-app{ data: { policy: @policy.to_json, #js-policy-builder-app{ data: data }
policy_type: @policy_type,
project_path: @project.full_path,
project_id: @project.id } }
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::Security::PoliciesController, type: :request do RSpec.describe Projects::Security::PoliciesController, type: :request do
let_it_be(:owner) { create(:user) } let_it_be(:owner) { create(:user) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: owner.namespace) } let_it_be(:project) { create(:project, :repository, namespace: owner.namespace) }
let_it_be(:policy_management_project) { create(:project, :repository, namespace: owner.namespace) } let_it_be(:policy_management_project) { create(:project, :repository, namespace: owner.namespace) }
let_it_be(:policy_configuration) { create(:security_orchestration_policy_configuration, security_policy_management_project: policy_management_project, project: project) } let_it_be(:policy_configuration) { create(:security_orchestration_policy_configuration, security_policy_management_project: policy_management_project, project: project) }
let_it_be(:policy) do let_it_be(:policy) do
...@@ -52,6 +52,53 @@ RSpec.describe Projects::Security::PoliciesController, type: :request do ...@@ -52,6 +52,53 @@ RSpec.describe Projects::Security::PoliciesController, type: :request do
expect(app.attributes['data-policy-type'].value).to eq(type) expect(app.attributes['data-policy-type'].value).to eq(type)
end end
context 'when type is container_runtime' do
let_it_be(:type) { 'container_policy' }
let_it_be(:environment) { create(:environment, :with_review_app, project: project) }
let(:environment_id) { environment.id }
let(:kind) { 'CiliumNetworkPolicy' }
let(:policy_name) { 'policy' }
let(:network_policy) do
Gitlab::Kubernetes::CiliumNetworkPolicy.new(
name: policy_name,
namespace: 'another',
selector: { matchLabels: { role: 'db' } },
ingress: [{ from: [{ namespaceSelector: { matchLabels: { project: 'myproject' } } }] }]
)
end
let(:service) { instance_double('NetworkPolicies::FindResourceService', execute: ServiceResponse.success(payload: network_policy)) }
let(:edit) do
edit_project_security_policy_url(
project,
id: policy_name,
type: type,
environment_id: environment_id,
kind: kind
)
end
before do
allow(NetworkPolicies::FindResourceService).to(
receive(:new)
.with(resource_name: policy_name, environment: environment, kind: Gitlab::Kubernetes::CiliumNetworkPolicy::KIND)
.and_return(service)
)
end
it 'renders edit page with network policy' do
get edit
app = Nokogiri::HTML.parse(response.body).at_css('div#js-policy-builder-app')
expect(app.attributes['data-policy'].value).to eq(network_policy.to_json)
expect(app.attributes['data-policy-type'].value).to eq(type)
expect(app.attributes['data-environment-id'].value).to eq(environment_id.to_s)
end
end
context 'when type is missing' do context 'when type is missing' do
let_it_be(:edit) { edit_project_security_policy_url(project, id: policy[:name]) } let_it_be(:edit) { edit_project_security_policy_url(project, id: policy[:name]) }
......
...@@ -21,9 +21,10 @@ RSpec.describe Security::SecurityOrchestrationPolicies::PolicyConfigurationValid ...@@ -21,9 +21,10 @@ RSpec.describe Security::SecurityOrchestrationPolicies::PolicyConfigurationValid
let(:policy_blob) { { scan_execution_policy: [policy] }.to_yaml } let(:policy_blob) { { scan_execution_policy: [policy] }.to_yaml }
let(:type) { :scan_execution_policy } let(:type) { :scan_execution_policy }
let(:environment_id) { nil }
subject(:service) do subject(:service) do
described_class.new(policy_configuration: policy_configuration, type: type) described_class.new(policy_configuration: policy_configuration, type: type, environment_id: environment_id)
end end
before do before do
...@@ -88,6 +89,22 @@ RSpec.describe Security::SecurityOrchestrationPolicies::PolicyConfigurationValid ...@@ -88,6 +89,22 @@ RSpec.describe Security::SecurityOrchestrationPolicies::PolicyConfigurationValid
end end
end end
context 'when type is container_runtime' do
let(:type) { :container_policy }
context 'when environment_id is missing' do
let(:environment_id) { nil }
it 'returns an error' do
response = service.execute
expect(response[:status]).to eq(:error)
expect(response[:message]).to eq('environment_id parameter is required when type is container_policy')
expect(response[:invalid_component]).to eq(:parameter)
end
end
end
context 'when policy.yml is empty' do context 'when policy.yml is empty' do
let(:policy_blob) { {}.to_yaml } let(:policy_blob) { {}.to_yaml }
......
...@@ -39253,6 +39253,9 @@ msgstr "" ...@@ -39253,6 +39253,9 @@ msgstr ""
msgid "entries cannot contain HTML tags" msgid "entries cannot contain HTML tags"
msgstr "" msgstr ""
msgid "environment_id parameter is required when type is container_policy"
msgstr ""
msgid "epic" msgid "epic"
msgstr "" msgstr ""
......
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