Commit e15faf16 authored by Max Woolf's avatar Max Woolf

Adds a complianceFramework edge from Project

Adds support to the GraphQL API to get
basic information about a project's compliance
framework if it exists
parent 9c688654
......@@ -1346,6 +1346,51 @@ enum CommitEncoding {
TEXT
}
"""
Represents a ComplianceFramework associated with a Project
"""
type ComplianceFramework {
"""
Name of the compliance framework
"""
name: ProjectSettingEnum!
}
"""
The connection type for ComplianceFramework.
"""
type ComplianceFrameworkConnection {
"""
A list of edges.
"""
edges: [ComplianceFrameworkEdge]
"""
A list of nodes.
"""
nodes: [ComplianceFramework]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type ComplianceFrameworkEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: ComplianceFramework
}
"""
A tag expiration policy designed to keep only the images that matter most
"""
......@@ -8750,6 +8795,31 @@ type Project {
last: Int
): BoardConnection
"""
Compliance frameworks associated with the project
"""
complianceFrameworks(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): ComplianceFrameworkConnection
"""
The container expiration policy of the project
"""
......@@ -10026,6 +10096,17 @@ type ProjectPermissions {
uploadFile: Boolean!
}
"""
Names of compliance frameworks that can be assigned to a Project
"""
enum ProjectSettingEnum {
gdpr
hipaa
pci_dss
soc_2
sox
}
type ProjectStatistics {
"""
Build artifacts size of the project
......
......@@ -3607,6 +3607,149 @@
],
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "ComplianceFramework",
"description": "Represents a ComplianceFramework associated with a Project",
"fields": [
{
"name": "name",
"description": "Name of the compliance framework",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "ProjectSettingEnum",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "ComplianceFrameworkConnection",
"description": "The connection type for ComplianceFramework.",
"fields": [
{
"name": "edges",
"description": "A list of edges.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "ComplianceFrameworkEdge",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "nodes",
"description": "A list of nodes.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "ComplianceFramework",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pageInfo",
"description": "Information to aid in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PageInfo",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "ComplianceFrameworkEdge",
"description": "An edge in a connection.",
"fields": [
{
"name": "cursor",
"description": "A cursor for use in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "node",
"description": "The item at the end of the edge.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "ComplianceFramework",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "ContainerExpirationPolicy",
......@@ -26105,6 +26248,59 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "complianceFrameworks",
"description": "Compliance frameworks associated with the project",
"args": [
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "ComplianceFrameworkConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "containerExpirationPolicy",
"description": "The container expiration policy of the project",
......@@ -29593,6 +29789,47 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "ProjectSettingEnum",
"description": "Names of compliance frameworks that can be assigned to a Project",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": [
{
"name": "gdpr",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "hipaa",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pci_dss",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "soc_2",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "sox",
"description": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "ProjectStatistics",
......@@ -238,6 +238,14 @@ Autogenerated return type of CommitCreate
| `commit` | Commit | The commit after mutation |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
## ComplianceFramework
Represents a ComplianceFramework associated with a Project
| Name | Type | Description |
| --- | ---- | ---------- |
| `name` | ProjectSettingEnum! | Name of the compliance framework |
## ContainerExpirationPolicy
A tag expiration policy designed to keep only the images that matter most
......
# frozen_string_literal: true
# rubocop: disable Graphql/AuthorizeTypes because ComplianceFrameworkType is, and should only be, accessible via ProjectType
module EE
module Types
module ComplianceManagement
class ComplianceFrameworkType < ::Types::BaseObject
graphql_name 'ComplianceFramework'
description 'Represents a ComplianceFramework associated with a Project'
field :name, ComplianceManagement::ProjectSettingEnum,
null: false,
description: 'Name of the compliance framework',
method: :framework
end
end
end
end
# frozen_string_literal: true
module EE
module Types
module ComplianceManagement
class ProjectSettingEnum < ::Types::BaseEnum
description 'Names of compliance frameworks that can be assigned to a Project'
::ComplianceManagement::ComplianceFramework::ProjectSettings.frameworks.keys.each do |k|
value(k)
end
end
end
end
end
......@@ -46,6 +46,11 @@ module EE
description: 'Packages of the project',
resolver: ::Resolvers::PackagesResolver
field :compliance_frameworks, Types::ComplianceManagement::ComplianceFrameworkType.connection_type,
description: 'Compliance frameworks associated with the project',
resolver: ::Resolvers::ComplianceFrameworksResolver,
null: true
def self.requirements_available?(project, user)
::Feature.enabled?(:requirements_management, project, default_enabled: true) && Ability.allowed?(user, :read_requirement, project)
end
......
# frozen_string_literal: true
module Resolvers
class ComplianceFrameworksResolver < BaseResolver
type EE::Types::ComplianceManagement::ComplianceFrameworkType, null: true
alias_method :project, :object
def resolve(**args)
Array.wrap(project.compliance_framework_setting)
end
end
end
---
title: Add Project.complianceFrameworks field to GraphQL schema
merge_request: 34838
author:
type: added
......@@ -5,8 +5,10 @@ FactoryBot.define do
project
framework { ComplianceManagement::ComplianceFramework::ProjectSettings.frameworks.keys.sample }
trait :sox do
framework { 'sox' }
ComplianceManagement::ComplianceFramework::ProjectSettings.frameworks.keys.each do |k|
trait k do
framework { k }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::ComplianceFrameworksResolver do
include GraphqlHelpers
let(:project) { create(:project) }
describe '#resolve' do
subject { resolve_compliance_frameworks(project) }
context 'when a project has a compliance framework set' do
before do
project.update!(compliance_framework_setting: create(:compliance_framework_project_setting, :sox))
end
it 'includes the name of the compliance frameworks' do
expect(subject).to contain_exactly(have_attributes(framework: 'sox'))
end
end
context 'when a project has no compliance framework set' do
it 'is an empty array' do
expect(subject).to be_empty
end
end
end
def resolve_compliance_frameworks(project)
resolve(described_class, obj: project)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['ComplianceFramework'] do
it { expect(described_class).to have_graphql_field(:name) }
end
......@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Project'] do
expected_fields = %w[
service_desk_enabled service_desk_address vulnerabilities
requirement_states_count vulnerability_severities_count packages
compliance_frameworks
]
expect(described_class).to include_graphql_fields(*expected_fields)
......
# frozen_string_literal: true
require 'spec_helper'
describe 'getting a compliance frameworks list for a project' do
include GraphqlHelpers
let_it_be(:project_member) { create(:project_member, :maintainer) }
let_it_be(:project) { project_member.project }
let_it_be(:current_user) { project_member.user }
let_it_be(:query) do
graphql_query_for(
:project, { full_path: project.full_path }, 'complianceFrameworks { nodes { name } }'
)
end
let(:compliance_frameworks) { graphql_data.dig('project', 'complianceFrameworks', 'nodes') }
context 'when the project has no compliance framework assigned' do
it 'is an empty array' do
post_graphql(query, current_user: current_user)
expect(compliance_frameworks).to be_empty
end
end
context 'when the project has a compliance framework assigned' do
before do
project.update!(compliance_framework_setting: create(:compliance_framework_project_setting, :sox))
end
it 'includes its name' do
post_graphql(query, current_user: current_user)
expect(compliance_frameworks).to contain_exactly('name' => 'sox')
end
end
end
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