<commit_before>function _can_read_file(file_name::String)
    return isfile(file_name) && try
        isreadable(open(file_name, "r"))
    catch e
        false
    end
end
_begins_with_ec2(file_name::String) = return uppercase(String(read(file_name, 3))) == "EC2"
function _ends_with_ec2(file_name::String)
    return endswith(strip(uppercase(read(file_name, String))), "EC2")
end

"""
Generate a valid role session name. Currently only ensures that the session name is
64-characters or less.
"""
function _role_session_name(prefix, name, suffix)
    b = IOBuffer()
    write(b, prefix, name)
    truncate(b, min(64 - length(suffix), b.size))  # Assumes ASCII
    write(b, suffix)
    return String(take!(b))
end

"""
Get the value for `key` in the `ini` file for a given `profile`.
"""
function _get_ini_value(
    ini::Inifile, profile::AbstractString, key::AbstractString; default_value=nothing
)
    value = get(ini, "profile $profile", key)
    value === :notfound && (value = get(ini, profile, key))
    value === :notfound && (value = default_value)

    return value
end

function _aws_profile_config(ini::Inifile, profile::AbstractString)
    if profile != "default"
        profile = "profile $profile"
    end

    return get(sections(ini), profile, Dict())
end

function _aws_profile_config(ini::Inifile, profile::Nothing)
    return _aws_profile_config(ini, _aws_get_profile())
end

function _aws_profile_config(config_file::AbstractString, profile)
    isfile(config_file) || return Dict()
    return _aws_profile_config(read(Inifile(), config_file), profile)
end

function _aws_profile_config(config_file::Nothing, profile)
    return _aws_profile_config(dot_aws_config_file(), profile)
end

"""
Retrieve the `AWSCredentials` for a given role from Security Token Services (STS).
"""
function _aws_get_role(role::AbstractString, ini::Inifile)
    settings = aws_get_profile_settings(role, ini)
    source_profile = get(settings, "source_profile", nothing)
    role_arn = get(settings, "role_arn", nothing)
    mfa_serial = get(settings, "mfa_serial", nothing)

    source_profile === nothing && return nothing

    credentials = nothing
    for f in (dot_aws_credentials, dot_aws_config)
        credentials = f(source_profile)
        credentials === nothing || break
    end

    credentials === nothing && return nothing
    config = AWSConfig(;
        creds=credentials, region=aws_get_region(; config=ini, profile=source_profile)
    )

    params = LittleDict(
        "RoleArn" => role_arn, "RoleSessionName" => replace(role, r"[^\w+=,.@-]" => s"-")
    )

    if mfa_serial !== nothing
        params["SerialNumber"] = mfa_serial
        token = Base.getpass("Enter MFA code for $mfa_serial")
        params["TokenCode"] = read(token, String)
        Base.shred!(token)
    end

    # RoleSessionName Documentation
    # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
    role = AWSServices.sts("AssumeRole", params; aws_config=config)

    role_creds = role["AssumeRoleResult"]["Credentials"]<commit_msg>Early exit if profile settings are nothing<commit_after>function _can_read_file(file_name::String)
    return isfile(file_name) && try
        isreadable(open(file_name, "r"))
    catch e
        false
    end
end
_begins_with_ec2(file_name::String) = return uppercase(String(read(file_name, 3))) == "EC2"
function _ends_with_ec2(file_name::String)
    return endswith(strip(uppercase(read(file_name, String))), "EC2")
end

"""
Generate a valid role session name. Currently only ensures that the session name is
64-characters or less.
"""
function _role_session_name(prefix, name, suffix)
    b = IOBuffer()
    write(b, prefix, name)
    truncate(b, min(64 - length(suffix), b.size))  # Assumes ASCII
    write(b, suffix)
    return String(take!(b))
end

"""
Get the value for `key` in the `ini` file for a given `profile`.
"""
function _get_ini_value(
    ini::Inifile, profile::AbstractString, key::AbstractString; default_value=nothing
)
    value = get(ini, "profile $profile", key)
    value === :notfound && (value = get(ini, profile, key))
    value === :notfound && (value = default_value)

    return value
end

function _aws_profile_config(ini::Inifile, profile::AbstractString)
    if profile != "default"
        profile = "profile $profile"
    end

    return get(sections(ini), profile, Dict())
end

function _aws_profile_config(ini::Inifile, profile::Nothing)
    return _aws_profile_config(ini, _aws_get_profile())
end

function _aws_profile_config(config_file::AbstractString, profile)
    isfile(config_file) || return Dict()
    return _aws_profile_config(read(Inifile(), config_file), profile)
end

function _aws_profile_config(config_file::Nothing, profile)
    return _aws_profile_config(dot_aws_config_file(), profile)
end

"""
Retrieve the `AWSCredentials` for a given role from Security Token Services (STS).
"""
function _aws_get_role(role::AbstractString, ini::Inifile)
    settings = aws_get_profile_settings(role, ini)
    settings === nothing && return nothing

    source_profile = get(settings, "source_profile", nothing)
    source_profile === nothing && return nothing

    role_arn = get(settings, "role_arn", nothing)
    mfa_serial = get(settings, "mfa_serial", nothing)

    credentials = nothing
    for f in (dot_aws_credentials, dot_aws_config)
        credentials = f(source_profile)
        credentials === nothing || break
    end

    credentials === nothing && return nothing
    config = AWSConfig(;
        creds=credentials, region=aws_get_region(; config=ini, profile=source_profile)
    )

    params = LittleDict(
        "RoleArn" => role_arn, "RoleSessionName" => replace(role, r"[^\w+=,.@-]" => s"-")
    )

    if mfa_serial !== nothing
        params["SerialNumber"] = mfa_serial
        token = Base.getpass("Enter MFA code for $mfa_serial")
        params["TokenCode"] = read(token, String)
        Base.shred!(token)
    end

    # RoleSessionName Documentation
    # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
    role = AWSServices.sts("AssumeRole", params; aws_config=config)

    role_creds = role["AssumeRoleResult"]["Credentials"]
{'fraction_non_alphanumeric': 0.12247209189451545, 'fraction_numerical': 0.002912150137518201, 'mean_word_length': 4.375652173913044, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4012588', 'n_tokens_mistral': 1975, 'n_tokens_neox': 1932, 'n_words': 465}