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 { ...@@ -1346,6 +1346,51 @@ enum CommitEncoding {
TEXT 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 A tag expiration policy designed to keep only the images that matter most
""" """
...@@ -8750,6 +8795,31 @@ type Project { ...@@ -8750,6 +8795,31 @@ type Project {
last: Int last: Int
): BoardConnection ): 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 The container expiration policy of the project
""" """
...@@ -10026,6 +10096,17 @@ type ProjectPermissions { ...@@ -10026,6 +10096,17 @@ type ProjectPermissions {
uploadFile: Boolean! uploadFile: Boolean!
} }
"""
Names of compliance frameworks that can be assigned to a Project
"""
enum ProjectSettingEnum {
gdpr
hipaa
pci_dss
soc_2
sox
}
type ProjectStatistics { type ProjectStatistics {
""" """
Build artifacts size of the project Build artifacts size of the project
......
...@@ -3607,6 +3607,149 @@ ...@@ -3607,6 +3607,149 @@
], ],
"possibleTypes": null "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", "kind": "OBJECT",
"name": "ContainerExpirationPolicy", "name": "ContainerExpirationPolicy",
...@@ -26105,6 +26248,59 @@ ...@@ -26105,6 +26248,59 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "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", "name": "containerExpirationPolicy",
"description": "The container expiration policy of the project", "description": "The container expiration policy of the project",
...@@ -29593,6 +29789,47 @@ ...@@ -29593,6 +29789,47 @@
"enumValues": null, "enumValues": null,
"possibleTypes": 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", "kind": "OBJECT",
"name": "ProjectStatistics", "name": "ProjectStatistics",
...@@ -238,6 +238,14 @@ Autogenerated return type of CommitCreate ...@@ -238,6 +238,14 @@ Autogenerated return type of CommitCreate
| `commit` | Commit | The commit after mutation | | `commit` | Commit | The commit after mutation |
| `errors` | String! => Array | Errors encountered during execution of the 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 ## ContainerExpirationPolicy
A tag expiration policy designed to keep only the images that matter most 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 ...@@ -46,6 +46,11 @@ module EE
description: 'Packages of the project', description: 'Packages of the project',
resolver: ::Resolvers::PackagesResolver 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) def self.requirements_available?(project, user)
::Feature.enabled?(:requirements_management, project, default_enabled: true) && Ability.allowed?(user, :read_requirement, project) ::Feature.enabled?(:requirements_management, project, default_enabled: true) && Ability.allowed?(user, :read_requirement, project)
end 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 ...@@ -5,8 +5,10 @@ FactoryBot.define do
project project
framework { ComplianceManagement::ComplianceFramework::ProjectSettings.frameworks.keys.sample } framework { ComplianceManagement::ComplianceFramework::ProjectSettings.frameworks.keys.sample }
trait :sox do ComplianceManagement::ComplianceFramework::ProjectSettings.frameworks.keys.each do |k|
framework { 'sox' } trait k do
framework { k }
end
end end
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 ...@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Project'] do
expected_fields = %w[ expected_fields = %w[
service_desk_enabled service_desk_address vulnerabilities service_desk_enabled service_desk_address vulnerabilities
requirement_states_count vulnerability_severities_count packages requirement_states_count vulnerability_severities_count packages
compliance_frameworks
] ]
expect(described_class).to include_graphql_fields(*expected_fields) 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