From fe5e1f5f87befad7fdc0baf4d7561223d51c610e Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 24 Jan 2024 13:35:47 -0800 Subject: [PATCH 01/16] Establish token provider trait (#3381) This PR creates a trait to provide access tokens, which will be used to configure token providers in `SdkConfig`. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --- .../aws-config/external-types.toml | 6 +- .../src/credentials_impl.rs | 2 + .../aws-credential-types/src/lib.rs | 2 + .../aws-credential-types/src/provider.rs | 306 +----------------- .../src/provider/credentials.rs | 176 ++++++++++ .../src/provider/error.rs | 274 ++++++++++++++++ .../src/provider/future.rs | 63 ++++ .../src/provider/token.rs | 64 ++++ .../aws-credential-types/src/token_impl.rs | 72 +++++ .../aws-inlineable/external-types.toml | 2 +- .../aws-types/external-types.toml | 2 +- 11 files changed, 664 insertions(+), 305 deletions(-) create mode 100644 aws/rust-runtime/aws-credential-types/src/provider/credentials.rs create mode 100644 aws/rust-runtime/aws-credential-types/src/provider/error.rs create mode 100644 aws/rust-runtime/aws-credential-types/src/provider/future.rs create mode 100644 aws/rust-runtime/aws-credential-types/src/provider/token.rs create mode 100644 aws/rust-runtime/aws-credential-types/src/token_impl.rs diff --git a/aws/rust-runtime/aws-config/external-types.toml b/aws/rust-runtime/aws-config/external-types.toml index 38a34bd786..58a946ea9f 100644 --- a/aws/rust-runtime/aws-config/external-types.toml +++ b/aws/rust-runtime/aws-config/external-types.toml @@ -4,9 +4,9 @@ # to the exposed SDK crates happens. allowed_external_types = [ "aws_credential_types::cache::CredentialsCache", - "aws_credential_types::provider::ProvideCredentials", - "aws_credential_types::provider::Result", - "aws_credential_types::provider::SharedCredentialsProvider", + "aws_credential_types::provider::credentials::ProvideCredentials", + "aws_credential_types::provider::credentials::Result", + "aws_credential_types::provider::credentials::SharedCredentialsProvider", "aws_smithy_async::rt::sleep::AsyncSleep", "aws_smithy_async::rt::sleep::SharedAsyncSleep", "aws_smithy_async::time::SharedTimeSource", diff --git a/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs b/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs index c7595bb66c..ebd646d466 100644 --- a/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs +++ b/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs @@ -57,6 +57,8 @@ impl Debug for Credentials { } else { creds.field("expires_after", &expiry); } + } else { + creds.field("expires_after", &"never"); } creds.finish() } diff --git a/aws/rust-runtime/aws-credential-types/src/lib.rs b/aws/rust-runtime/aws-credential-types/src/lib.rs index e2bb7858ff..fb3a2980aa 100644 --- a/aws/rust-runtime/aws-credential-types/src/lib.rs +++ b/aws/rust-runtime/aws-credential-types/src/lib.rs @@ -23,5 +23,7 @@ pub mod credential_fn; mod credentials_impl; pub mod provider; +mod token_impl; pub use credentials_impl::Credentials; +pub use token_impl::AccessToken; diff --git a/aws/rust-runtime/aws-credential-types/src/provider.rs b/aws/rust-runtime/aws-credential-types/src/provider.rs index 35c6f91448..1180503bef 100644 --- a/aws/rust-runtime/aws-credential-types/src/provider.rs +++ b/aws/rust-runtime/aws-credential-types/src/provider.rs @@ -19,7 +19,7 @@ #![cfg_attr( feature = "hardcoded-credentials", doc = r##" -See [`Credentials::from_keys`] for an example on how to use static credentials. +See [`Credentials::from_keys`](crate::Credentials::from_keys) for an example on how to use static credentials. "## )] #![cfg_attr( @@ -71,303 +71,9 @@ construct credentials from hardcoded values. //! } //! ``` -use crate::Credentials; -use aws_smithy_runtime_api::client::identity::{Identity, IdentityFuture, ResolveIdentity}; -use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; -use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace}; -use std::sync::Arc; +mod credentials; +pub mod error; +pub mod future; +pub mod token; -/// Credentials provider errors -pub mod error { - use std::error::Error; - use std::fmt; - use std::time::Duration; - - /// Details for [`CredentialsError::CredentialsNotLoaded`] - #[derive(Debug)] - pub struct CredentialsNotLoaded { - source: Box, - } - - /// Details for [`CredentialsError::ProviderTimedOut`] - #[derive(Debug)] - pub struct ProviderTimedOut { - timeout_duration: Duration, - } - - impl ProviderTimedOut { - /// Returns the maximum allowed timeout duration that was exceeded - pub fn timeout_duration(&self) -> Duration { - self.timeout_duration - } - } - - /// Details for [`CredentialsError::InvalidConfiguration`] - #[derive(Debug)] - pub struct InvalidConfiguration { - source: Box, - } - - /// Details for [`CredentialsError::ProviderError`] - #[derive(Debug)] - pub struct ProviderError { - source: Box, - } - - /// Details for [`CredentialsError::Unhandled`] - #[derive(Debug)] - pub struct Unhandled { - source: Box, - } - - /// Error returned when credentials failed to load. - #[derive(Debug)] - #[non_exhaustive] - pub enum CredentialsError { - /// No credentials were available for this provider - CredentialsNotLoaded(CredentialsNotLoaded), - - /// Loading credentials from this provider exceeded the maximum allowed duration - ProviderTimedOut(ProviderTimedOut), - - /// The provider was given an invalid configuration - /// - /// For example: - /// - syntax error in ~/.aws/config - /// - assume role profile that forms an infinite loop - InvalidConfiguration(InvalidConfiguration), - - /// The provider experienced an error during credential resolution - /// - /// This may include errors like a 503 from STS or a file system error when attempting to - /// read a configuration file. - ProviderError(ProviderError), - - /// An unexpected error occurred during credential resolution - /// - /// If the error is something that can occur during expected usage of a provider, `ProviderError` - /// should be returned instead. Unhandled is reserved for exceptional cases, for example: - /// - Returned data not UTF-8 - /// - A provider returns data that is missing required fields - Unhandled(Unhandled), - } - - impl CredentialsError { - /// The credentials provider did not provide credentials - /// - /// This error indicates the credentials provider was not enable or no configuration was set. - /// This contrasts with [`invalid_configuration`](CredentialsError::InvalidConfiguration), indicating - /// that the provider was configured in some way, but certain settings were invalid. - pub fn not_loaded(source: impl Into>) -> Self { - CredentialsError::CredentialsNotLoaded(CredentialsNotLoaded { - source: source.into(), - }) - } - - /// An unexpected error occurred loading credentials from this provider - /// - /// Unhandled errors should not occur during normal operation and should be reserved for exceptional - /// cases, such as a JSON API returning an output that was not parseable as JSON. - pub fn unhandled(source: impl Into>) -> Self { - Self::Unhandled(Unhandled { - source: source.into(), - }) - } - - /// The credentials provider returned an error - /// - /// Provider errors may occur during normal use of a credentials provider, e.g. a 503 when - /// retrieving credentials from IMDS. - pub fn provider_error(source: impl Into>) -> Self { - Self::ProviderError(ProviderError { - source: source.into(), - }) - } - - /// The provided configuration for a provider was invalid - pub fn invalid_configuration( - source: impl Into>, - ) -> Self { - Self::InvalidConfiguration(InvalidConfiguration { - source: source.into(), - }) - } - - /// The credentials provider did not provide credentials within an allotted duration - pub fn provider_timed_out(timeout_duration: Duration) -> Self { - Self::ProviderTimedOut(ProviderTimedOut { timeout_duration }) - } - } - - impl fmt::Display for CredentialsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CredentialsError::CredentialsNotLoaded(_) => { - write!(f, "the credential provider was not enabled") - } - CredentialsError::ProviderTimedOut(details) => write!( - f, - "credentials provider timed out after {} seconds", - details.timeout_duration.as_secs() - ), - CredentialsError::InvalidConfiguration(_) => { - write!(f, "the credentials provider was not properly configured") - } - CredentialsError::ProviderError(_) => { - write!(f, "an error occurred while loading credentials") - } - CredentialsError::Unhandled(_) => { - write!(f, "unexpected credentials error") - } - } - } - } - - impl Error for CredentialsError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - CredentialsError::CredentialsNotLoaded(details) => { - Some(details.source.as_ref() as _) - } - CredentialsError::ProviderTimedOut(_) => None, - CredentialsError::InvalidConfiguration(details) => { - Some(details.source.as_ref() as _) - } - CredentialsError::ProviderError(details) => Some(details.source.as_ref() as _), - CredentialsError::Unhandled(details) => Some(details.source.as_ref() as _), - } - } - } -} - -/// Result type for credential providers. -pub type Result = std::result::Result; - -/// Convenience `ProvideCredentials` struct that implements the `ProvideCredentials` trait. -pub mod future { - use aws_smithy_async::future::now_or_later::NowOrLater; - use std::future::Future; - use std::pin::Pin; - use std::task::{Context, Poll}; - - type BoxFuture<'a, T> = Pin + Send + 'a>>; - - /// Future new-type that `ProvideCredentials::provide_credentials` must return. - #[derive(Debug)] - pub struct ProvideCredentials<'a>(NowOrLater>); - - impl<'a> ProvideCredentials<'a> { - /// Creates a `ProvideCredentials` struct from a future. - pub fn new(future: impl Future + Send + 'a) -> Self { - ProvideCredentials(NowOrLater::new(Box::pin(future))) - } - - /// Creates a `ProvideCredentials` struct from a resolved credentials value. - pub fn ready(credentials: super::Result) -> Self { - ProvideCredentials(NowOrLater::ready(credentials)) - } - } - - impl Future for ProvideCredentials<'_> { - type Output = super::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx) - } - } -} - -/// Asynchronous Credentials Provider -pub trait ProvideCredentials: Send + Sync + std::fmt::Debug { - /// Returns a future that provides credentials. - fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a> - where - Self: 'a; - - /// Returns fallback credentials. - /// - /// This method should be used as a fallback plan, i.e., when - /// a call to `provide_credentials` is interrupted and its future - /// fails to complete. - /// - /// The fallback credentials should be set aside and ready to be returned - /// immediately. Therefore, the user should NOT go fetch new credentials - /// within this method, which might cause a long-running operation. - fn fallback_on_interrupt(&self) -> Option { - None - } -} - -impl ProvideCredentials for Credentials { - fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a> - where - Self: 'a, - { - future::ProvideCredentials::ready(Ok(self.clone())) - } -} - -impl ProvideCredentials for Arc { - fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a> - where - Self: 'a, - { - self.as_ref().provide_credentials() - } -} - -/// Credentials Provider wrapper that may be shared -/// -/// Newtype wrapper around ProvideCredentials that implements Clone using an internal -/// Arc. -#[derive(Clone, Debug)] -pub struct SharedCredentialsProvider(Arc); - -impl SharedCredentialsProvider { - /// Create a new SharedCredentials provider from `ProvideCredentials` - /// - /// The given provider will be wrapped in an internal `Arc`. If your - /// provider is already in an `Arc`, use `SharedCredentialsProvider::from(provider)` instead. - pub fn new(provider: impl ProvideCredentials + 'static) -> Self { - Self(Arc::new(provider)) - } -} - -impl AsRef for SharedCredentialsProvider { - fn as_ref(&self) -> &(dyn ProvideCredentials + 'static) { - self.0.as_ref() - } -} - -impl From> for SharedCredentialsProvider { - fn from(provider: Arc) -> Self { - SharedCredentialsProvider(provider) - } -} - -impl ProvideCredentials for SharedCredentialsProvider { - fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a> - where - Self: 'a, - { - self.0.provide_credentials() - } -} - -impl Storable for SharedCredentialsProvider { - type Storer = StoreReplace; -} - -impl ResolveIdentity for SharedCredentialsProvider { - fn resolve_identity<'a>( - &'a self, - _runtime_components: &'a RuntimeComponents, - _config_bag: &'a ConfigBag, - ) -> IdentityFuture<'a> { - IdentityFuture::new(async move { Ok(self.provide_credentials().await?.into()) }) - } - - fn fallback_on_interrupt(&self) -> Option { - ProvideCredentials::fallback_on_interrupt(self).map(|creds| creds.into()) - } -} +pub use credentials::{ProvideCredentials, Result, SharedCredentialsProvider}; diff --git a/aws/rust-runtime/aws-credential-types/src/provider/credentials.rs b/aws/rust-runtime/aws-credential-types/src/provider/credentials.rs new file mode 100644 index 0000000000..5b63ad1547 --- /dev/null +++ b/aws/rust-runtime/aws-credential-types/src/provider/credentials.rs @@ -0,0 +1,176 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! AWS SDK Credentials +//! +//! ## Implementing your own credentials provider +//! +//! While for many use cases, using a built in credentials provider is sufficient, you may want to +//! implement your own credential provider. +//! +//! ### With static credentials +//! +//! _Note: In general, you should prefer to use the credential providers that come +//! with the AWS SDK to get credentials. It is __NOT__ secure to hardcode credentials +//! into your application. Only use this approach if you really know what you're doing._ +//! +#![cfg_attr( + feature = "hardcoded-credentials", + doc = r##" +See [`Credentials::from_keys`] for an example on how to use static credentials. + "## +)] +#![cfg_attr( + not(feature = "hardcoded-credentials"), + doc = r##" +Enable the `hardcoded-credentials` feature to be able to use `Credentials::from_keys` to +construct credentials from hardcoded values. + "## +)] + +//! +//! ### With dynamically loaded credentials +//! If you are loading credentials dynamically, you can provide your own implementation of +//! [`ProvideCredentials`](crate::provider::ProvideCredentials). Generally, this is best done by +//! defining an inherent `async fn` on your structure, then calling that method directly from +//! the trait implementation. +//! ```rust +//! use aws_credential_types::{ +//! provider::{self, future, error::CredentialsError, ProvideCredentials}, +//! Credentials, +//! }; +//! #[derive(Debug)] +//! struct SubprocessCredentialProvider; +//! +//! async fn invoke_command(command: &str) -> String { +//! // implementation elided... +//! # String::from("some credentials") +//! } +//! +//! /// Parse access key and secret from the first two lines of a string +//! fn parse_credentials(creds: &str) -> provider::Result { +//! let mut lines = creds.lines(); +//! let akid = lines.next().ok_or(CredentialsError::provider_error("invalid credentials"))?; +//! let secret = lines.next().ok_or(CredentialsError::provider_error("invalid credentials"))?; +//! Ok(Credentials::new(akid, secret, None, None, "CustomCommand")) +//! } +//! +//! impl SubprocessCredentialProvider { +//! async fn load_credentials(&self) -> provider::Result { +//! let creds = invoke_command("load-credentials.py").await; +//! parse_credentials(&creds) +//! } +//! } +//! +//! impl ProvideCredentials for SubprocessCredentialProvider { +//! fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a> where Self: 'a { +//! future::ProvideCredentials::new(self.load_credentials()) +//! } +//! } +//! ``` + +use crate::Credentials; +use aws_smithy_runtime_api::client::identity::{Identity, IdentityFuture, ResolveIdentity}; +use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; +use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace}; +use std::sync::Arc; + +/// Result type for credential providers. +pub type Result = std::result::Result; + +/// Asynchronous Credentials Provider +pub trait ProvideCredentials: Send + Sync + std::fmt::Debug { + /// Returns a future that provides credentials. + fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a> + where + Self: 'a; + + /// Returns fallback credentials. + /// + /// This method should be used as a fallback plan, i.e., when + /// a call to `provide_credentials` is interrupted and its future + /// fails to complete. + /// + /// The fallback credentials should be set aside and ready to be returned + /// immediately. Therefore, the user should NOT go fetch new credentials + /// within this method, which might cause a long-running operation. + fn fallback_on_interrupt(&self) -> Option { + None + } +} + +impl ProvideCredentials for Credentials { + fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a> + where + Self: 'a, + { + super::future::ProvideCredentials::ready(Ok(self.clone())) + } +} + +impl ProvideCredentials for Arc { + fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a> + where + Self: 'a, + { + self.as_ref().provide_credentials() + } +} + +/// Credentials Provider wrapper that may be shared +/// +/// Newtype wrapper around ProvideCredentials that implements Clone using an internal +/// Arc. +#[derive(Clone, Debug)] +pub struct SharedCredentialsProvider(Arc); + +impl SharedCredentialsProvider { + /// Create a new SharedCredentials provider from `ProvideCredentials` + /// + /// The given provider will be wrapped in an internal `Arc`. If your + /// provider is already in an `Arc`, use `SharedCredentialsProvider::from(provider)` instead. + pub fn new(provider: impl ProvideCredentials + 'static) -> Self { + Self(Arc::new(provider)) + } +} + +impl AsRef for SharedCredentialsProvider { + fn as_ref(&self) -> &(dyn ProvideCredentials + 'static) { + self.0.as_ref() + } +} + +impl From> for SharedCredentialsProvider { + fn from(provider: Arc) -> Self { + SharedCredentialsProvider(provider) + } +} + +impl ProvideCredentials for SharedCredentialsProvider { + fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a> + where + Self: 'a, + { + self.0.provide_credentials() + } +} + +impl Storable for SharedCredentialsProvider { + type Storer = StoreReplace; +} + +impl ResolveIdentity for SharedCredentialsProvider { + fn resolve_identity<'a>( + &'a self, + _runtime_components: &'a RuntimeComponents, + _config_bag: &'a ConfigBag, + ) -> IdentityFuture<'a> { + IdentityFuture::new(async move { Ok(self.provide_credentials().await?.into()) }) + } + + fn fallback_on_interrupt(&self) -> Option { + ProvideCredentials::fallback_on_interrupt(self).map(|creds| creds.into()) + } +} diff --git a/aws/rust-runtime/aws-credential-types/src/provider/error.rs b/aws/rust-runtime/aws-credential-types/src/provider/error.rs new file mode 100644 index 0000000000..813842893b --- /dev/null +++ b/aws/rust-runtime/aws-credential-types/src/provider/error.rs @@ -0,0 +1,274 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Credentials provider errors + +use std::error::Error; +use std::fmt; +use std::time::Duration; + +/// Details for [`CredentialsError::CredentialsNotLoaded`] +#[derive(Debug)] +pub struct CredentialsNotLoaded { + source: Box, +} + +/// Details for [`CredentialsError::ProviderTimedOut`] or [`AccessTokenError::ProviderTimedOut`] +#[derive(Debug)] +pub struct ProviderTimedOut { + timeout_duration: Duration, +} + +impl ProviderTimedOut { + /// Returns the maximum allowed timeout duration that was exceeded + pub fn timeout_duration(&self) -> Duration { + self.timeout_duration + } +} + +/// Details for [`CredentialsError::InvalidConfiguration`] or [`AccessTokenError::InvalidConfiguration`] +#[derive(Debug)] +pub struct InvalidConfiguration { + source: Box, +} + +/// Details for [`CredentialsError::ProviderError`] or [`AccessTokenError::ProviderError`] +#[derive(Debug)] +pub struct ProviderError { + source: Box, +} + +/// Details for [`CredentialsError::Unhandled`] or [`AccessTokenError::Unhandled`] +#[derive(Debug)] +pub struct Unhandled { + source: Box, +} + +/// Error returned when credentials failed to load. +#[derive(Debug)] +#[non_exhaustive] +pub enum CredentialsError { + /// No credentials were available for this provider + CredentialsNotLoaded(CredentialsNotLoaded), + + /// Loading credentials from this provider exceeded the maximum allowed duration + ProviderTimedOut(ProviderTimedOut), + + /// The provider was given an invalid configuration + /// + /// For example: + /// - syntax error in ~/.aws/config + /// - assume role profile that forms an infinite loop + InvalidConfiguration(InvalidConfiguration), + + /// The provider experienced an error during credential resolution + /// + /// This may include errors like a 503 from STS or a file system error when attempting to + /// read a configuration file. + ProviderError(ProviderError), + + /// An unexpected error occurred during credential resolution + /// + /// If the error is something that can occur during expected usage of a provider, `ProviderError` + /// should be returned instead. Unhandled is reserved for exceptional cases, for example: + /// - Returned data not UTF-8 + /// - A provider returns data that is missing required fields + Unhandled(Unhandled), +} + +impl CredentialsError { + /// The credentials provider did not provide credentials + /// + /// This error indicates the credentials provider was not enable or no configuration was set. + /// This contrasts with [`invalid_configuration`](CredentialsError::InvalidConfiguration), indicating + /// that the provider was configured in some way, but certain settings were invalid. + pub fn not_loaded(source: impl Into>) -> Self { + CredentialsError::CredentialsNotLoaded(CredentialsNotLoaded { + source: source.into(), + }) + } + + /// An unexpected error occurred loading credentials from this provider + /// + /// Unhandled errors should not occur during normal operation and should be reserved for exceptional + /// cases, such as a JSON API returning an output that was not parseable as JSON. + pub fn unhandled(source: impl Into>) -> Self { + Self::Unhandled(Unhandled { + source: source.into(), + }) + } + + /// The credentials provider returned an error + /// + /// Provider errors may occur during normal use of a credentials provider, e.g. a 503 when + /// retrieving credentials from IMDS. + pub fn provider_error(source: impl Into>) -> Self { + Self::ProviderError(ProviderError { + source: source.into(), + }) + } + + /// The provided configuration for a provider was invalid + pub fn invalid_configuration( + source: impl Into>, + ) -> Self { + Self::InvalidConfiguration(InvalidConfiguration { + source: source.into(), + }) + } + + /// The credentials provider did not provide credentials within an allotted duration + pub fn provider_timed_out(timeout_duration: Duration) -> Self { + Self::ProviderTimedOut(ProviderTimedOut { timeout_duration }) + } +} + +impl fmt::Display for CredentialsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CredentialsError::CredentialsNotLoaded(_) => { + write!(f, "the credential provider was not enabled") + } + CredentialsError::ProviderTimedOut(details) => write!( + f, + "credentials provider timed out after {} seconds", + details.timeout_duration.as_secs() + ), + CredentialsError::InvalidConfiguration(_) => { + write!(f, "the credentials provider was not properly configured") + } + CredentialsError::ProviderError(_) => { + write!(f, "an error occurred while loading credentials") + } + CredentialsError::Unhandled(_) => { + write!(f, "unexpected credentials error") + } + } + } +} + +impl Error for CredentialsError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + CredentialsError::CredentialsNotLoaded(details) => Some(details.source.as_ref() as _), + CredentialsError::ProviderTimedOut(_) => None, + CredentialsError::InvalidConfiguration(details) => Some(details.source.as_ref() as _), + CredentialsError::ProviderError(details) => Some(details.source.as_ref() as _), + CredentialsError::Unhandled(details) => Some(details.source.as_ref() as _), + } + } +} + +/// Details for [`AccessTokenError::TokenNotLoaded`] +#[derive(Debug)] +pub struct TokenNotLoaded { + source: Box, +} + +/// Error returned when an access token provider fails to provide an access token. +#[derive(Debug)] +pub enum AccessTokenError { + /// This provider couldn't provide a token. + TokenNotLoaded(TokenNotLoaded), + + /// Loading a token from this provider exceeded the maximum allowed time. + ProviderTimedOut(ProviderTimedOut), + + /// The provider was given invalid configuration. + /// + /// For example, a syntax error in `~/.aws/config`. + InvalidConfiguration(InvalidConfiguration), + + /// The provider experienced an error during credential resolution. + ProviderError(ProviderError), + + /// An unexpected error occurred during token resolution. + /// + /// If the error is something that can occur during expected usage of a provider, `ProviderError` + /// should be returned instead. Unhandled is reserved for exceptional cases, for example: + /// - Returned data not UTF-8 + /// - A provider returns data that is missing required fields + Unhandled(Unhandled), +} + +impl AccessTokenError { + /// The access token provider couldn't provide a token. + /// + /// This error indicates the token provider was not enable or no configuration was set. + /// This contrasts with [`invalid_configuration`](AccessTokenError::InvalidConfiguration), indicating + /// that the provider was configured in some way, but certain settings were invalid. + pub fn not_loaded(source: impl Into>) -> Self { + AccessTokenError::TokenNotLoaded(TokenNotLoaded { + source: source.into(), + }) + } + + /// An unexpected error occurred loading an access token from this provider. + /// + /// Unhandled errors should not occur during normal operation and should be reserved for exceptional + /// cases, such as a JSON API returning an output that was not parseable as JSON. + pub fn unhandled(source: impl Into>) -> Self { + Self::Unhandled(Unhandled { + source: source.into(), + }) + } + + /// The access token provider returned an error. + pub fn provider_error(source: impl Into>) -> Self { + Self::ProviderError(ProviderError { + source: source.into(), + }) + } + + /// The provided configuration for a provider was invalid. + pub fn invalid_configuration( + source: impl Into>, + ) -> Self { + Self::InvalidConfiguration(InvalidConfiguration { + source: source.into(), + }) + } + + /// The access token provider did not provide a token within an allotted amount of time. + pub fn provider_timed_out(timeout_duration: Duration) -> Self { + Self::ProviderTimedOut(ProviderTimedOut { timeout_duration }) + } +} + +impl fmt::Display for AccessTokenError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AccessTokenError::TokenNotLoaded(_) => { + write!(f, "the access token provider was not enabled") + } + AccessTokenError::ProviderTimedOut(details) => write!( + f, + "access token provider timed out after {} seconds", + details.timeout_duration.as_secs() + ), + AccessTokenError::InvalidConfiguration(_) => { + write!(f, "the access token provider was not properly configured") + } + AccessTokenError::ProviderError(_) => { + write!(f, "an error occurred while loading an access token") + } + AccessTokenError::Unhandled(_) => { + write!(f, "unexpected access token providererror") + } + } + } +} + +impl Error for AccessTokenError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + AccessTokenError::TokenNotLoaded(details) => Some(details.source.as_ref() as _), + AccessTokenError::ProviderTimedOut(_) => None, + AccessTokenError::InvalidConfiguration(details) => Some(details.source.as_ref() as _), + AccessTokenError::ProviderError(details) => Some(details.source.as_ref() as _), + AccessTokenError::Unhandled(details) => Some(details.source.as_ref() as _), + } + } +} diff --git a/aws/rust-runtime/aws-credential-types/src/provider/future.rs b/aws/rust-runtime/aws-credential-types/src/provider/future.rs new file mode 100644 index 0000000000..49476dd343 --- /dev/null +++ b/aws/rust-runtime/aws-credential-types/src/provider/future.rs @@ -0,0 +1,63 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Convenience `ProvideCredentials` struct that implements the `ProvideCredentials` trait. + +use crate::provider::token::Result as TokenResult; +use crate::provider::Result as CredsResult; +use aws_smithy_async::future::now_or_later::NowOrLater; +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +type BoxFuture<'a, T> = Pin + Send + 'a>>; + +/// Future new-type that `ProvideCredentials::provide_credentials` must return. +#[derive(Debug)] +pub struct ProvideCredentials<'a>(NowOrLater>); + +impl<'a> ProvideCredentials<'a> { + /// Creates a `ProvideCredentials` struct from a future. + pub fn new(future: impl Future + Send + 'a) -> Self { + ProvideCredentials(NowOrLater::new(Box::pin(future))) + } + + /// Creates a `ProvideCredentials` struct from a resolved credentials value. + pub fn ready(credentials: CredsResult) -> Self { + ProvideCredentials(NowOrLater::ready(credentials)) + } +} + +impl Future for ProvideCredentials<'_> { + type Output = CredsResult; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Pin::new(&mut self.0).poll(cx) + } +} + +/// Future new-type that `ProvideAccessToken::provide_access_token` must return. +#[derive(Debug)] +pub struct ProvideAccessToken<'a>(NowOrLater>); + +impl<'a> ProvideAccessToken<'a> { + /// Creates a `ProvideAccessToken` struct from a future. + pub fn new(future: impl Future + Send + 'a) -> Self { + ProvideAccessToken(NowOrLater::new(Box::pin(future))) + } + + /// Creates a `ProvideAccessToken` struct from a resolved credentials value. + pub fn ready(credentials: TokenResult) -> Self { + ProvideAccessToken(NowOrLater::ready(credentials)) + } +} + +impl Future for ProvideAccessToken<'_> { + type Output = TokenResult; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Pin::new(&mut self.0).poll(cx) + } +} diff --git a/aws/rust-runtime/aws-credential-types/src/provider/token.rs b/aws/rust-runtime/aws-credential-types/src/provider/token.rs new file mode 100644 index 0000000000..f463ffbc74 --- /dev/null +++ b/aws/rust-runtime/aws-credential-types/src/provider/token.rs @@ -0,0 +1,64 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! AWS Access Tokens for SSO +//! +//! When authenticating with an AWS Builder ID, single sign-on (SSO) will provide +//! an access token that can then be used to authenticate with services such as +//! Code Catalyst. +//! +//! This module provides the [`ProvideAccessToken`] trait that is used to configure +//! token providers in the SDK config. + +use crate::{provider::error::AccessTokenError, provider::future, AccessToken}; +use std::sync::Arc; + +/// Result type for token providers +pub type Result = std::result::Result; + +/// Access Token Provider +pub trait ProvideAccessToken: Send + Sync + std::fmt::Debug { + /// Returns a future that provides an access token. + fn provide_access_token<'a>(&'a self) -> future::ProvideAccessToken<'a> + where + Self: 'a; +} + +/// Access token provider wrapper that may be shared. +/// +/// Newtype wrapper around [`ProvideAccessToken`] that implements `Clone` using an internal `Arc`. +#[derive(Clone, Debug)] +pub struct SharedAccessTokenProvider(Arc); + +impl SharedAccessTokenProvider { + /// Create a new [`SharedAccessTokenProvider`] from [`ProvideAccessToken`]. + /// + /// The given provider will be wrapped in an internal `Arc`. If your + /// provider is already in an `Arc`, use `SharedAccessTokenProvider::from(provider)` instead. + pub fn new(provider: impl ProvideAccessToken + 'static) -> Self { + Self(Arc::new(provider)) + } +} + +impl AsRef for SharedAccessTokenProvider { + fn as_ref(&self) -> &(dyn ProvideAccessToken + 'static) { + self.0.as_ref() + } +} + +impl From> for SharedAccessTokenProvider { + fn from(provider: Arc) -> Self { + SharedAccessTokenProvider(provider) + } +} + +impl ProvideAccessToken for SharedAccessTokenProvider { + fn provide_access_token<'a>(&'a self) -> future::ProvideAccessToken<'a> + where + Self: 'a, + { + self.0.provide_access_token() + } +} diff --git a/aws/rust-runtime/aws-credential-types/src/token_impl.rs b/aws/rust-runtime/aws-credential-types/src/token_impl.rs new file mode 100644 index 0000000000..9e5b286568 --- /dev/null +++ b/aws/rust-runtime/aws-credential-types/src/token_impl.rs @@ -0,0 +1,72 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_smithy_types::date_time::Format; +use aws_smithy_types::DateTime; +use std::fmt; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; +use zeroize::Zeroizing; + +/// AWS Access Token +/// +/// Provides token which is used to securely authorize requests to AWS +/// services. A token is a string that the OAuth client uses to make requests to +/// the resource server. +/// +/// For more details on tokens, see: +#[non_exhaustive] +#[derive(Debug, Clone)] +pub struct AccessToken(Arc); + +impl AccessToken { + /// Create a new access token + pub fn new(token: impl Into, expires_after: Option) -> Self { + Self(Arc::new(Inner { + token: Zeroizing::new(token.into()), + expires_after, + })) + } + + /// Get the access token + pub fn token(&self) -> &str { + &self.0.token + } + + /// Get the token expiration time + pub fn expires_after(&self) -> Option { + self.0.expires_after + } +} + +struct Inner { + token: Zeroizing, + expires_after: Option, +} + +impl fmt::Debug for Inner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut dbg = f.debug_struct("AccessToken"); + dbg.field("token", &"** redacted **"); + if let Some(expires_after) = self.expires_after { + if let Some(formatted) = expires_after + .duration_since(UNIX_EPOCH) + .ok() + .and_then(|dur| { + DateTime::from_secs(dur.as_secs() as _) + .fmt(Format::DateTime) + .ok() + }) + { + dbg.field("expires_after", &formatted); + } else { + dbg.field("expires_after", &expires_after); + } + } else { + dbg.field("expires_after", &"never"); + } + dbg.finish() + } +} diff --git a/aws/rust-runtime/aws-inlineable/external-types.toml b/aws/rust-runtime/aws-inlineable/external-types.toml index 62904a6e4c..0e15e561d4 100644 --- a/aws/rust-runtime/aws-inlineable/external-types.toml +++ b/aws/rust-runtime/aws-inlineable/external-types.toml @@ -1,5 +1,5 @@ allowed_external_types = [ - "aws_credential_types::provider::ProvideCredentials", + "aws_credential_types::provider::credentials::ProvideCredentials", "aws_smithy_http::*", "aws_smithy_runtime_api::*", diff --git a/aws/rust-runtime/aws-types/external-types.toml b/aws/rust-runtime/aws-types/external-types.toml index 1e4e0c863d..d24d3dad09 100644 --- a/aws/rust-runtime/aws-types/external-types.toml +++ b/aws/rust-runtime/aws-types/external-types.toml @@ -1,6 +1,6 @@ allowed_external_types = [ "aws_credential_types::cache::CredentialsCache", - "aws_credential_types::provider::SharedCredentialsProvider", + "aws_credential_types::provider::credentials::SharedCredentialsProvider", "aws_smithy_async::rt::sleep::AsyncSleep", "aws_smithy_async::rt::sleep::SharedAsyncSleep", "aws_smithy_async::time::SharedTimeSource", From a9885d34199d8d5db6d320e8e5ff535f5f01fc09 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 23 Feb 2024 15:36:17 -0800 Subject: [PATCH 02/16] Implement the default token provider chain --- .../aws-config/src/default_provider.rs | 4 + .../src/default_provider/credentials.rs | 13 +- .../aws-config/src/default_provider/token.rs | 129 +++++++++ aws/rust-runtime/aws-config/src/lib.rs | 47 +++- aws/rust-runtime/aws-config/src/meta/mod.rs | 1 + aws/rust-runtime/aws-config/src/meta/token.rs | 114 ++++++++ .../aws-config/src/profile/credentials.rs | 5 +- .../src/profile/credentials/repr.rs | 22 +- .../aws-config/src/profile/mod.rs | 6 + .../aws-config/src/profile/token.rs | 248 ++++++++++++++++++ aws/rust-runtime/aws-config/src/sso/token.rs | 73 ++++-- aws/rust-runtime/aws-config/src/test_case.rs | 50 +++- .../profile_keys/env.json | 3 + .../profile_keys/fs/home/.aws/config | 7 + ...208e38164f558a1d06c99432ab77dbb346c45.json | 5 + .../profile_keys/http-traffic.json | 5 + .../profile_keys/test-case.json | 10 + .../profile_keys_case_insensitive/env.json | 3 + .../fs/home/.aws/config | 7 + ...208e38164f558a1d06c99432ab77dbb346c45.json | 5 + .../http-traffic.json | 5 + .../test-case.json | 10 + .../profile_name/env.json | 4 + .../profile_name/fs/home/.aws/config | 15 ++ ...aa2f70ab0f58f60e284d585d95865572f5cbd.json | 5 + .../profile_name/http-traffic.json | 5 + .../profile_name/test-case.json | 10 + .../aws-credential-types/Cargo.toml | 2 +- .../aws-credential-types/src/lib.rs | 11 +- .../src/provider/error.rs | 42 +-- .../src/provider/future.rs | 16 +- .../src/provider/token.rs | 47 ++-- .../aws-credential-types/src/token_fn.rs | 133 ++++++++++ .../aws-credential-types/src/token_impl.rs | 72 ----- aws/rust-runtime/aws-types/src/sdk_config.rs | 59 +++++ .../src/client/identity/http.rs | 5 + 36 files changed, 1026 insertions(+), 172 deletions(-) create mode 100644 aws/rust-runtime/aws-config/src/default_provider/token.rs create mode 100644 aws/rust-runtime/aws-config/src/meta/token.rs create mode 100644 aws/rust-runtime/aws-config/src/profile/token.rs create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/env.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/config create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/http-traffic.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/test-case.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/env.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/config create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/http-traffic.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/test-case.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/env.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/config create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/sso/cache/29faa2f70ab0f58f60e284d585d95865572f5cbd.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/http-traffic.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/test-case.json create mode 100644 aws/rust-runtime/aws-credential-types/src/token_fn.rs delete mode 100644 aws/rust-runtime/aws-credential-types/src/token_impl.rs diff --git a/aws/rust-runtime/aws-config/src/default_provider.rs b/aws/rust-runtime/aws-config/src/default_provider.rs index 21de20dd5c..5cbf1102ba 100644 --- a/aws/rust-runtime/aws-config/src/default_provider.rs +++ b/aws/rust-runtime/aws-config/src/default_provider.rs @@ -47,3 +47,7 @@ pub mod use_fips; /// Default dual-stack provider chain pub mod use_dual_stack; + +/// Default access token provider chain +#[cfg(feature = "sso")] +pub mod token; diff --git a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs index fcb9b19812..e1671b0272 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs @@ -198,10 +198,8 @@ impl Builder { #[cfg(test)] mod test { - use crate::test_case::TestEnvironment; - use crate::{ - default_provider::credentials::DefaultCredentialsChain, test_case::StaticTestProvider, - }; + use crate::default_provider::credentials::DefaultCredentialsChain; + use crate::test_case::{StaticTestProvider, TestEnvironment}; use aws_credential_types::provider::ProvideCredentials; use aws_smithy_async::time::StaticTimeSource; use std::time::UNIX_EPOCH; @@ -246,7 +244,10 @@ mod test { #[tokio::test] async fn $name() { let _ = crate::test_case::TestEnvironment::from_dir( - concat!("./test-data/default-credential-provider-chain/", stringify!($name)), + concat!( + "./test-data/default-credential-provider-chain/", + stringify!($name) + ), crate::test_case::test_credentials_provider(|config| { async move { crate::default_provider::credentials::Builder::default() @@ -256,7 +257,7 @@ mod test { .provide_credentials() .await } - }) + }), ) .await .unwrap() diff --git a/aws/rust-runtime/aws-config/src/default_provider/token.rs b/aws/rust-runtime/aws-config/src/default_provider/token.rs new file mode 100644 index 0000000000..164b71ae29 --- /dev/null +++ b/aws/rust-runtime/aws-config/src/default_provider/token.rs @@ -0,0 +1,129 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::{ + meta::{region::ProvideRegion, token::TokenProviderChain}, + provider_config::ProviderConfig, +}; +use aws_credential_types::provider::{future, token::ProvideToken}; + +/// Default access token provider chain +/// +/// The region from the default region provider will be used +pub async fn default_provider() -> impl ProvideToken { + DefaultTokenChain::builder().build().await +} + +/// Default access token provider chain +/// +/// Currently, the default chain only examines the shared config +/// (`~/.aws/config`) file and the SSO token cache to resolve an +/// access token. +/// +/// The AWS CLI can be used to retrieve the initial access token into +/// the SSO token cache. Once it's there, the SDK can refresh automatically +/// long as the it remains refreshable (it will eventually expire). +/// +/// # Examples +/// Create a default chain with a custom region: +/// ```no_run +/// use aws_types::region::Region; +/// use aws_config::default_provider::token::DefaultTokenChain; +/// let token_provider = DefaultTokenChain::builder() +/// .region(Region::new("us-west-1")) +/// .build(); +/// ``` +/// +/// Create a default chain with no overrides: +/// ```no_run +/// use aws_config::default_provider::token::DefaultTokenChain; +/// let token_provider = DefaultTokenChain::builder().build(); +/// ``` +/// +/// Create a default chain that uses a different profile: +/// ```no_run +/// use aws_config::default_provider::token::DefaultTokenChain; +/// let token_provider = DefaultTokenChain::builder() +/// .profile_name("otherprofile") +/// .build(); +/// ``` +#[derive(Debug)] +pub struct DefaultTokenChain { + provider_chain: TokenProviderChain, +} + +impl DefaultTokenChain { + /// Builder for `DefaultTokenChain`. + pub fn builder() -> Builder { + Builder::default() + } +} + +impl ProvideToken for DefaultTokenChain { + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> + where + Self: 'a, + { + self.provider_chain.provide_token() + } +} + +/// Builder for [`DefaultTokenChain`]. +#[derive(Debug, Default)] +pub struct Builder { + profile_file_builder: crate::profile::token::Builder, + region_override: Option>, + region_chain: crate::default_provider::region::Builder, + conf: Option, +} + +impl Builder { + /// Sets the region used when making requests to AWS services + /// + /// When unset, the default region resolver chain will be used. + pub fn region(mut self, region: impl ProvideRegion + 'static) -> Self { + self.set_region(Some(region)); + self + } + + /// Sets the region used when making requests to AWS services + /// + /// When unset, the default region resolver chain will be used. + pub fn set_region(&mut self, region: Option) -> &mut Self { + self.region_override = region.map(|provider| Box::new(provider) as _); + self + } + + /// Override the profile name used by this provider + /// + /// When unset, the value of the `AWS_PROFILE` environment variable will be used. + pub fn profile_name(mut self, name: &str) -> Self { + self.profile_file_builder = self.profile_file_builder.profile_name(name); + self.region_chain = self.region_chain.profile_name(name); + self + } + + /// Override the configuration used for this provider + pub fn configure(mut self, config: ProviderConfig) -> Self { + self.region_chain = self.region_chain.configure(&config); + self.conf = Some(config); + self + } + + /// Creates a [`DefaultTokenChain`]. + pub async fn build(self) -> DefaultTokenChain { + let region = match self.region_override { + Some(provider) => provider.region().await, + None => self.region_chain.build().region().await, + }; + let conf = self.conf.unwrap_or_default().with_region(region); + + let provider_chain = TokenProviderChain::first_try( + "Profile", + self.profile_file_builder.configure(&conf).build(), + ); + DefaultTokenChain { provider_chain } + } +} diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 96152efae1..6148a42978 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -214,7 +214,10 @@ mod loader { use crate::meta::region::ProvideRegion; use crate::profile::profile_file::ProfileFiles; use crate::provider_config::ProviderConfig; - use aws_credential_types::provider::{ProvideCredentials, SharedCredentialsProvider}; + use aws_credential_types::provider::{ + token::{ProvideToken, SharedTokenProvider}, + ProvideCredentials, SharedCredentialsProvider, + }; use aws_credential_types::Credentials; use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep}; use aws_smithy_async::time::{SharedTimeSource, TimeSource}; @@ -253,6 +256,7 @@ mod loader { app_name: Option, identity_cache: Option, credentials_provider: CredentialsProviderOption, + token_provider: Option, endpoint_url: Option, region: Option>, retry_config: Option, @@ -493,6 +497,28 @@ mod loader { self.credentials_provider(Credentials::for_tests()) } + /// Override the access token provider used to build [`SdkConfig`]. + /// + /// # Examples + /// + /// Override the token provider but load the default value for region: + /// ```no_run + /// # use aws_credential_types::Token; + /// # fn create_my_token_provider() -> Token { + /// # Token::new("example", None) + /// # } + /// # async fn create_config() { + /// let config = aws_config::from_env() + /// .token_provider(create_my_token_provider()) + /// .load() + /// .await; + /// # } + /// ``` + pub fn token_provider(mut self, token_provider: impl ProvideToken + 'static) -> Self { + self.token_provider = Some(SharedTokenProvider::new(token_provider)); + self + } + /// Override the name of the app used to build [`SdkConfig`]. /// /// This _optional_ name is used to identify the application in the user agent that @@ -754,6 +780,24 @@ mod loader { CredentialsProviderOption::ExplicitlyUnset => None, }; + let token_provider = match self.token_provider { + Some(provider) => Some(provider), + None => { + #[cfg(feature = "sso")] + { + let mut builder = + crate::default_provider::token::DefaultTokenChain::builder() + .configure(conf.clone()); + builder.set_region(region.clone()); + Some(SharedTokenProvider::new(builder.build().await)) + } + #[cfg(not(feature = "sso"))] + { + None + } + } + }; + let mut builder = SdkConfig::builder() .region(region) .retry_config(retry_config) @@ -765,6 +809,7 @@ mod loader { builder.set_app_name(app_name); builder.set_identity_cache(self.identity_cache); builder.set_credentials_provider(credentials_provider); + builder.set_token_provider(token_provider); builder.set_sleep_impl(sleep_impl); builder.set_endpoint_url(self.endpoint_url); builder.set_use_fips(use_fips); diff --git a/aws/rust-runtime/aws-config/src/meta/mod.rs b/aws/rust-runtime/aws-config/src/meta/mod.rs index f091a26c0f..b8160f5a38 100644 --- a/aws/rust-runtime/aws-config/src/meta/mod.rs +++ b/aws/rust-runtime/aws-config/src/meta/mod.rs @@ -7,3 +7,4 @@ pub mod credentials; pub mod region; +pub mod token; diff --git a/aws/rust-runtime/aws-config/src/meta/token.rs b/aws/rust-runtime/aws-config/src/meta/token.rs new file mode 100644 index 0000000000..424c6cab0e --- /dev/null +++ b/aws/rust-runtime/aws-config/src/meta/token.rs @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Token providers that augment existing token providers to add functionality + +use aws_credential_types::provider::{ + error::TokenError, future, token::ProvideToken, token::Result, +}; +use aws_smithy_types::error::display::DisplayErrorContext; +use std::borrow::Cow; +use tracing::Instrument; + +/// Access token provider that checks a series of inner providers. +/// +/// Each provider will be evaluated in order: +/// * If a provider returns valid [`Token`](aws_credential_types::Token) they will be returned immediately. +/// No other token providers will be used. +/// * Otherwise, if a provider returns [`TokenError::TokenNotLoaded`], the next provider will be checked. +/// * Finally, if a provider returns any other error condition, an error will be returned immediately. +/// +#[cfg_attr( + feature = "sso", + doc = r#" +# Examples + +```no_run +# fn example() { +use aws_config::meta::token::TokenProviderChain; +use aws_config::profile::ProfileFileTokenProvider; +use aws_credential_types::Token; + +let provider = TokenProviderChain::first_try("Profile", ProfileFileTokenProvider::builder().build()) + .or_else("Static", Token::new("example", None)); +# } +``` +"# +)] +#[derive(Debug)] +pub struct TokenProviderChain { + providers: Vec<(Cow<'static, str>, Box)>, +} + +impl TokenProviderChain { + /// Create a `TokenProviderChain` that begins by evaluating this provider + pub fn first_try( + name: impl Into>, + provider: impl ProvideToken + 'static, + ) -> Self { + TokenProviderChain { + providers: vec![(name.into(), Box::new(provider))], + } + } + + /// Add a fallback provider to the token provider chain + pub fn or_else( + mut self, + name: impl Into>, + provider: impl ProvideToken + 'static, + ) -> Self { + self.providers.push((name.into(), Box::new(provider))); + self + } + + /// Add a fallback to the default provider chain + #[cfg(feature = "sso")] + pub async fn or_default_provider(self) -> Self { + self.or_else( + "DefaultProviderChain", + crate::default_provider::token::default_provider().await, + ) + } + + /// Creates a token provider chain that starts with the default provider + #[cfg(feature = "sso")] + pub async fn default_provider() -> Self { + Self::first_try( + "DefaultProviderChain", + crate::default_provider::token::default_provider().await, + ) + } + + async fn token(&self) -> Result { + for (name, provider) in &self.providers { + let span = tracing::debug_span!("load_token", provider = %name); + match provider.provide_token().instrument(span).await { + Ok(credentials) => { + tracing::debug!(provider = %name, "loaded access token"); + return Ok(credentials); + } + Err(err @ TokenError::TokenNotLoaded(_)) => { + tracing::debug!(provider = %name, context = %DisplayErrorContext(&err), "provider in chain did not provide an access token"); + } + Err(err) => { + tracing::warn!(provider = %name, error = %DisplayErrorContext(&err), "provider failed to provide an access token"); + return Err(err); + } + } + } + Err(TokenError::not_loaded( + "no providers in chain provided tokens", + )) + } +} + +impl ProvideToken for TokenProviderChain { + fn provide_token<'a>(&'a self) -> future::ProvideToken<'_> + where + Self: 'a, + { + future::ProvideToken::new(self.token()) + } +} diff --git a/aws/rust-runtime/aws-config/src/profile/credentials.rs b/aws/rust-runtime/aws-config/src/profile/credentials.rs index ebca5f65a9..47478a4c42 100644 --- a/aws/rust-runtime/aws-config/src/profile/credentials.rs +++ b/aws/rust-runtime/aws-config/src/profile/credentials.rs @@ -40,7 +40,7 @@ use std::sync::Arc; use tracing::Instrument; mod exec; -mod repr; +pub(crate) mod repr; /// AWS Profile based credentials provider /// @@ -564,14 +564,13 @@ impl ChainProvider { #[cfg(test)] mod test { use crate::profile::credentials::Builder; - use crate::test_case::TestEnvironment; use aws_credential_types::provider::ProvideCredentials; macro_rules! make_test { ($name: ident) => { #[tokio::test] async fn $name() { - let _ = TestEnvironment::from_dir( + let _ = crate::test_case::TestEnvironment::from_dir( concat!("./test-data/profile-provider/", stringify!($name)), crate::test_case::test_credentials_provider(|config| async move { Builder::default() diff --git a/aws/rust-runtime/aws-config/src/profile/credentials/repr.rs b/aws/rust-runtime/aws-config/src/profile/credentials/repr.rs index d0a0906219..9f5ff001bd 100644 --- a/aws/rust-runtime/aws-config/src/profile/credentials/repr.rs +++ b/aws/rust-runtime/aws-config/src/profile/credentials/repr.rs @@ -25,17 +25,17 @@ use aws_credential_types::Credentials; /// ProfileChain is a direct representation of the Profile. It can contain named providers /// that don't actually have implementations. #[derive(Debug)] -pub(super) struct ProfileChain<'a> { - pub(super) base: BaseProvider<'a>, - pub(super) chain: Vec>, +pub(crate) struct ProfileChain<'a> { + pub(crate) base: BaseProvider<'a>, + pub(crate) chain: Vec>, } impl<'a> ProfileChain<'a> { - pub(super) fn base(&self) -> &BaseProvider<'a> { + pub(crate) fn base(&self) -> &BaseProvider<'a> { &self.base } - pub(super) fn chain(&self) -> &[RoleArn<'a>] { + pub(crate) fn chain(&self) -> &[RoleArn<'a>] { self.chain.as_slice() } } @@ -46,7 +46,7 @@ impl<'a> ProfileChain<'a> { /// e.g. IMDS, ECS, Environment variables #[derive(Clone, Debug)] #[non_exhaustive] -pub(super) enum BaseProvider<'a> { +pub(crate) enum BaseProvider<'a> { /// A profile that specifies a named credential source /// Eg: `credential_source = Ec2InstanceMetadata` /// @@ -100,18 +100,18 @@ pub(super) enum BaseProvider<'a> { /// A RoleArn can only be created from either a profile with `source_profile` /// or one with `credential_source`. #[derive(Debug)] -pub(super) struct RoleArn<'a> { +pub(crate) struct RoleArn<'a> { /// Role to assume - pub(super) role_arn: &'a str, + pub(crate) role_arn: &'a str, /// external_id parameter to pass to the assume role provider - pub(super) external_id: Option<&'a str>, + pub(crate) external_id: Option<&'a str>, /// session name parameter to pass to the assume role provider - pub(super) session_name: Option<&'a str>, + pub(crate) session_name: Option<&'a str>, } /// Resolve a ProfileChain from a ProfileSet or return an error -pub(super) fn resolve_chain( +pub(crate) fn resolve_chain( profile_set: &ProfileSet, ) -> Result, ProfileFileError> { // If there are no profiles, allow flowing into the next provider diff --git a/aws/rust-runtime/aws-config/src/profile/mod.rs b/aws/rust-runtime/aws-config/src/profile/mod.rs index 970dddef46..8e3fa73c40 100644 --- a/aws/rust-runtime/aws-config/src/profile/mod.rs +++ b/aws/rust-runtime/aws-config/src/profile/mod.rs @@ -22,6 +22,12 @@ pub mod credentials; pub mod profile_file; pub mod region; +#[cfg(feature = "sso")] +pub mod token; +#[cfg(feature = "sso")] +#[doc(inline)] +pub use token::ProfileFileTokenProvider; + #[doc(inline)] pub use credentials::ProfileFileCredentialsProvider; #[doc(inline)] diff --git a/aws/rust-runtime/aws-config/src/profile/token.rs b/aws/rust-runtime/aws-config/src/profile/token.rs new file mode 100644 index 0000000000..74928d105e --- /dev/null +++ b/aws/rust-runtime/aws-config/src/profile/token.rs @@ -0,0 +1,248 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Profile File Based Token Providers + +use crate::{ + profile::{cell::ErrorTakingOnceCell, profile_file::ProfileFiles, ProfileSet}, + provider_config::ProviderConfig, + sso::SsoTokenProvider, +}; +use aws_credential_types::provider::{ + error::TokenError, future, token::ProvideToken, token::Result as TokenResult, +}; +use aws_types::{region::Region, SdkConfig}; + +async fn load_profile_set(provider_config: &ProviderConfig) -> Result<&ProfileSet, TokenError> { + provider_config + .try_profile() + .await + .map_err(|parse_err| TokenError::invalid_configuration(parse_err.clone())) +} + +fn create_token_provider( + sdk_config: &SdkConfig, + provider_config: &ProviderConfig, + profile_set: &ProfileSet, +) -> Result { + let repr = crate::profile::credentials::repr::resolve_chain(profile_set) + .map_err(TokenError::invalid_configuration)?; + match repr.base { + crate::profile::credentials::repr::BaseProvider::Sso { + sso_session_name, + sso_region, + sso_start_url, + .. + } => { + let mut builder = SsoTokenProvider::builder().configure(sdk_config); + builder.set_session_name(sso_session_name.map(|s| s.to_string())); + Ok(builder + .region(Region::new(sso_region.to_string())) + .start_url(sso_start_url) + .build_with(provider_config.env(), provider_config.fs())) + } + _ => Err(TokenError::not_loaded( + "no sso-session configured in profile file", + )), + } +} + +/// AWS profile-based access token provider +/// +/// This token provider loads SSO session config from `~/.aws/config`, +/// and uses that config to resolve a cached SSO token from `~/.aws/sso/cache`. +/// The AWS CLI can be used to establish the cached SSO token. +/// +/// Generally, this provider is constructed via the default provider chain. However, +/// it can also be manually constructed with the builder: +/// ```rust,no_run +/// use aws_config::profile::ProfileFileTokenProvider; +/// let provider = ProfileFileTokenProvider::builder().build(); +/// ``` +/// _Note: this provider, when called, will load and parse the `~/.aws/config` file +/// only once. Parsed file contents will be cached indefinitely._ +/// +/// This provider requires a profile with a `sso_session` configured. For example, +/// ```ini +/// [default] +/// sso_session = example +/// region = us-west-2 +/// +/// [sso-session example] +/// sso_start_url = https://example.awsapps.com/start +/// sso_region = us-west-2 +/// ``` +#[derive(Debug)] +pub struct ProfileFileTokenProvider { + sdk_config: SdkConfig, + provider_config: ProviderConfig, + inner_provider: ErrorTakingOnceCell, +} + +impl ProfileFileTokenProvider { + /// Builder for this token provider. + pub fn builder() -> Builder { + Builder::default() + } + + async fn load_token(&self) -> TokenResult { + let inner_provider = self + .inner_provider + .get_or_init( + { + let sdk_config = self.sdk_config.clone(); + let provider_config = self.provider_config.clone(); + move || async move { + let profile_set = load_profile_set(&provider_config).await?; + create_token_provider(&sdk_config, &provider_config, profile_set) + } + }, + TokenError::unhandled( + "profile file token provider initialization error already taken", + ), + ) + .await?; + + inner_provider.provide_token().await + } +} + +impl ProvideToken for ProfileFileTokenProvider { + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> + where + Self: 'a, + { + future::ProvideToken::new(self.load_token()) + } +} + +/// Builder for [`ProfileFileTokenProvider`]. +#[derive(Debug, Default)] +pub struct Builder { + provider_config: Option, + profile_override: Option, + profile_files: Option, +} + +impl Builder { + /// Override the configuration for the [`ProfileFileTokenProvider`] + /// + /// # Examples + /// + /// ```no_run + /// # async fn test() { + /// use aws_config::profile::ProfileFileTokenProvider; + /// use aws_config::provider_config::ProviderConfig; + /// let provider = ProfileFileTokenProvider::builder() + /// .configure(&ProviderConfig::with_default_region().await) + /// .build(); + /// # } + /// ``` + pub fn configure(mut self, provider_config: &ProviderConfig) -> Self { + self.provider_config = Some(provider_config.clone()); + self + } + + /// Override the profile name used by the [`ProfileFileTokenProvider`] + pub fn profile_name(mut self, profile_name: impl Into) -> Self { + self.profile_override = Some(profile_name.into()); + self + } + + /// Set the profile file that should be used by the [`ProfileFileTokenProvider`] + pub fn profile_files(mut self, profile_files: ProfileFiles) -> Self { + self.profile_files = Some(profile_files); + self + } + + /// Builds a [`ProfileFileTokenProvider`] + pub fn build(self) -> ProfileFileTokenProvider { + let build_span = tracing::debug_span!("build_profile_token_provider"); + let _enter = build_span.enter(); + let conf = self + .provider_config + .unwrap_or_default() + .with_profile_config(self.profile_files, self.profile_override); + + ProfileFileTokenProvider { + sdk_config: conf.client_config(), + provider_config: conf, + inner_provider: ErrorTakingOnceCell::new(), + } + } +} + +#[cfg(test)] +mod test { + use aws_credential_types::provider::token::ProvideToken; + + /// Test generation macro + /// + /// # Examples + /// **Run the test case in `test-data/default-token-provider-chain/test_name` + /// ```no_run + /// make_test!(test_name); + /// ``` + /// + /// **Update (responses are replayed but new requests are recorded) the test case**: + /// ```no_run + /// make_test!(update: test_name) + /// ``` + /// + /// **Run the test case against a real HTTPS connection:** + /// > Note: Be careful to remove sensitive information before committing. Always use a temporary + /// > AWS account when recording live traffic. + /// ```no_run + /// make_test!(live: test_name) + /// ``` + macro_rules! make_test { + ($name:ident $(#[$m:meta])*) => { + make_test!($name, execute, $(#[$m])*); + }; + (update: $name:ident) => { + make_test!($name, execute_and_update); + }; + (live: $name:ident) => { + make_test!($name, execute_from_live_traffic); + }; + ($name:ident, $func:ident, $(#[$m:meta])*) => { + make_test!($name, $func, std::convert::identity $(, #[$m])*); + }; + ($name:ident, builder: $provider_config_builder:expr) => { + make_test!($name, execute, $provider_config_builder); + }; + ($name:ident, $func:ident, $provider_config_builder:expr $(, #[$m:meta])*) => { + $(#[$m])* + #[tokio::test] + async fn $name() { + let _ = crate::test_case::TestEnvironment::from_dir( + concat!( + "./test-data/default-token-provider-chain/", + stringify!($name) + ), + crate::test_case::test_token_provider(|config| { + async move { + crate::default_provider::token::Builder::default() + .configure(config) + .build() + .await + .provide_token() + .await + } + }), + ) + .await + .unwrap() + .map_provider_config($provider_config_builder) + .$func() + .await; + } + }; + } + + make_test!(profile_keys); + make_test!(profile_keys_case_insensitive); + make_test!(profile_name); +} diff --git a/aws/rust-runtime/aws-config/src/sso/token.rs b/aws/rust-runtime/aws-config/src/sso/token.rs index 2ff6f027b6..98b2b28f5f 100644 --- a/aws/rust-runtime/aws-config/src/sso/token.rs +++ b/aws/rust-runtime/aws-config/src/sso/token.rs @@ -14,13 +14,17 @@ use crate::identity::IdentityCache; use crate::sso::cache::{ load_cached_token, save_cached_token, CachedSsoToken, CachedSsoTokenError, }; +use aws_credential_types::provider::token::ProvideToken; +use aws_credential_types::provider::{ + error::TokenError, future::ProvideToken as ProvideTokenFuture, +}; use aws_sdk_ssooidc::error::DisplayErrorContext; use aws_sdk_ssooidc::operation::create_token::CreateTokenOutput; use aws_sdk_ssooidc::Client as SsoOidcClient; use aws_smithy_async::time::SharedTimeSource; use aws_smithy_runtime::expiring_cache::ExpiringCache; use aws_smithy_runtime_api::client::identity::http::Token; -use aws_smithy_runtime_api::client::identity::{Identity, IdentityFuture, ResolveIdentity}; +use aws_smithy_runtime_api::client::identity::{IdentityFuture, ResolveIdentity}; use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; use aws_smithy_types::config_bag::ConfigBag; use aws_types::os_shim_internal::{Env, Fs}; @@ -148,8 +152,7 @@ impl SsoTokenProvider { pub(super) fn resolve_token( &self, time_source: SharedTimeSource, - ) -> impl std::future::Future> + 'static - { + ) -> impl std::future::Future> + 'static { let token_cache = self.token_cache.clone(); let inner = self.inner.clone(); @@ -216,33 +219,50 @@ impl SsoTokenProvider { let expires_at = token.expires_at; Ok((token, expires_at)) }) - .await?; + .await + .map_err(TokenError::provider_error)?; Ok(token) } } } -impl ResolveIdentity for SsoTokenProvider { - fn resolve_identity<'a>( - &'a self, - runtime_components: &'a RuntimeComponents, - _config_bag: &'a ConfigBag, - ) -> IdentityFuture<'a> { - let time_source = runtime_components +impl ProvideToken for SsoTokenProvider { + fn provide_token<'a>(&'a self) -> ProvideTokenFuture<'a> + where + Self: 'a, + { + let time_source = self + .inner + .sdk_config .time_source() .expect("a time source required by SsoTokenProvider"); let token_future = self.resolve_token(time_source); - IdentityFuture::new(Box::pin(async move { + ProvideTokenFuture::new(Box::pin(async move { let token = token_future.await?; - Ok(Identity::new( - Token::new(token.access_token.as_str(), Some(token.expires_at)), + Ok(Token::new( + token.access_token.as_str(), Some(token.expires_at), )) })) } } +impl ResolveIdentity for SsoTokenProvider { + fn resolve_identity<'a>( + &'a self, + runtime_components: &'a RuntimeComponents, + config_bag: &'a ConfigBag, + ) -> IdentityFuture<'a> { + IdentityFuture::new(Box::pin(async move { + self.provide_token() + .await? + .resolve_identity(runtime_components, config_bag) + .await + })) + } +} + /// Builder for [`SsoTokenProvider`]. #[derive(Debug, Default)] pub struct Builder { @@ -386,10 +406,11 @@ mod tests { use aws_smithy_async::rt::sleep::TokioSleep; use aws_smithy_async::test_util::instant_time_and_sleep; use aws_smithy_async::time::{StaticTimeSource, TimeSource}; - use aws_smithy_runtime::client::http::test_util::{ - capture_request, ReplayEvent, StaticReplayClient, - }; use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs; + use aws_smithy_runtime::{ + assert_str_contains, + client::http::test_util::{capture_request, ReplayEvent, StaticReplayClient}, + }; use aws_smithy_runtime_api::client::http::HttpClient; use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder; use aws_smithy_types::body::SdkBody; @@ -466,15 +487,15 @@ mod tests { } async fn expect_expired_token_err(&self) { - let err = self - .token_provider - .resolve_token(self.time_source.clone()) - .await - .expect_err("expected failure"); - assert!( - matches!(err, SsoTokenProviderError::ExpiredToken), - "expected {err:?} to be `ExpiredToken`" - ); + let err = DisplayErrorContext( + &self + .token_provider + .resolve_token(self.time_source.clone()) + .await + .expect_err("expected failure"), + ) + .to_string(); + assert_str_contains!(err, "the SSO token has expired"); } fn last_refresh_attempt_time(&self) -> Option { diff --git a/aws/rust-runtime/aws-config/src/test_case.rs b/aws/rust-runtime/aws-config/src/test_case.rs index 0c54466354..992d4f65e5 100644 --- a/aws/rust-runtime/aws-config/src/test_case.rs +++ b/aws/rust-runtime/aws-config/src/test_case.rs @@ -13,7 +13,7 @@ use aws_smithy_runtime::client::http::test_util::dvr::{ use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs; use aws_smithy_runtime_api::box_error::BoxError; use aws_smithy_runtime_api::shared::IntoShared; -use aws_smithy_types::error::display::DisplayErrorContext; +use aws_smithy_types::{date_time::Format, error::display::DisplayErrorContext, DateTime}; use aws_types::os_shim_internal::{Env, Fs}; use aws_types::sdk_config::SharedHttpClient; use serde::Deserialize; @@ -79,6 +79,39 @@ impl From for Credentials { } } +/// Test case token +/// +/// Token for use in test cases. These implement Serialize/Deserialize and have a +/// non-hidden debug implementation. +#[derive(Deserialize, Debug, Eq, PartialEq)] +pub(crate) struct Token { + pub(crate) token: String, + pub(crate) expiration: Option, +} + +impl Secrets for Token { + fn secrets(&self) -> Vec { + vec![self.token.clone()] + } +} + +impl From<&aws_credential_types::Token> for Token { + fn from(value: &aws_credential_types::Token) -> Self { + Self { + token: value.token().into(), + expiration: value + .expiration() + .map(|s| DateTime::from(s).fmt(Format::DateTime).unwrap()), + } + } +} + +impl From for Token { + fn from(value: aws_credential_types::Token) -> Self { + Self::from(&value) + } +} + /// Connector which expects no traffic pub(crate) fn no_traffic_client() -> SharedHttpClient { ReplayingClient::new(Vec::new()).into_shared() @@ -120,7 +153,7 @@ where } (Err(actual_error), GenericTestResult::Ok(expected_creds)) => { panic!( - "expected credentials ({:?}) but an error was returned: {}", + "expected output ({:?}) but an error was returned: {}", expected_creds, DisplayErrorContext(actual_error) ) @@ -192,6 +225,19 @@ where }) } +pub(crate) fn test_token_provider( + run_provider_fn: F, +) -> impl RunTestProvider +where + F: Fn(ProviderConfig) -> Fut + Send + Clone + 'static, + Fut: Future> + Send, +{ + StaticTestProvider::::new(move |config| { + let run_provider_fn = run_provider_fn.clone(); + Box::pin(async move { (run_provider_fn)(config).await.map(Into::into) }) + }) +} + /// Provider test environment /// /// A provider test environment is a directory containing: diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/env.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/env.json new file mode 100644 index 0000000000..f86eb48eb6 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/env.json @@ -0,0 +1,3 @@ +{ + "HOME": "/home" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/config b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/config new file mode 100644 index 0000000000..8600cea368 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/config @@ -0,0 +1,7 @@ +[profile default] +sso_session = test-sso +region=us-west-2 + +[sso-session test-sso] +sso_start_url = https://ssotest.awsapps.com/start +sso_region = us-east-2 diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json new file mode 100644 index 0000000000..29c690fd09 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json @@ -0,0 +1,5 @@ +{ + "accessToken": "foobarbaz", + "expiresAt": "2080-10-16T03:56:45Z", + "startUrl": "https://ssotest.awsapps.com/start" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/http-traffic.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/http-traffic.json new file mode 100644 index 0000000000..51c2a6c20d --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/http-traffic.json @@ -0,0 +1,5 @@ +{ + "version": "V0", + "docs": "Load a SSO bearer token from the default profile", + "events": [] +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/test-case.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/test-case.json new file mode 100644 index 0000000000..547c0dfe72 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys/test-case.json @@ -0,0 +1,10 @@ +{ + "name": "profile_keys", + "docs": "Load a SSO bearer token from the default profile", + "result": { + "Ok": { + "token": "foobarbaz", + "expiration": "2080-10-16T03:56:45Z" + } + } +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/env.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/env.json new file mode 100644 index 0000000000..f86eb48eb6 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/env.json @@ -0,0 +1,3 @@ +{ + "HOME": "/home" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/config b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/config new file mode 100644 index 0000000000..170ea69cf5 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/config @@ -0,0 +1,7 @@ +[profile default] +SSO_SESSION = test-sso +REGION=us-west-2 + +[sso-session test-sso] +SSO_START_URL = https://ssotest.awsapps.com/start +SSO_REGION = us-east-2 diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json new file mode 100644 index 0000000000..29c690fd09 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/fs/home/.aws/sso/cache/d12208e38164f558a1d06c99432ab77dbb346c45.json @@ -0,0 +1,5 @@ +{ + "accessToken": "foobarbaz", + "expiresAt": "2080-10-16T03:56:45Z", + "startUrl": "https://ssotest.awsapps.com/start" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/http-traffic.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/http-traffic.json new file mode 100644 index 0000000000..66531cb7fb --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/http-traffic.json @@ -0,0 +1,5 @@ +{ + "version": "V0", + "docs": "Load a SSO bearer token from the default profile with case insensitive keys", + "events": [] +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/test-case.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/test-case.json new file mode 100644 index 0000000000..8e0930f2ac --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_keys_case_insensitive/test-case.json @@ -0,0 +1,10 @@ +{ + "name": "profile_keys_case_insensitive", + "docs": "Load a SSO bearer token from the default profile with case insensitive keys", + "result": { + "Ok": { + "token": "foobarbaz", + "expiration": "2080-10-16T03:56:45Z" + } + } +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/env.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/env.json new file mode 100644 index 0000000000..95de9aa008 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/env.json @@ -0,0 +1,4 @@ +{ + "HOME": "/home", + "AWS_PROFILE": "correct-sso" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/config b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/config new file mode 100644 index 0000000000..3be74934fa --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/config @@ -0,0 +1,15 @@ +[profile incorrect-sso] +sso_session = incorrect-sso +region=us-west-2 + +[sso-session incorrect-sso] +sso_start_url = https://incorrect-ssotest.awsapps.com/start +sso_region = us-east-2 + +[profile correct-sso] +sso_session = correct-sso +region=us-west-2 + +[sso-session correct-sso] +sso_start_url = https://ssotest.awsapps.com/start +sso_region = us-east-2 diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/sso/cache/29faa2f70ab0f58f60e284d585d95865572f5cbd.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/sso/cache/29faa2f70ab0f58f60e284d585d95865572f5cbd.json new file mode 100644 index 0000000000..29c690fd09 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/fs/home/.aws/sso/cache/29faa2f70ab0f58f60e284d585d95865572f5cbd.json @@ -0,0 +1,5 @@ +{ + "accessToken": "foobarbaz", + "expiresAt": "2080-10-16T03:56:45Z", + "startUrl": "https://ssotest.awsapps.com/start" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/http-traffic.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/http-traffic.json new file mode 100644 index 0000000000..e73bae7f4a --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/http-traffic.json @@ -0,0 +1,5 @@ +{ + "version": "V0", + "docs": "Load a SSO bearer token from a profile named correct-sso", + "events": [] +} diff --git a/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/test-case.json b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/test-case.json new file mode 100644 index 0000000000..169e400f66 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-token-provider-chain/profile_name/test-case.json @@ -0,0 +1,10 @@ +{ + "name": "profile_name", + "docs": "Load a SSO bearer token from a profile named correct-sso", + "result": { + "Ok": { + "token": "foobarbaz", + "expiration": "2080-10-16T03:56:45Z" + } + } +} diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 9b25683c15..4060690b08 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -14,7 +14,7 @@ test-util = [] [dependencies] aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" } -aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client"] } +aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client", "http-auth"] } zeroize = "1" [dev-dependencies] diff --git a/aws/rust-runtime/aws-credential-types/src/lib.rs b/aws/rust-runtime/aws-credential-types/src/lib.rs index fb3a2980aa..e345945677 100644 --- a/aws/rust-runtime/aws-credential-types/src/lib.rs +++ b/aws/rust-runtime/aws-credential-types/src/lib.rs @@ -23,7 +23,14 @@ pub mod credential_fn; mod credentials_impl; pub mod provider; -mod token_impl; +pub mod token_fn; pub use credentials_impl::Credentials; -pub use token_impl::AccessToken; + +/// AWS Access Token +/// +/// This access token type is used to authenticate to AWS services that use HTTP Bearer +/// Auth with an AWS Builder ID such as CodeCatalyst. +/// +/// For more details on tokens, see: +pub type Token = aws_smithy_runtime_api::client::identity::http::Token; diff --git a/aws/rust-runtime/aws-credential-types/src/provider/error.rs b/aws/rust-runtime/aws-credential-types/src/provider/error.rs index a54145d1d8..88261c688b 100644 --- a/aws/rust-runtime/aws-credential-types/src/provider/error.rs +++ b/aws/rust-runtime/aws-credential-types/src/provider/error.rs @@ -15,7 +15,7 @@ pub struct CredentialsNotLoaded { source: Option>, } -/// Details for [`CredentialsError::ProviderTimedOut`] or [`AccessTokenError::ProviderTimedOut`] +/// Details for [`CredentialsError::ProviderTimedOut`] or [`TokenError::ProviderTimedOut`] #[derive(Debug)] pub struct ProviderTimedOut { timeout_duration: Duration, @@ -28,19 +28,19 @@ impl ProviderTimedOut { } } -/// Details for [`CredentialsError::InvalidConfiguration`] or [`AccessTokenError::InvalidConfiguration`] +/// Details for [`CredentialsError::InvalidConfiguration`] or [`TokenError::InvalidConfiguration`] #[derive(Debug)] pub struct InvalidConfiguration { source: Box, } -/// Details for [`CredentialsError::ProviderError`] or [`AccessTokenError::ProviderError`] +/// Details for [`CredentialsError::ProviderError`] or [`TokenError::ProviderError`] #[derive(Debug)] pub struct ProviderError { source: Box, } -/// Details for [`CredentialsError::Unhandled`] or [`AccessTokenError::Unhandled`] +/// Details for [`CredentialsError::Unhandled`] or [`TokenError::Unhandled`] #[derive(Debug)] pub struct Unhandled { source: Box, @@ -172,7 +172,7 @@ impl Error for CredentialsError { } } -/// Details for [`AccessTokenError::TokenNotLoaded`] +/// Details for [`TokenError::TokenNotLoaded`] #[derive(Debug)] pub struct TokenNotLoaded { source: Box, @@ -180,7 +180,7 @@ pub struct TokenNotLoaded { /// Error returned when an access token provider fails to provide an access token. #[derive(Debug)] -pub enum AccessTokenError { +pub enum TokenError { /// This provider couldn't provide a token. TokenNotLoaded(TokenNotLoaded), @@ -204,14 +204,14 @@ pub enum AccessTokenError { Unhandled(Unhandled), } -impl AccessTokenError { +impl TokenError { /// The access token provider couldn't provide a token. /// /// This error indicates the token provider was not enable or no configuration was set. - /// This contrasts with [`invalid_configuration`](AccessTokenError::InvalidConfiguration), indicating + /// This contrasts with [`invalid_configuration`](TokenError::InvalidConfiguration), indicating /// that the provider was configured in some way, but certain settings were invalid. pub fn not_loaded(source: impl Into>) -> Self { - AccessTokenError::TokenNotLoaded(TokenNotLoaded { + TokenError::TokenNotLoaded(TokenNotLoaded { source: source.into(), }) } @@ -248,38 +248,38 @@ impl AccessTokenError { } } -impl fmt::Display for AccessTokenError { +impl fmt::Display for TokenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - AccessTokenError::TokenNotLoaded(_) => { + TokenError::TokenNotLoaded(_) => { write!(f, "the access token provider was not enabled") } - AccessTokenError::ProviderTimedOut(details) => write!( + TokenError::ProviderTimedOut(details) => write!( f, "access token provider timed out after {} seconds", details.timeout_duration.as_secs() ), - AccessTokenError::InvalidConfiguration(_) => { + TokenError::InvalidConfiguration(_) => { write!(f, "the access token provider was not properly configured") } - AccessTokenError::ProviderError(_) => { + TokenError::ProviderError(_) => { write!(f, "an error occurred while loading an access token") } - AccessTokenError::Unhandled(_) => { + TokenError::Unhandled(_) => { write!(f, "unexpected access token providererror") } } } } -impl Error for AccessTokenError { +impl Error for TokenError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { - AccessTokenError::TokenNotLoaded(details) => Some(details.source.as_ref() as _), - AccessTokenError::ProviderTimedOut(_) => None, - AccessTokenError::InvalidConfiguration(details) => Some(details.source.as_ref() as _), - AccessTokenError::ProviderError(details) => Some(details.source.as_ref() as _), - AccessTokenError::Unhandled(details) => Some(details.source.as_ref() as _), + TokenError::TokenNotLoaded(details) => Some(details.source.as_ref() as _), + TokenError::ProviderTimedOut(_) => None, + TokenError::InvalidConfiguration(details) => Some(details.source.as_ref() as _), + TokenError::ProviderError(details) => Some(details.source.as_ref() as _), + TokenError::Unhandled(details) => Some(details.source.as_ref() as _), } } } diff --git a/aws/rust-runtime/aws-credential-types/src/provider/future.rs b/aws/rust-runtime/aws-credential-types/src/provider/future.rs index 49476dd343..a9f3f77709 100644 --- a/aws/rust-runtime/aws-credential-types/src/provider/future.rs +++ b/aws/rust-runtime/aws-credential-types/src/provider/future.rs @@ -38,23 +38,23 @@ impl Future for ProvideCredentials<'_> { } } -/// Future new-type that `ProvideAccessToken::provide_access_token` must return. +/// Future new-type that `ProvideToken::provide_token` must return. #[derive(Debug)] -pub struct ProvideAccessToken<'a>(NowOrLater>); +pub struct ProvideToken<'a>(NowOrLater>); -impl<'a> ProvideAccessToken<'a> { - /// Creates a `ProvideAccessToken` struct from a future. +impl<'a> ProvideToken<'a> { + /// Creates a `ProvideToken` struct from a future. pub fn new(future: impl Future + Send + 'a) -> Self { - ProvideAccessToken(NowOrLater::new(Box::pin(future))) + ProvideToken(NowOrLater::new(Box::pin(future))) } - /// Creates a `ProvideAccessToken` struct from a resolved credentials value. + /// Creates a `ProvideToken` struct from a resolved credentials value. pub fn ready(credentials: TokenResult) -> Self { - ProvideAccessToken(NowOrLater::ready(credentials)) + ProvideToken(NowOrLater::ready(credentials)) } } -impl Future for ProvideAccessToken<'_> { +impl Future for ProvideToken<'_> { type Output = TokenResult; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { diff --git a/aws/rust-runtime/aws-credential-types/src/provider/token.rs b/aws/rust-runtime/aws-credential-types/src/provider/token.rs index f463ffbc74..14d361b885 100644 --- a/aws/rust-runtime/aws-credential-types/src/provider/token.rs +++ b/aws/rust-runtime/aws-credential-types/src/provider/token.rs @@ -9,56 +9,65 @@ //! an access token that can then be used to authenticate with services such as //! Code Catalyst. //! -//! This module provides the [`ProvideAccessToken`] trait that is used to configure +//! This module provides the [`ProvideToken`] trait that is used to configure //! token providers in the SDK config. -use crate::{provider::error::AccessTokenError, provider::future, AccessToken}; +use crate::{provider::error::TokenError, provider::future, Token}; use std::sync::Arc; /// Result type for token providers -pub type Result = std::result::Result; +pub type Result = std::result::Result; /// Access Token Provider -pub trait ProvideAccessToken: Send + Sync + std::fmt::Debug { +pub trait ProvideToken: Send + Sync + std::fmt::Debug { /// Returns a future that provides an access token. - fn provide_access_token<'a>(&'a self) -> future::ProvideAccessToken<'a> + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> where Self: 'a; } +impl ProvideToken for Token { + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> + where + Self: 'a, + { + future::ProvideToken::ready(Ok(self.clone())) + } +} + /// Access token provider wrapper that may be shared. /// -/// Newtype wrapper around [`ProvideAccessToken`] that implements `Clone` using an internal `Arc`. +/// Newtype wrapper around [`ProvideToken`] that implements `Clone` using an internal `Arc`. #[derive(Clone, Debug)] -pub struct SharedAccessTokenProvider(Arc); +pub struct SharedTokenProvider(Arc); -impl SharedAccessTokenProvider { - /// Create a new [`SharedAccessTokenProvider`] from [`ProvideAccessToken`]. +impl SharedTokenProvider { + /// Create a new [`SharedTokenProvider`] from [`ProvideToken`]. /// /// The given provider will be wrapped in an internal `Arc`. If your - /// provider is already in an `Arc`, use `SharedAccessTokenProvider::from(provider)` instead. - pub fn new(provider: impl ProvideAccessToken + 'static) -> Self { + /// provider is already in an `Arc`, use `SharedTokenProvider::from(provider)` instead. + pub fn new(provider: impl ProvideToken + 'static) -> Self { Self(Arc::new(provider)) } } -impl AsRef for SharedAccessTokenProvider { - fn as_ref(&self) -> &(dyn ProvideAccessToken + 'static) { +impl AsRef for SharedTokenProvider { + fn as_ref(&self) -> &(dyn ProvideToken + 'static) { self.0.as_ref() } } -impl From> for SharedAccessTokenProvider { - fn from(provider: Arc) -> Self { - SharedAccessTokenProvider(provider) +impl From> for SharedTokenProvider { + fn from(provider: Arc) -> Self { + SharedTokenProvider(provider) } } -impl ProvideAccessToken for SharedAccessTokenProvider { - fn provide_access_token<'a>(&'a self) -> future::ProvideAccessToken<'a> +impl ProvideToken for SharedTokenProvider { + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> where Self: 'a, { - self.0.provide_access_token() + self.0.provide_token() } } diff --git a/aws/rust-runtime/aws-credential-types/src/token_fn.rs b/aws/rust-runtime/aws-credential-types/src/token_fn.rs new file mode 100644 index 0000000000..bbd2fc6861 --- /dev/null +++ b/aws/rust-runtime/aws-credential-types/src/token_fn.rs @@ -0,0 +1,133 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Types that allow an access token provider to be created from a closure + +use crate::provider::{future, token::ProvideToken}; +use std::fmt::{self, Debug, Formatter}; +use std::future::Future; +use std::marker::PhantomData; + +/// A [`ProvideToken`] implemented by a closure. +/// +/// See [`provide_token_fn`] for more details. +#[derive(Copy, Clone)] +pub struct ProvideTokenFn<'c, T> { + f: T, + phantom: PhantomData<&'c T>, +} + +impl Debug for ProvideTokenFn<'_, T> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "ProvideTokenFn") + } +} + +impl<'c, T, F> ProvideToken for ProvideTokenFn<'c, T> +where + T: Fn() -> F + Send + Sync + 'c, + F: Future + Send + 'static, +{ + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> + where + Self: 'a, + { + future::ProvideToken::new((self.f)()) + } +} + +/// Returns a new token provider built with the given closure. This allows you +/// to create an [`ProvideToken`] implementation from an async block that returns +/// a [`crate::provider::token::Result`]. +/// +/// # Examples +/// +/// ```no_run +/// use aws_credential_types::Token; +/// use aws_credential_types::token_fn::provide_token_fn; +/// +/// async fn load_token() -> Token { +/// todo!() +/// } +/// +/// provide_token_fn(|| async { +/// // Async process to retrieve a token goes here +/// let token = load_token().await; +/// Ok(token) +/// }); +/// ``` +pub fn provide_token_fn<'c, T, F>(f: T) -> ProvideTokenFn<'c, T> +where + T: Fn() -> F + Send + Sync + 'c, + F: Future + Send + 'static, +{ + ProvideTokenFn { + f, + phantom: Default::default(), + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::Token; + use async_trait::async_trait; + use std::fmt::{Debug, Formatter}; + + fn assert_send_sync() {} + + #[test] + fn creds_are_send_sync() { + assert_send_sync::() + } + + #[async_trait] + trait AnotherTrait: Send + Sync { + async fn token(&self) -> Token; + } + + struct AnotherTraitWrapper { + inner: T, + } + + impl Debug for AnotherTraitWrapper { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "wrapper") + } + } + + impl ProvideToken for AnotherTraitWrapper { + fn provide_token<'a>(&'a self) -> future::ProvideToken<'a> + where + Self: 'a, + { + future::ProvideToken::new(async move { Ok(self.inner.token().await) }) + } + } + + // Test that the closure passed to `provide_token_fn` is allowed to borrow things + #[tokio::test] + async fn provide_token_fn_closure_can_borrow() { + fn check_is_str_ref(_input: &str) {} + async fn test_async_provider(input: String) -> crate::provider::token::Result { + Ok(Token::new(input, None)) + } + + let things_to_borrow = vec!["one".to_string(), "two".to_string()]; + + let mut providers = Vec::new(); + for thing in &things_to_borrow { + let provider = provide_token_fn(move || { + check_is_str_ref(thing); + test_async_provider(thing.into()) + }); + providers.push(provider); + } + + let (two, one) = (providers.pop().unwrap(), providers.pop().unwrap()); + assert_eq!("one", one.provide_token().await.unwrap().token()); + assert_eq!("two", two.provide_token().await.unwrap().token()); + } +} diff --git a/aws/rust-runtime/aws-credential-types/src/token_impl.rs b/aws/rust-runtime/aws-credential-types/src/token_impl.rs deleted file mode 100644 index 9e5b286568..0000000000 --- a/aws/rust-runtime/aws-credential-types/src/token_impl.rs +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use aws_smithy_types::date_time::Format; -use aws_smithy_types::DateTime; -use std::fmt; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; -use zeroize::Zeroizing; - -/// AWS Access Token -/// -/// Provides token which is used to securely authorize requests to AWS -/// services. A token is a string that the OAuth client uses to make requests to -/// the resource server. -/// -/// For more details on tokens, see: -#[non_exhaustive] -#[derive(Debug, Clone)] -pub struct AccessToken(Arc); - -impl AccessToken { - /// Create a new access token - pub fn new(token: impl Into, expires_after: Option) -> Self { - Self(Arc::new(Inner { - token: Zeroizing::new(token.into()), - expires_after, - })) - } - - /// Get the access token - pub fn token(&self) -> &str { - &self.0.token - } - - /// Get the token expiration time - pub fn expires_after(&self) -> Option { - self.0.expires_after - } -} - -struct Inner { - token: Zeroizing, - expires_after: Option, -} - -impl fmt::Debug for Inner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut dbg = f.debug_struct("AccessToken"); - dbg.field("token", &"** redacted **"); - if let Some(expires_after) = self.expires_after { - if let Some(formatted) = expires_after - .duration_since(UNIX_EPOCH) - .ok() - .and_then(|dur| { - DateTime::from_secs(dur.as_secs() as _) - .fmt(Format::DateTime) - .ok() - }) - { - dbg.field("expires_after", &formatted); - } else { - dbg.field("expires_after", &expires_after); - } - } else { - dbg.field("expires_after", &"never"); - } - dbg.finish() - } -} diff --git a/aws/rust-runtime/aws-types/src/sdk_config.rs b/aws/rust-runtime/aws-types/src/sdk_config.rs index f88f52ae3f..43022f9ca1 100644 --- a/aws/rust-runtime/aws-types/src/sdk_config.rs +++ b/aws/rust-runtime/aws-types/src/sdk_config.rs @@ -13,6 +13,7 @@ use crate::app_name::AppName; use crate::docs_for; use crate::region::Region; +use aws_credential_types::provider::token::SharedTokenProvider; pub use aws_credential_types::provider::SharedCredentialsProvider; use aws_smithy_async::rt::sleep::AsyncSleep; pub use aws_smithy_async::rt::sleep::SharedAsyncSleep; @@ -55,6 +56,7 @@ pub struct SdkConfig { app_name: Option, identity_cache: Option, credentials_provider: Option, + token_provider: Option, region: Option, endpoint_url: Option, retry_config: Option, @@ -78,6 +80,7 @@ pub struct Builder { app_name: Option, identity_cache: Option, credentials_provider: Option, + token_provider: Option, region: Option, endpoint_url: Option, retry_config: Option, @@ -415,6 +418,55 @@ impl Builder { self } + /// Set the bearer auth token provider for the builder + /// + /// # Examples + /// ```rust + /// use aws_credential_types::provider::token::{ProvideToken, SharedTokenProvider}; + /// use aws_types::SdkConfig; + /// + /// fn make_provider() -> impl ProvideToken { + /// // ... + /// # aws_credential_types::Token::new("example", None) + /// } + /// + /// let config = SdkConfig::builder() + /// .token_provider(SharedTokenProvider::new(make_provider())) + /// .build(); + /// ``` + pub fn token_provider(mut self, provider: SharedTokenProvider) -> Self { + self.set_token_provider(Some(provider)); + self + } + + /// Set the bearer auth token provider for the builder + /// + /// # Examples + /// ```rust + /// use aws_credential_types::provider::token::{ProvideToken, SharedTokenProvider}; + /// use aws_types::SdkConfig; + /// + /// fn make_provider() -> impl ProvideToken { + /// // ... + /// # aws_credential_types::Token::new("example", None) + /// } + /// + /// fn override_provider() -> bool { + /// // ... + /// # true + /// } + /// + /// let mut builder = SdkConfig::builder(); + /// if override_provider() { + /// builder.set_token_provider(Some(SharedTokenProvider::new(make_provider()))); + /// } + /// let config = builder.build(); + /// ``` + pub fn set_token_provider(&mut self, provider: Option) -> &mut Self { + self.token_provider = provider; + self + } + /// Sets the name of the app that is using the client. /// /// This _optional_ name is used to identify the application in the user agent that @@ -560,6 +612,7 @@ impl Builder { app_name: self.app_name, identity_cache: self.identity_cache, credentials_provider: self.credentials_provider, + token_provider: self.token_provider, region: self.region, endpoint_url: self.endpoint_url, retry_config: self.retry_config, @@ -682,6 +735,11 @@ impl SdkConfig { self.credentials_provider.clone() } + /// Configured bearer auth token provider + pub fn token_provider(&self) -> Option { + self.token_provider.clone() + } + /// Configured time source pub fn time_source(&self) -> Option { self.time_source.clone() @@ -737,6 +795,7 @@ impl SdkConfig { app_name: self.app_name, identity_cache: self.identity_cache, credentials_provider: self.credentials_provider, + token_provider: self.token_provider, region: self.region, endpoint_url: self.endpoint_url, retry_config: self.retry_config, diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs index 5ec332cf3e..2666ef2a01 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs @@ -47,6 +47,11 @@ impl Token { pub fn token(&self) -> &str { &self.0.token } + + /// Returns the expiration time (if any) for this token. + pub fn expiration(&self) -> Option { + self.0.expiration + } } impl From<&str> for Token { From cc24998b0df88b8d56456b6ed79440068e7e7c38 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 23 Feb 2024 16:11:12 -0800 Subject: [PATCH 03/16] Fix external type checks --- aws/rust-runtime/aws-config/external-types.toml | 1 + aws/rust-runtime/aws-credential-types/external-types.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/aws/rust-runtime/aws-config/external-types.toml b/aws/rust-runtime/aws-config/external-types.toml index 58a946ea9f..13cdd87597 100644 --- a/aws/rust-runtime/aws-config/external-types.toml +++ b/aws/rust-runtime/aws-config/external-types.toml @@ -7,6 +7,7 @@ allowed_external_types = [ "aws_credential_types::provider::credentials::ProvideCredentials", "aws_credential_types::provider::credentials::Result", "aws_credential_types::provider::credentials::SharedCredentialsProvider", + "aws_credential_types::provider::token::ProvideToken", "aws_smithy_async::rt::sleep::AsyncSleep", "aws_smithy_async::rt::sleep::SharedAsyncSleep", "aws_smithy_async::time::SharedTimeSource", diff --git a/aws/rust-runtime/aws-credential-types/external-types.toml b/aws/rust-runtime/aws-credential-types/external-types.toml index e1d82c7db4..f8b06e0f47 100644 --- a/aws/rust-runtime/aws-credential-types/external-types.toml +++ b/aws/rust-runtime/aws-credential-types/external-types.toml @@ -2,6 +2,7 @@ allowed_external_types = [ "aws_smithy_async::rt::sleep::AsyncSleep", "aws_smithy_async::rt::sleep::SharedAsyncSleep", "aws_smithy_runtime_api::client::identity::ResolveIdentity", + "aws_smithy_runtime_api::client::identity::http::Token", "aws_smithy_types::config_bag::storable::Storable", "aws_smithy_types::config_bag::storable::StoreReplace", "aws_smithy_types::config_bag::storable::Storer", From 3d6919443ddcd8c28f1ff36022a7c2935f3f949e Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Mon, 26 Feb 2024 14:16:33 -0800 Subject: [PATCH 04/16] Fix more external types --- aws/rust-runtime/aws-types/external-types.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/rust-runtime/aws-types/external-types.toml b/aws/rust-runtime/aws-types/external-types.toml index d24d3dad09..5dce405f84 100644 --- a/aws/rust-runtime/aws-types/external-types.toml +++ b/aws/rust-runtime/aws-types/external-types.toml @@ -1,6 +1,7 @@ allowed_external_types = [ "aws_credential_types::cache::CredentialsCache", "aws_credential_types::provider::credentials::SharedCredentialsProvider", + "aws_credential_types::provider::token::SharedTokenProvider", "aws_smithy_async::rt::sleep::AsyncSleep", "aws_smithy_async::rt::sleep::SharedAsyncSleep", "aws_smithy_async::time::SharedTimeSource", From fc8b3aa99471076955b26d492e53806c0bc0775e Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Mon, 26 Feb 2024 14:20:18 -0800 Subject: [PATCH 05/16] Fix warning --- aws/rust-runtime/aws-config/src/test_case.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/rust-runtime/aws-config/src/test_case.rs b/aws/rust-runtime/aws-config/src/test_case.rs index 992d4f65e5..10261208bb 100644 --- a/aws/rust-runtime/aws-config/src/test_case.rs +++ b/aws/rust-runtime/aws-config/src/test_case.rs @@ -225,6 +225,7 @@ where }) } +#[cfg(feature = "sso")] pub(crate) fn test_token_provider( run_provider_fn: F, ) -> impl RunTestProvider From 98cb3753d4f6b4d72d7893c02e237e805073dffe Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 23 Feb 2024 17:32:22 -0800 Subject: [PATCH 06/16] Connect token providers via codegen --- .../aws-credential-types/Cargo.toml | 2 +- .../src/provider/token.rs | 18 + .../smithy/rustsdk/AwsCodegenDecorator.kt | 1 + ...ers.kt => CredentialProvidersDecorator.kt} | 31 +- .../smithy/rustsdk/SigV4AuthDecorator.kt | 37 +- .../smithy/rustsdk/TokenProvidersDecorator.kt | 110 + .../rustsdk/TokenProvidersDecoratorTest.kt | 75 + aws/sdk/aws-models/codecatalyst.json | 5574 +++++++++++++++++ aws/sdk/integration-tests/Cargo.toml | 1 + .../integration-tests/codecatalyst/Cargo.toml | 17 + .../codecatalyst/tests/sso_bearer_auth.json | 126 + .../codecatalyst/tests/sso_bearer_auth.rs | 31 + .../customizations/HttpAuthDecorator.kt | 10 +- .../codegen/client/smithy/endpoint/Util.kt | 13 +- .../src/client/identity/http.rs | 20 +- 15 files changed, 6039 insertions(+), 27 deletions(-) rename aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/{CredentialProviders.kt => CredentialProvidersDecorator.kt} (86%) create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt create mode 100644 aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecoratorTest.kt create mode 100644 aws/sdk/aws-models/codecatalyst.json create mode 100644 aws/sdk/integration-tests/codecatalyst/Cargo.toml create mode 100644 aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json create mode 100644 aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 4060690b08..bdbb0aba6f 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/smithy-lang/smithy-rs" [features] hardcoded-credentials = [] -test-util = [] +test-util = ["aws-smithy-runtime-api/test-util"] [dependencies] aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } diff --git a/aws/rust-runtime/aws-credential-types/src/provider/token.rs b/aws/rust-runtime/aws-credential-types/src/provider/token.rs index 14d361b885..e59ff7665c 100644 --- a/aws/rust-runtime/aws-credential-types/src/provider/token.rs +++ b/aws/rust-runtime/aws-credential-types/src/provider/token.rs @@ -13,6 +13,12 @@ //! token providers in the SDK config. use crate::{provider::error::TokenError, provider::future, Token}; +use aws_smithy_runtime_api::client::{ + identity::{IdentityFuture, ResolveIdentity}, + runtime_components::RuntimeComponents, +}; +use aws_smithy_runtime_api::impl_shared_conversions; +use aws_smithy_types::config_bag::ConfigBag; use std::sync::Arc; /// Result type for token providers @@ -71,3 +77,15 @@ impl ProvideToken for SharedTokenProvider { self.0.provide_token() } } + +impl ResolveIdentity for SharedTokenProvider { + fn resolve_identity<'a>( + &'a self, + _runtime_components: &'a RuntimeComponents, + _config_bag: &'a ConfigBag, + ) -> IdentityFuture<'a> { + IdentityFuture::new(async move { Ok(self.provide_token().await?.into()) }) + } +} + +impl_shared_conversions!(convert SharedTokenProvider from ProvideToken using SharedTokenProvider::new); diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt index 3bc616a9b8..e246227f53 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt @@ -56,6 +56,7 @@ val DECORATORS: List = InvocationIdDecorator(), RetryInformationHeaderDecorator(), RemoveDefaultsDecorator(), + TokenProvidersDecorator(), ), // Service specific decorators ApiGatewayDecorator().onlyApplyTo("com.amazonaws.apigateway#BackplaneControlService"), diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt similarity index 86% rename from aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt rename to aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt index ce8610e51b..73b60cf8b6 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt @@ -5,12 +5,14 @@ package software.amazon.smithy.rustsdk +import software.amazon.smithy.aws.traits.auth.SigV4Trait +import software.amazon.smithy.model.knowledge.ServiceIndex import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.configReexport import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.customize.TestUtilFeature -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.supportedAuthSchemes +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.usesSigV4a import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.core.rustlang.featureGateBlock @@ -22,29 +24,38 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.pre import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomization +import software.amazon.smithy.rust.codegen.core.util.letIf class CredentialsProviderDecorator : ClientCodegenDecorator { override val name: String = "CredentialsProvider" override val order: Byte = 0 + private fun applies(codegenContext: ClientCodegenContext): Boolean = + ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) + .containsKey(SigV4Trait.ID) || codegenContext.serviceShape.usesSigV4a() + override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List { - return baseCustomizations + CredentialProviderConfig(codegenContext) - } + ): List = + baseCustomizations.letIf(applies(codegenContext)) { it + CredentialProviderConfig(codegenContext) } override fun extraSections(codegenContext: ClientCodegenContext): List = - listOf( - adhocCustomization { section -> - rust("${section.serviceConfigBuilder}.set_credentials_provider(${section.sdkConfig}.credentials_provider());") - }, - ) + emptyList().letIf(applies(codegenContext)) { + it + + adhocCustomization { section -> + rust("${section.serviceConfigBuilder}.set_credentials_provider(${section.sdkConfig}.credentials_provider());") + } + } override fun extras( codegenContext: ClientCodegenContext, rustCrate: RustCrate, ) { + if (!applies(codegenContext)) { + return + } + rustCrate.mergeFeature(TestUtilFeature.copy(deps = listOf("aws-credential-types/test-util"))) rustCrate.withModule(ClientRustModule.config) { @@ -125,7 +136,7 @@ class CredentialProviderConfig(private val codegenContext: ClientCodegenContext) """, *codegenScope, ) { - if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { + if (codegenContext.serviceShape.usesSigV4a()) { featureGateBlock("sigv4a") { rustTemplate( "self.runtime_components.set_identity_resolver(#{SIGV4A_SCHEME_ID}, credentials_provider.clone());", diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index fb1385bdc6..f942f36314 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -14,7 +14,7 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.supportedAuthSchemes +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.usesSigV4a import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization @@ -35,6 +35,7 @@ import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.hasEventStreamOperations import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.isInputEventStream +import software.amazon.smithy.rust.codegen.core.util.letIf import software.amazon.smithy.rust.codegen.core.util.thenSingletonListOf class SigV4AuthDecorator : ClientCodegenDecorator { @@ -43,6 +44,10 @@ class SigV4AuthDecorator : ClientCodegenDecorator { private val sigv4a = "sigv4a" + private fun applies(codegenContext: ClientCodegenContext): Boolean = + ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) + .containsKey(SigV4Trait.ID) || codegenContext.serviceShape.usesSigV4a() + private fun sigv4(runtimeConfig: RuntimeConfig) = writable { val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") @@ -62,8 +67,12 @@ class SigV4AuthDecorator : ClientCodegenDecorator { operationShape: OperationShape, baseAuthSchemeOptions: List, ): List { + if (!applies(codegenContext)) { + return baseAuthSchemeOptions + } + val supportsSigV4a = - codegenContext.serviceShape.supportedAuthSchemes().contains(sigv4a) + codegenContext.serviceShape.usesSigV4a() .thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } return baseAuthSchemeOptions + AuthSchemeOption.StaticAuthSchemeOption( @@ -76,25 +85,39 @@ class SigV4AuthDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = - baseCustomizations + listOf(AuthServiceRuntimePluginCustomization(codegenContext)) + baseCustomizations.letIf(applies(codegenContext)) { + it + + listOf( + AuthServiceRuntimePluginCustomization( + codegenContext, + ), + ) + } override fun operationCustomizations( codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, - ): List = baseCustomizations + AuthOperationCustomization(codegenContext) + ): List = + baseCustomizations.letIf(applies(codegenContext)) { it + AuthOperationCustomization(codegenContext) } override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = - baseCustomizations + SigV4SigningConfig(codegenContext.runtimeConfig, codegenContext.serviceShape.getTrait()) + baseCustomizations.letIf(applies(codegenContext)) { + it + + SigV4SigningConfig( + codegenContext.runtimeConfig, + codegenContext.serviceShape.getTrait(), + ) + } override fun extras( codegenContext: ClientCodegenContext, rustCrate: RustCrate, ) { - if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { + if (codegenContext.serviceShape.usesSigV4a()) { // Add optional feature for SigV4a support rustCrate.mergeFeature(Feature("sigv4a", true, listOf("aws-runtime/sigv4a"))) } @@ -185,7 +208,7 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: rustTemplate("#{SharedAuthScheme}::new(#{SigV4AuthScheme}::new())", *codegenScope) } - if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { + if (codegenContext.serviceShape.usesSigV4a()) { featureGateBlock("sigv4a") { section.registerAuthScheme(this) { rustTemplate("#{SharedAuthScheme}::new(#{SigV4aAuthScheme}::new())", *codegenScope) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt new file mode 100644 index 0000000000..5a9864a3ed --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt @@ -0,0 +1,110 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.rustsdk + +import software.amazon.smithy.model.knowledge.ServiceIndex +import software.amazon.smithy.model.traits.HttpBearerAuthTrait +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.configReexport +import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig +import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.core.rustlang.writable +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization +import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomization + +class TokenProvidersDecorator : ClientCodegenDecorator { + override val name: String get() = "TokenProvidersDecorator" + override val order: Byte = 0 + + private fun applies(codegenContext: ClientCodegenContext): Boolean = + ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) + .containsKey(HttpBearerAuthTrait.ID) + + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + if (applies(codegenContext)) { + baseCustomizations + TokenProviderConfig(codegenContext) + } else { + baseCustomizations + } + + override fun extraSections(codegenContext: ClientCodegenContext): List = + if (applies(codegenContext)) { + listOf( + adhocCustomization { section -> + rust("${section.serviceConfigBuilder}.set_token_provider(${section.sdkConfig}.token_provider());") + }, + ) + } else { + emptyList() + } +} + +/** + * Add a `.token_provider` field and builder to the `Config` for a given service + */ +class TokenProviderConfig(private val codegenContext: ClientCodegenContext) : ConfigCustomization() { + private val runtimeConfig = codegenContext.runtimeConfig + private val codegenScope = + arrayOf( + *RuntimeType.preludeScope, + "Token" to configReexport(AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("Token")), + "ProvideToken" to + configReexport( + AwsRuntimeType.awsCredentialTypes(runtimeConfig) + .resolve("provider::token::ProvideToken"), + ), + "SharedTokenProvider" to + configReexport( + AwsRuntimeType.awsCredentialTypes(runtimeConfig) + .resolve("provider::token::SharedTokenProvider"), + ), + "TestToken" to AwsRuntimeType.awsCredentialTypesTestUtil(runtimeConfig).resolve("Token"), + "HTTP_BEARER_AUTH_SCHEME_ID" to + CargoDependency.smithyRuntimeApiClient(runtimeConfig) + .withFeature("http-auth").toType().resolve("client::auth::http").resolve("HTTP_BEARER_AUTH_SCHEME_ID"), + ) + + override fun section(section: ServiceConfig) = + writable { + when (section) { + ServiceConfig.BuilderImpl -> { + rustTemplate( + """ + /// Sets the access token provider for this service + pub fn token_provider(mut self, token_provider: impl #{ProvideToken} + 'static) -> Self { + self.set_token_provider(#{Some}(#{SharedTokenProvider}::new(token_provider))); + self + } + + /// Sets the access token provider for this service + pub fn set_token_provider(&mut self, token_provider: #{Option}<#{SharedTokenProvider}>) -> &mut Self { + if let Some(token_provider) = token_provider { + self.runtime_components.set_identity_resolver(#{HTTP_BEARER_AUTH_SCHEME_ID}, token_provider); + } + self + } + """, + *codegenScope, + ) + } + + is ServiceConfig.DefaultForTests -> + rustTemplate( + "${section.configBuilderRef}.set_token_provider(Some(#{SharedTokenProvider}::new(#{TestToken}::for_tests())));", + *codegenScope, + ) + + else -> emptySection + } + } +} diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecoratorTest.kt new file mode 100644 index 0000000000..01ea19dc96 --- /dev/null +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecoratorTest.kt @@ -0,0 +1,75 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rustsdk + +import org.junit.jupiter.api.Test +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel +import software.amazon.smithy.rust.codegen.core.testutil.integrationTest +import software.amazon.smithy.rust.codegen.core.testutil.tokioTest + +class TokenProvidersDecoratorTest { + val model = + """ + namespace test + + use aws.api#service + use aws.protocols#restJson1 + use smithy.rules#endpointRuleSet + + @service(sdkId: "dontcare") + @restJson1 + @httpBearerAuth + @endpointRuleSet({ + "version": "1.0", + "rules": [{ "type": "endpoint", "conditions": [], "endpoint": { "url": "https://example.com" } }], + "parameters": { + "Region": { "required": false, "type": "String", "builtIn": "AWS::Region" }, + } + }) + service TestService { + version: "2023-01-01", + operations: [SomeOperation] + } + + structure SomeOutput { + someAttribute: Long, + someVal: String + } + + @http(uri: "/SomeOperation", method: "GET") + operation SomeOperation { + output: SomeOutput + } + """.asSmithyModel() + + @Test + fun `it adds token provider configuration`() { + awsSdkIntegrationTest(model) { ctx, rustCrate -> + rustCrate.integrationTest("token_providers") { + tokioTest("configuring_credentials_provider_at_operation_level_should_work") { + val moduleName = ctx.moduleUseName() + rustTemplate( + """ + // this should compile + let _ = $moduleName::Config::builder() + .token_provider(#{TestToken}::for_tests()) + .build(); + + // this should also compile + $moduleName::Config::builder() + .set_token_provider(Some(#{SharedTokenProvider}::new(#{TestToken}::for_tests()))); + """, + "TestToken" to AwsRuntimeType.awsCredentialTypesTestUtil(ctx.runtimeConfig).resolve("Token"), + "SharedTokenProvider" to + AwsRuntimeType.awsCredentialTypes(ctx.runtimeConfig) + .resolve("provider::token::SharedTokenProvider"), + ) + } + } + } + } +} diff --git a/aws/sdk/aws-models/codecatalyst.json b/aws/sdk/aws-models/codecatalyst.json new file mode 100644 index 0000000000..846a5a2ad0 --- /dev/null +++ b/aws/sdk/aws-models/codecatalyst.json @@ -0,0 +1,5574 @@ +{ + "smithy": "2.0", + "shapes": { + "com.amazonaws.codecatalyst#AccessDeniedException": { + "type": "structure", + "members": { + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

The request was denied because you don't have sufficient access to perform this action. Verify that you are a member of a role that allows this action.

", + "smithy.api#error": "client", + "smithy.api#httpError": 403 + } + }, + "com.amazonaws.codecatalyst#AccessToken": { + "type": "resource", + "identifiers": { + "accessTokenId": { + "target": "com.amazonaws.codecatalyst#AccessTokenId" + } + }, + "create": { + "target": "com.amazonaws.codecatalyst#CreateAccessToken" + }, + "delete": { + "target": "com.amazonaws.codecatalyst#DeleteAccessToken" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListAccessTokens" + } + }, + "com.amazonaws.codecatalyst#AccessTokenId": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 36 + } + } + }, + "com.amazonaws.codecatalyst#AccessTokenName": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 100 + } + } + }, + "com.amazonaws.codecatalyst#AccessTokenSecret": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 4000 + }, + "smithy.api#sensitive": {} + } + }, + "com.amazonaws.codecatalyst#AccessTokenSummaries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#AccessTokenSummary" + } + }, + "com.amazonaws.codecatalyst#AccessTokenSummary": { + "type": "structure", + "members": { + "id": { + "target": "com.amazonaws.codecatalyst#AccessTokenId", + "traits": { + "smithy.api#documentation": "

The system-generated ID of the personal access token.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "accessTokenId" + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#AccessTokenName", + "traits": { + "smithy.api#documentation": "

The friendly name of the personal access token.

", + "smithy.api#required": {} + } + }, + "expiresTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time when the personal access token will expire, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#timestampFormat": "date-time" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a specified personal access token (PAT).

" + } + }, + "com.amazonaws.codecatalyst#ClientToken": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 1024 + } + } + }, + "com.amazonaws.codecatalyst#CodeCatalyst": { + "type": "service", + "version": "2022-09-28", + "operations": [ + { + "target": "com.amazonaws.codecatalyst#GetUserDetails" + }, + { + "target": "com.amazonaws.codecatalyst#VerifySession" + } + ], + "resources": [ + { + "target": "com.amazonaws.codecatalyst#AccessToken" + }, + { + "target": "com.amazonaws.codecatalyst#Space" + } + ], + "errors": [ + { + "target": "com.amazonaws.codecatalyst#AccessDeniedException" + }, + { + "target": "com.amazonaws.codecatalyst#ConflictException" + }, + { + "target": "com.amazonaws.codecatalyst#ResourceNotFoundException" + }, + { + "target": "com.amazonaws.codecatalyst#ServiceQuotaExceededException" + }, + { + "target": "com.amazonaws.codecatalyst#ThrottlingException" + }, + { + "target": "com.amazonaws.codecatalyst#ValidationException" + } + ], + "traits": { + "aws.api#service": { + "sdkId": "CodeCatalyst", + "endpointPrefix": "codecatalyst" + }, + "aws.protocols#restJson1": {}, + "smithy.api#documentation": "

Welcome to the Amazon CodeCatalyst API reference. This reference provides descriptions of operations and data types for Amazon CodeCatalyst. You can use the Amazon CodeCatalyst \n API to work with the following objects.

\n

Spaces, by calling the following:

\n
    \n
  • \n

    \n DeleteSpace, which deletes a space.

    \n
  • \n
  • \n

    \n GetSpace, which returns information about a space.

    \n
  • \n
  • \n

    \n GetSubscription, which returns information about the Amazon Web Services account used for billing purposes \n and the billing plan for the space.

    \n
  • \n
  • \n

    \n ListSpaces, which retrieves a list of spaces.

    \n
  • \n
  • \n

    \n UpdateSpace, which changes one or more values for a space.

    \n
  • \n
\n

Projects, by calling the following:

\n
    \n
  • \n

    \n CreateProject which creates a project in a specified space.

    \n
  • \n
  • \n

    \n GetProject, which returns information about a project.

    \n
  • \n
  • \n

    \n ListProjects, which retrieves a list of projects in a space.

    \n
  • \n
\n

Users, by calling the following:

\n
    \n
  • \n

    \n GetUserDetails, which returns information about a user in Amazon CodeCatalyst.

    \n
  • \n
\n

Source repositories, by calling the following:

\n \n

Dev Environments and the Amazon Web Services Toolkits, by calling the following:

\n \n

Workflows, by calling the following:

\n
    \n
  • \n

    \n GetWorkflow, which returns information about a workflow.

    \n
  • \n
  • \n

    \n GetWorkflowRun, which returns information about a specified run of a workflow.

    \n
  • \n
  • \n

    \n ListWorkflowRuns, which retrieves a list of runs of a specified workflow.

    \n
  • \n
  • \n

    \n ListWorkflows, which retrieves a list of workflows in a specified project.

    \n
  • \n
  • \n

    \n StartWorkflowRun, which starts a run of a specified workflow.

    \n
  • \n
\n

Security, activity, and resource management in Amazon CodeCatalyst, by calling the following:

\n
    \n
  • \n

    \n CreateAccessToken, which creates a personal access token (PAT) for the current user.

    \n
  • \n
  • \n

    \n DeleteAccessToken, which deletes a specified personal access token (PAT).

    \n
  • \n
  • \n

    \n ListAccessTokens, which lists all personal access tokens (PATs) associated with a user.

    \n
  • \n
  • \n

    \n ListEventLogs, which retrieves a list of events that occurred during a specified time period in a space.

    \n
  • \n
  • \n

    \n VerifySession, which verifies whether the calling user has a valid Amazon CodeCatalyst login and session.

    \n
  • \n
\n \n

If you are using the Amazon CodeCatalyst APIs with an SDK or the CLI, you must configure your computer to work with Amazon CodeCatalyst and single sign-on (SSO).\n For more information, see Setting up to use the CLI with Amazon CodeCatalyst\n and the SSO documentation for your SDK.

\n
", + "smithy.api#httpBearerAuth": {}, + "smithy.api#title": "Amazon CodeCatalyst", + "smithy.rules#endpointRuleSet": { + "version": "1.0", + "parameters": { + "UseFIPS": { + "builtIn": "AWS::UseFIPS", + "required": true, + "default": false, + "documentation": "When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.", + "type": "Boolean" + }, + "Region": { + "builtIn": "AWS::Region", + "required": false, + "documentation": "The AWS region used to dispatch the request.", + "type": "String" + }, + "Endpoint": { + "builtIn": "SDK::Endpoint", + "required": false, + "documentation": "Override the endpoint used to send this request", + "type": "String" + } + }, + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + } + ], + "endpoint": { + "url": { + "ref": "Endpoint" + }, + "properties": {}, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Region" + } + ] + } + ] + }, + { + "fn": "aws.partition", + "argv": [ + "us-west-2" + ], + "assign": "PartitionResult" + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + }, + false + ] + } + ], + "error": "Partition does not support FIPS.", + "type": "error" + }, + { + "conditions": [], + "endpoint": { + "url": "https://codecatalyst-fips.global.{PartitionResult#dualStackDnsSuffix}", + "properties": {}, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "endpoint": { + "url": "https://codecatalyst.global.{PartitionResult#dualStackDnsSuffix}", + "properties": {}, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Region" + } + ] + }, + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "PartitionResult" + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + }, + false + ] + } + ], + "error": "Partition does not support FIPS.", + "type": "error" + }, + { + "conditions": [], + "endpoint": { + "url": "https://codecatalyst-fips.global.{PartitionResult#dualStackDnsSuffix}", + "properties": {}, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "endpoint": { + "url": "https://codecatalyst.global.{PartitionResult#dualStackDnsSuffix}", + "properties": {}, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + } + ] + }, + "smithy.rules#endpointTests": { + "version": "1", + "testCases": [ + { + "documentation": "Override endpoint", + "expect": { + "endpoint": { + "url": "https://test.codecatalyst.global.api.aws" + } + }, + "params": { + "Endpoint": "https://test.codecatalyst.global.api.aws" + } + }, + { + "documentation": "Default endpoint (region not set)", + "expect": { + "endpoint": { + "url": "https://codecatalyst.global.api.aws" + } + }, + "params": {} + }, + { + "documentation": "Default FIPS endpoint (region not set)", + "expect": { + "endpoint": { + "url": "https://codecatalyst-fips.global.api.aws" + } + }, + "params": { + "UseFIPS": true + } + }, + { + "documentation": "Default endpoint (region: aws-global)", + "expect": { + "endpoint": { + "url": "https://codecatalyst.global.api.aws" + } + }, + "params": { + "Region": "aws-global" + } + }, + { + "documentation": "Default FIPS endpoint (region: aws-global)", + "expect": { + "endpoint": { + "url": "https://codecatalyst-fips.global.api.aws" + } + }, + "params": { + "Region": "aws-global", + "UseFIPS": true + } + }, + { + "documentation": "Default endpoint for a valid home region (region: us-west-2)", + "expect": { + "endpoint": { + "url": "https://codecatalyst.global.api.aws" + } + }, + "params": { + "Region": "us-west-2" + } + }, + { + "documentation": "Default FIPS endpoint for a valid home region (region: us-west-2)", + "expect": { + "endpoint": { + "url": "https://codecatalyst-fips.global.api.aws" + } + }, + "params": { + "Region": "us-west-2", + "UseFIPS": true + } + }, + { + "documentation": "Default endpoint for an unavailable home region (region: us-east-1)", + "expect": { + "endpoint": { + "url": "https://codecatalyst.global.api.aws" + } + }, + "params": { + "Region": "us-east-1" + } + }, + { + "documentation": "Default FIPS endpoint for an unavailable home region (region: us-east-1)", + "expect": { + "endpoint": { + "url": "https://codecatalyst-fips.global.api.aws" + } + }, + "params": { + "Region": "us-east-1", + "UseFIPS": true + } + } + ] + } + } + }, + "com.amazonaws.codecatalyst#ComparisonOperator": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "EQUALS", + "value": "EQ" + }, + { + "name": "GREATER_THAN", + "value": "GT" + }, + { + "name": "GREATER_THAN_OR_EQUALS", + "value": "GE" + }, + { + "name": "LESS_THAN", + "value": "LT" + }, + { + "name": "LESS_THAN_OR_EQUALS", + "value": "LE" + }, + { + "name": "BEGINS_WITH", + "value": "BEGINS_WITH" + } + ] + } + }, + "com.amazonaws.codecatalyst#ConflictException": { + "type": "structure", + "members": { + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

The request was denied because the requested operation would cause a conflict with the current state of a service resource associated with the request. \n Another user might have updated the resource. Reload, make sure you have the latest data, and then try again.

", + "smithy.api#error": "client", + "smithy.api#httpError": 409 + } + }, + "com.amazonaws.codecatalyst#CreateAccessToken": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#CreateAccessTokenRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#CreateAccessTokenResponse" + }, + "traits": { + "smithy.api#documentation": "

Creates a personal access token (PAT) for the current user. A personal access token (PAT) is similar to a password. \n It is associated with your user identity for use across all spaces and projects in Amazon CodeCatalyst. You use PATs to access CodeCatalyst \n from resources that include integrated development environments (IDEs) and Git-based source repositories. \n PATs represent you in Amazon CodeCatalyst and you can manage them in your user settings.For more information, see \n Managing personal access tokens in Amazon CodeCatalyst.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/accessTokens", + "code": 201 + } + } + }, + "com.amazonaws.codecatalyst#CreateAccessTokenRequest": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#AccessTokenName", + "traits": { + "smithy.api#documentation": "

The friendly name of the personal access token.

", + "smithy.api#required": {} + } + }, + "expiresTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the personal access token expires, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#timestampFormat": "date-time" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateAccessTokenResponse": { + "type": "structure", + "members": { + "secret": { + "target": "com.amazonaws.codecatalyst#AccessTokenSecret", + "traits": { + "smithy.api#documentation": "

The secret value of the personal access token.

", + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#AccessTokenName", + "traits": { + "smithy.api#documentation": "

The friendly name of the personal access token.

", + "smithy.api#required": {} + } + }, + "expiresTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the personal access token expires, in coordinated universal time (UTC) timestamp format as specified in RFC 3339. If not specified, the default is one year from creation.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "accessTokenId": { + "target": "com.amazonaws.codecatalyst#AccessTokenId", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the access token.

", + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#CreateDevEnvironment": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#CreateDevEnvironmentRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#CreateDevEnvironmentResponse" + }, + "traits": { + "smithy.api#documentation": "

Creates a Dev Environment in Amazon CodeCatalyst, a cloud-based development environment that you can use to quickly work on the code stored \n in the source repositories of your project.

\n \n

When created in the Amazon CodeCatalyst console, by default a Dev Environment is configured to have a 2 core processor, 4GB of RAM, and 16GB of persistent storage. None of these\n defaults apply to a Dev Environment created programmatically.

\n
", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments", + "code": 201 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#CreateDevEnvironmentRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "repositories": { + "target": "com.amazonaws.codecatalyst#RepositoriesInput", + "traits": { + "smithy.api#documentation": "

The source repository that contains the branch to clone into the Dev Environment.

" + } + }, + "clientToken": { + "target": "com.amazonaws.codecatalyst#ClientToken", + "traits": { + "smithy.api#documentation": "

A user-specified idempotency token. Idempotency ensures that an API request completes only once. \n With an idempotent request, if the original request completes successfully, the subsequent retries return the result from the original successful request and have no additional effect.

" + } + }, + "alias": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The user-defined alias for a Dev Environment.

", + "smithy.api#length": { + "min": 1, + "max": 128 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_\\.][a-zA-Z0-9]+)*$" + } + }, + "ides": { + "target": "com.amazonaws.codecatalyst#IdeConfigurationList", + "traits": { + "smithy.api#documentation": "

Information about the integrated development environment (IDE) configured for a\n Dev Environment.

\n \n

An IDE is required to create a Dev Environment. For Dev Environment creation, this field\n contains configuration information and must be provided.

\n
" + } + }, + "instanceType": { + "target": "com.amazonaws.codecatalyst#InstanceType", + "traits": { + "smithy.api#documentation": "

The Amazon EC2 instace type to use for the Dev Environment.

", + "smithy.api#required": {} + } + }, + "inactivityTimeoutMinutes": { + "target": "com.amazonaws.codecatalyst#InactivityTimeoutMinutes", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

The amount of time the Dev Environment will run without any activity detected before stopping, in minutes. Only whole integers are allowed. Dev Environments consume compute minutes when running.

" + } + }, + "persistentStorage": { + "target": "com.amazonaws.codecatalyst#PersistentStorageConfiguration", + "traits": { + "smithy.api#documentation": "

Information about the amount of storage allocated to the Dev Environment.

\n \n

By default, a Dev Environment is configured to have 16GB of persistent storage when created from the Amazon CodeCatalyst console, but there is no default when programmatically\n creating a Dev Environment. \n Valid values for persistent storage are based on memory sizes in 16GB increments. Valid\n values are 16, 32, and 64.

\n
", + "smithy.api#required": {} + } + }, + "vpcConnectionName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the connection to use connect to a Amazon VPC.

" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateDevEnvironmentResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "vpcConnectionName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the connection used to connect to Amazon VPC used when the Dev Environment was created, if any.

" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateProject": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#CreateProjectRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#CreateProjectResponse" + }, + "traits": { + "smithy.api#documentation": "

Creates a project in a specified space.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects", + "code": 201 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#CreateProjectRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "displayName": { + "target": "com.amazonaws.codecatalyst#ProjectDisplayName", + "traits": { + "smithy.api#documentation": "

The friendly name of the project that will be displayed to users.

", + "smithy.api#required": {} + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#ProjectDescription", + "traits": { + "smithy.api#documentation": "

The description of the project. This description will be displayed to all users of the project. We recommend providing a brief description of the project and its intended purpose.

" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateProjectResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

" + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "projectName" + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the project.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the project.

" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateSourceRepository": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#CreateSourceRepositoryRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#CreateSourceRepositoryResponse" + }, + "traits": { + "smithy.api#documentation": "

Creates an empty Git-based source repository in a specified project. The repository is\n created with an initial empty commit with a default branch named main.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories/{name}", + "code": 201 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#CreateSourceRepositoryBranch": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#CreateSourceRepositoryBranchRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#CreateSourceRepositoryBranchResponse" + }, + "traits": { + "smithy.api#documentation": "

Creates a branch in a specified source repository in Amazon CodeCatalyst.

\n \n

This API only creates a branch in a source repository hosted in Amazon CodeCatalyst. You cannot use this API to create a branch in a linked repository.

\n
", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories/{sourceRepositoryName}/branches/{name}", + "code": 201 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#CreateSourceRepositoryBranchRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the repository where you want to create a branch.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name for the branch you're creating.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "sourceRepositoryBranchName" + } + }, + "headCommitId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The commit ID in an existing branch from which you want to create the new branch.

" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateSourceRepositoryBranchResponse": { + "type": "structure", + "members": { + "ref": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchRefString", + "traits": { + "smithy.api#documentation": "

The Git reference name of the branch.

" + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name of the newly created branch.

" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the branch was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#timestampFormat": "date-time" + } + }, + "headCommitId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The commit ID of the tip of the newly created branch.

" + } + } + } + }, + "com.amazonaws.codecatalyst#CreateSourceRepositoryRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository. For more information about name requirements, see Quotas for source repositories.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "sourceRepositoryName" + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryDescriptionString", + "traits": { + "smithy.api#documentation": "

The description of the source repository.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#CreateSourceRepositoryResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#required": {} + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryDescriptionString", + "traits": { + "smithy.api#documentation": "

The description of the source repository.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#DeleteAccessToken": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#DeleteAccessTokenRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#DeleteAccessTokenResponse" + }, + "traits": { + "smithy.api#documentation": "

Deletes a specified personal access token (PAT). A personal access token can only be deleted by the user who created it.

", + "smithy.api#http": { + "method": "DELETE", + "uri": "/v1/accessTokens/{id}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#DeleteAccessTokenRequest": { + "type": "structure", + "members": { + "id": { + "target": "com.amazonaws.codecatalyst#AccessTokenId", + "traits": { + "smithy.api#documentation": "

The ID of the personal access token to delete. You can find the IDs of all PATs associated with your Amazon Web Services Builder ID in a space by calling ListAccessTokens.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "accessTokenId" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#DeleteAccessTokenResponse": { + "type": "structure", + "members": {}, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#DeleteDevEnvironment": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#DeleteDevEnvironmentRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#DeleteDevEnvironmentResponse" + }, + "traits": { + "smithy.api#documentation": "

Deletes a Dev Environment.

", + "smithy.api#http": { + "method": "DELETE", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#DeleteDevEnvironmentRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment you want to delete. To retrieve a list of Dev Environment IDs, use ListDevEnvironments.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + } + } + }, + "com.amazonaws.codecatalyst#DeleteDevEnvironmentResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the deleted Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + } + } + }, + "com.amazonaws.codecatalyst#DeleteProject": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#DeleteProjectRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#DeleteProjectResponse" + }, + "traits": { + "smithy.api#documentation": "

Deletes a project in a space.

", + "smithy.api#http": { + "method": "DELETE", + "uri": "/v1/spaces/{spaceName}/projects/{name}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#DeleteProjectRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space. To retrieve a list of project names, use ListProjects.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "projectName" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#DeleteProjectResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "projectName" + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name displayed to users of the project in Amazon CodeCatalyst.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#DeleteSourceRepository": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#DeleteSourceRepositoryRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#DeleteSourceRepositoryResponse" + }, + "traits": { + "smithy.api#documentation": "

Deletes a source repository in Amazon CodeCatalyst. You cannot use this API to delete a linked repository. It can only be used to delete a Amazon CodeCatalyst source repository.

", + "smithy.api#http": { + "method": "DELETE", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories/{name}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#DeleteSourceRepositoryRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "sourceRepositoryName" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#DeleteSourceRepositoryResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the repository.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#DeleteSpace": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#DeleteSpaceRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#DeleteSpaceResponse" + }, + "traits": { + "smithy.api#documentation": "

Deletes a space.

\n \n

Deleting a space cannot be undone. Additionally, since space names must be unique across Amazon CodeCatalyst, you cannot reuse names of deleted spaces.

\n
", + "smithy.api#http": { + "method": "DELETE", + "uri": "/v1/spaces/{name}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#DeleteSpaceRequest": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space. To retrieve a list of space names, use ListSpaces.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "spaceName" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#DeleteSpaceResponse": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "spaceName" + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the space displayed to users of the space in Amazon CodeCatalyst.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#DevEnvironment": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "devEnvironmentId": { + "target": "com.amazonaws.codecatalyst#Uuid" + } + }, + "create": { + "target": "com.amazonaws.codecatalyst#CreateDevEnvironment" + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetDevEnvironment" + }, + "update": { + "target": "com.amazonaws.codecatalyst#UpdateDevEnvironment" + }, + "delete": { + "target": "com.amazonaws.codecatalyst#DeleteDevEnvironment" + }, + "operations": [ + { + "target": "com.amazonaws.codecatalyst#ListDevEnvironmentSessions" + }, + { + "target": "com.amazonaws.codecatalyst#StartDevEnvironment" + }, + { + "target": "com.amazonaws.codecatalyst#StartDevEnvironmentSession" + }, + { + "target": "com.amazonaws.codecatalyst#StopDevEnvironment" + }, + { + "target": "com.amazonaws.codecatalyst#StopDevEnvironmentSession" + } + ] + }, + "com.amazonaws.codecatalyst#DevEnvironmentAccessDetails": { + "type": "structure", + "members": { + "streamUrl": { + "target": "com.amazonaws.codecatalyst#SensitiveString", + "traits": { + "smithy.api#documentation": "

The URL used to send commands to and from the Dev Environment.

", + "smithy.api#required": {} + } + }, + "tokenValue": { + "target": "com.amazonaws.codecatalyst#SensitiveString", + "traits": { + "smithy.api#documentation": "

An encrypted token value that contains session and caller information used to authenticate the connection.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about connection details for a Dev Environment.

", + "smithy.api#sensitive": {} + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentRepositorySummaries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentRepositorySummary" + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentRepositorySummary": { + "type": "structure", + "members": { + "repositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#required": {} + } + }, + "branchName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name of the branch in a source repository cloned into the Dev Environment.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the source repsitory for a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentSessionConfiguration": { + "type": "structure", + "members": { + "sessionType": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentSessionType", + "traits": { + "smithy.api#documentation": "

The type of the session.

", + "smithy.api#required": {} + } + }, + "executeCommandSessionConfiguration": { + "target": "com.amazonaws.codecatalyst#ExecuteCommandSessionConfiguration", + "traits": { + "smithy.api#documentation": "

Information about optional commands that will be run on the Dev Environment when the SSH session begins.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the configuration of a Dev Environment session.

" + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentSessionSummary": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "devEnvironmentId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "startedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the session started, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "id": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment session.

", + "smithy.api#length": { + "min": 1, + "max": 96 + }, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about active sessions for a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentSessionType": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "SSM", + "value": "SSM" + }, + { + "name": "SSH", + "value": "SSH" + } + ] + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentSessionsSummaryList": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentSessionSummary" + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentStatus": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "PENDING", + "value": "PENDING" + }, + { + "name": "RUNNING", + "value": "RUNNING" + }, + { + "name": "STARTING", + "value": "STARTING" + }, + { + "name": "STOPPING", + "value": "STOPPING" + }, + { + "name": "STOPPED", + "value": "STOPPED" + }, + { + "name": "FAILED", + "value": "FAILED" + }, + { + "name": "DELETING", + "value": "DELETING" + }, + { + "name": "DELETED", + "value": "DELETED" + } + ] + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentSummary": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

" + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

" + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID for the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time when the Dev Environment was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "creatorId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the user who created the Dev Environment.

", + "smithy.api#length": { + "max": 1024 + }, + "smithy.api#required": {} + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentStatus", + "traits": { + "smithy.api#documentation": "

The status of the Dev Environment.

", + "smithy.api#required": {} + } + }, + "statusReason": { + "target": "com.amazonaws.codecatalyst#StatusReason", + "traits": { + "smithy.api#documentation": "

The reason for the status.

" + } + }, + "repositories": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentRepositorySummaries", + "traits": { + "smithy.api#documentation": "

Information about the repositories that will be cloned into the Dev Environment. If no rvalue is specified, no repository is cloned.

", + "smithy.api#required": {} + } + }, + "alias": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The user-specified alias for the Dev Environment.

", + "smithy.api#length": { + "max": 128 + } + } + }, + "ides": { + "target": "com.amazonaws.codecatalyst#Ides", + "traits": { + "smithy.api#documentation": "

Information about the integrated development environment (IDE) configured for a Dev Environment.

" + } + }, + "instanceType": { + "target": "com.amazonaws.codecatalyst#InstanceType", + "traits": { + "smithy.api#documentation": "

The Amazon EC2 instace type used for the Dev Environment.

", + "smithy.api#required": {} + } + }, + "inactivityTimeoutMinutes": { + "target": "com.amazonaws.codecatalyst#InactivityTimeoutMinutes", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

The amount of time the Dev Environment will run without any activity detected before stopping, in minutes. Dev Environments consume compute minutes when running.

", + "smithy.api#required": {} + } + }, + "persistentStorage": { + "target": "com.amazonaws.codecatalyst#PersistentStorage", + "traits": { + "smithy.api#documentation": "

Information about the configuration of persistent storage for the Dev Environment.

", + "smithy.api#required": {} + } + }, + "vpcConnectionName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the connection used to connect to Amazon VPC used when the Dev Environment was created, if any.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#DevEnvironmentSummaryList": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentSummary" + } + }, + "com.amazonaws.codecatalyst#EmailAddress": { + "type": "structure", + "members": { + "email": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The email address.

" + } + }, + "verified": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "

Whether the email address has been verified.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about an email address.

" + } + }, + "com.amazonaws.codecatalyst#EventLogEntries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#EventLogEntry" + } + }, + "com.amazonaws.codecatalyst#EventLogEntry": { + "type": "structure", + "members": { + "id": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the event.

", + "smithy.api#required": {} + } + }, + "eventName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the event.

", + "smithy.api#required": {} + } + }, + "eventType": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The type of the event.

", + "smithy.api#required": {} + } + }, + "eventCategory": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The category for the event.

", + "smithy.api#required": {} + } + }, + "eventSource": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The source of the event.

", + "smithy.api#required": {} + } + }, + "eventTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the event took place, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "operationType": { + "target": "com.amazonaws.codecatalyst#OperationType", + "traits": { + "smithy.api#documentation": "

The type of the event.

", + "smithy.api#required": {} + } + }, + "userIdentity": { + "target": "com.amazonaws.codecatalyst#UserIdentity", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the user whose actions are recorded in the event.

", + "smithy.api#required": {} + } + }, + "projectInformation": { + "target": "com.amazonaws.codecatalyst#ProjectInformation", + "traits": { + "smithy.api#documentation": "

Information about the project where the event occurred.

" + } + }, + "requestId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the request.

" + } + }, + "requestPayload": { + "target": "com.amazonaws.codecatalyst#EventPayload", + "traits": { + "smithy.api#documentation": "

Information about the payload of the request.

" + } + }, + "responsePayload": { + "target": "com.amazonaws.codecatalyst#EventPayload", + "traits": { + "smithy.api#documentation": "

Information about the payload of the response, if any.

" + } + }, + "errorCode": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The code of the error, if any.

" + } + }, + "sourceIpAddress": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The IP address of the user whose actions are recorded in the event.

" + } + }, + "userAgent": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The user agent whose actions are recorded in the event.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about an entry in an event log of Amazon CodeCatalyst activity.

" + } + }, + "com.amazonaws.codecatalyst#EventLogResource": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "eventLogId": { + "target": "smithy.api#String" + } + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListEventLogs" + } + }, + "com.amazonaws.codecatalyst#EventPayload": { + "type": "structure", + "members": { + "contentType": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The type of content in the event payload.

" + } + }, + "data": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The data included in the event payload.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the payload of an event recording Amazon CodeCatalyst activity.

" + } + }, + "com.amazonaws.codecatalyst#ExecuteCommandSessionConfiguration": { + "type": "structure", + "members": { + "command": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The command used at the beginning of the SSH session to a Dev Environment.

", + "smithy.api#length": { + "min": 1, + "max": 255 + }, + "smithy.api#required": {} + } + }, + "arguments": { + "target": "com.amazonaws.codecatalyst#ExecuteCommandSessionConfigurationArguments", + "traits": { + "smithy.api#documentation": "

An array of arguments containing arguments and members.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the commands that will be run on a Dev Environment when an SSH session begins.

" + } + }, + "com.amazonaws.codecatalyst#ExecuteCommandSessionConfigurationArguments": { + "type": "list", + "member": { + "target": "smithy.api#String", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 255 + } + } + } + }, + "com.amazonaws.codecatalyst#Filter": { + "type": "structure", + "members": { + "key": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A key that can be used to sort results.

", + "smithy.api#required": {} + } + }, + "values": { + "target": "com.amazonaws.codecatalyst#StringList", + "traits": { + "smithy.api#documentation": "

The values of the key.

", + "smithy.api#required": {} + } + }, + "comparisonOperator": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The operator used to compare the fields.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a filter used to limit results of a query.

" + } + }, + "com.amazonaws.codecatalyst#FilterKey": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "HAS_ACCESS_TO", + "value": "hasAccessTo" + }, + { + "name": "NAME", + "value": "name" + } + ] + } + }, + "com.amazonaws.codecatalyst#Filters": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#Filter" + } + }, + "com.amazonaws.codecatalyst#GetDevEnvironment": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetDevEnvironmentRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetDevEnvironmentResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about a Dev Environment for a source repository in a project. Dev Environments are specific to the user who creates them.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetDevEnvironmentRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment for which you want to view information. To retrieve a list of Dev Environment IDs, use ListDevEnvironments.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + } + } + }, + "com.amazonaws.codecatalyst#GetDevEnvironmentResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time when the Dev Environment was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "creatorId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the user who created the Dev Environment.

", + "smithy.api#length": { + "max": 1024 + }, + "smithy.api#required": {} + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentStatus", + "traits": { + "smithy.api#documentation": "

The current status of the Dev Environment.

", + "smithy.api#required": {} + } + }, + "statusReason": { + "target": "com.amazonaws.codecatalyst#StatusReason", + "traits": { + "smithy.api#documentation": "

The reason for the status.

" + } + }, + "repositories": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentRepositorySummaries", + "traits": { + "smithy.api#documentation": "

The source repository that contains the branch cloned into the Dev Environment.

", + "smithy.api#required": {} + } + }, + "alias": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The user-specified alias for the Dev Environment.

", + "smithy.api#length": { + "max": 128 + } + } + }, + "ides": { + "target": "com.amazonaws.codecatalyst#Ides", + "traits": { + "smithy.api#documentation": "

Information about the integrated development environment (IDE) configured for the Dev Environment.

" + } + }, + "instanceType": { + "target": "com.amazonaws.codecatalyst#InstanceType", + "traits": { + "smithy.api#documentation": "

The Amazon EC2 instace type to use for the Dev Environment.

", + "smithy.api#required": {} + } + }, + "inactivityTimeoutMinutes": { + "target": "com.amazonaws.codecatalyst#InactivityTimeoutMinutes", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

The amount of time the Dev Environment will run without any activity detected before stopping, in minutes.

", + "smithy.api#required": {} + } + }, + "persistentStorage": { + "target": "com.amazonaws.codecatalyst#PersistentStorage", + "traits": { + "smithy.api#documentation": "

Information about the amount of storage allocated to the Dev Environment. By default, a Dev Environment is configured to have 16GB of persistent storage.

", + "smithy.api#required": {} + } + }, + "vpcConnectionName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the connection used to connect to Amazon VPC used when the Dev Environment was created, if any.

" + } + } + } + }, + "com.amazonaws.codecatalyst#GetProject": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetProjectRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetProjectResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about a project.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/projects/{name}", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetProjectRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "projectName" + } + } + } + }, + "com.amazonaws.codecatalyst#GetProjectResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

" + } + }, + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the project displayed to users in Amazon CodeCatalyst.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the project.

" + } + } + } + }, + "com.amazonaws.codecatalyst#GetSourceRepository": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetSourceRepositoryRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetSourceRepositoryResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about a source repository.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories/{name}", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetSourceRepositoryCloneUrls": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetSourceRepositoryCloneUrlsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetSourceRepositoryCloneUrlsResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about the URLs that can be used with a Git client to clone a source\n repository.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories/{sourceRepositoryName}/cloneUrls", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetSourceRepositoryCloneUrlsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#GetSourceRepositoryCloneUrlsResponse": { + "type": "structure", + "members": { + "https": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The HTTPS URL to use when cloning the source repository.

", + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#GetSourceRepositoryRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "sourceRepositoryName" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#GetSourceRepositoryResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#required": {} + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryDescriptionString", + "traits": { + "smithy.api#documentation": "

The description of the source repository.

" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the source repository was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {} + } + }, + "createdTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the source repository was created, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#GetSpace": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetSpaceRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetSpaceResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about an space.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{name}", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetSpaceRequest": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "spaceName" + } + } + } + }, + "com.amazonaws.codecatalyst#GetSpaceResponse": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "regionName": { + "target": "com.amazonaws.codecatalyst#RegionString", + "traits": { + "smithy.api#documentation": "

The Amazon Web Services Region where the space exists.

", + "smithy.api#required": {} + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the space displayed to users.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the space.

" + } + } + } + }, + "com.amazonaws.codecatalyst#GetSubscription": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetSubscriptionRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetSubscriptionResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about the Amazon Web Services account used for billing purposes \n and the billing plan for the space.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/subscription", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetSubscriptionRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#GetSubscriptionResponse": { + "type": "structure", + "members": { + "subscriptionType": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The type of the billing plan for the space.

" + } + }, + "awsAccountName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The display name of the Amazon Web Services account used for billing for the space.

" + } + } + } + }, + "com.amazonaws.codecatalyst#GetUserDetails": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetUserDetailsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetUserDetailsResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about a user.

", + "smithy.api#http": { + "method": "GET", + "uri": "/userDetails", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetUserDetailsRequest": { + "type": "structure", + "members": { + "id": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the user.

", + "smithy.api#httpQuery": "id", + "smithy.api#length": { + "min": 1, + "max": 256 + } + } + }, + "userName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the user as displayed in Amazon CodeCatalyst.

", + "smithy.api#httpQuery": "userName", + "smithy.api#length": { + "min": 3, + "max": 100 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]{3,100}$" + } + } + } + }, + "com.amazonaws.codecatalyst#GetUserDetailsResponse": { + "type": "structure", + "members": { + "userId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the user.

" + } + }, + "userName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the user as displayed in Amazon CodeCatalyst.

" + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name displayed for the user in Amazon CodeCatalyst.

" + } + }, + "primaryEmail": { + "target": "com.amazonaws.codecatalyst#EmailAddress", + "traits": { + "smithy.api#documentation": "

The email address provided by the user when they signed up.

" + } + }, + "version": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

" + } + } + } + }, + "com.amazonaws.codecatalyst#GetWorkflow": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetWorkflowRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetWorkflowResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about a workflow.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/workflows/{id}", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetWorkflowRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The ID of the workflow. To rerieve a list of workflow IDs, use ListWorkflows.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "workflowId" + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1 + }, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#GetWorkflowResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The ID of the workflow.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "workflowId" + } + }, + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the workflow.

", + "smithy.api#required": {} + } + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository where the workflow YAML is stored.

" + } + }, + "sourceBranchName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name of the branch that contains the workflow YAML.

" + } + }, + "definition": { + "target": "com.amazonaws.codecatalyst#WorkflowDefinition", + "traits": { + "smithy.api#documentation": "

Information about the workflow definition file for the workflow.

", + "smithy.api#required": {} + } + }, + "createdTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow was created, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "runMode": { + "target": "com.amazonaws.codecatalyst#WorkflowRunMode", + "traits": { + "smithy.api#documentation": "

The behavior to use when multiple workflows occur at the same time. For more information, see \n https://docs.aws.amazon.com/codecatalyst/latest/userguide/workflows-configure-runs.html in the Amazon CodeCatalyst User Guide.

", + "smithy.api#required": {} + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#WorkflowStatus", + "traits": { + "smithy.api#documentation": "

The status of the workflow.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#GetWorkflowRun": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#GetWorkflowRunRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#GetWorkflowRunResponse" + }, + "traits": { + "smithy.api#documentation": "

Returns information about a specified run of a workflow.

", + "smithy.api#http": { + "method": "GET", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/workflowRuns/{id}", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#GetWorkflowRunRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The ID of the workflow run. To retrieve a list of workflow run IDs, use ListWorkflowRuns.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "workflowRunId" + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1 + }, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#GetWorkflowRunResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The ID of the workflow run.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "workflowRunId" + } + }, + "workflowId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The ID of the workflow.

", + "smithy.api#required": {} + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#WorkflowRunStatus", + "traits": { + "smithy.api#documentation": "

The status of the workflow run.

", + "smithy.api#required": {} + } + }, + "statusReasons": { + "target": "com.amazonaws.codecatalyst#WorkflowRunStatusReasons", + "traits": { + "smithy.api#documentation": "

Information about the reasons for the status of the workflow run.

" + } + }, + "startTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow run began, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "endTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow run ended, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#timestampFormat": "date-time" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow run status was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#Ide": { + "type": "structure", + "members": { + "runtime": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A link to the IDE runtime image.

", + "smithy.api#length": { + "min": 1, + "max": 400 + } + } + }, + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the IDE.

", + "smithy.api#length": { + "min": 1, + "max": 128 + } + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about an integrated development environment (IDE) used in a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#IdeConfiguration": { + "type": "structure", + "members": { + "runtime": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A link to the IDE runtime image.

\n \n

This parameter is not required for VSCode.

\n
", + "smithy.api#length": { + "min": 1, + "max": 400 + } + } + }, + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the IDE. Valid values include Cloud9, IntelliJ, PyCharm, GoLand, and VSCode.

", + "smithy.api#length": { + "min": 1, + "max": 128 + } + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the configuration of an integrated development environment (IDE) for a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#IdeConfigurationList": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#IdeConfiguration" + }, + "traits": { + "smithy.api#length": { + "min": 0, + "max": 1 + } + } + }, + "com.amazonaws.codecatalyst#Ides": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#Ide" + }, + "traits": { + "smithy.api#length": { + "min": 0, + "max": 1 + } + } + }, + "com.amazonaws.codecatalyst#InactivityTimeoutMinutes": { + "type": "integer", + "traits": { + "smithy.api#default": 0, + "smithy.api#range": { + "min": 0, + "max": 1200 + } + } + }, + "com.amazonaws.codecatalyst#InstanceType": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "DEV_STANDARD1_SMALL", + "value": "dev.standard1.small" + }, + { + "name": "DEV_STANDARD1_MEDIUM", + "value": "dev.standard1.medium" + }, + { + "name": "DEV_STANDARD1_LARGE", + "value": "dev.standard1.large" + }, + { + "name": "DEV_STANDARD1_XLARGE", + "value": "dev.standard1.xlarge" + } + ] + } + }, + "com.amazonaws.codecatalyst#ListAccessTokens": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListAccessTokensRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListAccessTokensResponse" + }, + "traits": { + "smithy.api#documentation": "

Lists all personal access tokens (PATs) associated with the user who calls the API. You can only list PATs associated with your Amazon Web Services Builder ID.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/accessTokens", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListAccessTokensRequest": { + "type": "structure", + "members": { + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "max": 10 + } + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#ListAccessTokensResponse": { + "type": "structure", + "members": { + "items": { + "target": "com.amazonaws.codecatalyst#AccessTokenSummaries", + "traits": { + "smithy.api#documentation": "

A list of personal access tokens (PATs) associated with the calling user identity.

", + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#ListDevEnvironmentSessions": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListDevEnvironmentSessionsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListDevEnvironmentSessionsResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of active sessions for a Dev Environment in a project.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{devEnvironmentId}/sessions", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListDevEnvironmentSessionsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "devEnvironmentId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "min": 1, + "max": 200 + } + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#ListDevEnvironmentSessionsResponse": { + "type": "structure", + "members": { + "items": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentSessionsSummaryList", + "traits": { + "smithy.api#documentation": "

Information about each session retrieved in the list.

", + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#ListDevEnvironments": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListDevEnvironmentsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListDevEnvironmentsResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of Dev Environments in a project.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/devEnvironments", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListDevEnvironmentsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

" + } + }, + "filters": { + "target": "com.amazonaws.codecatalyst#Filters", + "traits": { + "smithy.api#documentation": "

Information about filters to apply to narrow the results returned in the list.

" + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "min": 1, + "max": 50 + } + } + } + } + }, + "com.amazonaws.codecatalyst#ListDevEnvironmentsResponse": { + "type": "structure", + "members": { + "items": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentSummaryList", + "traits": { + "smithy.api#documentation": "

Information about the Dev Environments in a project.

", + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + } + } + }, + "com.amazonaws.codecatalyst#ListEventLogs": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListEventLogsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListEventLogsResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of events that occurred during a specific time in a space. You can\n use these events to audit user and system activity in a space. For more information, see\n Monitoring in the Amazon CodeCatalyst User Guide.

\n \n

ListEventLogs guarantees events for the last 30 days in a given space. You can also\n view and retrieve a list of management events over the last 90 days for Amazon CodeCatalyst in the\n CloudTrail console by viewing Event history, or by creating a trail to create\n and maintain a record of events that extends past 90 days. For more information, see Working with CloudTrail Event History and Working with\n CloudTrail trails.

\n
", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/eventLogs", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListEventLogsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "startTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time when you want to start retrieving events, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "endTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time after which you do not want any events retrieved, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "eventName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the event.

" + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "min": 1, + "max": 250 + } + } + } + } + }, + "com.amazonaws.codecatalyst#ListEventLogsResponse": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + }, + "items": { + "target": "com.amazonaws.codecatalyst#EventLogEntries", + "traits": { + "smithy.api#documentation": "

Information about each event retrieved in the list.

", + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#ListProjects": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListProjectsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListProjectsResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of projects.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/projects", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListProjectsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "min": 1, + "max": 100 + } + } + }, + "filters": { + "target": "com.amazonaws.codecatalyst#ProjectListFilters", + "traits": { + "smithy.api#documentation": "

Information about filters to apply to narrow the results returned in the list.

" + } + } + } + }, + "com.amazonaws.codecatalyst#ListProjectsResponse": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + }, + "items": { + "target": "com.amazonaws.codecatalyst#ProjectSummaries", + "traits": { + "smithy.api#documentation": "

Information about the projects.

" + } + } + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositories": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoriesRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoriesResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of source repositories in a project.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoriesItem": { + "type": "structure", + "members": { + "id": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryIdString", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the source repository.

", + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#required": {} + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryDescriptionString", + "traits": { + "smithy.api#documentation": "

The description of the repository, if any.

" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the source repository was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {} + } + }, + "createdTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the source repository was created, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a source repository returned in a list of source repositories.

" + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoriesItems": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoriesItem" + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoriesRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "min": 1, + "max": 200 + } + } + } + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoriesResponse": { + "type": "structure", + "members": { + "items": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoriesItems", + "traits": { + "smithy.api#documentation": "

Information about the source repositories.

" + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + } + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoryBranches": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of branches in a specified source repository.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/sourceRepositories/{sourceRepositoryName}/branches", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesItem": { + "type": "structure", + "members": { + "ref": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchRefString", + "traits": { + "smithy.api#documentation": "

The Git reference name of the branch.

" + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name of the branch.

" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The time the branch was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#timestampFormat": "date-time" + } + }, + "headCommitId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The commit ID of the tip of the branch at the time of the request, also known as the head commit.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a branch of a source repository returned in a list of branches.

" + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesItems": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesItem" + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#range": { + "min": 1, + "max": 50 + } + } + } + } + }, + "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesResponse": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + }, + "items": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoryBranchesItems", + "traits": { + "smithy.api#documentation": "

Information about the source branches.

", + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#ListSpaces": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListSpacesRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListSpacesResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of spaces.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListSpacesRequest": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#length": { + "min": 1, + "max": 10000 + } + } + } + } + }, + "com.amazonaws.codecatalyst#ListSpacesResponse": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + }, + "items": { + "target": "com.amazonaws.codecatalyst#SpaceSummaries", + "traits": { + "smithy.api#documentation": "

Information about the spaces.

" + } + } + } + }, + "com.amazonaws.codecatalyst#ListWorkflowRuns": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListWorkflowRunsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListWorkflowRunsResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of workflow runs of a specified workflow.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/workflowRuns", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListWorkflowRunsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "workflowId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The ID of the workflow. To retrieve a list of workflow IDs, use ListWorkflows.

", + "smithy.api#httpQuery": "workflowId" + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1 + }, + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#httpQuery": "nextToken", + "smithy.api#length": { + "min": 1, + "max": 2048 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#httpQuery": "maxResults", + "smithy.api#range": { + "min": 1, + "max": 50 + } + } + }, + "sortBy": { + "target": "com.amazonaws.codecatalyst#WorkflowRunSortCriteriaList", + "traits": { + "smithy.api#documentation": "

Information used to sort the items in the returned list.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#ListWorkflowRunsResponse": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + }, + "items": { + "target": "com.amazonaws.codecatalyst#WorkflowRunSummaries", + "traits": { + "smithy.api#documentation": "

Information about the runs of a workflow.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#ListWorkflows": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#ListWorkflowsRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#ListWorkflowsResponse" + }, + "traits": { + "smithy.api#documentation": "

Retrieves a list of workflows in a specified project.

", + "smithy.api#http": { + "method": "POST", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/workflows", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "nextToken", + "outputToken": "nextToken", + "pageSize": "maxResults", + "items": "items" + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#ListWorkflowsRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1 + }, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

", + "smithy.api#httpQuery": "nextToken", + "smithy.api#length": { + "min": 1, + "max": 2048 + } + } + }, + "maxResults": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The maximum number of results to show in a single call to this API. If the number of results is larger than the number you specified, the response will include a NextToken element, which you can use to obtain additional results.

", + "smithy.api#httpQuery": "maxResults", + "smithy.api#range": { + "min": 1, + "max": 100 + } + } + }, + "sortBy": { + "target": "com.amazonaws.codecatalyst#WorkflowSortCriteriaList", + "traits": { + "smithy.api#documentation": "

Information used to sort the items in the returned list.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#ListWorkflowsResponse": { + "type": "structure", + "members": { + "nextToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A token returned from a call to this API to indicate the next batch of results to return, if any.

" + } + }, + "items": { + "target": "com.amazonaws.codecatalyst#WorkflowSummaries", + "traits": { + "smithy.api#documentation": "

Information about the workflows in a project.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#NameString": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 3, + "max": 63 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_\\.][a-zA-Z0-9]+)*$" + } + }, + "com.amazonaws.codecatalyst#OperationType": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "READONLY", + "value": "READONLY" + }, + { + "name": "MUTATION", + "value": "MUTATION" + } + ] + } + }, + "com.amazonaws.codecatalyst#PersistentStorage": { + "type": "structure", + "members": { + "sizeInGiB": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The size of the persistent storage in gigabytes (specifically GiB).

\n \n

Valid values for storage are based on memory sizes in 16GB increments. Valid values are\n 16, 32, and 64.

\n
", + "smithy.api#range": { + "min": 0, + "max": 64 + }, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the persistent storage for a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#PersistentStorageConfiguration": { + "type": "structure", + "members": { + "sizeInGiB": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "

The size of the persistent storage in gigabytes (specifically GiB).

\n \n

Valid values for storage are based on memory sizes in 16GB increments. Valid values are\n 16, 32, and 64.

\n
", + "smithy.api#range": { + "min": 0, + "max": 64 + }, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the configuration of persistent storage for a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#Project": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString" + } + }, + "create": { + "target": "com.amazonaws.codecatalyst#CreateProject" + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetProject" + }, + "update": { + "target": "com.amazonaws.codecatalyst#UpdateProject" + }, + "delete": { + "target": "com.amazonaws.codecatalyst#DeleteProject" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListProjects" + }, + "resources": [ + { + "target": "com.amazonaws.codecatalyst#DevEnvironment" + }, + { + "target": "com.amazonaws.codecatalyst#SourceRepository" + }, + { + "target": "com.amazonaws.codecatalyst#Workflow" + }, + { + "target": "com.amazonaws.codecatalyst#WorkflowRun" + } + ] + }, + "com.amazonaws.codecatalyst#ProjectDescription": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 0, + "max": 200 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_a-zA-Z0-9.,;:/\\+=?&$% \n\t\r])*$" + } + }, + "com.amazonaws.codecatalyst#ProjectDisplayName": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 3, + "max": 63 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_\\. ][a-zA-Z0-9]+)*$" + } + }, + "com.amazonaws.codecatalyst#ProjectInformation": { + "type": "structure", + "members": { + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

" + } + }, + "projectId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the project.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a project in a space.

" + } + }, + "com.amazonaws.codecatalyst#ProjectListFilter": { + "type": "structure", + "members": { + "key": { + "target": "com.amazonaws.codecatalyst#FilterKey", + "traits": { + "smithy.api#documentation": "

A key that can be used to sort results.

", + "smithy.api#required": {} + } + }, + "values": { + "target": "com.amazonaws.codecatalyst#StringList", + "traits": { + "smithy.api#documentation": "

The values of the key.

", + "smithy.api#required": {} + } + }, + "comparisonOperator": { + "target": "com.amazonaws.codecatalyst#ComparisonOperator", + "traits": { + "smithy.api#documentation": "

The operator used to compare the fields.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

nformation about the filter used to narrow the results returned in a list of projects.

" + } + }, + "com.amazonaws.codecatalyst#ProjectListFilters": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#ProjectListFilter" + } + }, + "com.amazonaws.codecatalyst#ProjectSummaries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#ProjectSummary" + } + }, + "com.amazonaws.codecatalyst#ProjectSummary": { + "type": "structure", + "members": { + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name displayed to users of the project in Amazon CodeCatalyst.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the project.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a project.

" + } + }, + "com.amazonaws.codecatalyst#RegionString": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 3, + "max": 16 + }, + "smithy.api#pattern": "^(us(?:-gov)?|af|ap|ca|cn|eu|sa)-(central|(?:north|south)?(?:east|west)?)-(\\d+)$" + } + }, + "com.amazonaws.codecatalyst#RepositoriesInput": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#RepositoryInput" + } + }, + "com.amazonaws.codecatalyst#RepositoryInput": { + "type": "structure", + "members": { + "repositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository.

", + "smithy.api#required": {} + } + }, + "branchName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name of the branch in a source repository.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a repository that will be cloned to a Dev Environment.

" + } + }, + "com.amazonaws.codecatalyst#ResourceNotFoundException": { + "type": "structure", + "members": { + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

The request was denied because the specified resource was not found. Verify that the spelling is correct and that you have access to the resource.

", + "smithy.api#error": "client", + "smithy.api#httpError": 404 + } + }, + "com.amazonaws.codecatalyst#SensitiveString": { + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } + }, + "com.amazonaws.codecatalyst#ServiceQuotaExceededException": { + "type": "structure", + "members": { + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

The request was denied because one or more resources has reached its limits for the tier the space belongs to. Either reduce\n the number of resources, or change the tier if applicable.

", + "smithy.api#error": "client", + "smithy.api#httpError": 402 + } + }, + "com.amazonaws.codecatalyst#SourceRepository": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString" + } + }, + "put": { + "target": "com.amazonaws.codecatalyst#CreateSourceRepository" + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetSourceRepository" + }, + "delete": { + "target": "com.amazonaws.codecatalyst#DeleteSourceRepository" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositories" + }, + "operations": [ + { + "target": "com.amazonaws.codecatalyst#GetSourceRepositoryCloneUrls" + } + ], + "resources": [ + { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranch" + } + ], + "traits": { + "smithy.api#noReplace": {} + } + }, + "com.amazonaws.codecatalyst#SourceRepositoryBranch": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString" + }, + "sourceRepositoryBranchName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString" + } + }, + "put": { + "target": "com.amazonaws.codecatalyst#CreateSourceRepositoryBranch" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListSourceRepositoryBranches" + }, + "traits": { + "smithy.api#noReplace": {} + } + }, + "com.amazonaws.codecatalyst#SourceRepositoryBranchRefString": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 255 + } + } + }, + "com.amazonaws.codecatalyst#SourceRepositoryBranchString": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 100 + } + } + }, + "com.amazonaws.codecatalyst#SourceRepositoryDescriptionString": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 255 + } + } + }, + "com.amazonaws.codecatalyst#SourceRepositoryIdString": { + "type": "string", + "traits": { + "smithy.api#pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + } + }, + "com.amazonaws.codecatalyst#SourceRepositoryNameString": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 100 + }, + "smithy.api#pattern": "^(?!.*[.]git$)[\\w\\-.]*$" + } + }, + "com.amazonaws.codecatalyst#Space": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + } + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetSpace" + }, + "update": { + "target": "com.amazonaws.codecatalyst#UpdateSpace" + }, + "delete": { + "target": "com.amazonaws.codecatalyst#DeleteSpace" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListSpaces" + }, + "operations": [ + { + "target": "com.amazonaws.codecatalyst#ListDevEnvironments" + } + ], + "resources": [ + { + "target": "com.amazonaws.codecatalyst#EventLogResource" + }, + { + "target": "com.amazonaws.codecatalyst#Project" + }, + { + "target": "com.amazonaws.codecatalyst#Subscription" + } + ] + }, + "com.amazonaws.codecatalyst#SpaceDescription": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 0, + "max": 200 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_a-zA-Z0-9.,;:/\\+=?&$% \n\t\r])*$" + } + }, + "com.amazonaws.codecatalyst#SpaceSummaries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#SpaceSummary" + } + }, + "com.amazonaws.codecatalyst#SpaceSummary": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "regionName": { + "target": "com.amazonaws.codecatalyst#RegionString", + "traits": { + "smithy.api#documentation": "

The Amazon Web Services Region\n where the space exists.

", + "smithy.api#required": {} + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the space displayed to users.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the space.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about an space.

" + } + }, + "com.amazonaws.codecatalyst#StartDevEnvironment": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#StartDevEnvironmentRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#StartDevEnvironmentResponse" + }, + "traits": { + "smithy.api#documentation": "

Starts a specified Dev Environment and puts it into an active state.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}/start", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#StartDevEnvironmentRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "ides": { + "target": "com.amazonaws.codecatalyst#IdeConfigurationList", + "traits": { + "smithy.api#documentation": "

Information about the integrated development environment (IDE) configured for a Dev Environment.

" + } + }, + "instanceType": { + "target": "com.amazonaws.codecatalyst#InstanceType", + "traits": { + "smithy.api#documentation": "

The Amazon EC2 instace type to use for the Dev Environment.

" + } + }, + "inactivityTimeoutMinutes": { + "target": "com.amazonaws.codecatalyst#InactivityTimeoutMinutes", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

The amount of time the Dev Environment will run without any activity detected before stopping, in minutes. Only whole integers are allowed. Dev Environments consume compute minutes when running.

" + } + } + } + }, + "com.amazonaws.codecatalyst#StartDevEnvironmentResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentStatus", + "traits": { + "smithy.api#documentation": "

The status of the Dev Environment.

", + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#StartDevEnvironmentSession": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#StartDevEnvironmentSessionRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#StartDevEnvironmentSessionResponse" + }, + "traits": { + "smithy.api#documentation": "

Starts a session for a specified Dev Environment.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}/session", + "code": 200 + } + } + }, + "com.amazonaws.codecatalyst#StartDevEnvironmentSessionRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "sessionConfiguration": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentSessionConfiguration", + "traits": { + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#StartDevEnvironmentSessionResponse": { + "type": "structure", + "members": { + "accessDetails": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentAccessDetails", + "traits": { + "smithy.api#required": {} + } + }, + "sessionId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment session.

