diff --git a/app/repositories/app_event_repository.rb b/app/repositories/app_event_repository.rb index 64347ba6690..4bf531f95cc 100644 --- a/app/repositories/app_event_repository.rb +++ b/app/repositories/app_event_repository.rb @@ -194,18 +194,20 @@ def app_audit_hash(request_attrs) changes[censored] = Presenters::Censorship::PRIVATE_DATA_HIDDEN if changes.key?(censored) end - v2_buildpack = changes.key?('buildpack') - v3_buildpack = changes.key?('lifecycle') && changes['lifecycle'].key?('data') && changes['lifecycle']['data'].key?('buildpack') - - if v2_buildpack - buildpack_attr = changes['buildpack'] - changes['buildpack'] = CloudController::UrlSecretObfuscator.obfuscate(buildpack_attr) if buildpack_attr - elsif v3_buildpack - buildpack_attr = changes['lifecycle']['data']['buildpack'] - changes['lifecycle']['data']['buildpack'] = CloudController::UrlSecretObfuscator.obfuscate(buildpack_attr) if buildpack_attr - end + obfuscate_buildpack_urls(changes) end end + + def obfuscate_buildpack_urls(changes) + # Top-level 'buildpack' is v2-only; remove with the v2 API. + changes['buildpack'] = CloudController::UrlSecretObfuscator.obfuscate(changes['buildpack']) if changes['buildpack'] + + lifecycle_data = changes['lifecycle']['data'] if changes.key?('lifecycle') && changes['lifecycle'].key?('data') + return unless lifecycle_data + + lifecycle_data['buildpack'] = CloudController::UrlSecretObfuscator.obfuscate(lifecycle_data['buildpack']) if lifecycle_data['buildpack'] + lifecycle_data['buildpacks'] = lifecycle_data['buildpacks'].map { |b| CloudController::UrlSecretObfuscator.obfuscate(b) } if lifecycle_data['buildpacks'] + end end end end diff --git a/app/repositories/service_event_repository.rb b/app/repositories/service_event_repository.rb index ad068bd881a..6fca4a338fd 100644 --- a/app/repositories/service_event_repository.rb +++ b/app/repositories/service_event_repository.rb @@ -133,7 +133,7 @@ def record_service_instance_event(event, service_instance, params=nil) end def record_user_provided_service_instance_event(event, service_instance, params=nil) - metadata = { request: with_credentials_redacted(params) } + metadata = { request: with_url_credentials_obfuscated(with_credentials_redacted(params)) } create_service_instance_event( 'user_provided_service_instance', @@ -218,6 +218,16 @@ def with_credentials_redacted(request_data) redact(request_data, for_key: 'credentials', with: Presenters::Censorship::REDACTED) end + def with_url_credentials_obfuscated(request_data) + return request_data unless request_data.respond_to?(:[]=) + + request_data.dup.tap do |data| + %w[syslog_drain_url route_service_url].each do |url_key| + data[url_key] = CloudController::UrlSecretObfuscator.obfuscate(data[url_key]) if data[url_key] + end + end + end + def redact( params, for_key:, diff --git a/spec/unit/repositories/app_event_repository_spec.rb b/spec/unit/repositories/app_event_repository_spec.rb index e2115cfdb06..78bae9d0949 100644 --- a/spec/unit/repositories/app_event_repository_spec.rb +++ b/spec/unit/repositories/app_event_repository_spec.rb @@ -528,6 +528,60 @@ module Repositories end end end + + context 'v3 with a buildpacks array' do + let(:app) { create(:app_model) } + let(:attrs) do + { + 'lifecycle' => { + 'type' => 'buildpack', + 'data' => { 'buildpacks' => buildpacks } + } + } + end + + context 'when the buildpacks are not nil' do + let(:buildpacks) do + [ + 'https://user:password@example.com/first.git', + 'https://user:password@example.com/second.git' + ] + end + + it 'obfuscates each buildpack url' do + event = app_event_repository.record_app_update(app, space, user_audit_info, attrs).reload + + expect(event.metadata.dig('request', 'lifecycle', 'data', 'buildpacks')).to eq( + [ + 'https://***:***@example.com/first.git', + 'https://***:***@example.com/second.git' + ] + ) + end + + it 'calls out to UrlSecretObfuscator once per buildpack' do + allow(CloudController::UrlSecretObfuscator).to receive(:obfuscate) + app_event_repository.record_app_update(app, space, user_audit_info, attrs) + expect(CloudController::UrlSecretObfuscator).to have_received(:obfuscate).exactly :twice + end + end + + context 'when the buildpacks are nil' do + let(:buildpacks) { nil } + + it 'does nothing' do + event = app_event_repository.record_app_update(app, space, user_audit_info, attrs).reload + + expected_request = { + 'lifecycle' => { + 'type' => 'buildpack', + 'data' => { 'buildpacks' => nil } + } + } + expect(event.metadata.fetch('request')).to eq expected_request + end + end + end end context 'with a v3 app' do diff --git a/spec/unit/repositories/service_event_repository_spec.rb b/spec/unit/repositories/service_event_repository_spec.rb index 3d3a9193e9d..142a59c216f 100644 --- a/spec/unit/repositories/service_event_repository_spec.rb +++ b/spec/unit/repositories/service_event_repository_spec.rb @@ -616,6 +616,31 @@ module Repositories }) end end + + context 'when the params contain urls with credentials' do + let(:params) do + { + 'name' => 'my-upsi', + 'space_guid' => instance.space.guid, + 'syslog_drain_url' => 'https://drain-user:drain-password@drain.example.com/logs', + 'route_service_url' => 'https://route-user:route-password@route.example.com/proxy' + } + end + + it 'obfuscates the credentials in the syslog_drain_url' do + repository.record_user_provided_service_instance_event(:create, instance, params) + event = Event.first(type: 'audit.user_provided_service_instance.create') + + expect(event.metadata.dig('request', 'syslog_drain_url')).to eq('https://***:***@drain.example.com/logs') + end + + it 'obfuscates the credentials in the route_service_url' do + repository.record_user_provided_service_instance_event(:create, instance, params) + event = Event.first(type: 'audit.user_provided_service_instance.create') + + expect(event.metadata.dig('request', 'route_service_url')).to eq('https://***:***@route.example.com/proxy') + end + end end describe '#record_service_key_event' do