-module(aws@internal@providers@process). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/aws/internal/providers/process.gleam"). -export([fetch/2]). -export_type([process_credentials/0, error/0, raw_output/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Credential-process provider. Runs an external command and reads JSON\n" " credentials from its standard output, per the AWS CLI's\n" " `credential_process` spec.\n" "\n" " Expected output:\n" " {\n" " \"Version\": 1,\n" " \"AccessKeyId\": \"...\",\n" " \"SecretAccessKey\": \"...\",\n" " \"SessionToken\": \"...\", // optional\n" " \"Expiration\": \"ISO 8601 Z\" // optional; absent = non-expiring\n" " }\n" ). -type process_credentials() :: {process_credentials, binary(), binary(), gleam@option:option(binary()), gleam@option:option(integer())}. -type error() :: {launch_failed, binary()} | {bad_output, binary()}. -type raw_output() :: {raw_output, integer(), binary(), binary(), gleam@option:option(binary()), gleam@option:option(binary())}. -file("src/aws/internal/providers/process.gleam", 119). -spec raw_decoder() -> gleam@dynamic@decode:decoder(raw_output()). raw_decoder() -> gleam@dynamic@decode:field( <<"Version"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Version) -> gleam@dynamic@decode:field( <<"AccessKeyId"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Access_key_id) -> gleam@dynamic@decode:field( <<"SecretAccessKey"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Secret_access_key) -> gleam@dynamic@decode:then( gleam@dynamic@decode:optionally_at( [<<"SessionToken"/utf8>>], none, gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Field@0) -> {some, Field@0} end ) ), fun(Session_token) -> gleam@dynamic@decode:then( gleam@dynamic@decode:optionally_at( [<<"Expiration"/utf8>>], none, gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Field@0) -> {some, Field@0} end ) ), fun(Expiration) -> gleam@dynamic@decode:success( {raw_output, Version, Access_key_id, Secret_access_key, Session_token, Expiration} ) end ) end ) end ) end ) end ). -file("src/aws/internal/providers/process.gleam", 142). -spec decode_credentials(bitstring()) -> {ok, process_credentials()} | {error, error()}. decode_credentials(Stdout) -> gleam@result:'try'( begin _pipe = gleam@bit_array:to_string(Stdout), gleam@result:replace_error( _pipe, {bad_output, <<"non-utf8 stdout"/utf8>>} ) end, fun(Text) -> gleam@result:'try'( begin _pipe@1 = gleam@json:parse(Text, raw_decoder()), gleam@result:map_error( _pipe@1, fun(_) -> {bad_output, <<"stdout is not the expected credential_process JSON"/utf8>>} end ) end, fun(Raw) -> case erlang:element(2, Raw) of 1 -> Expires_at = case erlang:element(6, Raw) of {some, Ts} -> case aws_ffi:parse_iso8601(Ts) of {ok, T} -> {some, T}; {error, _} -> none end; none -> none end, {ok, {process_credentials, erlang:element(3, Raw), erlang:element(4, Raw), erlang:element(5, Raw), Expires_at}}; Other -> {error, {bad_output, <<"unsupported credential_process Version "/utf8, (erlang:integer_to_binary(Other))/binary>>}} end end ) end ). -file("src/aws/internal/providers/process.gleam", 100). -spec do_reverse(list(HLA), list(HLA)) -> list(HLA). do_reverse(Xs, Acc) -> case Xs of [] -> Acc; [H | T] -> do_reverse(T, [H | Acc]) end. -file("src/aws/internal/providers/process.gleam", 96). -spec list_reverse(list(HKX)) -> list(HKX). list_reverse(Xs) -> do_reverse(Xs, []). -file("src/aws/internal/providers/process.gleam", 85). -spec do_filter(list(HKT), fun((HKT) -> boolean()), list(HKT)) -> list(HKT). do_filter(Xs, Keep, Acc) -> case Xs of [] -> list_reverse(Acc); [H | T] -> case Keep(H) of true -> do_filter(T, Keep, [H | Acc]); false -> do_filter(T, Keep, Acc) end end. -file("src/aws/internal/providers/process.gleam", 81). -spec list_filter(list(HKQ), fun((HKQ) -> boolean())) -> list(HKQ). list_filter(Xs, Keep) -> do_filter(Xs, Keep, []). -file("src/aws/internal/providers/process.gleam", 70). -spec split_command(binary()) -> {ok, {binary(), list(binary())}} | {error, nil}. split_command(Command) -> Parts = begin _pipe = Command, _pipe@1 = gleam@string:split(_pipe, <<" "/utf8>>), list_filter(_pipe@1, fun(S) -> S /= <<""/utf8>> end) end, case Parts of [] -> {error, nil}; [Program | Args] -> {ok, {Program, Args}} end. -file("src/aws/internal/providers/process.gleam", 45). ?DOC( " Run the given command line and decode its stdout as credential-process\n" " JSON. `command` is the verbatim string from `credential_process`; we\n" " split it on whitespace into program + arguments before launch.\n" ). -spec fetch( fun((binary(), list(binary())) -> {ok, {integer(), bitstring()}} | {error, nil}), binary() ) -> {ok, process_credentials()} | {error, error()}. fetch(Runner, Command) -> gleam@result:'try'( begin _pipe = split_command(Command), gleam@result:replace_error( _pipe, {launch_failed, <<"empty credential_process command"/utf8>>} ) end, fun(_use0) -> {Program, Args} = _use0, gleam@result:'try'( begin _pipe@1 = Runner(Program, Args), gleam@result:replace_error( _pipe@1, {launch_failed, <<<<"could not run '"/utf8, Program/binary>>/binary, "'"/utf8>>} ) end, fun(_use0@1) -> {Exit, Stdout} = _use0@1, case Exit of 0 -> decode_credentials(Stdout); Code -> {error, {bad_output, <<"credential_process exited with status "/utf8, (erlang:integer_to_binary(Code))/binary>>}} end end ) end ).