Skip to content

Commit

Permalink
feat(APIv2): RHINENG-13307 create tailorings via API explicitly
Browse files Browse the repository at this point in the history
  • Loading branch information
skateman committed Oct 8, 2024
1 parent 8a9fdda commit 505c9ee
Show file tree
Hide file tree
Showing 8 changed files with 4,822 additions and 4,629 deletions.
20 changes: 20 additions & 0 deletions app/controllers/v2/tailorings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module V2
# API for Tailorings
class TailoringsController < ApplicationController
CREATE_ATTRIBUTES = { os_minor_version: ParamType.integer & ParamType.gte(0) }.freeze
UPDATE_ATTRIBUTES = { value_overrides: ParamType.map }.freeze

def index
Expand All @@ -15,6 +16,21 @@ def show
end
permission_for_action :show, Rbac::POLICY_READ

def create
# Look up the latest Profile supporting the given OS minor version
new_tailoring = V2::Tailoring.for_policy(policy, permitted_params[:os_minor_version])
new_tailoring.account = current_user.account

if new_tailoring.save
render_json new_tailoring, status: :created
audit_success("Created tailoring #{new_tailoring.id}")
else
render_model_errors new_tailoring
end
end
permission_for_action :create, Rbac::POLICY_WRITE
permitted_params_for_action :create, { id: ID_TYPE, **CREATE_ATTRIBUTES }

def update
if tailoring.update(permitted_params.to_h.slice(*UPDATE_ATTRIBUTES.keys))
render_json tailoring, status: :accepted
Expand Down Expand Up @@ -45,6 +61,10 @@ def tailoring
@tailoring ||= authorize(expand_resource.find(permitted_params[:id]))
end

def policy
V2::Policy.find(permitted_params[:policy_id])
end

def build_file(format)
builder = format == :json ? JsonTailoringFile : XccdfTailoringFile

Expand Down
6 changes: 6 additions & 0 deletions app/models/v2/tailoring.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ class Tailoring < ApplicationRecord
TailoringRule.import(data, on_duplicate_key_ignore: true, validate: false)
end

def self.for_policy(policy, os_minor_version)
profile = policy.profile.variant_for_minor(os_minor_version)
V2::Tailoring.new(policy: policy, os_minor_version: os_minor_version,
profile: profile, value_overrides: profile.value_overrides)
end

def os_major_version
attributes['security_guide__os_major_version'] || try(:security_guide)&.os_major_version
end
Expand Down
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def draw_routes(prefix)
end

resources :policies, except: %i[new edit] do
resources :tailorings, only: %i[index show update], parents: %i[policy] do
resources :tailorings, only: %i[index show create update], parents: %i[policy] do
resources :rules, only: %i[index create update destroy], parents: %i[policies tailorings]
get :tailoring_file, on: :member, defaults: { format: 'xml' }, constraints: { format: /json|xml/ }
end
Expand Down
1 change: 1 addition & 0 deletions spec/api/v2/schemas.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module Schemas
supported_profile: SUPPORTED_PROFILE,
system: SYSTEM,
tailoring: TAILORING,
tailoring_create: TAILORING_CREATE,
tailoring_file: TAILORING_FILE,
test_result: TEST_RESULT,
value_definition: VALUE_DEFINITION
Expand Down
12 changes: 12 additions & 0 deletions spec/api/v2/schemas/tailoring.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ module Tailoring
}
}
}.freeze

TAILORING_CREATE = {
type: :object,
properties: {
os_minor_version: {
type: :number,
examples: [1],
required: true,
description: 'Minor version of the Operating System that the Tailoring covers'
}
}
}.freeze
end
end
end
Expand Down
37 changes: 37 additions & 0 deletions spec/controllers/v2/tailorings_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,43 @@
it_behaves_like 'indexable', :os_minor_version, :policy
end

describe 'POST create' do
let(:os_minor_version) { SecureRandom.random_number(10) }
let(:parent) { FactoryBot.create(:v2_policy, account: current_user.account, profile: canonical_profile) }
let(:params) { { policy_id: parent.id, os_minor_version: os_minor_version, parents: [:policy] } }

let(:canonical_profile) do
FactoryBot.create(:v2_profile, ref_id_suffix: 'foo', supports_minors: [os_minor_version])
end

it 'creates a tailoring according to the OS minor version' do
post :create, params: params

expect(response).to have_http_status :created
expect(parent.tailorings.map(&:id)).to include(response_body_data['id'])
end

context 'tailoring already exists' do
before { FactoryBot.create(:v2_tailoring, policy: parent, os_minor_version: os_minor_version) }

it 'fails with an error' do
post :create, params: params

expect(response).to have_http_status :not_acceptable
end
end

context 'unsupported OS minor version' do
let(:canonical_profile) { FactoryBot.create(:v2_profile, ref_id_suffix: 'foo', supports_minors: []) }

it 'returns not found' do
post :create, params: params

expect(response).to have_http_status :not_found
end
end
end

describe 'PATCH update' do
let(:os_minor_version) { SecureRandom.random_number(10) }
let(:parent) { FactoryBot.create(:v2_policy, account: current_user.account, profile: canonical_profile) }
Expand Down
49 changes: 39 additions & 10 deletions spec/integration/v2/tailorings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,6 @@
).id
end

before do
25.times.map do |version|
FactoryBot.create(
:v2_tailoring,
policy: V2::Policy.find(policy_id),
os_minor_version: version
)
end
end

get 'Request Tailorings' do
v2_auth_header
tags 'Policies'
Expand All @@ -44,6 +34,16 @@
sort_params_v2(V2::Tailoring)
search_params_v2(V2::Tailoring)

before do
25.times.map do |version|
FactoryBot.create(
:v2_tailoring,
policy: V2::Policy.find(policy_id),
os_minor_version: version
)
end
end

parameter name: :policy_id, in: :path, type: :string, required: true

response '200', 'Lists Tailorings' do
Expand Down Expand Up @@ -91,6 +91,35 @@
run_test!
end
end

post 'Create a Tailoring' do
let(:policy_id) do
FactoryBot.create(
:v2_policy,
account: user.account,
profile: FactoryBot.create(:v2_profile, ref_id_suffix: 'foo', supports_minors: [1])
).id
end

v2_auth_header
tags 'Policies'
description 'Create a Tailoring with the provided attributes (for ImageBuilder only)'
operationId 'CreateTailoring'
content_types

parameter name: :policy_id, in: :path, type: :string, required: true
parameter name: :data, in: :body, schema: ref_schema('tailoring_create')

response '201', 'Creates a Tailoring' do
let(:data) { { os_minor_version: 1 } }

v2_item_schema('tailoring')

after { |e| autogenerate_examples(e) }

run_test!
end
end
end

path '/policies/{policy_id}/tailorings/{tailoring_id}' do
Expand Down
Loading

0 comments on commit 505c9ee

Please sign in to comment.