Skip to content

feat: emit bearer business metric #1348

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

Merged
merged 10 commits into from
Aug 7, 2025
Merged
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
2 changes: 2 additions & 0 deletions runtime/auth/http-auth/api/http-auth.api
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public abstract interface class aws/smithy/kotlin/runtime/http/auth/CloseableBea
public final class aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProvider : aws/smithy/kotlin/runtime/http/auth/BearerTokenProvider {
public fun <init> (Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;)V
public synthetic fun <init> (Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun resolve (Laws/smithy/kotlin/runtime/collections/Attributes;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,37 @@
*/
package aws.smithy.kotlin.runtime.http.auth

import aws.smithy.kotlin.runtime.businessmetrics.SmithyBusinessMetric
import aws.smithy.kotlin.runtime.businessmetrics.emitBusinessMetric
import aws.smithy.kotlin.runtime.collections.Attributes
import aws.smithy.kotlin.runtime.collections.emptyAttributes
import aws.smithy.kotlin.runtime.collections.mutableAttributes
import aws.smithy.kotlin.runtime.time.Instant
import aws.smithy.kotlin.runtime.util.PlatformProvider

/**
* A [BearerTokenProvider] that extracts the bearer token from the target environment variable.
* A [BearerTokenProvider] that extracts the bearer token from JVM system properties or environment variables.
*/
public class EnvironmentBearerTokenProvider(
private val key: String,
private val sysPropKey: String,
private val envKey: String,
private val platform: PlatformProvider = PlatformProvider.System,
) : BearerTokenProvider {
@Deprecated("This constructor does not support a parameter for a system property key and will be removed in version 1.6.x")
public constructor(
envKey: String,
platform: PlatformProvider = PlatformProvider.System,
) : this("", envKey, platform)

override suspend fun resolve(attributes: Attributes): BearerToken {
val bearerToken = platform.getenv(key)
?: error("$key environment variable is not set")
val bearerToken = sysPropKey.takeUnless(String::isBlank)?.let(platform::getProperty)
?: platform.getenv(envKey)
if (bearerToken.isNullOrBlank()) throw IllegalStateException("""Missing values for system property "$sysPropKey" and environment variable "$envKey"""")

return object : BearerToken {
override val token: String = bearerToken
override val attributes: Attributes = emptyAttributes()
override val attributes: Attributes = mutableAttributes().apply {
emitBusinessMetric(SmithyBusinessMetric.BEARER_SERVICE_ENV_VARS)
}
override val expiration: Instant? = null
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package aws.smithy.kotlin.runtime.http.auth

import aws.smithy.kotlin.runtime.collections.emptyAttributes
import aws.smithy.kotlin.runtime.util.TestPlatformProvider
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
Expand All @@ -9,27 +8,65 @@ import kotlin.test.assertFailsWith

class EnvironmentBearerTokenProviderTest {
@Test
fun testResolveWithValidToken() = runTest {
fun testResolveFromEnvVar() = runTest {
val provider = EnvironmentBearerTokenProvider(
"TEST_TOKEN",
TestPlatformProvider(mutableMapOf("TEST_TOKEN" to "test-bearer-token")),
"TEST_SYS_PROPS_TOKEN",
"TEST_ENV_TOKEN",
TestPlatformProvider(
env = mapOf("TEST_ENV_TOKEN" to "test-env-bearer-token"),
),
)

val token = provider.resolve()

assertEquals("test-bearer-token", token.token)
assertEquals("test-env-bearer-token", token.token)
}

@Test
fun testResolveFromSysProps() = runTest {
val provider = EnvironmentBearerTokenProvider(
"TEST_SYS_PROPS_TOKEN",
"TEST_ENV_TOKEN",
TestPlatformProvider(
props = mapOf("TEST_SYS_PROPS_TOKEN" to "test-sys-props-bearer-token"),
),
)

val token = provider.resolve()

assertEquals("test-sys-props-bearer-token", token.token)
}

@Test
fun testResolutionOrder() = runTest {
val provider = EnvironmentBearerTokenProvider(
"TEST_SYS_PROPS_TOKEN",
"TEST_ENV_TOKEN",
TestPlatformProvider(
props = mapOf("TEST_SYS_PROPS_TOKEN" to "test-sys-props-bearer-token"),
env = mapOf("TEST_ENV_TOKEN" to "test-env-bearer-token"),
),
)

val token = provider.resolve()

assertEquals("test-sys-props-bearer-token", token.token)
}

@Test
fun testResolveWithMissingToken() = runTest {
val provider = EnvironmentBearerTokenProvider(
"MISSING_TEST_TOKEN",
TestPlatformProvider(mutableMapOf()),
"MISSING_TEST_TOKEN",
TestPlatformProvider(
env = mapOf("TEST_TOKEN" to "test-env-bearer-token"),
props = mapOf("TEST_TOKEN" to "test-sys-props-bearer-token"),
),
)

val exception = assertFailsWith<IllegalStateException> {
provider.resolve(emptyAttributes())
provider.resolve()
}
assertEquals("MISSING_TEST_TOKEN environment variable is not set", exception.message)
assertEquals("Missing values for system property \"MISSING_TEST_TOKEN\" and environment variable \"MISSING_TEST_TOKEN\"", exception.message)
}
}
1 change: 1 addition & 0 deletions runtime/runtime-core/api/runtime-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public final class aws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetri
public static final field ACCOUNT_ID_MODE_DISABLED Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
public static final field ACCOUNT_ID_MODE_PREFERRED Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
public static final field ACCOUNT_ID_MODE_REQUIRED Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
public static final field BEARER_SERVICE_ENV_VARS Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
public static final field FLEXIBLE_CHECKSUMS_REQ_CRC32 Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
public static final field FLEXIBLE_CHECKSUMS_REQ_CRC32C Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
public static final field FLEXIBLE_CHECKSUMS_REQ_SHA1 Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public enum class SmithyBusinessMetric(public override val identifier: String) :
FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED("a"),
FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED("b"),
FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED("c"),
BEARER_SERVICE_ENV_VARS("3"),
;

override fun toString(): String = identifier
Expand Down
Loading