", + "smithy.api#length": { + "min": 1, + "max": 96 + } + } + }, + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + } + } + }, + "com.amazonaws.codecatalyst#StartWorkflowRun": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#StartWorkflowRunRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#StartWorkflowRunResponse" + }, + "traits": { + "smithy.api#documentation": "

Begins a run of a specified workflow.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/workflowRuns", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#StartWorkflowRunRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1 + }, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1 + }, + "smithy.api#required": {} + } + }, + "workflowId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the workflow. To retrieve a list of workflow IDs, use ListWorkflows.

", + "smithy.api#httpQuery": "workflowId", + "smithy.api#required": {} + } + }, + "clientToken": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

A user-specified idempotency token. Idempotency ensures that an API request completes only once. \n With an idempotent request, if the original request completes successfully, the subsequent retries return the result from the original successful request and have no additional effect.

", + "smithy.api#idempotencyToken": {}, + "smithy.api#length": { + "min": 1, + "max": 64 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_\\.][a-zA-Z0-9]+)*$" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#StartWorkflowRunResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the workflow run.

", + "smithy.api#required": {} + } + }, + "workflowId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the workflow.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#StatusReason": { + "type": "string", + "traits": { + "smithy.api#length": { + "max": 1024 + } + } + }, + "com.amazonaws.codecatalyst#StopDevEnvironment": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#StopDevEnvironmentRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#StopDevEnvironmentResponse" + }, + "traits": { + "smithy.api#documentation": "

