Skip to content

Conversation

lauzadis
Copy link
Contributor

Issue #

Description of changes

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@lauzadis lauzadis requested a review from a team as a code owner March 20, 2025 14:50
@lauzadis lauzadis added the no-changelog Indicates that a changelog entry isn't required for a pull request. Use sparingly. label Mar 20, 2025
@lauzadis lauzadis added the acknowledge-api-break Acknowledge that a change is API breaking and may be backwards-incompatible. Review carefully! label Mar 21, 2025
Comment on lines 63 to 70
internal val AwsSigningConfig.credentialScope: String
get() = run {
val signingDate = signingDate.format(TimestampFormat.ISO_8601_CONDENSED_DATE)
return when (algorithm) {
AwsSigningAlgorithm.SIGV4 -> "$signingDate/$region/$service/aws4_request"
AwsSigningAlgorithm.SIGV4_ASYMMETRIC -> "$signingDate/$service/aws4_request"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The run function is good for assignments but just adds clutter to function definitions. Just use braces:

internal val AwsSigningConfig.credentialScope: String
    get() {
        val signingDate = signingDate.format(TimestampFormat.ISO_8601_CONDENSED_DATE)
        return when (algorithm) {
            AwsSigningAlgorithm.SIGV4 -> "$signingDate/$region/$service/aws4_request"
            AwsSigningAlgorithm.SIGV4_ASYMMETRIC -> "$signingDate/$service/aws4_request"
        }
    }

Comment on lines +18 to +30
/** Creates a customized instance of [AwsSigner] */
@Suppress("ktlint:standard:function-naming")
public fun DefaultAwsSigner(block: DefaultAwsSignerBuilder.() -> Unit): AwsSigner =
DefaultAwsSignerBuilder().apply(block).build()

/** A builder class for creating instances of [AwsSigner] using the default implementation */
public class DefaultAwsSignerBuilder {
public var telemetryProvider: TelemetryProvider? = null

public fun build(): AwsSigner = DefaultAwsSignerImpl(
telemetryProvider = telemetryProvider,
)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opinion: It now feels weird that this factory function and builder type exist only in JVM when the named value exists in all source sets.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed separately and agreed that this API disparity is fine for now and can be reexamined if we ever see problems or get feedback.

Comment on lines 14 to 16
/** The default implementation of [AwsSigner] */
public actual val DefaultAwsSigner: AwsSigner
get() = DefaultAwsSignerImpl()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why is a new signer instantiated on every call? Before it was initialized only once and then reused everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be refactored, same applies for CrtAwsSigner

Comment on lines 9 to 11
/** The default implementation of [AwsSigner] */
public actual val DefaultAwsSigner: AwsSigner
get() = CrtAwsSigner
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Do we have to use a getter for this or can we just set the value one time?

public actual val DefaultAwsSigner: AwsSigner = CrtAwsSigner

Comment on lines -10 to +14
internal actual fun transferRequestBody(outgoing: SdkBuffer, dest: MutableBuffer): Int = TODO("Not yet implemented")
internal actual fun transferRequestBody(outgoing: SdkBuffer, dest: MutableBuffer): Int {
val length = minOf(outgoing.size, dest.writeRemaining.toLong())
if (length <= 0) return 0
return dest.write(outgoing.readByteArray(length))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why is this different than the JVM (formerly common) implementation? Why won't simply outgoing.read(dest.buffer) work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dest.buffer exists only on JVM

@IgnoreNative // FIXME Re-enable after Kotlin/Native Implementation.
@Test
fun testStreamError() = runTest {
CRT.initRuntime()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: This shouldn't properly be here, right? Does this need a FIXME because some underlying component is not properly initializing the CRT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not decide which underlying component needs to initialize CRT in this test. This is testing the SdkStreamResponseHandler which is a callback machine for reading a CRT HttpStream. We're not creating a CRT engine or anything else which might initialize CRT here.

The only reason this initRuntime is needed is for the final assertion:
ex.message.shouldContain("socket is closed.; crtErrorCode=$socketClosedEc")

CRT needs to be initialized to return human-readable error codes, otherwise it returns "unknown". This assertion is on an exception message which we typically avoid doing, so I could remove that assertion / remove CRT.init?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes removing the CRT.initRuntime() is probably the simplest thing to do for this test. But I still worry we have our CRT initialization calls in so many disparate places and that we may still be missing the calls in other places.

Copy link
Contributor Author

@lauzadis lauzadis Mar 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll keep the CRT.initRuntime() and the assertion in place. I'll add a comment* explaining why we need to initialize the CRT here.

Comment on lines 264 to 262
val cause = assertNotNull(ex.cause)
val cause = assertNotNull(ex.cause ?: ex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why is there a fallback in this test? Why would the exception have a cause in one run/target but not another?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent a few hours on this one and could not figure out the root cause.

On JVM, the exception ex is a copy of its cause (ex.cause), but the cause is the one which has all of the suppressed exceptions. On all other platforms, there is just a single exception ex which holds all of the suppressed exceptions.

This test is focused on suppressed exceptions, which do work consistently across platforms, so I think it's ok. I could leave a FIXME / open up a backlog task to investigate the ex.cause if you'd like?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it'd be good to understand what's duplicating it. A FIXME seems correct.

Comment on lines -13 to +10
public actual fun ecdsaSecp256r1(key: ByteArray, message: ByteArray): ByteArray = TODO("Not yet implemented")
public actual fun ecdsaSecp256r1(key: ByteArray, message: ByteArray): ByteArray = error("This function should not be invoked on Native, which uses the CrtAwsSigner.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: It feels weird to have an actual function that we'll never implement and should never call. That, to me, indicates that our expect declaration is on the wrong component and should be higher up.

Comment on lines -7 to -9
// FIXME Implement using aws-c-cal: https://github.com/awslabs/aws-c-cal/blob/main/include/aws/cal/ecc.h
// Will need to be implemented and exposed in aws-crt-kotlin. Or maybe we can _only_ offer the CRT signer on Native?
// Will require updating DefaultAwsSigner to be expect/actual and set to CrtSigner on Native.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Did we go down the road of binding to CRT's crypto primitives and abandon it for some reason? Or did we just decide to use the whole CRT signer for a more important reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I didn't even start binding to CRT for this. We previously discussed using CrtAwsSigner as the default on Native so that's where I went.

It sounds like you've changed your mind on this, we can talk about it and decide what to do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We agreed to keep the CrtAwsSigner as default on Native and evaluate the decision if/when we get user feedback

@aws-sdk-kotlin-ci aws-sdk-kotlin-ci merged commit f7c8f82 into kn-main Mar 26, 2025
18 checks passed
@aws-sdk-kotlin-ci aws-sdk-kotlin-ci deleted the kn-misc branch March 26, 2025 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

acknowledge-api-break Acknowledge that a change is API breaking and may be backwards-incompatible. Review carefully! no-changelog Indicates that a changelog entry isn't required for a pull request. Use sparingly.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants