Skip to content
代码片段 群组 项目
未验证 提交 56b44ede 编辑于 作者: Harsimar Sandhu's avatar Harsimar Sandhu 提交者: GitLab
浏览文件

Merge branch 'dakotadux/download-compliance-framework-json-export-service' into 'master'

No related branches found
No related tags found
无相关合并请求
......@@ -47,6 +47,14 @@ class ComplianceRequirementsControl < ApplicationRecord
validates :name, uniqueness: { scope: :compliance_requirement_id }
validates :secret_token, presence: true, if: :external?
def expression_as_hash
::Gitlab::Json.parse(expression)
rescue JSON::ParserError
errors.add(:expression, _('should be a valid json object.'))
nil
end
private
def controls_count_per_requirement
......@@ -62,14 +70,15 @@ def controls_count_per_requirement
def validate_internal_expression
return if expression.blank?
expression_schema_errors = CONTROL_EXPRESSION_SCHEMA.validate(Gitlab::Json.parse(expression)).to_a
hashed_expression = expression_as_hash
return if errors[:expression].any?
expression_schema_errors = CONTROL_EXPRESSION_SCHEMA.validate(hashed_expression).to_a
return if expression_schema_errors.blank?
expression_schema_errors.each do |error|
errors.add(:expression, JSONSchemer::Errors.pretty(error))
end
rescue JSON::ParserError
errors.add(:expression, _('should be a valid json object.'))
end
end
end
......
# frozen_string_literal: true
module ComplianceManagement
module Frameworks
class JsonExportService
def initialize(user:, group:, framework:)
@user = user
@group = group
@framework = framework
end
def execute
return ServiceResponse.error(message: 'namespace must be a group') unless group.is_a?(Group)
return ServiceResponse.error(message: "Access to group denied for user with ID: #{user.id}") unless allowed?
begin
success
rescue StandardError => e
Gitlab::ErrorTracking.track_exception(e, group_id: group.id, user_id: user.id, framework_id: framework.id)
error
end
end
private
attr_reader :user, :group, :framework
def allowed? = Ability.allowed?(user, :read_compliance_dashboard, group)
def success = ServiceResponse.success(payload:)
def error = ServiceResponse.error(message: _('Failed to export framework'))
def payload
{
name: framework.name,
description: framework.description,
color: framework.color,
requirements: framework.compliance_requirements.map do |requirement|
{
name: requirement.name,
description: requirement.description,
controls: requirement.compliance_requirements_controls.map do |control|
{
name: control.name,
control_type: control.control_type,
expression: control.expression_as_hash
}
end
}
end
}.to_json
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ComplianceManagement::Frameworks::JsonExportService, feature_category: :compliance_management do
subject(:service) { described_class.new user:, group:, framework: }
let_it_be(:user) { create :user, name: 'Rick Sanchez' }
let_it_be(:group) { create :group, name: 'parent' }
let_it_be(:framework) do
create(:compliance_framework, name: 'ISO 27001',
description: 'International standard to manage information security.',
color: '#808080')
end
let_it_be(:requirement) do
create(:compliance_requirement,
name: 'A.6.1.2 Segregation of duties',
description: "Conflicting duties and areas of responsibility shall be segregated to reduce opportunities for " \
"unauthorized or unintentional modification or misuse of the organization's assets",
framework: framework)
end
let_it_be(:expression) do
{
operator: "=",
field: "minimum_approvals_required",
value: 2
}.to_json
end
let_it_be(:control) do
create(:compliance_requirements_control,
name: 'minimum_approvals_required_2',
compliance_requirement: requirement)
end
before do
stub_licensed_features(group_level_compliance_dashboard: true)
end
describe "#execute" do
before_all do
group.add_owner user
end
context 'when group_level_compliance_dashboard is disabled' do
before do
stub_licensed_features(group_level_compliance_dashboard: false)
end
context 'when user is an owner' do
before_all do
group.add_owner(user)
end
it 'returns an access denied error' do
result = service.execute
expect(result).to be_error
expect(result.message).to eq("Access to group denied for user with ID: #{user.id}")
end
it 'returns the expected JSON structure' do
result = ::Gitlab::Json.parse(service.execute.payload)
expect(result).to match({})
end
end
end
context 'when namespace is not a group' do
let_it_be(:group) { create(:project) }
it 'returns an error' do
result = service.execute
expect(result).to be_error
expect(result.message).to eq('namespace must be a group')
end
end
context 'when user is owner of namespace' do
it { expect(service.execute).to be_success }
it 'returns a valid JSON payload' do
result = service.execute
expect { ::Gitlab::Json.parse(result.payload) }.not_to raise_error
end
it 'returns the expected JSON structure' do
result = ::Gitlab::Json.parse(service.execute.payload)
expect(result).to match({
'name' => 'ISO 27001',
'description' => 'International standard to manage information security.',
'color' => '#808080',
'requirements' => [
{
'name' => 'A.6.1.2 Segregation of duties',
'description' => "Conflicting duties and areas of responsibility shall be segregated to reduce " \
"opportunities for unauthorized or unintentional modification or misuse of the organization's assets",
'controls' => [{
"control_type" => "internal",
"expression" => { "field" => "minimum_approvals_required", "operator" => "=", "value" => 2 },
"name" => "minimum_approvals_required_2"
}]
}
]
})
end
end
context 'when user is a maintainer' do
before_all do
group.add_maintainer(user)
end
it 'returns an access denied error' do
result = service.execute
expect(result).to be_error
expect(result.message).to eq("Access to group denied for user with ID: #{user.id}")
end
it 'returns an empty JSON structure' do
result = ::Gitlab::Json.parse(service.execute.payload)
expect(result).to match({})
end
end
context 'when an unexpected error occurs' do
before do
allow(service).to receive(:payload).and_raise(StandardError.new('Unexpected error'))
end
it 'tracks the exception and returns an error response' do
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
instance_of(StandardError),
group_id: group.id,
user_id: user.id,
framework_id: framework.id
)
result = service.execute
expect(result).to be_error
expect(result.message).to eq('Failed to export framework')
end
end
end
end
......@@ -24084,6 +24084,9 @@ msgstr ""
msgid "Failed to enqueue the rebase operation, possibly due to a long-lived transaction. Try again later."
msgstr ""
 
msgid "Failed to export framework"
msgstr ""
msgid "Failed to fetch Namespace: %{fullPath}"
msgstr ""
 
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册