Skip to content
Snippets Groups Projects
Commit 0ca58f91 authored by Brian Williams's avatar Brian Williams
Browse files

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
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -21,24 +21,20 @@ def show
 
def edit
@policy_name = URI.decode_www_form_component(params[:id])
@policy_type = params[:type]
@policy = policy
 
result = ::Security::SecurityOrchestrationPolicies::FetchPolicyService
.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
render_404 if @policy.nil?
end
 
private
 
def validate_policy_configuration
type = params[:type]
result = ::Security::SecurityOrchestrationPolicies::PolicyConfigurationValidationService
.new(policy_configuration: policy_configuration, type: (type.to_sym if type)).execute
@policy_type = params[:type].presence&.to_sym
result = ::Security::SecurityOrchestrationPolicies::PolicyConfigurationValidationService.new(
policy_configuration: policy_configuration,
type: @policy_type,
environment_id: params[:environment_id].presence
).execute
 
if result[:status] == :error
case result[:invalid_component]
Loading
Loading
@@ -62,6 +58,39 @@ def validate_policy_configuration
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
@policy_configuration ||= project.security_orchestration_policy_configuration
end
Loading
Loading
Loading
Loading
@@ -14,4 +14,21 @@ def assigned_policy_project(project)
branch: security_policy_management_project.default_branch_or_main
}
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
Loading
Loading
@@ -5,14 +5,16 @@ module SecurityOrchestrationPolicies
class PolicyConfigurationValidationService
include BaseServiceUtility
 
def initialize(policy_configuration:, type:)
def initialize(policy_configuration:, type:, environment_id:)
@policy_configuration = policy_configuration
@type = type
@environment_id = environment_id
end
 
def execute
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(_('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?
 
unless policy_configuration.policy_configuration_exists?
Loading
Loading
@@ -39,8 +41,13 @@ def error_response(message, invalid_component)
error(message, pass_back: { invalid_component: invalid_component })
end
 
def container_policy?
type == :container_policy
end
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
Loading
Loading
- add_to_breadcrumbs s_("SecurityOrchestration|Policies"), project_security_policy_path(@project)
- breadcrumb_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,
policy_type: @policy_type,
project_path: @project.full_path,
project_id: @project.id } }
#js-policy-builder-app{ data: data }
Loading
Loading
@@ -5,7 +5,7 @@
RSpec.describe Projects::Security::PoliciesController, type: :request do
let_it_be(:owner) { 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_configuration) { create(:security_orchestration_policy_configuration, security_policy_management_project: policy_management_project, project: project) }
let_it_be(:policy) do
Loading
Loading
@@ -52,6 +52,53 @@
expect(app.attributes['data-policy-type'].value).to eq(type)
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
let_it_be(:edit) { edit_project_security_policy_url(project, id: policy[:name]) }
 
Loading
Loading
Loading
Loading
@@ -21,9 +21,10 @@
 
let(:policy_blob) { { scan_execution_policy: [policy] }.to_yaml }
let(:type) { :scan_execution_policy }
let(:environment_id) { nil }
 
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
 
before do
Loading
Loading
@@ -88,6 +89,22 @@
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
let(:policy_blob) { {}.to_yaml }
 
Loading
Loading
Loading
Loading
@@ -39253,6 +39253,9 @@ msgstr ""
msgid "entries cannot contain HTML tags"
msgstr ""
 
msgid "environment_id parameter is required when type is container_policy"
msgstr ""
msgid "epic"
msgstr ""
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment