diff --git a/config/dev_sys.config.src b/config/dev_sys.config.src index dad93ed..e1e174b 100644 --- a/config/dev_sys.config.src +++ b/config/dev_sys.config.src @@ -35,6 +35,7 @@ ]}, {kura, [ {repo, asobi_repo}, + {backend, kura_backend_postgres}, {host, "${ASOBI_DB_HOST}"}, {port, 5432}, {database, "${ASOBI_DB_NAME}"}, diff --git a/config/prod_sys.config.src b/config/prod_sys.config.src index ef77b46..d1e9dd6 100644 --- a/config/prod_sys.config.src +++ b/config/prod_sys.config.src @@ -36,6 +36,7 @@ ]}, {kura, [ {repo, asobi_repo}, + {backend, kura_backend_postgres}, {host, "${ASOBI_DB_HOST}"}, {port, 5432}, {database, "${ASOBI_DB_NAME}"}, diff --git a/rebar.lock b/rebar.lock index d557e07..e1336a7 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,13 +1,13 @@ {"1.2.0", [{<<"asobi">>, {git,"https://github.com/widgrensit/asobi.git", - {ref,"fc59c974d87c5977d599b380c7086cc94d5368e4"}}, + {ref,"a6e376a7b6166e95009e0ba9088c9ade2c11471e"}}, 0}, {<<"backoff">>,{pkg,<<"backoff">>,<<"1.1.6">>},3}, - {<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.13.0">>},2}, - {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.16.1">>},3}, + {<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.15.0">>},2}, + {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.17.1">>},3}, {<<"erlydtl">>,{pkg,<<"erlydtl">>,<<"0.14.0">>},2}, - {<<"jhn_stdlib">>,{pkg,<<"jhn_stdlib">>,<<"5.4.0">>},2}, + {<<"jhn_stdlib">>,{pkg,<<"jhn_stdlib">>,<<"5.11.2">>},2}, {<<"jose">>,{pkg,<<"jose">>,<<"1.11.12">>},3}, {<<"kura">>, {git,"https://github.com/Taure/kura.git", @@ -18,7 +18,7 @@ {ref,"30651b35986bda5fc84d89fc141936cb70b636ab"}}, 1}, {<<"luerl">>,{pkg,<<"luerl">>,<<"1.5.1">>},0}, - {<<"nova">>,{pkg,<<"nova">>,<<"0.14.1">>},1}, + {<<"nova">>,{pkg,<<"nova">>,<<"0.14.3">>},1}, {<<"nova_auth">>,{pkg,<<"nova_auth">>,<<"0.1.1">>},1}, {<<"nova_auth_oidc">>,{pkg,<<"nova_auth_oidc">>,<<"0.1.0">>},1}, {<<"nova_resilience">>,{pkg,<<"nova_resilience">>,<<"1.0.3">>},1}, @@ -30,19 +30,19 @@ {<<"routing_tree">>,{pkg,<<"routing_tree">>,<<"1.0.11">>},2}, {<<"seki">>,{pkg,<<"seki">>,<<"0.4.3">>},1}, {<<"shigoto">>,{pkg,<<"shigoto">>,<<"1.2.2">>},1}, - {<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.4.1">>},2}, + {<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.4.2">>},2}, {<<"telemetry_registry">>,{pkg,<<"telemetry_registry">>,<<"0.3.2">>},3}, {<<"thoas">>,{pkg,<<"thoas">>,<<"1.2.1">>},2}]}. [ {pkg_hash,[ {<<"backoff">>, <<"83B72ED2108BA1EE8F7D1C22E0B4A00CFE3593A67DBC792799E8CCE9F42F796B">>}, - {<<"cowboy">>, <<"09D770DD5F6A22CC60C071F432CD7CB87776164527F205C5A6B0F24FF6B38990">>}, - {<<"cowlib">>, <<"318D385D55F657E9A5005838C4E426E13DCD724A691438384B6165A69687E531">>}, + {<<"cowboy">>, <<"9CFE86ED7117BF045E10ADBEDB0170AF7BE57F2A3637E7BE143433D8DD267396">>}, + {<<"cowlib">>, <<"3E6053016D1AB245730F0AF688755476DCEDB1C25ED8FB5751F59A2BFDC0C9AF">>}, {<<"erlydtl">>, <<"964B2DC84F8C17ACFAA69C59BA129EF26AC45D2BA898C3C6AD9B5BDC8BA13CED">>}, - {<<"jhn_stdlib">>, <<"FAC6F19B35351278F1CB156E23A5B2A6047A9DD5AB1FD9E1189A7918006DF7ED">>}, + {<<"jhn_stdlib">>, <<"785074F3CA368EAA8E9AF1592BC19AE9EF1F7AF30B2CD6456A6083173A8F5CCB">>}, {<<"jose">>, <<"06E62B467B61D3726CBC19E9B5489F7549C37993DE846DFB3EE8259F9ED208B3">>}, {<<"luerl">>, <<"F6700420950FC6889137E7A0C11C4A8467DEA04A8C23F707A40D83566D14E786">>}, - {<<"nova">>, <<"426AAA12DFB38E5CA4EC6EE3AA6066917BDCBD91C00BE53BF875161963CBA216">>}, + {<<"nova">>, <<"2F08F11162A871CB1AA361BFEFE66D945F3284243F7EA6582AD8CA709BAFE2F3">>}, {<<"nova_auth">>, <<"59C481D5AF498AF8780936FB428E22320051D63A900F7D63E3692D302913369A">>}, {<<"nova_auth_oidc">>, <<"C0077E345186F945CA12701366ED9953131CF585E5E91B26D6608AC0116D7B88">>}, {<<"nova_resilience">>, <<"353C95496647B8FFF390D3367F2BA126F2998F6EACFFC4F06BA900CD401B3441">>}, @@ -54,18 +54,18 @@ {<<"routing_tree">>, <<"72ACEF2095F0EC804F7AFD07EF781DDE5009425A1CA0A28F0706B1DB334A4812">>}, {<<"seki">>, <<"3A9209AD6154DA08084E8409C8F97586C79855450A748D989EDF23483B90B8B8">>}, {<<"shigoto">>, <<"7DAA82CD28FDAD50CDEF227B4B4BEE301EAA1F9CC1F5ED585EC756763178EABF">>}, - {<<"telemetry">>, <<"AB6DE178E2B29B58E8256B92B382EA3F590A47152CA3651EA857A6CAE05AC423">>}, + {<<"telemetry">>, <<"A0CB522801DFFB1C49FE6E30561BADFFC7B6D0E180DB1300DF759FAA22062855">>}, {<<"telemetry_registry">>, <<"701576890320BE6428189BFF963E865E8F23E0FF3615EADE8F78662BE0FC003C">>}, {<<"thoas">>, <<"19A25F31177A17E74004D4840F66D791D4298C5738790FA2CC73731EB911F195">>}]}, {pkg_hash_ext,[ {<<"backoff">>, <<"CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39">>}, - {<<"cowboy">>, <<"E724D3A70995025D654C1992C7B11DBFEA95205C047D86FF9BF1CDA92DDC5614">>}, - {<<"cowlib">>, <<"58F1E425A9E04176F1D30E20116F57C4E90EF0E187552E9741C465BDF4044F70">>}, + {<<"cowboy">>, <<"179FB65140FB440A17B767AD53B755081506F9596C4DB5C49C0396D8C8643668">>}, + {<<"cowlib">>, <<"FF08BD17E6DD931445B18AF77315B9B5FE052407110964AD2588C686B57B5E3F">>}, {<<"erlydtl">>, <<"D80EC044CD8F58809C19D29AC5605BE09E955040911B644505E31E9DD8143431">>}, - {<<"jhn_stdlib">>, <<"7EABD1B01D2DEFF495BF7C5CA1DBA4D3FA0B84DC3AF03CA85F31D52EBB03C6FC">>}, + {<<"jhn_stdlib">>, <<"2329CD16DEE46704AAB6184D09508E59DBA31C4D3255271DBB7D34D115ECA508">>}, {<<"jose">>, <<"31E92B653E9210B696765CDD885437457DE1ADD2A9011D92F8CF63E4641BAB7B">>}, {<<"luerl">>, <<"ABF88D849BAA0D5DCA93B245A8688D4DE2EE3D588159BB2FAF51E15946509390">>}, - {<<"nova">>, <<"6E932989B70F4E235EBC8C7A6D0560E4B22A18760A651129BC84FA1A90C05B34">>}, + {<<"nova">>, <<"D35D0CEF073749958D2E7E446DED07354F5A3A6B96A31009A2E89D382BE72EF4">>}, {<<"nova_auth">>, <<"57CBF808DCA21CA4BDB877A92476E78622240A633DC61DCF9C80F846E32574B3">>}, {<<"nova_auth_oidc">>, <<"E7343A22815144E1ABFD1F73D93904FD0960E8A070E3C831FB5AE9BB0FABD69B">>}, {<<"nova_resilience">>, <<"FFF1FE82634386A944553B2B2483AB3D140DAEA27A24A42AA1AFDD3E0BB97B0B">>}, @@ -77,7 +77,7 @@ {<<"routing_tree">>, <<"85982C7AC502892C5179CD2A591331003BACD2D2A71723640BA7D23F45408E6E">>}, {<<"seki">>, <<"5493BAC387329DE722AC5BCB967364CACECC104AE3E6ED143863453263DC6DB4">>}, {<<"shigoto">>, <<"32BC87B8127507F31F2F007CB5B947C3AF4E3D1C9EC73059E72564E2F649A0DC">>}, - {<<"telemetry">>, <<"2172E05A27531D3D31DD9782841065C50DD5C3C7699D95266B2EDD54C2DAFA1C">>}, + {<<"telemetry">>, <<"928F6495066506077862C0D1646609EED891A4326BEE3126BA54B60AF61FEBB1">>}, {<<"telemetry_registry">>, <<"E7ED191EB1D115A3034AF8E1E35E4E63D5348851D556646D46CA3D1B4E16BAB9">>}, {<<"thoas">>, <<"E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A">>}]} ]. diff --git a/test/asobi_lua_release_config_tests.erl b/test/asobi_lua_release_config_tests.erl new file mode 100644 index 0000000..cd32a3d --- /dev/null +++ b/test/asobi_lua_release_config_tests.erl @@ -0,0 +1,55 @@ +-module(asobi_lua_release_config_tests). +-include_lib("eunit/include/eunit.hrl"). + +%% The prod release config is what gets baked into the published +%% ghcr.io/widgrensit/asobi_lua image. CI only ever boots the dev config, +%% so a prod-only regression (e.g. dropping kura's {backend, ...} key after +%% the kura v2 bump) ships silently and every self-host user crashes on +%% startup with {no_pool_module_configured, asobi_repo}. This pins the +%% invariant: prod's kura repo must declare a backend kura can resolve. + +prod_config_declares_kura_backend_test() -> + Kura = kura_env(consult_config("prod_sys.config.src")), + ?assert( + proplists:is_defined(backend, Kura) orelse + proplists:is_defined(dialect, Kura) orelse + proplists:is_defined(pool_module, Kura) orelse + proplists:is_defined(repos, Kura) + ). + +dev_config_declares_kura_backend_test() -> + Kura = kura_env(consult_config("dev_sys.config.src")), + ?assert( + proplists:is_defined(backend, Kura) orelse + proplists:is_defined(dialect, Kura) orelse + proplists:is_defined(pool_module, Kura) orelse + proplists:is_defined(repos, Kura) + ). + +-spec kura_env([{atom(), term()}]) -> [{atom(), term()}]. +kura_env(Config) -> + case proplists:get_value(kura, Config) of + Env when is_list(Env) -> Env; + _ -> error(no_kura_app_in_config) + end. + +-spec consult_config(string()) -> [{atom(), term()}]. +consult_config(Name) -> + {ok, Raw} = file:read_file(locate(Name)), + Substituted = re:replace(Raw, "\\$\\{[A-Z_]+\\}", "placeholder", [global, {return, binary}]), + Tmp = filename:join("/tmp", "asobi_lua_relcfg_" ++ Name), + ok = file:write_file(Tmp, Substituted), + {ok, [Config]} = file:consult(Tmp), + ok = file:delete(Tmp), + Config. + +-spec locate(string()) -> file:filename_all(). +locate(Name) -> + Candidates = [ + filename:join(["config", Name]), + filename:join([filename:dirname(?FILE), "..", "config", Name]) + ], + case lists:dropwhile(fun(P) -> not filelib:is_regular(P) end, Candidates) of + [Path | _] -> Path; + [] -> error({config_not_found, Name}) + end.