Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(codegen): add AssumeRoleOutput #214

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions codegen/src/v1/aws_conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub fn codegen(ops: &Operations, rust_types: &RustTypes) {
match name.as_str() {
"SelectObjectContentRequest" => continue,
"SelectObjectContentInput" => continue,
"AssumeRoleOutput" => continue,
_ if super::sts::NAMES.iter().any(|n| n.eq_ignore_ascii_case(name)) => continue,
_ => {}
}

Expand Down
3 changes: 2 additions & 1 deletion codegen/src/v1/dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use rust_utils::default::default;
use serde_json::Value;

pub fn to_type_name(shape_name: &str) -> &str {
shape_name.strip_prefix("com.amazonaws.s3#").unwrap()
let Some((_, name)) = shape_name.split_once('#') else { panic!() };
name
}

pub type RustTypes = BTreeMap<String, rust::Type>;
Expand Down
9 changes: 8 additions & 1 deletion codegen/src/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod error;
mod headers;
mod ops;
mod s3_trait;
mod sts;
mod xml;

mod aws_conv;
Expand All @@ -17,7 +18,13 @@ mod aws_proxy;
use codegen_writer::Codegen;

pub fn run() {
let model = smithy::Model::load_json("model/s3.json");
let model = {
let mut s3_model = smithy::Model::load_json("model/s3.json");
let mut sts_model = smithy::Model::load_json("model/sts.json");
sts::reduce(&mut sts_model);
s3_model.shapes.append(&mut sts_model.shapes);
s3_model
};

let ops = ops::collect_operations(&model);
let rust_types = dto::collect_rust_types(&model, &ops);
Expand Down
54 changes: 54 additions & 0 deletions codegen/src/v1/sts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::v2::smithy;
use crate::v2::utils::o;

use std::mem;
use std::ops::Not;

use heck::ToUpperCamelCase;

pub const NAMES: &[&str] = &[
"AssumeRoleResponse",
"AssumedRoleUser",
"Credentials",
"nonNegativeIntegerType",
"sourceIdentityType",
"arnType",
"accessKeyIdType",
"accessKeySecretType",
"dateType",
"tokenType",
"assumedRoleIdType",
];

pub fn reduce(model: &mut smithy::Model) {
for (shape_name, mut shape) in mem::take(&mut model.shapes) {
let Some((_, name)) = shape_name.split_once('#') else { panic!() };
if NAMES.contains(&name).not() {
continue;
}

let Some((_, name)) = shape_name.split_once('#') else { panic!() };
let new_name = match name {
"AssumeRoleResponse" => o("AssumeRoleOutput"),
_ if name.as_bytes()[0].is_ascii_lowercase() => name.to_upper_camel_case(),
_ => o(name),
};

if let smithy::Shape::Structure(ref mut shape) = shape {
for member in shape.members.values_mut() {
let Some((_, name)) = member.target.split_once('#') else { panic!() };
let new_name = match name {
_ if name.as_bytes()[0].is_ascii_lowercase() => name.to_upper_camel_case(),
_ => continue,
};
member.target = member.target.replace(name, &new_name);
}
if name == "AssumeRoleResponse" {
shape.traits.set("smithy.api#xmlName", name.into());
}
}

let new_shape_name = format!("com.amazonaws.s3#{new_name}");
assert!(model.shapes.insert(new_shape_name, shape).is_none());
}
}
43 changes: 35 additions & 8 deletions codegen/src/v1/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ pub fn codegen(ops: &Operations, rust_types: &RustTypes) {
for (&ty_name, &xml_name) in &root_type_names {
match xml_name {
Some(xml_name) if xml_name != ty_name => {
g!("// Serialize: {ty_name} {xml_name:?}");
if can_impl_serialize(ty_name) {
g!("// Serialize: {ty_name} {xml_name:?}");
}
if can_impl_deserialize(rust_types, ty_name) {
g!("// Deserialize: {ty_name} {xml_name:?}");
}
}
_ => {
g!("// Serialize: {ty_name}");
if can_impl_serialize(ty_name) {
g!("// Serialize: {ty_name}");
}
if can_impl_deserialize(rust_types, ty_name) {
g!("// Deserialize: {ty_name}");
}
Expand All @@ -44,8 +48,10 @@ pub fn codegen(ops: &Operations, rust_types: &RustTypes) {
}
g!();
for ty_name in &field_type_names {
g!("// SerializeContent: {ty_name}");
if can_impl_deserialize(rust_types, ty_name) {
if can_impl_serialize_content(ty_name) {
g!("// SerializeContent: {ty_name}");
}
if can_impl_deserialize_content(rust_types, ty_name) {
g!("// DeserializeContent: {ty_name}");
}
}
Expand Down Expand Up @@ -100,7 +106,7 @@ fn collect_xml_types<'a>(
}

{
let extra = ["Progress", "Stats"];
let extra = ["Progress", "Stats", "AssumeRoleOutput"];
for ty_name in extra {
root_type_names.insert(ty_name, None);
field_type_names.insert(ty_name);
Expand Down Expand Up @@ -153,7 +159,28 @@ fn collect_xml_types<'a>(
(root_type_names, field_type_names)
}

const SPECIAL_TYPES: &[&str] = &["AssumeRoleOutput"];

fn can_impl_serialize(ty_name: &str) -> bool {
if SPECIAL_TYPES.contains(&ty_name) {
return false;
}
can_impl_serialize_content(ty_name)
}

fn can_impl_serialize_content(_ty_name: &str) -> bool {
true
}

fn can_impl_deserialize(rust_types: &RustTypes, ty_name: &str) -> bool {
if SPECIAL_TYPES.contains(&ty_name) {
return false;
}

can_impl_deserialize_content(rust_types, ty_name)
}

fn can_impl_deserialize_content(rust_types: &RustTypes, ty_name: &str) -> bool {
let rust_type = &rust_types[ty_name];
match rust_type {
rust::Type::Struct(ty) => {
Expand Down Expand Up @@ -191,7 +218,7 @@ fn codegen_xml_serde(ops: &Operations, rust_types: &RustTypes, root_type_names:
// https://github.com/Nugine/s3s/issues/2
let xml_name = xml_name.or(ty.xml_name.as_deref()).unwrap_or(&ty.name);

{
if can_impl_serialize(&ty.name) {
g!("impl Serialize for {} {{", ty.name);
g!("fn serialize<W: Write>(&self, s: &mut Serializer<W>) -> SerResult {{");

Expand Down Expand Up @@ -280,7 +307,7 @@ fn codegen_xml_serde_content(ops: &Operations, rust_types: &RustTypes, field_typ

#[allow(clippy::too_many_lines)]
fn codegen_xml_serde_content_struct(_ops: &Operations, rust_types: &RustTypes, ty: &rust::Struct) {
{
if can_impl_serialize_content(&ty.name) {
g!("impl SerializeContent for {} {{", ty.name);
g!(
"fn serialize_content<W: Write>(&self, {}: &mut Serializer<W>) -> SerResult {{",
Expand Down Expand Up @@ -341,7 +368,7 @@ fn codegen_xml_serde_content_struct(_ops: &Operations, rust_types: &RustTypes, t
g!("}}");
g!();
}
if can_impl_deserialize(rust_types, &ty.name) {
if can_impl_deserialize_content(rust_types, &ty.name) {
g!("impl<'xml> DeserializeContent<'xml> for {} {{", ty.name);
g!(
"fn deserialize_content({}: &mut Deserializer<'xml>) -> DeResult<Self> {{",
Expand Down
5 changes: 5 additions & 0 deletions codegen/src/v2/smithy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ impl Model {
}

impl Traits {
pub fn set(&mut self, key: &str, value: Value) {
let map = self.0.get_or_insert_with(Map::new);
map.insert(key.to_owned(), value);
}

pub fn get(&self, key: &str) -> Option<&Value> {
let map = self.0.as_ref()?;
map.get(key)
Expand Down
121 changes: 120 additions & 1 deletion crates/s3s/src/dto/generated.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Auto generated by `codegen/src/v1/dto.rs:347`
//! Auto generated by `codegen/src/v1/dto.rs:348`

#![allow(clippy::empty_structs_with_brackets)]
#![allow(clippy::too_many_lines)]
Expand Down Expand Up @@ -161,8 +161,12 @@ impl fmt::Debug for AccessControlTranslation {
}
}

pub type AccessKeyIdType = String;

pub type AccessKeyIdValue = String;

pub type AccessKeySecretType = String;

pub type AccessPointAlias = bool;

pub type AccessPointArn = String;
Expand Down Expand Up @@ -376,6 +380,88 @@ impl FromStr for ArchiveStatus {
}
}

pub type ArnType = String;

/// <p>Contains the response to a successful <a>AssumeRole</a> request, including
/// temporary Amazon Web Services credentials that can be used to make Amazon Web Services requests. </p>
#[derive(Clone, Default, PartialEq)]
pub struct AssumeRoleOutput {
/// <p>The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers that you
/// can use to refer to the resulting temporary security credentials. For example, you can
/// reference these credentials as a principal in a resource-based policy by using the ARN or
/// assumed role ID. The ARN and ID include the <code>RoleSessionName</code> that you specified
/// when you called <code>AssumeRole</code>. </p>
pub assumed_role_user: Option<AssumedRoleUser>,
/// <p>The temporary security credentials, which include an access key ID, a secret access key,
/// and a security (or session) token.</p>
/// <note>
/// <p>The size of the security token that STS API operations return is not fixed. We
/// strongly recommend that you make no assumptions about the maximum size.</p>
/// </note>
pub credentials: Option<Credentials>,
/// <p>A percentage value that indicates the packed size of the session policies and session
/// tags combined passed in the request. The request fails if the packed size is greater than 100 percent,
/// which means the policies and tags exceeded the allowed space.</p>
pub packed_policy_size: Option<NonNegativeIntegerType>,
/// <p>The source identity specified by the principal that is calling the
/// <code>AssumeRole</code> operation.</p>
/// <p>You can require users to specify a source identity when they assume a role. You do this
/// by using the <code>sts:SourceIdentity</code> condition key in a role trust policy. You can
/// use source identity information in CloudTrail logs to determine who took actions with a role.
/// You can use the <code>aws:SourceIdentity</code> condition key to further control access to
/// Amazon Web Services resources based on the value of source identity. For more information about using
/// source identity, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html">Monitor and control
/// actions taken with assumed roles</a> in the
/// <i>IAM User Guide</i>.</p>
/// <p>The regex used to validate this parameter is a string of characters consisting of upper-
/// and lower-case alphanumeric characters with no spaces. You can also include underscores or
/// any of the following characters: =,.@-</p>
pub source_identity: Option<SourceIdentityType>,
}

impl fmt::Debug for AssumeRoleOutput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("AssumeRoleOutput");
if let Some(ref val) = self.assumed_role_user {
d.field("assumed_role_user", val);
}
if let Some(ref val) = self.credentials {
d.field("credentials", val);
}
if let Some(ref val) = self.packed_policy_size {
d.field("packed_policy_size", val);
}
if let Some(ref val) = self.source_identity {
d.field("source_identity", val);
}
d.finish_non_exhaustive()
}
}

pub type AssumedRoleIdType = String;

/// <p>The identifiers for the temporary security credentials that the operation
/// returns.</p>
#[derive(Clone, PartialEq)]
pub struct AssumedRoleUser {
/// <p>The ARN of the temporary security credentials that are returned from the <a>AssumeRole</a> action. For more information about ARNs and how to use them in
/// policies, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html">IAM Identifiers</a> in the
/// <i>IAM User Guide</i>.</p>
pub arn: ArnType,
/// <p>A unique identifier that contains the role ID and the role session name of the role that
/// is being assumed. The role ID is generated by Amazon Web Services when the role is created.</p>
pub assumed_role_id: AssumedRoleIdType,
}

impl fmt::Debug for AssumedRoleUser {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("AssumedRoleUser");
d.field("arn", &self.arn);
d.field("assumed_role_id", &self.assumed_role_id);
d.finish_non_exhaustive()
}
}

/// <p> In terms of implementation, a Bucket is a resource. </p>
#[derive(Clone, Default, PartialEq)]
pub struct Bucket {
Expand Down Expand Up @@ -3326,6 +3412,31 @@ impl fmt::Debug for CreateMultipartUploadOutput {

pub type CreationDate = Timestamp;

/// <p>Amazon Web Services credentials for API authentication.</p>
#[derive(Clone, PartialEq)]
pub struct Credentials {
/// <p>The access key ID that identifies the temporary security credentials.</p>
pub access_key_id: AccessKeyIdType,
/// <p>The date on which the current credentials expire.</p>
pub expiration: DateType,
/// <p>The secret access key that can be used to sign requests.</p>
pub secret_access_key: AccessKeySecretType,
/// <p>The token that users must pass to the service API to use the temporary
/// credentials.</p>
pub session_token: TokenType,
}

impl fmt::Debug for Credentials {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("Credentials");
d.field("access_key_id", &self.access_key_id);
d.field("expiration", &self.expiration);
d.field("secret_access_key", &self.secret_access_key);
d.field("session_token", &self.session_token);
d.finish_non_exhaustive()
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DataRedundancy(Cow<'static, str>);

Expand Down Expand Up @@ -3364,6 +3475,8 @@ impl FromStr for DataRedundancy {

pub type Date = Timestamp;

pub type DateType = Timestamp;

pub type Days = i32;

pub type DaysAfterInitiation = i32;
Expand Down Expand Up @@ -12623,6 +12736,8 @@ impl fmt::Debug for NoSuchUpload {
}
}

pub type NonNegativeIntegerType = i32;

/// <p>Specifies when noncurrent object versions expire. Upon expiration, Amazon S3 permanently
/// deletes the noncurrent object versions. You set this lifecycle configuration action on a
/// bucket that has versioning enabled (or suspended) to request that Amazon S3 delete noncurrent
Expand Down Expand Up @@ -17959,6 +18074,8 @@ pub type Size = i64;

pub type SkipValidation = bool;

pub type SourceIdentityType = String;

/// <p>A container that describes additional filters for identifying the source objects that
/// you want to replicate. You can choose to enable or disable the replication of these
/// objects. Currently, Amazon S3 supports only the filter that you can specify for objects created
Expand Down Expand Up @@ -18430,6 +18547,8 @@ pub type TieringList = List<Tiering>;

pub type Token = String;

pub type TokenType = String;

pub type TopicArn = String;

/// <p>A container for specifying the configuration for publication of messages to an Amazon
Expand Down
Loading