Unverified Commit 238cf8b4 authored by Julian Antonielli's avatar Julian Antonielli Committed by GitHub
Browse files

Fix @sensitive handling in Display implementations on error shapes (#1802)

* Use `Sensitive` wrapper in Debug impl for structures

* Fix using the wrong import path for `Sensitive`

* Use redactMemberIfNecessary

* Fix display implementation on errors to respect @sensitive trait

* Don't use Sensitive type just yet

* Add entry in changelog

* Improve redaction of sensitive error message

* Use correct flags in changelog

* Run ktlint
parent e78da559
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -36,6 +36,12 @@ references = ["smithy-rs#1803"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "server"}
author = "LukeMathWalker"

[[smithy-rs]]
message = "Sensitive fields in errors now respect @sensitive trait and are properly redacted."
references = ["smithy-rs#1802"]
meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "all" }
author = "jjant"

[[smithy-rs]]
message = "Pokémon Service example code now runs clippy during build."
references = ["smithy-rs#1727"]
+2 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ open class StructureGenerator(
    fun render(forWhom: CodegenTarget = CodegenTarget.CLIENT) {
        renderStructure()
        errorTrait?.also { errorTrait ->
            ErrorGenerator(symbolProvider, writer, shape, errorTrait).render(forWhom)
            ErrorGenerator(model, symbolProvider, writer, shape, errorTrait).render(forWhom)
        }
    }

@@ -109,6 +109,7 @@ open class StructureGenerator(
                members.forEach { member ->
                    val memberName = symbolProvider.toMemberName(member)
                    val fieldValue = member.redactIfNecessary(model, "self.$memberName")

                    rust(
                        "formatter.field(${memberName.dq()}, &$fieldValue);",
                    )
+10 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

package software.amazon.smithy.rust.codegen.core.smithy.generators.error

import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.model.traits.ErrorTrait
import software.amazon.smithy.model.traits.RetryableTrait
@@ -19,10 +20,12 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.StdError
import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider
import software.amazon.smithy.rust.codegen.core.smithy.isOptional
import software.amazon.smithy.rust.codegen.core.util.REDACTION
import software.amazon.smithy.rust.codegen.core.util.dq
import software.amazon.smithy.rust.codegen.core.util.errorMessageMember
import software.amazon.smithy.rust.codegen.core.util.getTrait
import software.amazon.smithy.rust.codegen.core.util.letIf
import software.amazon.smithy.rust.codegen.core.util.shouldRedact

sealed class ErrorKind {
    abstract fun writable(runtimeConfig: RuntimeConfig): Writable
@@ -60,6 +63,7 @@ fun StructureShape.modeledRetryKind(errorTrait: ErrorTrait): ErrorKind? {
}

class ErrorGenerator(
    private val model: Model,
    private val symbolProvider: RustSymbolProvider,
    private val writer: RustWriter,
    private val shape: StructureShape,
@@ -118,10 +122,14 @@ class ErrorGenerator(
                }
                write("write!(f, ${errorDesc.dq()})?;")
                messageShape?.let {
                    if (it.shouldRedact(model)) {
                        write("""write!(f, ": {}", $REDACTION)?;""")
                    } else {
                        ifSet(it, symbolProvider.toSymbol(it), "&self.message") { field ->
                            write("""write!(f, ": {}", $field)?;""")
                        }
                    }
                }
                write("Ok(())")
            }
        }
+12 −7
Original line number Diff line number Diff line
@@ -84,15 +84,20 @@ fun ServiceShape.hasEventStreamOperations(model: Model): Boolean = operations.an
    model.expectShape(id, OperationShape::class.java).isEventStream(model)
}

fun Shape.redactIfNecessary(model: Model, safeToPrint: String): String =
fun Shape.shouldRedact(model: Model): Boolean =
    when (this) {
        is MemberShape -> model.expectShape(this.target).redactIfNecessary(model, safeToPrint)
        else -> if (this.hasTrait<SensitiveTrait>()) {
            "*** Sensitive Data Redacted ***".dq()
        is MemberShape -> model.expectShape(this.target).shouldRedact(model)
        else -> this.hasTrait<SensitiveTrait>()
    }

const val REDACTION = "\"*** Sensitive Data Redacted ***\""

fun Shape.redactIfNecessary(model: Model, safeToPrint: String): String =
    if (this.shouldRedact(model)) {
        REDACTION
    } else {
        safeToPrint
    }
    }

/*
 * Returns the member of this structure targeted with streaming trait (if it exists).