Pauses a specified Dev Environment and places it in a non-running state. Stopped Dev Environments do not consume compute minutes.

", + "smithy.api#http": { + "method": "PUT", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}/stop", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#StopDevEnvironmentRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + } + } + }, + "com.amazonaws.codecatalyst#StopDevEnvironmentResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#DevEnvironmentStatus", + "traits": { + "smithy.api#documentation": "

The status of the Dev Environment.

", + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#StopDevEnvironmentSession": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#StopDevEnvironmentSessionRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#StopDevEnvironmentSessionResponse" + }, + "traits": { + "smithy.api#documentation": "

Stops a session for a specified Dev Environment.

", + "smithy.api#http": { + "method": "DELETE", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}/session/{sessionId}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#StopDevEnvironmentSessionRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment. To obtain this ID, use ListDevEnvironments.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "sessionId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment session. This ID is returned by StartDevEnvironmentSession.

", + "smithy.api#httpLabel": {}, + "smithy.api#length": { + "min": 1, + "max": 96 + }, + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#StopDevEnvironmentSessionResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "sessionId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment session.

", + "smithy.api#length": { + "min": 1, + "max": 96 + }, + "smithy.api#required": {} + } + } + } + }, + "com.amazonaws.codecatalyst#StringList": { + "type": "list", + "member": { + "target": "smithy.api#String" + } + }, + "com.amazonaws.codecatalyst#Subscription": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + } + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetSubscription" + } + }, + "com.amazonaws.codecatalyst#ThrottlingException": { + "type": "structure", + "members": { + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

