Skip to content

Commit 8a67176

Browse files
committed
Add buildpack upload audit event
1 parent 0c2c53d commit 8a67176

File tree

9 files changed

+194
-6
lines changed

9 files changed

+194
-6
lines changed

app/actions/buildpack_upload.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
module VCAP::CloudController
22
class BuildpackUpload
3+
def initialize(user_audit_info)
4+
@user_audit_info = user_audit_info
5+
end
6+
37
def upload_async(message:, buildpack:, config:)
48
logger.info("uploading buildpacks bits for buildpack #{buildpack.guid}")
59

6-
upload_job = Jobs::V3::BuildpackBits.new(buildpack.guid, message.bits_path, message.bits_name)
10+
upload_job = Jobs::V3::BuildpackBits.new(buildpack.guid, message.bits_path, message.bits_name, @user_audit_info, message.audit_hash)
711
Jobs::Enqueuer.new(queue: Jobs::Queues.local(config)).enqueue_pollable(upload_job)
812
end
913

app/controllers/v3/buildpacks_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def upload
8282

8383
unprocessable!('Buildpack is locked') if buildpack.locked
8484

85-
pollable_job = BuildpackUpload.new.upload_async(
85+
pollable_job = BuildpackUpload.new(user_audit_info).upload_async(
8686
message: message,
8787
buildpack: buildpack,
8888
config: configuration

app/jobs/v3/buildpack_bits.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'cloud_controller/upload_buildpack'
2+
require 'repositories/buildpack_event_repository'
23

34
module VCAP::CloudController
45
module Jobs
@@ -7,10 +8,12 @@ class BuildpackBits
78
attr_reader :buildpack_guid
89
alias_method :resource_guid, :buildpack_guid
910

10-
def initialize(buildpack_guid, buildpack_bits_path, buildpack_bits_name)
11+
def initialize(buildpack_guid, buildpack_bits_path, buildpack_bits_name, user_audit_info=nil, request_attrs=nil)
1112
@buildpack_guid = buildpack_guid
1213
@file_path = buildpack_bits_path
1314
@file_name = buildpack_bits_name
15+
@user_audit_info = user_audit_info
16+
@request_attrs = request_attrs
1417
end
1518

1619
def perform
@@ -19,7 +22,9 @@ def perform
1922
buildpack_blobstore = CloudController::DependencyLocator.instance.buildpack_blobstore
2023
buildpack = Buildpack.find(guid: buildpack_guid)
2124

22-
VCAP::CloudController::UploadBuildpack.new(buildpack_blobstore).upload_buildpack(buildpack, file_path, file_name)
25+
upload_successful = VCAP::CloudController::UploadBuildpack.new(buildpack_blobstore).upload_buildpack(buildpack, file_path, file_name)
26+
27+
Repositories::BuildpackEventRepository.new.record_buildpack_upload(buildpack, @user_audit_info, @request_attrs || {}) if upload_successful && @user_audit_info
2328
ensure
2429
FileUtils.rm_f(file_path)
2530
end

app/repositories/buildpack_event_repository.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,25 @@ def record_buildpack_delete(buildpack, user_audit_info)
5757
metadata: {}
5858
)
5959
end
60+
61+
def record_buildpack_upload(buildpack, user_audit_info, request_attrs)
62+
Event.create(
63+
type: EventTypes::BUILDPACK_UPLOAD,
64+
actee: buildpack.guid,
65+
actee_type: 'buildpack',
66+
actee_name: buildpack.name,
67+
actor: user_audit_info.user_guid,
68+
actor_type: 'user',
69+
actor_name: user_audit_info.user_email,
70+
actor_username: user_audit_info.user_name,
71+
timestamp: Sequel::CURRENT_TIMESTAMP,
72+
space_guid: '',
73+
organization_guid: '',
74+
metadata: {
75+
request: request_attrs
76+
}
77+
)
78+
end
6079
end
6180
end
6281
end

docs/v3/source/includes/resources/audit_events/_header.md.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ For more information, see the [Cloud Foundry docs](https://docs.cloudfoundry.org
5454
- `audit.buildpack.create`
5555
- `audit.buildpack.delete`
5656
- `audit.buildpack.update`
57+
- `audit.buildpack.upload`
5758

5859
##### Organization lifecycle
5960
- `audit.organization.create`

spec/unit/actions/buildpack_upload_spec.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33

44
module VCAP::CloudController
55
RSpec.describe BuildpackUpload do
6-
subject(:buildpack_upload) { BuildpackUpload.new }
6+
let(:user) { User.make }
7+
let(:user_email) { '[email protected]' }
8+
let(:user_name) { 'user-name' }
9+
let(:user_audit_info) { UserAuditInfo.new(user_guid: user.guid, user_email: user_email, user_name: user_name) }
10+
11+
subject(:buildpack_upload) { BuildpackUpload.new(user_audit_info) }
712

813
describe '#upload_async' do
914
let!(:buildpack) { VCAP::CloudController::Buildpack.create_from_hash({ name: 'upload_binary_buildpack', stack: nil, position: 0 }) }
@@ -37,7 +42,9 @@ module VCAP::CloudController
3742
expect(Jobs::V3::BuildpackBits).to receive(:new).with(
3843
buildpack.guid,
3944
'/tmp/path',
40-
'buildpack.zip'
45+
'buildpack.zip',
46+
user_audit_info,
47+
message.audit_hash
4148
).and_call_original
4249
buildpack_upload.upload_async(message:, buildpack:, config:)
4350
end

spec/unit/jobs/v3/buildpack_bits_spec.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module Jobs::V3
88
let(:filename) { 'buildpack.zip' }
99
let!(:buildpack) { Buildpack.make }
1010
let(:buildpack_guid) { buildpack.guid }
11+
let(:user) { User.make }
12+
let(:user_email) { '[email protected]' }
13+
let(:user_name) { 'user-name' }
14+
let(:user_audit_info) { UserAuditInfo.new(user_guid: user.guid, user_email: user_email, user_name: user_name) }
15+
let(:request_attrs) { { 'bits_name' => filename } }
1116

1217
subject(:job) do
1318
BuildpackBits.new(buildpack_guid, uploaded_path, filename)
@@ -27,6 +32,63 @@ module Jobs::V3
2732
it 'knows its job name' do
2833
expect(job.job_name_in_configuration).to equal(:buildpack_bits)
2934
end
35+
36+
context 'when user_audit_info is provided' do
37+
subject(:job) do
38+
BuildpackBits.new(buildpack_guid, uploaded_path, filename, user_audit_info, request_attrs)
39+
end
40+
41+
it 'creates an audit event when upload is successful' do
42+
uploader = instance_double(UploadBuildpack)
43+
allow(UploadBuildpack).to receive(:new).and_return(uploader)
44+
allow(uploader).to receive(:upload_buildpack).and_return(true)
45+
allow(FileUtils).to receive(:rm_f)
46+
47+
expect do
48+
job.perform
49+
end.to change(Event, :count).by(1)
50+
51+
event = Event.last
52+
expect(event.values).to include(
53+
type: 'audit.buildpack.upload',
54+
actee: buildpack.guid,
55+
actee_type: 'buildpack',
56+
actee_name: buildpack.name,
57+
actor: user_audit_info.user_guid,
58+
actor_type: 'user',
59+
actor_name: user_audit_info.user_email,
60+
actor_username: user_audit_info.user_name,
61+
space_guid: '',
62+
organization_guid: ''
63+
)
64+
expect(event.metadata).to eq({ 'request' => request_attrs })
65+
expect(event.timestamp).to be
66+
end
67+
68+
it 'does not create an audit event when upload fails' do
69+
uploader = instance_double(UploadBuildpack)
70+
allow(UploadBuildpack).to receive(:new).and_return(uploader)
71+
allow(uploader).to receive(:upload_buildpack).and_return(false)
72+
allow(FileUtils).to receive(:rm_f)
73+
74+
expect do
75+
job.perform
76+
end.not_to change(Event, :count)
77+
end
78+
end
79+
80+
context 'when user_audit_info is not provided' do
81+
it 'does not create an audit event' do
82+
uploader = instance_double(UploadBuildpack)
83+
allow(UploadBuildpack).to receive(:new).and_return(uploader)
84+
allow(uploader).to receive(:upload_buildpack).and_return(true)
85+
allow(FileUtils).to receive(:rm_f)
86+
87+
expect do
88+
job.perform
89+
end.not_to change(Event, :count)
90+
end
91+
end
3092
end
3193
end
3294
end
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
require 'spec_helper'
2+
require 'repositories/buildpack_event_repository'
3+
4+
module VCAP::CloudController
5+
module Repositories
6+
RSpec.describe BuildpackEventRepository do
7+
let(:request_attrs) { { 'name' => 'new-buildpack' } }
8+
let(:user) { User.make }
9+
let(:buildpack) { Buildpack.make }
10+
let(:user_email) { 'email address' }
11+
let(:user_name) { 'user name' }
12+
let(:user_audit_info) { UserAuditInfo.new(user_email: user_email, user_guid: user.guid, user_name: user_name) }
13+
14+
subject(:buildpack_event_repository) { BuildpackEventRepository.new }
15+
16+
describe '#record_buildpack_create' do
17+
it 'records event correctly' do
18+
event = buildpack_event_repository.record_buildpack_create(buildpack, user_audit_info, request_attrs)
19+
event.reload
20+
expect(event.space_guid).to eq('')
21+
expect(event.organization_guid).to eq('')
22+
expect(event.type).to eq('audit.buildpack.create')
23+
expect(event.actee).to eq(buildpack.guid)
24+
expect(event.actee_type).to eq('buildpack')
25+
expect(event.actee_name).to eq(buildpack.name)
26+
expect(event.actor).to eq(user.guid)
27+
expect(event.actor_type).to eq('user')
28+
expect(event.actor_name).to eq(user_email)
29+
expect(event.actor_username).to eq(user_name)
30+
expect(event.metadata).to eq({ 'request' => request_attrs })
31+
end
32+
end
33+
34+
describe '#record_buildpack_update' do
35+
it 'records event correctly' do
36+
event = buildpack_event_repository.record_buildpack_update(buildpack, user_audit_info, request_attrs)
37+
event.reload
38+
expect(event.space_guid).to eq('')
39+
expect(event.organization_guid).to eq('')
40+
expect(event.type).to eq('audit.buildpack.update')
41+
expect(event.actee).to eq(buildpack.guid)
42+
expect(event.actee_type).to eq('buildpack')
43+
expect(event.actee_name).to eq(buildpack.name)
44+
expect(event.actor).to eq(user.guid)
45+
expect(event.actor_type).to eq('user')
46+
expect(event.actor_name).to eq(user_email)
47+
expect(event.actor_username).to eq(user_name)
48+
expect(event.metadata).to eq({ 'request' => request_attrs })
49+
end
50+
end
51+
52+
describe '#record_buildpack_delete' do
53+
it 'records event correctly' do
54+
event = buildpack_event_repository.record_buildpack_delete(buildpack, user_audit_info)
55+
event.reload
56+
expect(event.space_guid).to eq('')
57+
expect(event.organization_guid).to eq('')
58+
expect(event.type).to eq('audit.buildpack.delete')
59+
expect(event.actee).to eq(buildpack.guid)
60+
expect(event.actee_type).to eq('buildpack')
61+
expect(event.actee_name).to eq(buildpack.name)
62+
expect(event.actor).to eq(user.guid)
63+
expect(event.actor_type).to eq('user')
64+
expect(event.actor_name).to eq(user_email)
65+
expect(event.actor_username).to eq(user_name)
66+
expect(event.metadata).to eq({})
67+
end
68+
end
69+
70+
describe '#record_buildpack_upload' do
71+
it 'records event correctly' do
72+
event = buildpack_event_repository.record_buildpack_upload(buildpack, user_audit_info, request_attrs)
73+
event.reload
74+
expect(event.space_guid).to eq('')
75+
expect(event.organization_guid).to eq('')
76+
expect(event.type).to eq('audit.buildpack.upload')
77+
expect(event.actee).to eq(buildpack.guid)
78+
expect(event.actee_type).to eq('buildpack')
79+
expect(event.actee_name).to eq(buildpack.name)
80+
expect(event.actor).to eq(user.guid)
81+
expect(event.actor_type).to eq('user')
82+
expect(event.actor_name).to eq(user_email)
83+
expect(event.actor_username).to eq(user_name)
84+
expect(event.metadata).to eq({ 'request' => request_attrs })
85+
end
86+
end
87+
end
88+
end
89+
end

spec/unit/repositories/event_types_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ module Repositories
6767
'audit.buildpack.create',
6868
'audit.buildpack.update',
6969
'audit.buildpack.delete',
70+
'audit.buildpack.upload',
7071
'audit.service.create',
7172
'audit.service.update',
7273
'audit.service.delete',

0 commit comments

Comments
 (0)