Skip to content

Commit 7d5d5fd

Browse files
authored
[WX-1615] Stop converting metadata values to strings before inserting them into the database (#7427)
1 parent e03b417 commit 7d5d5fd

File tree

2 files changed

+94
-6
lines changed

2 files changed

+94
-6
lines changed

services/src/main/scala/cromwell/services/metadata/impl/WriteMetadataActor.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import cromwell.core.Dispatcher.ServiceDispatcher
66
import cromwell.core.Mailbox.PriorityMailbox
77
import cromwell.core.WorkflowId
88
import cromwell.core.instrumentation.InstrumentationPrefixes
9-
import cromwell.services.metadata.{MetadataEvent, MetadataValue}
9+
import cromwell.services.metadata.{MetadataEvent, MetadataString, MetadataValue}
1010
import cromwell.services.metadata.MetadataService._
1111
import cromwell.services.metadata.impl.MetadataStatisticsRecorder.MetadataStatisticsRecorderSettings
1212
import cromwell.services.{EnhancedBatchActor, MetadataServicesStore}
@@ -65,7 +65,12 @@ class WriteMetadataActor(override val batchSize: Int,
6565
val metadataEvents =
6666
metadataWriteAction.events.map { event =>
6767
event.value match {
68-
case Some(eventVal) => event.copy(value = Option(MetadataValue(StringUtil.cleanUtf8mb4(eventVal.value))))
68+
case Some(eventVal) =>
69+
if (eventVal.valueType == MetadataString && metadataKeysToClean.contains(event.key.key)) {
70+
event.copy(value = Option(MetadataValue(StringUtil.cleanUtf8mb4(eventVal.value))))
71+
} else {
72+
event
73+
}
6974
case None => event
7075
}
7176
}

services/src/test/scala/cromwell/services/metadata/impl/WriteMetadataActorSpec.scala

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cromwell.services.metadata.impl
22

33
import java.sql.{Connection, Timestamp}
4-
54
import akka.actor.ActorRef
65
import akka.testkit.{TestFSMRef, TestProbe}
76
import cats.data.NonEmptyVector
@@ -19,7 +18,7 @@ import cromwell.services.metadata.MetadataService.{
1918
}
2019
import cromwell.services.metadata.impl.MetadataStatisticsRecorder.MetadataStatisticsDisabled
2120
import cromwell.services.metadata.impl.WriteMetadataActorSpec.BatchSizeCountingWriteMetadataActor
22-
import cromwell.services.metadata.{MetadataEvent, MetadataKey, MetadataValue}
21+
import cromwell.services.metadata.{MetadataEvent, MetadataInt, MetadataKey, MetadataValue}
2322
import org.scalatest.concurrent.Eventually
2423
import org.scalatest.flatspec.AnyFlatSpecLike
2524
import org.scalatest.matchers.should.Matchers
@@ -178,7 +177,7 @@ class WriteMetadataActorSpec extends TestKitSuite with AnyFlatSpecLike with Matc
178177

179178
sanitizedWriteActions.map { writeAction =>
180179
writeAction.events.map { event =>
181-
if (event.value.getOrElse(fail("Removed value from metadata event")).value.matches("[\\x{10000}-\\x{FFFFF}]")) {
180+
if (event.value.getOrElse(fail("Removed value from metadata event")).value.contains("\uD83C\uDF89")) {
182181
fail("Metadata event contains emoji")
183182
}
184183

@@ -220,7 +219,7 @@ class WriteMetadataActorSpec extends TestKitSuite with AnyFlatSpecLike with Matc
220219

221220
sanitizedWriteActions.map { writeAction =>
222221
writeAction.events.map { event =>
223-
if (event.value.getOrElse(fail("Removed value from metadata event")).value.matches("[\\x{10000}-\\x{FFFFF}]")) {
222+
if (event.value.getOrElse(fail("Removed value from metadata event")).value.contains("\uD83C\uDF89")) {
224223
fail("Metadata event contains emoji")
225224
}
226225

@@ -231,6 +230,90 @@ class WriteMetadataActorSpec extends TestKitSuite with AnyFlatSpecLike with Matc
231230
}
232231
}
233232

233+
it should s"test sanitize inputs does not modify metadata values whose keys are not included in the keys to clean" in {
234+
val registry = TestProbe().ref
235+
val writeActor =
236+
TestFSMRef(new BatchSizeCountingWriteMetadataActor(10, 10.millis, registry, Int.MaxValue, List("some_key")) {
237+
override val metadataDatabaseInterface = mockDatabaseInterface(100)
238+
})
239+
240+
def metadataEvent(index: Int, probe: ActorRef) = PutMetadataActionAndRespond(
241+
List(
242+
MetadataEvent(MetadataKey(WorkflowId.randomId(), None, "metadata_key"), MetadataValue(s"🎉_$index"))
243+
),
244+
probe
245+
)
246+
247+
val probes = (0 until 43)
248+
.map { _ =>
249+
val probe = TestProbe()
250+
probe
251+
}
252+
.zipWithIndex
253+
.map { case (probe, index) =>
254+
probe -> metadataEvent(index, probe.ref)
255+
}
256+
257+
val metadataWriteActions = probes.map(probe => probe._2).toVector
258+
val metadataWriteActionNE = NonEmptyVector(metadataWriteActions.head, metadataWriteActions.tail)
259+
260+
val sanitizedWriteActions = writeActor.underlyingActor.sanitizeInputs(metadataWriteActionNE)
261+
262+
sanitizedWriteActions.map { writeAction =>
263+
writeAction.events.map { event =>
264+
if (!event.value.getOrElse(fail("Removed value from metadata event")).value.contains("\uD83C\uDF89")) {
265+
fail("Metadata event was incorrectly sanitized")
266+
}
267+
268+
if (event.value.getOrElse(fail("Removed value from metadata event")).value.contains("\uFFFD")) {
269+
fail("Incorrectly replaced character in metadata event")
270+
}
271+
}
272+
}
273+
}
274+
275+
it should s"test sanitize inputs does not modify metadata values that are not strings" in {
276+
val registry = TestProbe().ref
277+
val writeActor =
278+
TestFSMRef(new BatchSizeCountingWriteMetadataActor(10, 10.millis, registry, Int.MaxValue, List("metadata_key")) {
279+
override val metadataDatabaseInterface = mockDatabaseInterface(100)
280+
})
281+
282+
def metadataEvent(index: Int, probe: ActorRef) = PutMetadataActionAndRespond(
283+
List(
284+
MetadataEvent(MetadataKey(WorkflowId.randomId(), None, "metadata_key"), MetadataValue(100))
285+
),
286+
probe
287+
)
288+
289+
val probes = (0 until 43)
290+
.map { _ =>
291+
val probe = TestProbe()
292+
probe
293+
}
294+
.zipWithIndex
295+
.map { case (probe, index) =>
296+
probe -> metadataEvent(index, probe.ref)
297+
}
298+
299+
val metadataWriteActions = probes.map(probe => probe._2).toVector
300+
val metadataWriteActionNE = NonEmptyVector(metadataWriteActions.head, metadataWriteActions.tail)
301+
302+
val sanitizedWriteActions = writeActor.underlyingActor.sanitizeInputs(metadataWriteActionNE)
303+
304+
sanitizedWriteActions.map { writeAction =>
305+
writeAction.events.map { event =>
306+
if (!(event.value.getOrElse(fail("Removed value from metadata event")).valueType == MetadataInt)) {
307+
fail("Changed metadata type")
308+
}
309+
310+
if (!event.value.getOrElse(fail("Removed value from metadata event")).value.equals("100")) {
311+
fail("Modified metadata value")
312+
}
313+
}
314+
}
315+
}
316+
234317
// Mock database interface.
235318
// A customizable number of failures occur between each success
236319
def mockDatabaseInterface(failuresBetweenEachSuccess: Int) = new MetadataSqlDatabase with SqlDatabase {

0 commit comments

Comments
 (0)