The request was denied due to request throttling.

", + "smithy.api#error": "client", + "smithy.api#httpError": 429, + "smithy.api#retryable": {} + } + }, + "com.amazonaws.codecatalyst#Timestamp": { + "type": "timestamp", + "traits": { + "smithy.api#timestampFormat": "date-time" + } + }, + "com.amazonaws.codecatalyst#UpdateDevEnvironment": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#UpdateDevEnvironmentRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#UpdateDevEnvironmentResponse" + }, + "traits": { + "smithy.api#documentation": "

Changes one or more values for a Dev Environment. Updating certain values of the Dev Environment will cause a restart.

", + "smithy.api#http": { + "method": "PATCH", + "uri": "/v1/spaces/{spaceName}/projects/{projectName}/devEnvironments/{id}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#UpdateDevEnvironmentRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "alias": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The user-specified alias for the Dev Environment. Changing this value will not cause a restart.

", + "smithy.api#length": { + "max": 128 + }, + "smithy.api#pattern": "^$|^[a-zA-Z0-9]+(?:[-_\\.][a-zA-Z0-9]+)*$" + } + }, + "ides": { + "target": "com.amazonaws.codecatalyst#IdeConfigurationList", + "traits": { + "smithy.api#documentation": "

Information about the integrated development environment (IDE) configured for a Dev Environment.

