Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for redacting/hiding sensitive test in inputText command #1944

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions maestro-client/src/main/java/maestro/Maestro.kt
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,10 @@ class Maestro(
return driver.waitForAppToSettle(initialHierarchy, appId, waitToSettleTimeoutMs)
}

fun inputText(text: String) {
LOGGER.info("Inputting text: $text")
fun inputText(text: String) = inputText(text, text)

fun inputText(text: String, redacted: String) {
LOGGER.info("Inputting text: $redacted")

driver.inputText(text)
waitForAppToSettle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

package maestro.orchestra

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import maestro.KeyCode
import maestro.Point
import maestro.ScrollDirection
Expand Down Expand Up @@ -395,20 +400,39 @@ data class AssertWithAICommand(
}
}

@JsonSerialize(using = InputTextCommand.Serializer::class)
data class InputTextCommand(
val text: String,
val label: String? = null,
val redact: Boolean = false,
) : Command {

val redacted: String get() = if (redact) "[REDACTED]" else text

override fun description(): String {
return label ?: "Input text $text"
return label ?: "Input text $redacted"
}

override fun evaluateScripts(jsEngine: JsEngine): InputTextCommand {
return copy(
text = text.evaluateScripts(jsEngine)
)
}

override fun toString(): String {
return "InputTextCommand(text=$redacted,label=$label)"
}

class Serializer : JsonSerializer<InputTextCommand>() {

override fun serialize(value: InputTextCommand, gen: JsonGenerator, provider: SerializerProvider) = with (gen) {
writeStartObject()
writeStringField("text", value.redacted)
if (value.label != null) writeStringField("label", value.label)
if (value.redact) writeBooleanField("redact", true)
writeEndObject()
}
}
}

data class LaunchAppCommand(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -813,11 +813,11 @@ class Orchestra(
.canEncode(command.text)

if (!isAscii) {
throw UnicodeNotSupportedError(command.text)
throw UnicodeNotSupportedError(command.redacted)
}
}

maestro.inputText(command.text)
maestro.inputText(command.text, command.redacted)

return true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ data class YamlFluentCommand(
addMediaCommand = addMediaCommand(addMedia, flowPath)
)
)
inputText != null -> listOf(MaestroCommand(InputTextCommand(text = inputText.text, label = inputText.label)))
inputText != null -> listOf(MaestroCommand(InputTextCommand(text = inputText.text, label = inputText.label, redact = inputText.redact)))
inputRandomText != null -> listOf(MaestroCommand(InputRandomCommand(inputType = InputRandomType.TEXT, length = inputRandomText.length, label = inputRandomText.label)))
inputRandomNumber != null -> listOf(MaestroCommand(InputRandomCommand(inputType = InputRandomType.NUMBER, length = inputRandomNumber.length, label = inputRandomNumber.label)))
inputRandomEmail != null -> listOf(MaestroCommand(InputRandomCommand(inputType = InputRandomType.TEXT_EMAIL_ADDRESS, label = inputRandomEmail.label)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import java.lang.UnsupportedOperationException
data class YamlInputText(
val text: String,
val label: String? = null,
val redact: Boolean = false,
) {

companion object {
Expand All @@ -17,8 +18,9 @@ data class YamlInputText(
is String -> text
is Map<*, *> -> {
val input = text.getOrDefault("text", "") as String
val label = text.getOrDefault("label", "") as String
return YamlInputText(input, label)
val label = text.getOrDefault("label", null) as String?
val redact = text.getOrDefault("redact", "false") as Boolean
return YamlInputText(input, label, redact)
}
is Int, is Long, is Char, is Boolean, is Float, is Double -> text.toString()
else -> throw UnsupportedOperationException("Cannot deserialize input text with data type ${text.javaClass}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,34 @@ internal class MaestroCommandSerializationTest {
.isEqualTo(command)
}

@Test
fun `serialize redacted InputTextCommand`() {
// given
val command = MaestroCommand(
InputTextCommand("secret password", redact = true)
)
@Language("json")
val expectedJson = """
{
"inputTextCommand" : {
"text" : "[REDACTED]",
"redact" : true
}
}
""".trimIndent()

// when
val serializedCommandJson = command.toJson()
val deserializedCommand = objectMapper.readValue(serializedCommandJson, MaestroCommand::class.java)

// then
val expectedDeserialized = MaestroCommand(InputTextCommand("[REDACTED]", redact = true))
assertThat(serializedCommandJson)
.isEqualTo(expectedJson)
assertThat(deserializedCommand)
.isEqualTo(expectedDeserialized)
}

@Test
fun `serialize LaunchAppCommand`() {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ internal class YamlCommandReaderTest {
// Inputs
InputTextCommand(
text = "correct horse battery staple",
label = "Enter my secret password"
label = "Enter my secret password",
redact = true
),
InputRandomCommand(
inputType = InputRandomType.TEXT_EMAIL_ADDRESS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ appId: com.example.app
- inputText:
text: "correct horse battery staple"
label: "Enter my secret password"
redact: true
- inputRandomEmail:
label: "Enter a random email address"
- inputRandomPersonName:
Expand Down
3 changes: 2 additions & 1 deletion maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ class IntegrationTest {
// No test failure
driver.assertHasEvent(Event.InputText("Hello World"))
driver.assertHasEvent(Event.InputText("[email protected]"))
driver.assertCurrentTextInput("Hello [email protected]")
driver.assertHasEvent(Event.InputText("secret password"))
driver.assertCurrentTextInput("Hello [email protected] password")
}

@Test
Expand Down
5 changes: 4 additions & 1 deletion maestro-test/src/test/resources/012_input_text.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
appId: com.example.app
---
- inputText: "Hello World"
- inputText: [email protected]
- inputText: [email protected]
- inputText:
text: "secret password"
redact: true
Loading