Commit b51ededc authored by Kamil Trzcinski's avatar Kamil Trzcinski

Don't leak build tokens in build logs

parent 0ca43b1b
...@@ -35,7 +35,11 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -35,7 +35,11 @@ class Projects::BuildsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.json do format.json do
render json: @build.to_json(methods: :trace_html) render json: {
id: @build.id,
status: @build.status,
trace_html: @build.trace_html
}
end end
end end
end end
......
...@@ -241,12 +241,7 @@ module Ci ...@@ -241,12 +241,7 @@ module Ci
end end
def trace def trace
trace = raw_trace hide_secrets(raw_trace)
if project && trace.present? && project.runners_token.present?
trace.gsub(project.runners_token, 'xxxxxx')
else
trace
end
end end
def trace_length def trace_length
...@@ -259,6 +254,7 @@ module Ci ...@@ -259,6 +254,7 @@ module Ci
def trace=(trace) def trace=(trace)
recreate_trace_dir recreate_trace_dir
trace = hide_secrets(trace)
File.write(path_to_trace, trace) File.write(path_to_trace, trace)
end end
...@@ -272,6 +268,8 @@ module Ci ...@@ -272,6 +268,8 @@ module Ci
def append_trace(trace_part, offset) def append_trace(trace_part, offset)
recreate_trace_dir recreate_trace_dir
trace_part = hide_secrets(trace_part)
File.truncate(path_to_trace, offset) if File.exist?(path_to_trace) File.truncate(path_to_trace, offset) if File.exist?(path_to_trace)
File.open(path_to_trace, 'ab') do |f| File.open(path_to_trace, 'ab') do |f|
f.write(trace_part) f.write(trace_part)
...@@ -490,5 +488,11 @@ module Ci ...@@ -490,5 +488,11 @@ module Ci
pipeline.config_processor.build_attributes(name) pipeline.config_processor.build_attributes(name)
end end
def hide_secrets(trace)
trace = Ci::MaskSecret.mask(trace, project.runners_token) if project
trace = Ci::MaskSecret.mask(trace, token)
trace
end
end end
end end
module Ci::MaskSecret
class << self
def mask(value, token)
return value unless value.present? && token.present?
value.gsub(token, 'x' * token.length)
end
end
end
require 'spec_helper'
describe Ci::MaskSecret, lib: true do
subject { described_class }
describe '#mask' do
it 'masks exact number of characters' do
expect(subject.mask('token', 'oke')).to eq('txxxn')
end
it 'masks multiple occurrences' do
expect(subject.mask('token token token', 'oke')).to eq('txxxn txxxn txxxn')
end
it 'does not mask if not found' do
expect(subject.mask('token', 'not')).to eq('token')
end
end
end
...@@ -88,9 +88,7 @@ describe Ci::Build, models: true do ...@@ -88,9 +88,7 @@ describe Ci::Build, models: true do
end end
describe '#trace' do describe '#trace' do
subject { build.trace_html } it { expect(build.trace).to be_nil }
it { is_expected.to be_empty }
context 'when build.trace contains text' do context 'when build.trace contains text' do
let(:text) { 'example output' } let(:text) { 'example output' }
...@@ -98,16 +96,80 @@ describe Ci::Build, models: true do ...@@ -98,16 +96,80 @@ describe Ci::Build, models: true do
build.trace = text build.trace = text
end end
it { is_expected.to include(text) } it { expect(build.trace).to eq(text) }
it { expect(subject.length).to be >= text.length } end
context 'when build.trace hides runners token' do
let(:token) { 'my_secret_token' }
before do
build.update(trace: token)
build.project.update(runners_token: token)
end
it { expect(build.trace).not_to include(token) }
it { expect(build.raw_trace).to include(token) }
end
context 'when build.trace hides build token' do
let(:token) { 'my_secret_token' }
before do
build.update(trace: token)
build.update(token: token)
end
it { expect(build.trace).not_to include(token) }
it { expect(build.raw_trace).to include(token) }
end
end
describe '#raw_trace' do
subject { build.raw_trace }
context 'when build.trace hides runners token' do
let(:token) { 'my_secret_token' }
before do
build.project.update(runners_token: token)
build.update(trace: token)
end
it { is_expected.not_to include(token) }
end
context 'when build.trace hides build token' do
let(:token) { 'my_secret_token' }
before do
build.update(token: token)
build.update(trace: token)
end
it { is_expected.not_to include(token) }
end
end
context '#append_trace' do
subject { build.trace_html }
context 'when build.trace hides runners token' do
let(:token) { 'my_secret_token' }
before do
build.project.update(runners_token: token)
build.append_trace(token, 0)
end
it { is_expected.not_to include(token) }
end end
context 'when build.trace hides token' do context 'when build.trace hides build token' do
let(:token) { 'my_secret_token' } let(:token) { 'my_secret_token' }
before do before do
build.project.update_attributes(runners_token: token) build.update(token: token)
build.update_attributes(trace: token) build.append_trace(token, 0)
end end
it { is_expected.not_to include(token) } it { is_expected.not_to include(token) }
......
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