" + } + }, + "instanceType": { + "target": "com.amazonaws.codecatalyst#InstanceType", + "traits": { + "smithy.api#documentation": "

The Amazon EC2 instace type to use for the Dev Environment.

\n \n

Changing this value will cause a restart of the Dev Environment if it is running.

\n
" + } + }, + "inactivityTimeoutMinutes": { + "target": "com.amazonaws.codecatalyst#InactivityTimeoutMinutes", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

The amount of time the Dev Environment will run without any activity detected before stopping, in minutes. \n Only whole integers are allowed. Dev Environments consume compute minutes when running.

\n \n

Changing this value will cause a restart of the Dev Environment if it is running.

\n
" + } + }, + "clientToken": { + "target": "com.amazonaws.codecatalyst#ClientToken", + "traits": { + "smithy.api#documentation": "

A user-specified idempotency token. Idempotency ensures that an API request completes only once. \n With an idempotent request, if the original request completes successfully, the subsequent retries return the result from the original successful request and have no additional effect.

" + } + } + } + }, + "com.amazonaws.codecatalyst#UpdateDevEnvironmentResponse": { + "type": "structure", + "members": { + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the Dev Environment.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "devEnvironmentId" + } + }, + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#required": {} + } + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project in the space.

", + "smithy.api#required": {} + } + }, + "alias": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The user-specified alias for the Dev Environment.

