okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

Dylan Shepardfix(providers): harden cloud credentials and Vertex wire semantics794bda6

main
4.5 KiB67 linesraw
1%% Hermetic AWS file/helper fixtures: no network or user credentials.
2-module(albedo_bedrock_test_support).
3-export([profile_fixtures/0]).
4
5profile_fixtures() ->
6    Dir = filename:join("/tmp", "albedo-bedrock-" ++ os:getpid() ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))),
7    ok = file:make_dir(Dir),
8    Config = filename:join(Dir, "config"),
9    Creds = filename:join(Dir, "credentials"),
10    Helper = filename:join(Dir, "helper script.py"),
11    Settings = filename:join(Dir, "config.json"),
12    Vars = [{"AWS_PROFILE", "work"}, {"AWS_CONFIG_FILE", Config},
13            {"AWS_SHARED_CREDENTIALS_FILE", Creds}, {"BEDROCK_HELPER_TEST", "custom-value"},
14            {"AWS_ACCESS_KEY_ID", ""}, {"AWS_SECRET_ACCESS_KEY", ""},
15            {"AWS_SESSION_TOKEN", ""}, {"AWS_BEARER_TOKEN_BEDROCK", ""}],
16    Old = [{K, os:getenv(K)} || {K, _} <- Vars],
17    try
18        [os:putenv(K, V) || {K, V} <- Vars],
19        %% Credentials-only named profile; missing config is not a hard gate.
20        ok = file:write_file(Creds, <<"[work]\naws_access_key_id = shared\naws_secret_access_key = shared-secret\n">>),
21        {ok, {credentials, <<"shared">>, <<"shared-secret">>, none}} = resolve(),
22        %% Shared keys outrank config keys; never blend tokens across sources.
23        ok = file:write_file(Config, <<"[profile work]\naws_access_key_id = config\naws_secret_access_key = config-secret\naws_session_token = config-token\n">>),
24        {ok, {credentials, <<"shared">>, <<"shared-secret">>, none}} = resolve(),
25        ok = file:delete(Creds),
26        {ok, {credentials, <<"config">>, <<"config-secret">>, {some, <<"config-token">>}}} = resolve(),
27        %% Rewrites are read fresh, not cached.
28        ok = file:write_file(Config, <<"[profile work]\naws_access_key_id = refreshed\naws_secret_access_key = new-secret\n">>),
29        {ok, {credentials, <<"refreshed">>, <<"new-secret">>, none}} = resolve(),
30        %% A quoted script path/argument and custom environment survive argv parsing.
31        Python = os:find_executable("python3"),
32        true = is_list(Python),
33        ok = file:write_file(Helper, <<"import os,sys,json\nprint(json.dumps({'AccessKeyId':os.environ['AWS_PROFILE'], 'SecretAccessKey':os.environ['AWS_CONFIG_FILE'], 'SessionToken':os.environ['BEDROCK_HELPER_TEST'] + ':' + sys.argv[1]}))\n">>),
34        Command = iolist_to_binary(["\"", Python, "\" \"", Helper, "\" \"team account\""]),
35        ok = file:write_file(Config, ["[profile work]\ncredential_process = ", Command, "\n"]),
36        {ok, {credentials, <<"work">>, ConfigBin, {some, <<"custom-value:team account">>}}} = resolve(),
37        ConfigBin = unicode:characters_to_binary(Config),
38        %% Existing usage-feed API still strips AWS/custom vars.
39        {0, <<"filtered\n">>} = albedo_usage_core:run_command(
40            unicode:characters_to_binary(Python),
41            [<<"-c">>, <<"import os; print('filtered' if 'AWS_PROFILE' not in os.environ and 'BEDROCK_HELPER_TEST' not in os.environ else 'leaked')">>], none, {some, 15000}),
42        %% Failed stdout may contain credentials: never display it.
43        ok = file:write_file(Helper, <<"import sys\nprint('sensitive-secret')\nsys.exit(2)\n">>),
44        {error, <<"credential_process exited 2">>} = resolve(),
45        %% Default credentials-only profile also works.
46        os:putenv("AWS_PROFILE", ""),
47        ok = file:delete(Config),
48        ok = file:write_file(Creds, <<"[default]\naws_access_key_id = default-key\naws_secret_access_key = default-secret\n">>),
49        {ok, {credentials, <<"default-key">>, <<"default-secret">>, none}} = resolve(),
50        %% One resolved upstream must authenticate anew on each model step.
51        ok = file:write_file(Settings, <<"{\"providers\":{\"bedrock\":{\"baseUrl\":\"https://bedrock-runtime.us-east-1.amazonaws.com\"}}}">>),
52        nil = 'harness@bedrock_test':reused_upstream_refreshes(unicode:characters_to_binary(Dir), fun() ->
53            ok = file:delete(Creds), nil
54        end),
55        %% A partial source fails without borrowing its secret from config.
56        os:putenv("AWS_PROFILE", "work"),
57        ok = file:write_file(Creds, <<"[work]\naws_access_key_id = partial\n">>),
58        ok = file:write_file(Config, <<"[profile work]\naws_secret_access_key = other-secret\n">>),
59        {error, <<"profile work has no aws_secret_access_key">>} = resolve(),
60        true
61    after
62        [case V of false -> os:unsetenv(K); _ -> os:putenv(K, V) end || {K, V} <- Old],
63        [file:delete(P) || P <- [Config, Creds, Helper, Settings]],
64        file:del_dir(Dir)
65    end.
66
67resolve() -> 'albedo@harness@extensions@bedrock@aws_profile':resolve().