", + "smithy.api#length": { + "min": 1, + "max": 128 + }, + "smithy.api#pattern": "^[a-zA-Z0-9]+(?:[-_\\.][a-zA-Z0-9]+)*$" + } + }, + "ides": { + "target": "com.amazonaws.codecatalyst#IdeConfigurationList", + "traits": { + "smithy.api#documentation": "

Information about the integrated development environment (IDE) configured for the Dev Environment.

" + } + }, + "instanceType": { + "target": "com.amazonaws.codecatalyst#InstanceType", + "traits": { + "smithy.api#documentation": "

The Amazon EC2 instace type to use for the Dev Environment.

" + } + }, + "inactivityTimeoutMinutes": { + "target": "com.amazonaws.codecatalyst#InactivityTimeoutMinutes", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

The amount of time the Dev Environment will run without any activity detected before stopping, in minutes.

" + } + }, + "clientToken": { + "target": "com.amazonaws.codecatalyst#ClientToken", + "traits": { + "smithy.api#documentation": "

A user-specified idempotency token. Idempotency ensures that an API request completes only once. \n With an idempotent request, if the original request completes successfully, the subsequent retries return the result from the original successful request and have no additional effect.

" + } + } + } + }, + "com.amazonaws.codecatalyst#UpdateProject": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#UpdateProjectRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#UpdateProjectResponse" + }, + "traits": { + "smithy.api#documentation": "

Changes one or more values for a project.

", + "smithy.api#http": { + "method": "PATCH", + "uri": "/v1/spaces/{spaceName}/projects/{name}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#UpdateProjectRequest": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "projectName" + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#ProjectDescription", + "traits": { + "smithy.api#documentation": "

The description of the project.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#UpdateProjectResponse": { + "type": "structure", + "members": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

" + } + }, + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the project.

" + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the project displayed to users in Amazon CodeCatalyst.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the project.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#UpdateSpace": { + "type": "operation", + "input": { + "target": "com.amazonaws.codecatalyst#UpdateSpaceRequest" + }, + "output": { + "target": "com.amazonaws.codecatalyst#UpdateSpaceResponse" + }, + "traits": { + "smithy.api#documentation": "

Changes one or more values for a space.

", + "smithy.api#http": { + "method": "PATCH", + "uri": "/v1/spaces/{name}", + "code": 200 + }, + "smithy.api#idempotent": {} + } + }, + "com.amazonaws.codecatalyst#UpdateSpaceRequest": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "spaceName" + } + }, + "description": { + "target": "com.amazonaws.codecatalyst#SpaceDescription", + "traits": { + "smithy.api#documentation": "

The description of the space.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.codecatalyst#UpdateSpaceResponse": { + "type": "structure", + "members": { + "name": { + "target": "com.amazonaws.codecatalyst#NameString", + "traits": { + "smithy.api#documentation": "

The name of the space.

" + } + }, + "displayName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The friendly name of the space displayed to users in Amazon CodeCatalyst.

" + } + }, + "description": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The description of the space.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.codecatalyst#UserIdentity": { + "type": "structure", + "members": { + "userType": { + "target": "com.amazonaws.codecatalyst#UserType", + "traits": { + "smithy.api#documentation": "

The role assigned to the user in a Amazon CodeCatalyst space or project when the event occurred.

", + "smithy.api#required": {} + } + }, + "principalId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The ID of the Amazon CodeCatalyst service principal.

", + "smithy.api#required": {} + } + }, + "userName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The display name of the user in Amazon CodeCatalyst.

" + } + }, + "awsAccountId": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The Amazon Web Services account number of the user in Amazon Web Services, if any.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a user whose activity is recorded in an event for a space.

" + } + }, + "com.amazonaws.codecatalyst#UserType": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "USER", + "value": "USER" + }, + { + "name": "AWS_ACCOUNT", + "value": "AWS_ACCOUNT" + }, + { + "name": "UNKNOWN", + "value": "UNKNOWN" + } + ] + } + }, + "com.amazonaws.codecatalyst#Uuid": { + "type": "string", + "traits": { + "smithy.api#pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + } + }, + "com.amazonaws.codecatalyst#ValidationException": { + "type": "structure", + "members": { + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

The request was denied because an input failed to satisfy the constraints specified by the service. Check the spelling and input requirements, and then try again.

", + "smithy.api#error": "client", + "smithy.api#httpError": 400 + } + }, + "com.amazonaws.codecatalyst#VerifySession": { + "type": "operation", + "input": { + "target": "smithy.api#Unit" + }, + "output": { + "target": "com.amazonaws.codecatalyst#VerifySessionResponse" + }, + "traits": { + "smithy.api#documentation": "

Verifies whether the calling user has a valid Amazon CodeCatalyst login and session. If successful, this returns the ID of the user in Amazon CodeCatalyst.

", + "smithy.api#http": { + "method": "GET", + "uri": "/session", + "code": 200 + }, + "smithy.api#readonly": {} + } + }, + "com.amazonaws.codecatalyst#VerifySessionResponse": { + "type": "structure", + "members": { + "identity": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the user in Amazon CodeCatalyst.

", + "smithy.api#length": { + "min": 1, + "max": 256 + } + } + } + } + }, + "com.amazonaws.codecatalyst#Workflow": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "workflowId": { + "target": "com.amazonaws.codecatalyst#Uuid" + } + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetWorkflow" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListWorkflows" + } + }, + "com.amazonaws.codecatalyst#WorkflowDefinition": { + "type": "structure", + "members": { + "path": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The path to the workflow definition file stored in the source repository for the project, including the file name.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a workflow definition file.

" + } + }, + "com.amazonaws.codecatalyst#WorkflowDefinitionSummary": { + "type": "structure", + "members": { + "path": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The path to the workflow definition file stored in the source repository for the project, including the file name.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a workflow definition.

" + } + }, + "com.amazonaws.codecatalyst#WorkflowRun": { + "type": "resource", + "identifiers": { + "spaceName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "projectName": { + "target": "com.amazonaws.codecatalyst#NameString" + }, + "workflowRunId": { + "target": "com.amazonaws.codecatalyst#Uuid" + } + }, + "create": { + "target": "com.amazonaws.codecatalyst#StartWorkflowRun" + }, + "read": { + "target": "com.amazonaws.codecatalyst#GetWorkflowRun" + }, + "list": { + "target": "com.amazonaws.codecatalyst#ListWorkflowRuns" + } + }, + "com.amazonaws.codecatalyst#WorkflowRunMode": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "QUEUED", + "value": "QUEUED" + }, + { + "name": "PARALLEL", + "value": "PARALLEL" + }, + { + "name": "SUPERSEDED", + "value": "SUPERSEDED" + } + ] + } + }, + "com.amazonaws.codecatalyst#WorkflowRunSortCriteria": { + "type": "structure", + "members": {}, + "traits": { + "smithy.api#documentation": "

Information used to sort workflow runs in the returned list.

" + } + }, + "com.amazonaws.codecatalyst#WorkflowRunSortCriteriaList": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#WorkflowRunSortCriteria" + }, + "traits": { + "smithy.api#length": { + "max": 1 + } + } + }, + "com.amazonaws.codecatalyst#WorkflowRunStatus": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "SUCCEEDED", + "value": "SUCCEEDED" + }, + { + "name": "FAILED", + "value": "FAILED" + }, + { + "name": "STOPPED", + "value": "STOPPED" + }, + { + "name": "SUPERSEDED", + "value": "SUPERSEDED" + }, + { + "name": "CANCELLED", + "value": "CANCELLED" + }, + { + "name": "NOT_RUN", + "value": "NOT_RUN" + }, + { + "name": "VALIDATING", + "value": "VALIDATING" + }, + { + "name": "PROVISIONING", + "value": "PROVISIONING" + }, + { + "name": "IN_PROGRESS", + "value": "IN_PROGRESS" + }, + { + "name": "STOPPING", + "value": "STOPPING" + }, + { + "name": "ABANDONED", + "value": "ABANDONED" + } + ] + } + }, + "com.amazonaws.codecatalyst#WorkflowRunStatusReason": { + "type": "structure", + "members": {}, + "traits": { + "smithy.api#documentation": "

Information about the status of a workflow run.

" + } + }, + "com.amazonaws.codecatalyst#WorkflowRunStatusReasons": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#WorkflowRunStatusReason" + } + }, + "com.amazonaws.codecatalyst#WorkflowRunSummaries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#WorkflowRunSummary" + } + }, + "com.amazonaws.codecatalyst#WorkflowRunSummary": { + "type": "structure", + "members": { + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the workflow run.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "workflowRunId" + } + }, + "workflowId": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of the workflow.

", + "smithy.api#required": {} + } + }, + "workflowName": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the workflow.

", + "smithy.api#required": {} + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#WorkflowRunStatus", + "traits": { + "smithy.api#documentation": "

The status of the workflow run.

", + "smithy.api#required": {} + } + }, + "statusReasons": { + "target": "com.amazonaws.codecatalyst#WorkflowRunStatusReasons", + "traits": { + "smithy.api#documentation": "

The reasons for the workflow run status.

" + } + }, + "startTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow run began, in coordinated universal time (UTC) timestamp format as specified in RFC 3339.

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "endTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow run ended, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#timestampFormat": "date-time" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a workflow run.

" + } + }, + "com.amazonaws.codecatalyst#WorkflowSortCriteria": { + "type": "structure", + "members": {}, + "traits": { + "smithy.api#documentation": "

Information used to sort workflows in the returned list.

" + } + }, + "com.amazonaws.codecatalyst#WorkflowSortCriteriaList": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#WorkflowSortCriteria" + }, + "traits": { + "smithy.api#length": { + "max": 1 + } + } + }, + "com.amazonaws.codecatalyst#WorkflowStatus": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "name": "INVALID", + "value": "INVALID" + }, + { + "name": "ACTIVE", + "value": "ACTIVE" + } + ] + } + }, + "com.amazonaws.codecatalyst#WorkflowSummaries": { + "type": "list", + "member": { + "target": "com.amazonaws.codecatalyst#WorkflowSummary" + } + }, + "com.amazonaws.codecatalyst#WorkflowSummary": { + "type": "structure", + "members": { + "id": { + "target": "com.amazonaws.codecatalyst#Uuid", + "traits": { + "smithy.api#documentation": "

The system-generated unique ID of a workflow.

", + "smithy.api#required": {}, + "smithy.api#resourceIdentifier": "workflowId" + } + }, + "name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "

The name of the workflow.

", + "smithy.api#required": {} + } + }, + "sourceRepositoryName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryNameString", + "traits": { + "smithy.api#documentation": "

The name of the source repository where the workflow definition file is stored.

", + "smithy.api#required": {} + } + }, + "sourceBranchName": { + "target": "com.amazonaws.codecatalyst#SourceRepositoryBranchString", + "traits": { + "smithy.api#documentation": "

The name of the branch of the source repository where the workflow definition file is stored.

", + "smithy.api#required": {} + } + }, + "definition": { + "target": "com.amazonaws.codecatalyst#WorkflowDefinitionSummary", + "traits": { + "smithy.api#documentation": "

Information about the workflow definition file.

", + "smithy.api#required": {} + } + }, + "createdTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow was created, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "lastUpdatedTime": { + "target": "com.amazonaws.codecatalyst#Timestamp", + "traits": { + "smithy.api#documentation": "

The date and time the workflow was last updated, in coordinated universal time (UTC) timestamp format as specified in RFC 3339\n

", + "smithy.api#required": {}, + "smithy.api#timestampFormat": "date-time" + } + }, + "runMode": { + "target": "com.amazonaws.codecatalyst#WorkflowRunMode", + "traits": { + "smithy.api#documentation": "

The run mode of the workflow.

", + "smithy.api#required": {} + } + }, + "status": { + "target": "com.amazonaws.codecatalyst#WorkflowStatus", + "traits": { + "smithy.api#documentation": "

The status of the workflow.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a workflow.

" + } + } + } +} diff --git a/aws/sdk/integration-tests/Cargo.toml b/aws/sdk/integration-tests/Cargo.toml index 546c557175..a35c46448c 100644 --- a/aws/sdk/integration-tests/Cargo.toml +++ b/aws/sdk/integration-tests/Cargo.toml @@ -3,6 +3,7 @@ [workspace] resolver = "2" members = [ + "codecatalyst", "dynamodb", "ec2", "glacier", diff --git a/aws/sdk/integration-tests/codecatalyst/Cargo.toml b/aws/sdk/integration-tests/codecatalyst/Cargo.toml new file mode 100644 index 0000000000..d4fb2c8088 --- /dev/null +++ b/aws/sdk/integration-tests/codecatalyst/Cargo.toml @@ -0,0 +1,17 @@ +# This Cargo.toml is unused in generated code. It exists solely to enable these tests to compile in-situ +[package] +name = "codecatalyst-tests" +version = "0.1.0" +authors = ["AWS Rust SDK Team "] +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/smithy-lang/smithy-rs" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aws-sdk-codecatalyst = { path = "../../build/aws-sdk/sdk/codecatalyst", features = ["behavior-version-latest", "test-util"] } +aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "wire-mock", "test-util"] } +tokio = { version = "1.23.1", features = ["full", "test-util"] } +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } diff --git a/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json new file mode 100644 index 0000000000..7ffb08573a --- /dev/null +++ b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json @@ -0,0 +1,126 @@ +{ + "events": [ + { + "connection_id": 0, + "action": { + "Request": { + "request": { + "uri": "https://codecatalyst.global.api.aws/v1/spaces", + "headers": { + "x-amz-user-agent": [ + "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0" + ], + "authorization": [ + "Bearer sso_bearer_auth_test" + ], + "content-length": [ + "2" + ], + "user-agent": [ + "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0" + ], + "content-type": [ + "application/json" + ], + "amz-sdk-request": [ + "attempt=1; max=1" + ] + }, + "method": "POST" + } + } + } + }, + { + "connection_id": 0, + "action": { + "Data": { + "data": { + "Utf8": "{}" + }, + "direction": "Request" + } + } + }, + { + "connection_id": 0, + "action": { + "Eof": { + "ok": true, + "direction": "Request" + } + } + }, + { + "connection_id": 0, + "action": { + "Response": { + "response": { + "Ok": { + "status": 200, + "headers": { + "x-amzn-served-from": [ + "us-west-2,us-west-2" + ], + "access-control-allow-credentials": [ + "true" + ], + "content-type": [ + "application/json; charset=utf-8" + ], + "strict-transport-security": [ + "max-age=63072000; includeSubDomains" + ], + "access-control-expose-headers": [ + "anti-csrftoken-a2z,x-amzn-requestid" + ], + "date": [ + "Tue, 27 Feb 2024 00:12:28 GMT" + ], + "vary": [ + "Origin" + ], + "x-amzn-requestid": [ + "some-request-id" + ] + } + } + } + } + } + }, + { + "connection_id": 0, + "action": { + "Data": { + "data": { + "Utf8": "{\"nextToken\":\"\",\"items\":[{\"name\":\"somespacename\",\"regionName\":\"us-west-2\",\"displayName\":\"somedisplayname\"}]}" + }, + "direction": "Response" + } + } + }, + { + "connection_id": 0, + "action": { + "Data": { + "data": { + "Utf8": "" + }, + "direction": "Response" + } + } + }, + { + "connection_id": 0, + "action": { + "Eof": { + "ok": true, + "direction": "Response" + } + } + } + ], + "docs": "todo docs", + "version": "V0" +} diff --git a/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs new file mode 100644 index 0000000000..d499fb0243 --- /dev/null +++ b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs @@ -0,0 +1,31 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_sdk_codecatalyst::config::{ProvideToken, Token}; + +#[tokio::test] +async fn sso_bearer_auth() { + let replay = aws_smithy_runtime::client::http::test_util::dvr::ReplayingClient::from_file( + "tests/sso_bearer_auth.json", + ) + .unwrap(); + + let config = aws_sdk_codecatalyst::Config::builder() + .with_test_defaults() + .http_client(replay.clone()) + .token_provider(Token::new("sso_bearer_auth_test", None)) + .build(); + let client = aws_sdk_codecatalyst::Client::from_conf(config); + + let response = client + .list_spaces() + .send() + .await + .expect("successful response"); + let item = &response.items.unwrap()[0]; + assert_eq!("somespacename", item.name); + + replay.full_validate("application/json").await.unwrap(); +} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt index 676700e6d6..db2eee3090 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt @@ -26,6 +26,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.letIf @@ -37,6 +38,7 @@ private fun codegenScope(runtimeConfig: RuntimeConfig): Array> val authHttp = smithyRuntime.resolve("client::auth::http") val authHttpApi = smithyRuntimeApi.resolve("client::auth::http") return arrayOf( + "IntoShared" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared"), "Token" to configReexport(smithyRuntimeApi.resolve("client::identity::http::Token")), "Login" to configReexport(smithyRuntimeApi.resolve("client::identity::http::Login")), "ResolveIdentity" to configReexport(smithyRuntimeApi.resolve("client::identity::ResolveIdentity")), @@ -229,7 +231,7 @@ private class HttpAuthConfigCustomization( pub fn api_key_resolver(mut self, api_key_resolver: impl #{ResolveIdentity} + 'static) -> Self { self.runtime_components.set_identity_resolver( #{HTTP_API_KEY_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(api_key_resolver) + #{IntoShared}::<#{SharedIdentityResolver}>::into_shared(api_key_resolver) ); self } @@ -249,7 +251,7 @@ private class HttpAuthConfigCustomization( pub fn bearer_token_resolver(mut self, bearer_token_resolver: impl #{ResolveIdentity} + 'static) -> Self { self.runtime_components.set_identity_resolver( #{HTTP_BEARER_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(bearer_token_resolver) + #{IntoShared}::<#{SharedIdentityResolver}>::into_shared(bearer_token_resolver) ); self } @@ -269,7 +271,7 @@ private class HttpAuthConfigCustomization( pub fn basic_auth_login_resolver(mut self, basic_auth_resolver: impl #{ResolveIdentity} + 'static) -> Self { self.runtime_components.set_identity_resolver( #{HTTP_BASIC_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(basic_auth_resolver) + #{IntoShared}::<#{SharedIdentityResolver}>::into_shared(basic_auth_resolver) ); self } @@ -289,7 +291,7 @@ private class HttpAuthConfigCustomization( pub fn digest_auth_login_resolver(mut self, digest_auth_resolver: impl #{ResolveIdentity} + 'static) -> Self { self.runtime_components.set_identity_resolver( #{HTTP_DIGEST_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(digest_auth_resolver) + #{IntoShared}::<#{SharedIdentityResolver}>::into_shared(digest_auth_resolver) ); self } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt index 24831d0027..8b857b741d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt @@ -148,8 +148,13 @@ class AuthSchemeLister : RuleValueVisitor> { } /** - * Returns a service's supported auth schemes + * SigV4a doesn't have a Smithy auth trait yet, so this is a hack to determine if a service supports it. + * + * In the future, Smithy's `ServiceIndex.getEffectiveAuthSchemes` should be used instead. */ -fun ServiceShape.supportedAuthSchemes(): Set = - this.getTrait()?.ruleSet?.let { EndpointRuleSet.fromNode(it) }?.also { it.typeCheck() } - ?.let { AuthSchemeLister.authSchemesForRuleset(it) } ?: setOf() +fun ServiceShape.usesSigV4a(): Boolean { + val endpointAuthSchemes = + getTrait()?.ruleSet?.let { EndpointRuleSet.fromNode(it) }?.also { it.typeCheck() } + ?.let { AuthSchemeLister.authSchemesForRuleset(it) } ?: setOf() + return endpointAuthSchemes.contains("sigv4a") +} diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs index 2666ef2a01..be0e8f247f 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs @@ -52,6 +52,12 @@ impl Token { pub fn expiration(&self) -> Option { self.0.expiration } + + /// Creates a `Token` for tests. + #[cfg(feature = "test-util")] + pub fn for_tests() -> Self { + Self::new("test-token", None) + } } impl From<&str> for Token { @@ -75,7 +81,19 @@ impl ResolveIdentity for Token { _runtime_components: &'a RuntimeComponents, _config_bag: &'a ConfigBag, ) -> IdentityFuture<'a> { - IdentityFuture::ready(Ok(Identity::new(self.clone(), self.0.expiration))) + IdentityFuture::ready(Ok(self.into())) + } +} + +impl From<&Token> for Identity { + fn from(value: &Token) -> Self { + Identity::new(value.clone(), value.0.expiration) + } +} +impl From for Identity { + fn from(value: Token) -> Self { + let expiration = value.0.expiration; + Identity::new(value, expiration) } } From 48d3ea4170c5f1a4326fd6157dd6941848a0300d Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 27 Feb 2024 11:08:26 -0800 Subject: [PATCH 07/16] Minor fixes --- aws/rust-runtime/aws-credential-types/external-types.toml | 1 + aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/rust-runtime/aws-credential-types/external-types.toml b/aws/rust-runtime/aws-credential-types/external-types.toml index f8b06e0f47..5c3337a067 100644 --- a/aws/rust-runtime/aws-credential-types/external-types.toml +++ b/aws/rust-runtime/aws-credential-types/external-types.toml @@ -3,6 +3,7 @@ allowed_external_types = [ "aws_smithy_async::rt::sleep::SharedAsyncSleep", "aws_smithy_runtime_api::client::identity::ResolveIdentity", "aws_smithy_runtime_api::client::identity::http::Token", + "aws_smithy_runtime_api::shared::FromUnshared", "aws_smithy_types::config_bag::storable::Storable", "aws_smithy_types::config_bag::storable::StoreReplace", "aws_smithy_types::config_bag::storable::Storer", diff --git a/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs index d499fb0243..99b2b24812 100644 --- a/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs +++ b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -use aws_sdk_codecatalyst::config::{ProvideToken, Token}; +use aws_sdk_codecatalyst::config::Token; #[tokio::test] async fn sso_bearer_auth() { From e7cf9763cebe65d226eeb6cc62800071844095ba Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 28 Feb 2024 14:59:29 -0800 Subject: [PATCH 08/16] Make the ServiceSpecificDecorator more generic --- .../smithy/rustsdk/ConditionalDecorator.kt | 180 ++++++++++++++++++ .../customize/ServiceSpecificDecorator.kt | 178 +---------------- 2 files changed, 186 insertions(+), 172 deletions(-) create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt new file mode 100644 index 0000000000..5424e829c7 --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt @@ -0,0 +1,180 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rustsdk + +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.shapes.ToShapeId +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings +import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption +import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientProtocolMap +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.error.ErrorCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ProtocolTestGenerator +import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.ManifestCustomizations +import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ErrorImplCustomization + +/** + * Delegating decorator that only applies when a condition is true + */ +class ConditionalDecorator( + /** Decorator to delegate to */ + private val delegateTo: ClientCodegenDecorator, + /** Service ID this decorator is active for */ + private val predicate: (ClientCodegenContext?, ShapeId?) -> Boolean, +) : ClientCodegenDecorator { + override val name: String = delegateTo.name + override val order: Byte = delegateTo.order + + private fun T.maybeApply( + codegenContext: ClientCodegenContext? = null, + serviceShapeId: ToShapeId? = null, + delegatedValue: () -> T, + ): T = + if (predicate(codegenContext, (serviceShapeId ?: codegenContext?.serviceShape)?.toShapeId())) { + delegatedValue() + } else { + this + } + + // This kind of decorator gets explicitly added to the root sdk-codegen decorator + override fun classpathDiscoverable(): Boolean = false + + override fun authOptions( + codegenContext: ClientCodegenContext, + operationShape: OperationShape, + baseAuthSchemeOptions: List, + ): List = + baseAuthSchemeOptions.maybeApply(codegenContext) { + delegateTo.authOptions(codegenContext, operationShape, baseAuthSchemeOptions) + } + + override fun builderCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.builderCustomizations(codegenContext, baseCustomizations) + } + + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.configCustomizations(codegenContext, baseCustomizations) + } + + override fun crateManifestCustomizations(codegenContext: ClientCodegenContext): ManifestCustomizations = + emptyMap().maybeApply(codegenContext) { + delegateTo.crateManifestCustomizations(codegenContext) + } + + override fun endpointCustomizations(codegenContext: ClientCodegenContext): List = + emptyList().maybeApply(codegenContext) { + delegateTo.endpointCustomizations(codegenContext) + } + + override fun errorCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.errorCustomizations(codegenContext, baseCustomizations) + } + + override fun errorImplCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.errorImplCustomizations(codegenContext, baseCustomizations) + } + + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { + maybeApply(codegenContext) { + delegateTo.extras(codegenContext, rustCrate) + } + } + + override fun libRsCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.libRsCustomizations(codegenContext, baseCustomizations) + } + + override fun operationCustomizations( + codegenContext: ClientCodegenContext, + operation: OperationShape, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.operationCustomizations(codegenContext, operation, baseCustomizations) + } + + override fun protocols( + serviceId: ShapeId, + currentProtocols: ClientProtocolMap, + ): ClientProtocolMap = + currentProtocols.maybeApply(serviceShapeId = serviceId) { + delegateTo.protocols(serviceId, currentProtocols) + } + + override fun structureCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.structureCustomizations(codegenContext, baseCustomizations) + } + + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = + model.maybeApply(serviceShapeId = service) { + delegateTo.transformModel(service, model, settings) + } + + override fun serviceRuntimePluginCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.maybeApply(codegenContext) { + delegateTo.serviceRuntimePluginCustomizations(codegenContext, baseCustomizations) + } + + override fun protocolTestGenerator( + codegenContext: ClientCodegenContext, + baseGenerator: ProtocolTestGenerator, + ): ProtocolTestGenerator = + baseGenerator.maybeApply(codegenContext) { + delegateTo.protocolTestGenerator(codegenContext, baseGenerator) + } + + override fun extraSections(codegenContext: ClientCodegenContext): List = + listOf().maybeApply(codegenContext) { + delegateTo.extraSections(codegenContext) + } +} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt index 7a493f702d..78e49cccd9 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt @@ -5,184 +5,18 @@ package software.amazon.smithy.rustsdk.customize -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId -import software.amazon.smithy.model.shapes.ToShapeId -import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings -import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientProtocolMap -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.error.ErrorCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ProtocolTestGenerator -import software.amazon.smithy.rust.codegen.core.smithy.RustCrate -import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization -import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderCustomization -import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization -import software.amazon.smithy.rust.codegen.core.smithy.generators.ManifestCustomizations -import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureCustomization -import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ErrorImplCustomization +import software.amazon.smithy.rustsdk.ConditionalDecorator /** Only apply this decorator to the given service ID */ fun ClientCodegenDecorator.onlyApplyTo(serviceId: String): List = - listOf(ServiceSpecificDecorator(ShapeId.from(serviceId), this)) + listOf( + ConditionalDecorator(this) { _, serviceShapeId -> + serviceShapeId == ShapeId.from(serviceId) + }, + ) /** Apply the given decorators only to this service ID */ fun String.applyDecorators(vararg decorators: ClientCodegenDecorator): List = decorators.map { it.onlyApplyTo(this) }.flatten() - -/** - * Delegating decorator that only applies to a configured service ID - */ -class ServiceSpecificDecorator( - /** Service ID this decorator is active for */ - private val appliesToServiceId: ShapeId, - /** Decorator to delegate to */ - private val delegateTo: ClientCodegenDecorator, - /** Decorator name */ - override val name: String = "${appliesToServiceId.namespace}.${appliesToServiceId.name}", - /** Decorator order */ - override val order: Byte = 0, -) : ClientCodegenDecorator { - private fun T.maybeApply( - serviceId: ToShapeId, - delegatedValue: () -> T, - ): T = - if (appliesToServiceId == serviceId.toShapeId()) { - delegatedValue() - } else { - this - } - - // This kind of decorator gets explicitly added to the root sdk-codegen decorator - override fun classpathDiscoverable(): Boolean = false - - override fun authOptions( - codegenContext: ClientCodegenContext, - operationShape: OperationShape, - baseAuthSchemeOptions: List, - ): List = - baseAuthSchemeOptions.maybeApply(codegenContext.serviceShape) { - delegateTo.authOptions(codegenContext, operationShape, baseAuthSchemeOptions) - } - - override fun builderCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.builderCustomizations(codegenContext, baseCustomizations) - } - - override fun configCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.configCustomizations(codegenContext, baseCustomizations) - } - - override fun crateManifestCustomizations(codegenContext: ClientCodegenContext): ManifestCustomizations = - emptyMap().maybeApply(codegenContext.serviceShape) { - delegateTo.crateManifestCustomizations(codegenContext) - } - - override fun endpointCustomizations(codegenContext: ClientCodegenContext): List = - emptyList().maybeApply(codegenContext.serviceShape) { - delegateTo.endpointCustomizations(codegenContext) - } - - override fun errorCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.errorCustomizations(codegenContext, baseCustomizations) - } - - override fun errorImplCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.errorImplCustomizations(codegenContext, baseCustomizations) - } - - override fun extras( - codegenContext: ClientCodegenContext, - rustCrate: RustCrate, - ) { - maybeApply(codegenContext.serviceShape) { - delegateTo.extras(codegenContext, rustCrate) - } - } - - override fun libRsCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.libRsCustomizations(codegenContext, baseCustomizations) - } - - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.operationCustomizations(codegenContext, operation, baseCustomizations) - } - - override fun protocols( - serviceId: ShapeId, - currentProtocols: ClientProtocolMap, - ): ClientProtocolMap = - currentProtocols.maybeApply(serviceId) { - delegateTo.protocols(serviceId, currentProtocols) - } - - override fun structureCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.structureCustomizations(codegenContext, baseCustomizations) - } - - override fun transformModel( - service: ServiceShape, - model: Model, - settings: ClientRustSettings, - ): Model = - model.maybeApply(service) { - delegateTo.transformModel(service, model, settings) - } - - override fun serviceRuntimePluginCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.serviceRuntimePluginCustomizations(codegenContext, baseCustomizations) - } - - override fun protocolTestGenerator( - codegenContext: ClientCodegenContext, - baseGenerator: ProtocolTestGenerator, - ): ProtocolTestGenerator = - baseGenerator.maybeApply(codegenContext.serviceShape) { - delegateTo.protocolTestGenerator(codegenContext, baseGenerator) - } - - override fun extraSections(codegenContext: ClientCodegenContext): List = - listOf().maybeApply(codegenContext.serviceShape) { - delegateTo.extraSections(codegenContext) - } -} From 374b39ff288697b2a8c7c552ed66b1130af5ce4e Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 28 Feb 2024 16:08:16 -0800 Subject: [PATCH 09/16] Use ConditionalDecorator --- .../smithy/rustsdk/ConditionalDecorator.kt | 37 +++-- .../rustsdk/CredentialProvidersDecorator.kt | 72 ++++----- .../smithy/rustsdk/SigV4AuthDecorator.kt | 150 ++++++++---------- .../smithy/rustsdk/TokenProvidersDecorator.kt | 53 +++---- 4 files changed, 148 insertions(+), 164 deletions(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt index 5424e829c7..214b7f4009 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt @@ -32,11 +32,10 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ErrorImp /** * Delegating decorator that only applies when a condition is true */ -class ConditionalDecorator( +open class ConditionalDecorator( /** Decorator to delegate to */ private val delegateTo: ClientCodegenDecorator, - /** Service ID this decorator is active for */ - private val predicate: (ClientCodegenContext?, ShapeId?) -> Boolean, + private val predicate: (ClientCodegenContext?, ToShapeId?) -> Boolean, ) : ClientCodegenDecorator { override val name: String = delegateTo.name override val order: Byte = delegateTo.order @@ -55,7 +54,7 @@ class ConditionalDecorator( // This kind of decorator gets explicitly added to the root sdk-codegen decorator override fun classpathDiscoverable(): Boolean = false - override fun authOptions( + final override fun authOptions( codegenContext: ClientCodegenContext, operationShape: OperationShape, baseAuthSchemeOptions: List, @@ -64,7 +63,7 @@ class ConditionalDecorator( delegateTo.authOptions(codegenContext, operationShape, baseAuthSchemeOptions) } - override fun builderCustomizations( + final override fun builderCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -72,7 +71,7 @@ class ConditionalDecorator( delegateTo.builderCustomizations(codegenContext, baseCustomizations) } - override fun configCustomizations( + final override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -80,17 +79,17 @@ class ConditionalDecorator( delegateTo.configCustomizations(codegenContext, baseCustomizations) } - override fun crateManifestCustomizations(codegenContext: ClientCodegenContext): ManifestCustomizations = + final override fun crateManifestCustomizations(codegenContext: ClientCodegenContext): ManifestCustomizations = emptyMap().maybeApply(codegenContext) { delegateTo.crateManifestCustomizations(codegenContext) } - override fun endpointCustomizations(codegenContext: ClientCodegenContext): List = + final override fun endpointCustomizations(codegenContext: ClientCodegenContext): List = emptyList().maybeApply(codegenContext) { delegateTo.endpointCustomizations(codegenContext) } - override fun errorCustomizations( + final override fun errorCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -98,7 +97,7 @@ class ConditionalDecorator( delegateTo.errorCustomizations(codegenContext, baseCustomizations) } - override fun errorImplCustomizations( + final override fun errorImplCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -106,7 +105,7 @@ class ConditionalDecorator( delegateTo.errorImplCustomizations(codegenContext, baseCustomizations) } - override fun extras( + final override fun extras( codegenContext: ClientCodegenContext, rustCrate: RustCrate, ) { @@ -115,7 +114,7 @@ class ConditionalDecorator( } } - override fun libRsCustomizations( + final override fun libRsCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -123,7 +122,7 @@ class ConditionalDecorator( delegateTo.libRsCustomizations(codegenContext, baseCustomizations) } - override fun operationCustomizations( + final override fun operationCustomizations( codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, @@ -132,7 +131,7 @@ class ConditionalDecorator( delegateTo.operationCustomizations(codegenContext, operation, baseCustomizations) } - override fun protocols( + final override fun protocols( serviceId: ShapeId, currentProtocols: ClientProtocolMap, ): ClientProtocolMap = @@ -140,7 +139,7 @@ class ConditionalDecorator( delegateTo.protocols(serviceId, currentProtocols) } - override fun structureCustomizations( + final override fun structureCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -148,7 +147,7 @@ class ConditionalDecorator( delegateTo.structureCustomizations(codegenContext, baseCustomizations) } - override fun transformModel( + final override fun transformModel( service: ServiceShape, model: Model, settings: ClientRustSettings, @@ -157,7 +156,7 @@ class ConditionalDecorator( delegateTo.transformModel(service, model, settings) } - override fun serviceRuntimePluginCustomizations( + final override fun serviceRuntimePluginCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, ): List = @@ -165,7 +164,7 @@ class ConditionalDecorator( delegateTo.serviceRuntimePluginCustomizations(codegenContext, baseCustomizations) } - override fun protocolTestGenerator( + final override fun protocolTestGenerator( codegenContext: ClientCodegenContext, baseGenerator: ProtocolTestGenerator, ): ProtocolTestGenerator = @@ -173,7 +172,7 @@ class ConditionalDecorator( delegateTo.protocolTestGenerator(codegenContext, baseGenerator) } - override fun extraSections(codegenContext: ClientCodegenContext): List = + final override fun extraSections(codegenContext: ClientCodegenContext): List = listOf().maybeApply(codegenContext) { delegateTo.extraSections(codegenContext) } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt index 73b60cf8b6..a382dce282 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt @@ -24,48 +24,46 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.pre import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomization -import software.amazon.smithy.rust.codegen.core.util.letIf -class CredentialsProviderDecorator : ClientCodegenDecorator { - override val name: String = "CredentialsProvider" - override val order: Byte = 0 +class CredentialsProviderDecorator : ConditionalDecorator( + predicate = { codegenContext, _ -> + codegenContext?.let { + ServiceIndex.of(it.model).getEffectiveAuthSchemes(it.serviceShape) + .containsKey(SigV4Trait.ID) || it.serviceShape.usesSigV4a() + } ?: false + }, + delegateTo = + object : ClientCodegenDecorator { + override val name: String = "CredentialsProviderDecorator" + override val order: Byte = 0 - private fun applies(codegenContext: ClientCodegenContext): Boolean = - ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) - .containsKey(SigV4Trait.ID) || codegenContext.serviceShape.usesSigV4a() + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = baseCustomizations + CredentialProviderConfig(codegenContext) - override fun configCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.letIf(applies(codegenContext)) { it + CredentialProviderConfig(codegenContext) } + override fun extraSections(codegenContext: ClientCodegenContext): List = + listOf( + adhocCustomization { section -> + rust("${section.serviceConfigBuilder}.set_credentials_provider(${section.sdkConfig}.credentials_provider());") + }, + ) - override fun extraSections(codegenContext: ClientCodegenContext): List = - emptyList().letIf(applies(codegenContext)) { - it + - adhocCustomization { section -> - rust("${section.serviceConfigBuilder}.set_credentials_provider(${section.sdkConfig}.credentials_provider());") - } - } - - override fun extras( - codegenContext: ClientCodegenContext, - rustCrate: RustCrate, - ) { - if (!applies(codegenContext)) { - return - } - - rustCrate.mergeFeature(TestUtilFeature.copy(deps = listOf("aws-credential-types/test-util"))) + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { + rustCrate.mergeFeature(TestUtilFeature.copy(deps = listOf("aws-credential-types/test-util"))) - rustCrate.withModule(ClientRustModule.config) { - rust( - "pub use #T::Credentials;", - AwsRuntimeType.awsCredentialTypes(codegenContext.runtimeConfig), - ) - } - } -} + rustCrate.withModule(ClientRustModule.config) { + rust( + "pub use #T::Credentials;", + AwsRuntimeType.awsCredentialTypes(codegenContext.runtimeConfig), + ) + } + } + }, +) /** * Add a `.credentials_provider` field and builder to the `Config` for a given service diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index f942f36314..fe8c0dc109 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -35,94 +35,80 @@ import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.hasEventStreamOperations import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.isInputEventStream -import software.amazon.smithy.rust.codegen.core.util.letIf import software.amazon.smithy.rust.codegen.core.util.thenSingletonListOf -class SigV4AuthDecorator : ClientCodegenDecorator { - override val name: String get() = "SigV4AuthDecorator" - override val order: Byte = 0 +class SigV4AuthDecorator : ConditionalDecorator( + predicate = { codegenContext, _ -> + codegenContext?.let { + ServiceIndex.of(it.model).getEffectiveAuthSchemes(it.serviceShape) + .containsKey(SigV4Trait.ID) || it.serviceShape.usesSigV4a() + } ?: false + }, + delegateTo = + object : ClientCodegenDecorator { + override val name: String get() = "SigV4AuthDecorator" + override val order: Byte = 0 - private val sigv4a = "sigv4a" + private val sigv4a = "sigv4a" - private fun applies(codegenContext: ClientCodegenContext): Boolean = - ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) - .containsKey(SigV4Trait.ID) || codegenContext.serviceShape.usesSigV4a() + private fun sigv4(runtimeConfig: RuntimeConfig) = + writable { + val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") + rust("#T", awsRuntimeAuthModule.resolve("sigv4::SCHEME_ID")) + } - private fun sigv4(runtimeConfig: RuntimeConfig) = - writable { - val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") - rust("#T", awsRuntimeAuthModule.resolve("sigv4::SCHEME_ID")) - } + private fun sigv4a(runtimeConfig: RuntimeConfig) = + writable { + val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") + featureGateBlock(sigv4a) { + rust("#T", awsRuntimeAuthModule.resolve("sigv4a::SCHEME_ID")) + } + } - private fun sigv4a(runtimeConfig: RuntimeConfig) = - writable { - val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") - featureGateBlock(sigv4a) { - rust("#T", awsRuntimeAuthModule.resolve("sigv4a::SCHEME_ID")) + override fun authOptions( + codegenContext: ClientCodegenContext, + operationShape: OperationShape, + baseAuthSchemeOptions: List, + ): List { + val supportsSigV4a = + codegenContext.serviceShape.usesSigV4a() + .thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } + return baseAuthSchemeOptions + + AuthSchemeOption.StaticAuthSchemeOption( + SigV4Trait.ID, + listOf(sigv4(codegenContext.runtimeConfig)) + supportsSigV4a, + ) } - } - - override fun authOptions( - codegenContext: ClientCodegenContext, - operationShape: OperationShape, - baseAuthSchemeOptions: List, - ): List { - if (!applies(codegenContext)) { - return baseAuthSchemeOptions - } - val supportsSigV4a = - codegenContext.serviceShape.usesSigV4a() - .thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } - return baseAuthSchemeOptions + - AuthSchemeOption.StaticAuthSchemeOption( - SigV4Trait.ID, - listOf(sigv4(codegenContext.runtimeConfig)) + supportsSigV4a, - ) - } + override fun serviceRuntimePluginCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations + listOf(AuthServiceRuntimePluginCustomization(codegenContext)) - override fun serviceRuntimePluginCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.letIf(applies(codegenContext)) { - it + - listOf( - AuthServiceRuntimePluginCustomization( - codegenContext, - ), - ) - } + override fun operationCustomizations( + codegenContext: ClientCodegenContext, + operation: OperationShape, + baseCustomizations: List, + ): List = baseCustomizations + AuthOperationCustomization(codegenContext) - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List = - baseCustomizations.letIf(applies(codegenContext)) { it + AuthOperationCustomization(codegenContext) } + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations + SigV4SigningConfig(codegenContext.runtimeConfig, codegenContext.serviceShape.getTrait()) - override fun configCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - baseCustomizations.letIf(applies(codegenContext)) { - it + - SigV4SigningConfig( - codegenContext.runtimeConfig, - codegenContext.serviceShape.getTrait(), - ) - } - - override fun extras( - codegenContext: ClientCodegenContext, - rustCrate: RustCrate, - ) { - if (codegenContext.serviceShape.usesSigV4a()) { - // Add optional feature for SigV4a support - rustCrate.mergeFeature(Feature("sigv4a", true, listOf("aws-runtime/sigv4a"))) - } - } -} + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { + if (codegenContext.serviceShape.usesSigV4a()) { + // Add optional feature for SigV4a support + rustCrate.mergeFeature(Feature("sigv4a", true, listOf("aws-runtime/sigv4a"))) + } + } + }, +) private class SigV4SigningConfig( runtimeConfig: RuntimeConfig, @@ -189,7 +175,9 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: arrayOf( "SigV4AuthScheme" to awsRuntime.resolve("auth::sigv4::SigV4AuthScheme"), "SigV4aAuthScheme" to awsRuntime.resolve("auth::sigv4a::SigV4aAuthScheme"), - "SharedAuthScheme" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::auth::SharedAuthScheme"), + "SharedAuthScheme" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::auth::SharedAuthScheme"), ) } @@ -197,11 +185,13 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: writable { when (section) { is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { - val serviceHasEventStream = codegenContext.serviceShape.hasEventStreamOperations(codegenContext.model) + val serviceHasEventStream = + codegenContext.serviceShape.hasEventStreamOperations(codegenContext.model) if (serviceHasEventStream) { // enable the aws-runtime `sign-eventstream` feature addDependency( - AwsCargoDependency.awsRuntime(runtimeConfig).withFeature("event-stream").toType().toSymbol(), + AwsCargoDependency.awsRuntime(runtimeConfig).withFeature("event-stream").toType() + .toSymbol(), ) } section.registerAuthScheme(this) { diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt index 5a9864a3ed..15912824a9 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt @@ -19,35 +19,31 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomization -class TokenProvidersDecorator : ClientCodegenDecorator { - override val name: String get() = "TokenProvidersDecorator" - override val order: Byte = 0 +class TokenProvidersDecorator : ConditionalDecorator( + predicate = { codegenContext, _ -> + codegenContext?.let { + ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) + .containsKey(HttpBearerAuthTrait.ID) + } ?: false + }, + delegateTo = + object : ClientCodegenDecorator { + override val name: String get() = "TokenProvidersDecorator" + override val order: Byte = 0 - private fun applies(codegenContext: ClientCodegenContext): Boolean = - ServiceIndex.of(codegenContext.model).getEffectiveAuthSchemes(codegenContext.serviceShape) - .containsKey(HttpBearerAuthTrait.ID) + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = baseCustomizations + TokenProviderConfig(codegenContext) - override fun configCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = - if (applies(codegenContext)) { - baseCustomizations + TokenProviderConfig(codegenContext) - } else { - baseCustomizations - } - - override fun extraSections(codegenContext: ClientCodegenContext): List = - if (applies(codegenContext)) { - listOf( - adhocCustomization { section -> - rust("${section.serviceConfigBuilder}.set_token_provider(${section.sdkConfig}.token_provider());") - }, - ) - } else { - emptyList() - } -} + override fun extraSections(codegenContext: ClientCodegenContext): List = + listOf( + adhocCustomization { section -> + rust("${section.serviceConfigBuilder}.set_token_provider(${section.sdkConfig}.token_provider());") + }, + ) + }, +) /** * Add a `.token_provider` field and builder to the `Config` for a given service @@ -71,7 +67,8 @@ class TokenProviderConfig(private val codegenContext: ClientCodegenContext) : Co "TestToken" to AwsRuntimeType.awsCredentialTypesTestUtil(runtimeConfig).resolve("Token"), "HTTP_BEARER_AUTH_SCHEME_ID" to CargoDependency.smithyRuntimeApiClient(runtimeConfig) - .withFeature("http-auth").toType().resolve("client::auth::http").resolve("HTTP_BEARER_AUTH_SCHEME_ID"), + .withFeature("http-auth").toType().resolve("client::auth::http") + .resolve("HTTP_BEARER_AUTH_SCHEME_ID"), ) override fun section(section: ServiceConfig) = From 51c925ba2d5ae0cdf0270edb8acd544c0a0024df Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 28 Feb 2024 16:28:12 -0800 Subject: [PATCH 10/16] Refactor sig auth detection --- .../rustsdk/CredentialProvidersDecorator.kt | 12 ++----- .../smithy/rustsdk/SigV4AuthDecorator.kt | 34 +++++++++++++------ .../codegen/client/smithy/endpoint/Util.kt | 15 -------- 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt index a382dce282..6034939f3f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt @@ -5,14 +5,11 @@ package software.amazon.smithy.rustsdk -import software.amazon.smithy.aws.traits.auth.SigV4Trait -import software.amazon.smithy.model.knowledge.ServiceIndex import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.configReexport import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.customize.TestUtilFeature -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.usesSigV4a import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.core.rustlang.featureGateBlock @@ -26,12 +23,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomizat import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomization class CredentialsProviderDecorator : ConditionalDecorator( - predicate = { codegenContext, _ -> - codegenContext?.let { - ServiceIndex.of(it.model).getEffectiveAuthSchemes(it.serviceShape) - .containsKey(SigV4Trait.ID) || it.serviceShape.usesSigV4a() - } ?: false - }, + predicate = { codegenContext, _ -> codegenContext?.usesSigAuth() ?: false }, delegateTo = object : ClientCodegenDecorator { override val name: String = "CredentialsProviderDecorator" @@ -134,7 +126,7 @@ class CredentialProviderConfig(private val codegenContext: ClientCodegenContext) """, *codegenScope, ) { - if (codegenContext.serviceShape.usesSigV4a()) { + if (codegenContext.usesSigV4a()) { featureGateBlock("sigv4a") { rustTemplate( "self.runtime_components.set_identity_resolver(#{SIGV4A_SCHEME_ID}, credentials_provider.clone());", diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index fe8c0dc109..58247b019e 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -11,10 +11,12 @@ import software.amazon.smithy.model.knowledge.ServiceIndex import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.rulesengine.language.EndpointRuleSet +import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.usesSigV4a +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.AuthSchemeLister import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization @@ -37,13 +39,24 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.isInputEventStream import software.amazon.smithy.rust.codegen.core.util.thenSingletonListOf +internal fun ClientCodegenContext.usesSigAuth(): Boolean = + ServiceIndex.of(model).getEffectiveAuthSchemes(serviceShape).containsKey(SigV4Trait.ID) || + usesSigV4a() + +/** + * SigV4a doesn't have a Smithy auth trait yet, so this is a hack to determine if a service supports it. + * + * In the future, Smithy's `ServiceIndex.getEffectiveAuthSchemes` should be used instead. + */ +internal fun ClientCodegenContext.usesSigV4a(): Boolean { + val endpointAuthSchemes = + serviceShape.getTrait()?.ruleSet?.let { EndpointRuleSet.fromNode(it) } + ?.also { it.typeCheck() }?.let { AuthSchemeLister.authSchemesForRuleset(it) } ?: setOf() + return endpointAuthSchemes.contains("sigv4a") +} + class SigV4AuthDecorator : ConditionalDecorator( - predicate = { codegenContext, _ -> - codegenContext?.let { - ServiceIndex.of(it.model).getEffectiveAuthSchemes(it.serviceShape) - .containsKey(SigV4Trait.ID) || it.serviceShape.usesSigV4a() - } ?: false - }, + predicate = { codegenContext, _ -> codegenContext?.usesSigAuth() ?: false }, delegateTo = object : ClientCodegenDecorator { override val name: String get() = "SigV4AuthDecorator" @@ -71,8 +84,7 @@ class SigV4AuthDecorator : ConditionalDecorator( baseAuthSchemeOptions: List, ): List { val supportsSigV4a = - codegenContext.serviceShape.usesSigV4a() - .thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } + codegenContext.usesSigV4a().thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } return baseAuthSchemeOptions + AuthSchemeOption.StaticAuthSchemeOption( SigV4Trait.ID, @@ -102,7 +114,7 @@ class SigV4AuthDecorator : ConditionalDecorator( codegenContext: ClientCodegenContext, rustCrate: RustCrate, ) { - if (codegenContext.serviceShape.usesSigV4a()) { + if (codegenContext.usesSigV4a()) { // Add optional feature for SigV4a support rustCrate.mergeFeature(Feature("sigv4a", true, listOf("aws-runtime/sigv4a"))) } @@ -198,7 +210,7 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: rustTemplate("#{SharedAuthScheme}::new(#{SigV4AuthScheme}::new())", *codegenScope) } - if (codegenContext.serviceShape.usesSigV4a()) { + if (codegenContext.usesSigV4a()) { featureGateBlock("sigv4a") { section.registerAuthScheme(this) { rustTemplate("#{SharedAuthScheme}::new(#{SigV4aAuthScheme}::new())", *codegenScope) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt index 8b857b741d..43b79f16fc 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt @@ -6,7 +6,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.endpoint import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.rulesengine.language.Endpoint import software.amazon.smithy.rulesengine.language.EndpointRuleSet import software.amazon.smithy.rulesengine.language.syntax.Identifier @@ -17,7 +16,6 @@ import software.amazon.smithy.rulesengine.language.syntax.parameters.ParameterTy import software.amazon.smithy.rulesengine.language.syntax.rule.Rule import software.amazon.smithy.rulesengine.language.syntax.rule.RuleValueVisitor import software.amazon.smithy.rulesengine.traits.ContextParamTrait -import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointStdLib import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.FunctionRegistry import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency @@ -31,7 +29,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.makeOptional import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.smithy.unsafeToRustName -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.orNull @@ -146,15 +143,3 @@ class AuthSchemeLister : RuleValueVisitor> { return setOf() } } - -/** - * SigV4a doesn't have a Smithy auth trait yet, so this is a hack to determine if a service supports it. - * - * In the future, Smithy's `ServiceIndex.getEffectiveAuthSchemes` should be used instead. - */ -fun ServiceShape.usesSigV4a(): Boolean { - val endpointAuthSchemes = - getTrait()?.ruleSet?.let { EndpointRuleSet.fromNode(it) }?.also { it.typeCheck() } - ?.let { AuthSchemeLister.authSchemesForRuleset(it) } ?: setOf() - return endpointAuthSchemes.contains("sigv4a") -} From e7bfbce9e8e3881c18f10e57ebadb119af31aa2c Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 28 Feb 2024 16:28:29 -0800 Subject: [PATCH 11/16] Use IntoShared --- .../software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt index 15912824a9..9021fb7620 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt @@ -53,6 +53,7 @@ class TokenProviderConfig(private val codegenContext: ClientCodegenContext) : Co private val codegenScope = arrayOf( *RuntimeType.preludeScope, + "IntoShared" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared"), "Token" to configReexport(AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("Token")), "ProvideToken" to configReexport( @@ -79,7 +80,7 @@ class TokenProviderConfig(private val codegenContext: ClientCodegenContext) : Co """ /// Sets the access token provider for this service pub fn token_provider(mut self, token_provider: impl #{ProvideToken} + 'static) -> Self { - self.set_token_provider(#{Some}(#{SharedTokenProvider}::new(token_provider))); + self.set_token_provider(#{Some}(#{IntoShared}::<#{SharedTokenProvider}>::into_shared(token_provider))); self } From 10105e992482362f08fe39f74292a23ddd6e894f Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 29 Feb 2024 16:53:36 -0800 Subject: [PATCH 12/16] Move ConditionalDecorator into codegen-client --- .../amazon/smithy/rustsdk/CredentialProvidersDecorator.kt | 1 + .../software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt | 1 + .../amazon/smithy/rustsdk/TokenProvidersDecorator.kt | 1 + .../smithy/rustsdk/customize/ServiceSpecificDecorator.kt | 2 +- .../codegen/client/smithy/customize}/ConditionalDecorator.kt | 5 +---- 5 files changed, 5 insertions(+), 5 deletions(-) rename {aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk => codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize}/ConditionalDecorator.kt (96%) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt index 6034939f3f..3d698e379e 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProvidersDecorator.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.configReexport import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.ConditionalDecorator import software.amazon.smithy.rust.codegen.client.smithy.customize.TestUtilFeature import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index 58247b019e..707957a243 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -16,6 +16,7 @@ import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.ConditionalDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.AuthSchemeLister import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt index 9021fb7620..af6dc58586 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.model.traits.HttpBearerAuthTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.configReexport import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.ConditionalDecorator import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt index 78e49cccd9..c0a4586cde 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt @@ -7,7 +7,7 @@ package software.amazon.smithy.rustsdk.customize import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rustsdk.ConditionalDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.ConditionalDecorator /** Only apply this decorator to the given service ID */ fun ClientCodegenDecorator.onlyApplyTo(serviceId: String): List = diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ConditionalDecorator.kt similarity index 96% rename from aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt rename to codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ConditionalDecorator.kt index 214b7f4009..355d49b41f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/ConditionalDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ConditionalDecorator.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rustsdk +package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.OperationShape @@ -12,9 +12,6 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.ToShapeId import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings -import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption -import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientProtocolMap import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization From f742a351a24a478ec5becfcadd7ba7f26bb1e8b5 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 29 Feb 2024 17:06:25 -0800 Subject: [PATCH 13/16] Set test token in `ConfigLoader::test_credentials` --- aws/rust-runtime/aws-config/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 6148a42978..f6d374d04f 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -494,7 +494,14 @@ mod loader { /// Set test credentials for use when signing requests pub fn test_credentials(self) -> Self { - self.credentials_provider(Credentials::for_tests()) + #[allow(unused_mut)] + let mut ret = self.credentials_provider(Credentials::for_tests()); + #[cfg(all(feature = "sso", feature = "test-util"))] + { + use aws_smithy_runtime_api::client::identity::http::Token; + ret = ret.token_provider(Token::for_tests()); + } + ret } /// Override the access token provider used to build [`SdkConfig`]. From 3d924d6abc3e845a0b5102effd8476a5f01eda83 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 29 Feb 2024 17:25:34 -0800 Subject: [PATCH 14/16] Improve doc comments on token provider config methods --- .../smithy/rustsdk/TokenProvidersDecorator.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt index af6dc58586..d8ea105075 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/TokenProvidersDecorator.kt @@ -80,12 +80,26 @@ class TokenProviderConfig(private val codegenContext: ClientCodegenContext) : Co rustTemplate( """ /// Sets the access token provider for this service + /// + /// Note: the [`Self::bearer_token`] and [`Self::bearer_token_resolver`] methods are + /// equivalent to this method, but take the [`Token`] and [`ResolveIdentity`] types + /// respectively. + /// + /// [`Token`]: crate::config::Token + /// [`ResolveIdentity`]: crate::config::ResolveIdentity pub fn token_provider(mut self, token_provider: impl #{ProvideToken} + 'static) -> Self { self.set_token_provider(#{Some}(#{IntoShared}::<#{SharedTokenProvider}>::into_shared(token_provider))); self } /// Sets the access token provider for this service + /// + /// Note: the [`Self::bearer_token`] and [`Self::bearer_token_resolver`] methods are + /// equivalent to this method, but take the [`Token`] and [`ResolveIdentity`] types + /// respectively. + /// + /// [`Token`]: crate::config::Token + /// [`ResolveIdentity`]: crate::config::ResolveIdentity pub fn set_token_provider(&mut self, token_provider: #{Option}<#{SharedTokenProvider}>) -> &mut Self { if let Some(token_provider) = token_provider { self.runtime_components.set_identity_resolver(#{HTTP_BEARER_AUTH_SCHEME_ID}, token_provider); From ec3ba7a3cb6509b11114909dd9914365deffba85 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 29 Feb 2024 18:04:55 -0800 Subject: [PATCH 15/16] Update changelog --- CHANGELOG.next.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 99b785798a..ed8427b899 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -34,3 +34,9 @@ message = "[`SdkBody`](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/ references = ["smithy-rs#3365", "aws-sdk-rust#1046"] meta = { "breaking" = false, "tada" = true, "bug" = false, "target" = "all" } authors = ["cayman-amzn", "rcoh"] + +[[aws-sdk-rust]] +message = "Added support for SSO bearer token authentication. The aws-sdk-codecatalyst crate can now send requests without erroring." +references = ["aws-sdk-rust#703", "smithy-rs#3453"] +meta = { "breaking" = false, "bug" = false, "tada" = true } +author = "jdisanti" From 89a2ea8895f32066e1ad803ec634683c307b0c84 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 6 Mar 2024 11:24:44 -0800 Subject: [PATCH 16/16] Incorporate feedback --- .../aws-config/src/default_provider/token.rs | 2 +- aws/rust-runtime/aws-config/src/profile/token.rs | 14 +------------- .../codecatalyst/tests/sso_bearer_auth.json | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/aws/rust-runtime/aws-config/src/default_provider/token.rs b/aws/rust-runtime/aws-config/src/default_provider/token.rs index 164b71ae29..66236b32b0 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/token.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/token.rs @@ -106,7 +106,7 @@ impl Builder { } /// Override the configuration used for this provider - pub fn configure(mut self, config: ProviderConfig) -> Self { + pub(crate) fn configure(mut self, config: ProviderConfig) -> Self { self.region_chain = self.region_chain.configure(&config); self.conf = Some(config); self diff --git a/aws/rust-runtime/aws-config/src/profile/token.rs b/aws/rust-runtime/aws-config/src/profile/token.rs index 74928d105e..1865e65d7f 100644 --- a/aws/rust-runtime/aws-config/src/profile/token.rs +++ b/aws/rust-runtime/aws-config/src/profile/token.rs @@ -128,19 +128,7 @@ pub struct Builder { impl Builder { /// Override the configuration for the [`ProfileFileTokenProvider`] - /// - /// # Examples - /// - /// ```no_run - /// # async fn test() { - /// use aws_config::profile::ProfileFileTokenProvider; - /// use aws_config::provider_config::ProviderConfig; - /// let provider = ProfileFileTokenProvider::builder() - /// .configure(&ProviderConfig::with_default_region().await) - /// .build(); - /// # } - /// ``` - pub fn configure(mut self, provider_config: &ProviderConfig) -> Self { + pub(crate) fn configure(mut self, provider_config: &ProviderConfig) -> Self { self.provider_config = Some(provider_config.clone()); self } diff --git a/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json index 7ffb08573a..866b1b1e58 100644 --- a/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json +++ b/aws/sdk/integration-tests/codecatalyst/tests/sso_bearer_auth.json @@ -121,6 +121,6 @@ } } ], - "docs": "todo docs", + "docs": "traffic for codecatalyst sso_bearer_auth integration test", "version": "V0" }