@voxgig/sdkgen 4.10.0 → 4.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/package.json +1 -1
  3. package/project/.sdk/model/feature/secrets.aon +330 -0
  4. package/project/.sdk/model/target/c.aon +15 -2
  5. package/project/.sdk/model/target/cpp.aon +18 -0
  6. package/project/.sdk/model/target/lua.aon +17 -0
  7. package/project/.sdk/model/target/ocaml.aon +48 -5
  8. package/project/.sdk/model/target/zig.aon +30 -4
  9. package/project/.sdk/src/cmp/c/Config_c.ts +338 -1
  10. package/project/.sdk/src/cmp/c/Main_c.ts +57 -2
  11. package/project/.sdk/src/cmp/c/Package_c.ts +12 -2
  12. package/project/.sdk/src/cmp/cpp/Config_cpp.ts +324 -2
  13. package/project/.sdk/src/cmp/cpp/Gitignore_cpp.ts +2 -0
  14. package/project/.sdk/src/cmp/cpp/Main_cpp.ts +62 -4
  15. package/project/.sdk/src/cmp/cpp/Package_cpp.ts +10 -0
  16. package/project/.sdk/src/cmp/lua/Config_lua.ts +88 -0
  17. package/project/.sdk/src/cmp/lua/Gitignore_lua.ts +4 -0
  18. package/project/.sdk/src/cmp/lua/Main_lua.ts +93 -3
  19. package/project/.sdk/src/cmp/lua/Package_lua.ts +60 -0
  20. package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +10 -0
  21. package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +183 -5
  22. package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +160 -3
  23. package/project/.sdk/src/cmp/ocaml/Package_ocaml.ts +25 -1
  24. package/project/.sdk/src/cmp/zig/Config_zig.ts +130 -9
  25. package/project/.sdk/src/cmp/zig/Main_zig.ts +208 -4
  26. package/project/.sdk/{tm/zig/build.zig → src/cmp/zig/fragment/Build.fragment.zig} +7 -0
  27. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +25 -0
  28. package/project/.sdk/{tm/zig/root.zig → src/cmp/zig/fragment/Root.fragment.zig} +9 -0
  29. package/project/.sdk/tm/c/Makefile +58 -9
  30. package/project/.sdk/tm/c/core/sdk.h +10 -0
  31. package/project/.sdk/tm/c/feature/secrets/plugin/capability.c +133 -0
  32. package/project/.sdk/tm/c/feature/secrets/plugin/capability.h +39 -0
  33. package/project/.sdk/tm/c/feature/secrets/plugin/catalog.c +83 -0
  34. package/project/.sdk/tm/c/feature/secrets/plugin/catalog.h +48 -0
  35. package/project/.sdk/tm/c/feature/secrets/plugin/config.c +413 -0
  36. package/project/.sdk/tm/c/feature/secrets/plugin/config.h +24 -0
  37. package/project/.sdk/tm/c/feature/secrets/plugin/depend.c +264 -0
  38. package/project/.sdk/tm/c/feature/secrets/plugin/depend.h +29 -0
  39. package/project/.sdk/tm/c/feature/secrets/plugin/env.c +220 -0
  40. package/project/.sdk/tm/c/feature/secrets/plugin/env.h +19 -0
  41. package/project/.sdk/tm/c/feature/secrets/plugin/export.c +97 -0
  42. package/project/.sdk/tm/c/feature/secrets/plugin/export.h +19 -0
  43. package/project/.sdk/tm/c/feature/secrets/plugin/graph.c +237 -0
  44. package/project/.sdk/tm/c/feature/secrets/plugin/graph.h +17 -0
  45. package/project/.sdk/tm/c/feature/secrets/plugin/host.c +1494 -0
  46. package/project/.sdk/tm/c/feature/secrets/plugin/host.h +135 -0
  47. package/project/.sdk/tm/c/feature/secrets/plugin/order.c +288 -0
  48. package/project/.sdk/tm/c/feature/secrets/plugin/order.h +18 -0
  49. package/project/.sdk/tm/c/feature/secrets/plugin/point.c +141 -0
  50. package/project/.sdk/tm/c/feature/secrets/plugin/point.h +80 -0
  51. package/project/.sdk/tm/c/feature/secrets/plugin/ref.c +170 -0
  52. package/project/.sdk/tm/c/feature/secrets/plugin/ref.h +52 -0
  53. package/project/.sdk/tm/c/feature/secrets/plugin/resolve.c +98 -0
  54. package/project/.sdk/tm/c/feature/secrets/plugin/resolve.h +18 -0
  55. package/project/.sdk/tm/c/feature/secrets/plugin/types.c +150 -0
  56. package/project/.sdk/tm/c/feature/secrets/plugin/types.h +104 -0
  57. package/project/.sdk/tm/c/feature/secrets/plugin/value.c +649 -0
  58. package/project/.sdk/tm/c/feature/secrets/plugin/value.h +135 -0
  59. package/project/.sdk/tm/c/feature/secrets/plugin/version.c +151 -0
  60. package/project/.sdk/tm/c/feature/secrets/plugin/version.h +34 -0
  61. package/project/.sdk/tm/c/feature/secrets/plugins/aws.c +281 -0
  62. package/project/.sdk/tm/c/feature/secrets/plugins/azuresecrets.c +207 -0
  63. package/project/.sdk/tm/c/feature/secrets/plugins/boru.c +164 -0
  64. package/project/.sdk/tm/c/feature/secrets/plugins/clock.c +75 -0
  65. package/project/.sdk/tm/c/feature/secrets/plugins/doppler.c +141 -0
  66. package/project/.sdk/tm/c/feature/secrets/plugins/encode.c +144 -0
  67. package/project/.sdk/tm/c/feature/secrets/plugins/gcpsecrets.c +177 -0
  68. package/project/.sdk/tm/c/feature/secrets/plugins/hashicorp.c +239 -0
  69. package/project/.sdk/tm/c/feature/secrets/plugins/httpjson.c +599 -0
  70. package/project/.sdk/tm/c/feature/secrets/plugins/infisical.c +165 -0
  71. package/project/.sdk/tm/c/feature/secrets/plugins/onepassword.c +194 -0
  72. package/project/.sdk/tm/c/feature/secrets/plugins/proc.c +233 -0
  73. package/project/.sdk/tm/c/feature/secrets/plugins/secretspec.c +125 -0
  74. package/project/.sdk/tm/c/feature/secrets/plugins/sekretoplugins.h +125 -0
  75. package/project/.sdk/tm/c/feature/secrets/plugins/sha256.c +270 -0
  76. package/project/.sdk/tm/c/feature/secrets/plugins/sigv4.c +382 -0
  77. package/project/.sdk/tm/c/feature/secrets/plugins/support.h +153 -0
  78. package/project/.sdk/tm/c/feature/secrets/plugins/tls.c +420 -0
  79. package/project/.sdk/tm/c/feature/secrets/sekreto/internal.h +86 -0
  80. package/project/.sdk/tm/c/feature/secrets/sekreto/json.c +721 -0
  81. package/project/.sdk/tm/c/feature/secrets/sekreto/providers.c +813 -0
  82. package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.c +944 -0
  83. package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.h +490 -0
  84. package/project/.sdk/tm/c/feature/secrets/sekreto/util.c +442 -0
  85. package/project/.sdk/tm/c/feature/secrets.c +797 -0
  86. package/project/.sdk/tm/c/feature/secrets.h +46 -0
  87. package/project/.sdk/tm/c/src/feature/secrets/.gitkeep +0 -0
  88. package/project/.sdk/tm/c/tests/feature/secrets/secrets_test.c +802 -0
  89. package/project/.sdk/tm/clojure/feature/secrets/sdk/feature/secrets.clj +38 -11
  90. package/project/.sdk/tm/clojure/test/sdk/test/feature/secrets.clj +40 -6
  91. package/project/.sdk/tm/cpp/Makefile +48 -4
  92. package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.cpp +121 -0
  93. package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.hpp +41 -0
  94. package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.cpp +60 -0
  95. package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.hpp +66 -0
  96. package/project/.sdk/tm/cpp/feature/secrets/plugin/config.cpp +376 -0
  97. package/project/.sdk/tm/cpp/feature/secrets/plugin/config.hpp +29 -0
  98. package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.cpp +230 -0
  99. package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.hpp +31 -0
  100. package/project/.sdk/tm/cpp/feature/secrets/plugin/env.cpp +205 -0
  101. package/project/.sdk/tm/cpp/feature/secrets/plugin/env.hpp +25 -0
  102. package/project/.sdk/tm/cpp/feature/secrets/plugin/export.cpp +84 -0
  103. package/project/.sdk/tm/cpp/feature/secrets/plugin/export.hpp +24 -0
  104. package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.cpp +222 -0
  105. package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.hpp +21 -0
  106. package/project/.sdk/tm/cpp/feature/secrets/plugin/host.cpp +1200 -0
  107. package/project/.sdk/tm/cpp/feature/secrets/plugin/host.hpp +250 -0
  108. package/project/.sdk/tm/cpp/feature/secrets/plugin/order.cpp +250 -0
  109. package/project/.sdk/tm/cpp/feature/secrets/plugin/order.hpp +22 -0
  110. package/project/.sdk/tm/cpp/feature/secrets/plugin/point.cpp +110 -0
  111. package/project/.sdk/tm/cpp/feature/secrets/plugin/point.hpp +79 -0
  112. package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.cpp +136 -0
  113. package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.hpp +60 -0
  114. package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.cpp +82 -0
  115. package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.hpp +25 -0
  116. package/project/.sdk/tm/cpp/feature/secrets/plugin/types.cpp +90 -0
  117. package/project/.sdk/tm/cpp/feature/secrets/plugin/types.hpp +65 -0
  118. package/project/.sdk/tm/cpp/feature/secrets/plugin/value.cpp +491 -0
  119. package/project/.sdk/tm/cpp/feature/secrets/plugin/value.hpp +120 -0
  120. package/project/.sdk/tm/cpp/feature/secrets/plugin/version.cpp +143 -0
  121. package/project/.sdk/tm/cpp/feature/secrets/plugin/version.hpp +36 -0
  122. package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.cpp +248 -0
  123. package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.hpp +30 -0
  124. package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.cpp +149 -0
  125. package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.hpp +23 -0
  126. package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.cpp +117 -0
  127. package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.hpp +27 -0
  128. package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.cpp +180 -0
  129. package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.hpp +52 -0
  130. package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.cpp +87 -0
  131. package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.hpp +23 -0
  132. package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.cpp +121 -0
  133. package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.hpp +23 -0
  134. package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.cpp +153 -0
  135. package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.hpp +23 -0
  136. package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.cpp +666 -0
  137. package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.hpp +160 -0
  138. package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.cpp +123 -0
  139. package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.hpp +23 -0
  140. package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.cpp +125 -0
  141. package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.hpp +23 -0
  142. package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.cpp +223 -0
  143. package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.hpp +47 -0
  144. package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.cpp +104 -0
  145. package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.hpp +27 -0
  146. package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.cpp +242 -0
  147. package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.hpp +58 -0
  148. package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.cpp +260 -0
  149. package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.hpp +47 -0
  150. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.cpp +476 -0
  151. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.hpp +89 -0
  152. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.cpp +312 -0
  153. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.hpp +263 -0
  154. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.cpp +354 -0
  155. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.hpp +111 -0
  156. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.cpp +613 -0
  157. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.hpp +227 -0
  158. package/project/.sdk/tm/cpp/feature/secrets.hpp +745 -0
  159. package/project/.sdk/tm/cpp/src/feature/secrets/.gitkeep +0 -0
  160. package/project/.sdk/tm/cpp/test/feature/secrets/secrets_test.cpp +808 -0
  161. package/project/.sdk/tm/csharp/feature/SecretsFeature.cs +34 -8
  162. package/project/.sdk/tm/csharp/test/feature/secrets/SecretsFeatureTest.cs +85 -0
  163. package/project/.sdk/tm/elixir/lib/projectname/feature/secrets.ex +17 -2
  164. package/project/.sdk/tm/elixir/test/feature/secrets/secrets_test.exs +41 -0
  165. package/project/.sdk/tm/go/feature/secrets_feature.go +32 -10
  166. package/project/.sdk/tm/go/test/feature/secrets/secrets_feature_test.go +116 -0
  167. package/project/.sdk/tm/java/feature/SecretsFeature.java +33 -8
  168. package/project/.sdk/tm/java/test/feature/secrets/SecretsFeatureTest.java +64 -0
  169. package/project/.sdk/tm/js/src/feature/secrets/SecretsFeature.js +34 -11
  170. package/project/.sdk/tm/js/test/feature/secrets/Secrets.test.js +73 -0
  171. package/project/.sdk/tm/kotlin/feature/SecretsFeature.kt +32 -7
  172. package/project/.sdk/tm/kotlin/test/feature/secrets/SecretsTest.kt +69 -0
  173. package/project/.sdk/tm/lua/Makefile +15 -4
  174. package/project/.sdk/tm/lua/feature/secrets/native/sekretonet.c +806 -0
  175. package/project/.sdk/tm/lua/feature/secrets/plugin/capability.lua +135 -0
  176. package/project/.sdk/tm/lua/feature/secrets/plugin/catalog.lua +63 -0
  177. package/project/.sdk/tm/lua/feature/secrets/plugin/config.lua +361 -0
  178. package/project/.sdk/tm/lua/feature/secrets/plugin/depend.lua +232 -0
  179. package/project/.sdk/tm/lua/feature/secrets/plugin/env.lua +168 -0
  180. package/project/.sdk/tm/lua/feature/secrets/plugin/export.lua +66 -0
  181. package/project/.sdk/tm/lua/feature/secrets/plugin/graph.lua +194 -0
  182. package/project/.sdk/tm/lua/feature/secrets/plugin/host.lua +1190 -0
  183. package/project/.sdk/tm/lua/feature/secrets/plugin/json.lua +169 -0
  184. package/project/.sdk/tm/lua/feature/secrets/plugin/order.lua +207 -0
  185. package/project/.sdk/tm/lua/feature/secrets/plugin/point.lua +106 -0
  186. package/project/.sdk/tm/lua/feature/secrets/plugin/ref.lua +115 -0
  187. package/project/.sdk/tm/lua/feature/secrets/plugin/resolve.lua +78 -0
  188. package/project/.sdk/tm/lua/feature/secrets/plugin/types.lua +275 -0
  189. package/project/.sdk/tm/lua/feature/secrets/plugin/version.lua +131 -0
  190. package/project/.sdk/tm/lua/feature/secrets/plugin.lua +76 -0
  191. package/project/.sdk/tm/lua/feature/secrets/sekreto/addr.lua +124 -0
  192. package/project/.sdk/tm/lua/feature/secrets/sekreto/err.lua +47 -0
  193. package/project/.sdk/tm/lua/feature/secrets/sekreto/name.lua +315 -0
  194. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/aws.lua +228 -0
  195. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/azuresecrets.lua +137 -0
  196. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/boru.lua +124 -0
  197. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/crypto.lua +212 -0
  198. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/doppler.lua +89 -0
  199. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/gcpsecrets.lua +129 -0
  200. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/hashicorp.lua +154 -0
  201. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/httpjson.lua +248 -0
  202. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/infisical.lua +113 -0
  203. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/json.lua +449 -0
  204. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/net.lua +198 -0
  205. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/onepassword.lua +126 -0
  206. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/secretspec.lua +93 -0
  207. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/sigv4.lua +269 -0
  208. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/support.lua +146 -0
  209. package/project/.sdk/tm/lua/feature/secrets/sekreto/providers.lua +346 -0
  210. package/project/.sdk/tm/lua/feature/secrets/sekreto.lua +479 -0
  211. package/project/.sdk/tm/lua/feature/secrets_feature.lua +690 -0
  212. package/project/.sdk/tm/lua/src/feature/secrets/.gitkeep +0 -0
  213. package/project/.sdk/tm/lua/test/extend_test.lua +105 -0
  214. package/project/.sdk/tm/lua/test/feature/secrets/secrets_feature_test.lua +862 -0
  215. package/project/.sdk/tm/ocaml/Makefile +52 -8
  216. package/project/.sdk/tm/ocaml/feature/secrets/plugin/capability.ml +106 -0
  217. package/project/.sdk/tm/ocaml/feature/secrets/plugin/catalog.ml +43 -0
  218. package/project/.sdk/tm/ocaml/feature/secrets/plugin/config.ml +349 -0
  219. package/project/.sdk/tm/ocaml/feature/secrets/plugin/defs.ml +143 -0
  220. package/project/.sdk/tm/ocaml/feature/secrets/plugin/depend.ml +217 -0
  221. package/project/.sdk/tm/ocaml/feature/secrets/plugin/env.ml +197 -0
  222. package/project/.sdk/tm/ocaml/feature/secrets/plugin/export.ml +89 -0
  223. package/project/.sdk/tm/ocaml/feature/secrets/plugin/graph.ml +227 -0
  224. package/project/.sdk/tm/ocaml/feature/secrets/plugin/host.ml +1112 -0
  225. package/project/.sdk/tm/ocaml/feature/secrets/plugin/order.ml +202 -0
  226. package/project/.sdk/tm/ocaml/feature/secrets/plugin/point.ml +138 -0
  227. package/project/.sdk/tm/ocaml/feature/secrets/plugin/ref.ml +126 -0
  228. package/project/.sdk/tm/ocaml/feature/secrets/plugin/resolve.ml +62 -0
  229. package/project/.sdk/tm/ocaml/feature/secrets/plugin/types.ml +97 -0
  230. package/project/.sdk/tm/ocaml/feature/secrets/plugin/value.ml +387 -0
  231. package/project/.sdk/tm/ocaml/feature/secrets/plugin/version.ml +139 -0
  232. package/project/.sdk/tm/ocaml/feature/secrets/plugins/aws.ml +171 -0
  233. package/project/.sdk/tm/ocaml/feature/secrets/plugins/azuresecrets.ml +116 -0
  234. package/project/.sdk/tm/ocaml/feature/secrets/plugins/boru.ml +95 -0
  235. package/project/.sdk/tm/ocaml/feature/secrets/plugins/crypto.ml +149 -0
  236. package/project/.sdk/tm/ocaml/feature/secrets/plugins/doppler.ml +61 -0
  237. package/project/.sdk/tm/ocaml/feature/secrets/plugins/gcpsecrets.ml +93 -0
  238. package/project/.sdk/tm/ocaml/feature/secrets/plugins/hashicorp.ml +120 -0
  239. package/project/.sdk/tm/ocaml/feature/secrets/plugins/http.ml +421 -0
  240. package/project/.sdk/tm/ocaml/feature/secrets/plugins/httpjson.ml +66 -0
  241. package/project/.sdk/tm/ocaml/feature/secrets/plugins/infisical.ml +85 -0
  242. package/project/.sdk/tm/ocaml/feature/secrets/plugins/onepassword.ml +112 -0
  243. package/project/.sdk/tm/ocaml/feature/secrets/plugins/runcmd.ml +97 -0
  244. package/project/.sdk/tm/ocaml/feature/secrets/plugins/secretspec.ml +68 -0
  245. package/project/.sdk/tm/ocaml/feature/secrets/plugins/sigv4.ml +259 -0
  246. package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls.ml +44 -0
  247. package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls_stubs.c +358 -0
  248. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/json.ml +376 -0
  249. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/provider.ml +647 -0
  250. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/secret.ml +299 -0
  251. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/sekreto.ml +347 -0
  252. package/project/.sdk/tm/ocaml/feature/secrets_feature.ml +453 -0
  253. package/project/.sdk/tm/ocaml/src/feature/secrets/.gitkeep +0 -0
  254. package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +670 -0
  255. package/project/.sdk/tm/perl/feature/secrets_feature.pm +33 -12
  256. package/project/.sdk/tm/perl/t/feature/secrets/secrets.t +47 -0
  257. package/project/.sdk/tm/php/feature/SecretsFeature.php +30 -6
  258. package/project/.sdk/tm/php/test/feature/secrets/SecretsTest.php +98 -0
  259. package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +28 -6
  260. package/project/.sdk/tm/py/test/feature/secrets/test_secrets.py +114 -0
  261. package/project/.sdk/tm/rb/feature/secrets_feature.rb +28 -6
  262. package/project/.sdk/tm/rb/test/feature/secrets/secrets_feature_test.rb +93 -0
  263. package/project/.sdk/tm/rust/feature/secrets.rs +33 -10
  264. package/project/.sdk/tm/rust/tests/feature/secrets/main.rs +96 -0
  265. package/project/.sdk/tm/scala/feature/SecretsFeature.scala +29 -7
  266. package/project/.sdk/tm/scala/sdktest/feature/secrets/SecretsTestMain.scala +71 -0
  267. package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +35 -12
  268. package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +73 -0
  269. package/project/.sdk/tm/zig/feature/secrets/plugin/capability.zig +137 -0
  270. package/project/.sdk/tm/zig/feature/secrets/plugin/catalog.zig +90 -0
  271. package/project/.sdk/tm/zig/feature/secrets/plugin/config.zig +346 -0
  272. package/project/.sdk/tm/zig/feature/secrets/plugin/depend.zig +244 -0
  273. package/project/.sdk/tm/zig/feature/secrets/plugin/env.zig +201 -0
  274. package/project/.sdk/tm/zig/feature/secrets/plugin/export.zig +83 -0
  275. package/project/.sdk/tm/zig/feature/secrets/plugin/graph.zig +212 -0
  276. package/project/.sdk/tm/zig/feature/secrets/plugin/host.zig +1224 -0
  277. package/project/.sdk/tm/zig/feature/secrets/plugin/inst.zig +126 -0
  278. package/project/.sdk/tm/zig/feature/secrets/plugin/order.zig +228 -0
  279. package/project/.sdk/tm/zig/feature/secrets/plugin/plugin.zig +34 -0
  280. package/project/.sdk/tm/zig/feature/secrets/plugin/point.zig +166 -0
  281. package/project/.sdk/tm/zig/feature/secrets/plugin/ref.zig +147 -0
  282. package/project/.sdk/tm/zig/feature/secrets/plugin/resolve.zig +74 -0
  283. package/project/.sdk/tm/zig/feature/secrets/plugin/types.zig +140 -0
  284. package/project/.sdk/tm/zig/feature/secrets/plugin/value.zig +662 -0
  285. package/project/.sdk/tm/zig/feature/secrets/plugin/version.zig +139 -0
  286. package/project/.sdk/tm/zig/feature/secrets/plugins/aws.zig +294 -0
  287. package/project/.sdk/tm/zig/feature/secrets/plugins/azuresecrets.zig +222 -0
  288. package/project/.sdk/tm/zig/feature/secrets/plugins/boru.zig +188 -0
  289. package/project/.sdk/tm/zig/feature/secrets/plugins/doppler.zig +135 -0
  290. package/project/.sdk/tm/zig/feature/secrets/plugins/gcpsecrets.zig +170 -0
  291. package/project/.sdk/tm/zig/feature/secrets/plugins/hashicorp.zig +242 -0
  292. package/project/.sdk/tm/zig/feature/secrets/plugins/httpjson.zig +535 -0
  293. package/project/.sdk/tm/zig/feature/secrets/plugins/infisical.zig +167 -0
  294. package/project/.sdk/tm/zig/feature/secrets/plugins/onepassword.zig +202 -0
  295. package/project/.sdk/tm/zig/feature/secrets/plugins/secretspec.zig +160 -0
  296. package/project/.sdk/tm/zig/feature/secrets/plugins/sigv4.zig +336 -0
  297. package/project/.sdk/tm/zig/feature/secrets/sekreto/addr.zig +148 -0
  298. package/project/.sdk/tm/zig/feature/secrets/sekreto/builtins.zig +259 -0
  299. package/project/.sdk/tm/zig/feature/secrets/sekreto/provider.zig +440 -0
  300. package/project/.sdk/tm/zig/feature/secrets/sekreto/sekreto.zig +944 -0
  301. package/project/.sdk/tm/zig/feature/secrets.zig +854 -0
  302. package/project/.sdk/tm/zig/src/feature/secrets/.gitkeep +0 -0
  303. package/project/.sdk/tm/zig/test/feature/secrets/secrets_test.zig +891 -0
  304. package/project/sdkgen-package.json +1 -1
@@ -574,6 +574,69 @@ class SecretsFeatureTest < Minitest::Test
574
574
  "after the chain reports a miss the retracted credential must not go out; the wire saw #{last['auth'].inspect}")
575
575
  end
576
576
 
577
+ # A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this
578
+ # feature used to override from the layer above.
579
+ #
580
+ # DEFAULT caching here, which is the whole point: `cache: true` is about
581
+ # holding a HIT, and keeping the settled resolution after a miss meant the
582
+ # chain was never asked again for the life of the client. A secret
583
+ # provisioned after startup (a mounted file, a vault policy granted a
584
+ # minute late) was invisible forever, and the only workaround was giving
585
+ # up hit caching entirely.
586
+ def test_a_cached_miss_is_reasked
587
+ present = false
588
+ calls = 0
589
+ wire = Wire.new
590
+ client = secrets_client(wire, {
591
+ "feature" => { "secrets" => {
592
+ "active" => true,
593
+ "providers" => [CustomProvider.new { |_name|
594
+ calls += 1
595
+ present ? "LATEKEY01" : nil
596
+ }],
597
+ } },
598
+ })
599
+
600
+ drive_op(client, wire)
601
+ first = wire.api[0]
602
+ refute(first["has"] && !first["auth"].to_s.empty?,
603
+ "the chain has nothing yet, so no credential should go out")
604
+
605
+ asked = calls
606
+ assert_operator asked, :>, 0
607
+
608
+ # The secret is provisioned while the client is live.
609
+ present = true
610
+
611
+ drive_op(client, wire)
612
+ assert_credential(wire.api[-1]["auth"], "LATEKEY01")
613
+
614
+ assert_operator calls, :>, asked,
615
+ "the MISS was cached: a secret that appears later can never be picked up"
616
+ end
617
+
618
+ # The other half of the same rule: a HIT is still cached by default, so
619
+ # the fix above must not turn every request into a chain walk.
620
+ def test_a_cached_hit_is_kept
621
+ calls = 0
622
+ wire = Wire.new
623
+ client = secrets_client(wire, {
624
+ "feature" => { "secrets" => {
625
+ "active" => true,
626
+ "providers" => [CustomProvider.new { |_name|
627
+ calls += 1
628
+ "STABLEKEY01"
629
+ }],
630
+ } },
631
+ })
632
+
633
+ drive_op(client, wire)
634
+ drive_op(client, wire)
635
+
636
+ assert_equal 1, calls,
637
+ "a hit must be cached under the default cache: true"
638
+ end
639
+
577
640
  def test_auth_nil_suppresses_the_credential_chain_or_no_chain
578
641
  setenv("APIKEY", "ENVKEY03")
579
642
  wire = Wire.new
@@ -697,6 +760,36 @@ class SecretsFeatureTest < Minitest::Test
697
760
  clearenv("REFRESH_TOKEN")
698
761
  end
699
762
 
763
+ # `auth: nil` SUPPRESSES THE PURCHASE, not just the retry.
764
+ #
765
+ # resolve runs before _with_refresh's suppression check, so the refresh
766
+ # token used to go to the token endpoint in a request body even here.
767
+ # Stopping the retry does not unsend it - this asserts on the token
768
+ # endpoint, which is the half the API-header assertions cannot see.
769
+ def test_auth_nil_buys_no_token_at_all
770
+ setenv("REFRESH_TOKEN", "REFRESH01")
771
+ wire = Wire.new
772
+ wire.apistatus = [401]
773
+
774
+ client = secrets_client(wire, {
775
+ "auth" => nil,
776
+ "feature" => secrets_opts({
777
+ "name" => "refresh_token",
778
+ "exchange" => { "active" => true },
779
+ }),
780
+ })
781
+
782
+ drive_op(client, wire)
783
+
784
+ assert_equal 0, wire.token.length,
785
+ "auth nil suppressed the credential but the refresh token was still " \
786
+ "POSTed to the exchange endpoint"
787
+ refute wire.api[0]["has"],
788
+ "no credential may be sent when auth is suppressed"
789
+ ensure
790
+ clearenv("REFRESH_TOKEN")
791
+ end
792
+
700
793
  # A second refusal on a token bought moments ago is a real failure, not a
701
794
  # spin: exactly one rebuy, and the refusal is returned as it stands.
702
795
  def test_a_second_refusal_is_returned_as_is
@@ -507,9 +507,17 @@ fn secrets_call(state: &Rc<RefCell<SecretsState>>, arg: &Value) -> Value {
507
507
 
508
508
  // ---- resolution ---------------------------------------------------------
509
509
 
510
- // One resolution, shared by every request. A settled SUCCESS is kept only
511
- // when caching is on; a FAILURE is never kept, so a transient vault outage
512
- // never poisons the client permanently - the next operation asks again.
510
+ // One resolution, shared by every request. A settled HIT is kept only when
511
+ // caching is on; a FAILURE is never kept, so a transient vault outage never
512
+ // poisons the client permanently - the next operation asks again.
513
+ //
514
+ // A MISS is not kept either, however caching is set. That rule is
515
+ // sekreto's, not this feature's: `A miss is never cached: the next read
516
+ // asks again`, in sekreto's own source. Keeping a settled miss here would
517
+ // override that from the layer above, and a secret provisioned after
518
+ // startup - a mounted file, a policy granted a minute late - would never be
519
+ // picked up for the life of the client. `cache` is about caching a HIT; it
520
+ // was never a promise to keep saying no.
513
521
  fn resolve(state: &Rc<RefCell<SecretsState>>) -> Result<(), ProjectNameError> {
514
522
  {
515
523
  let s = state.borrow();
@@ -522,9 +530,9 @@ fn resolve(state: &Rc<RefCell<SecretsState>>) -> Result<(), ProjectNameError> {
522
530
  }
523
531
 
524
532
  match resolve_once(state) {
525
- Ok(()) => {
533
+ Ok(hit) => {
526
534
  let cache = state.borrow().cache;
527
- if cache {
535
+ if cache && hit {
528
536
  state.borrow_mut().resolved = true;
529
537
  }
530
538
  Ok(())
@@ -536,11 +544,14 @@ fn resolve(state: &Rc<RefCell<SecretsState>>) -> Result<(), ProjectNameError> {
536
544
  }
537
545
  }
538
546
 
539
- fn resolve_once(state: &Rc<RefCell<SecretsState>>) -> Result<(), ProjectNameError> {
547
+ // Resolve once, answering whether a credential came out of it. That bool is
548
+ // the whole of what resolve needs to tell a cacheable HIT from a miss it
549
+ // must not keep.
550
+ fn resolve_once(state: &Rc<RefCell<SecretsState>>) -> Result<bool, ProjectNameError> {
540
551
  let name = {
541
552
  let s = state.borrow();
542
553
  if s.sek.is_none() {
543
- return Ok(());
554
+ return Ok(false);
544
555
  }
545
556
  s.secretname.clone()
546
557
  };
@@ -568,8 +579,9 @@ fn resolve_once(state: &Rc<RefCell<SecretsState>>) -> Result<(), ProjectNameErro
568
579
  // apikey OPTION is never lost here - it seats FIRST in the
569
580
  // chain as a memory provider, so the chain HITS while one is
570
581
  // set and the miss branch is unreachable.)
582
+ let hit = found.is_some();
571
583
  s.cred = found.unwrap_or_default();
572
- return Ok(());
584
+ return Ok(hit);
573
585
  }
574
586
 
575
587
  // Exchanging: what the chain resolved is the REFRESH token, kept
@@ -589,11 +601,22 @@ fn resolve_once(state: &Rc<RefCell<SecretsState>>) -> Result<(), ProjectNameErro
589
601
  // A starting access token was supplied. Spend it: if it is
590
602
  // stale the API answers with an expiry status and the wrapper
591
603
  // buys another, which is the same path expiry takes anyway.
592
- return Ok(());
604
+ return Ok(true);
605
+ }
606
+
607
+ // `auth: null` is the documented way to send NO credential, and a
608
+ // purchase is a credential-bearing call: the refresh token goes to
609
+ // the token endpoint in the request body. with_refresh honours
610
+ // suppression for the RETRY, but it runs after this - by then the
611
+ // refresh token has already left the process, and no later check
612
+ // can call it back. The suppression has to be honoured here, before
613
+ // the first purchase, or it only ever half-held.
614
+ if !authactive(&s.options) {
615
+ return Ok(false);
593
616
  }
594
617
  }
595
618
 
596
- buy(state).map(|_| ())
619
+ buy(state).map(|_| true)
597
620
  }
598
621
 
599
622
  // ---- the transport seam -------------------------------------------------
@@ -989,6 +989,90 @@ fn cache_false_asks_the_chain_on_every_request() {
989
989
  credential_is(call_auth(&wire.api(), 1), "KEY2");
990
990
  }
991
991
 
992
+ // A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this feature
993
+ // used to override from the layer above.
994
+ //
995
+ // DEFAULT caching here, which is the whole point: `cache: true` is about
996
+ // holding a HIT (the test below pins that half), and keeping the settled
997
+ // resolution after a miss meant the chain was never asked again for the life
998
+ // of the client. A secret provisioned after startup (a mounted file, a vault
999
+ // policy granted a minute late) was invisible forever.
1000
+ #[test]
1001
+ fn cache_true_re_asks_after_a_miss() {
1002
+ let wire = Wire::new();
1003
+ let calls = Rc::new(RefCell::new(0i64));
1004
+ let present = Rc::new(RefCell::new(false));
1005
+ let n = calls.clone();
1006
+ let p = present.clone();
1007
+
1008
+ let client = sdk(
1009
+ &wire,
1010
+ vec![providers(vec![callable(move |_name| {
1011
+ *n.borrow_mut() += 1;
1012
+ if *p.borrow() {
1013
+ Value::str("LATEKEY01")
1014
+ } else {
1015
+ Value::Noval
1016
+ }
1017
+ })])],
1018
+ );
1019
+
1020
+ client
1021
+ .direct(jo(vec![("path", Value::str("/one"))]))
1022
+ .expect("direct");
1023
+ assert_eq!(
1024
+ call_auth(&wire.api(), 0),
1025
+ None,
1026
+ "the chain has nothing yet, so no credential should go out: {}",
1027
+ wire.trace()
1028
+ );
1029
+
1030
+ let asked = *calls.borrow();
1031
+ assert!(0 < asked, "the chain was never asked");
1032
+
1033
+ // The secret is provisioned while the client is live.
1034
+ *present.borrow_mut() = true;
1035
+
1036
+ client
1037
+ .direct(jo(vec![("path", Value::str("/two"))]))
1038
+ .expect("direct");
1039
+
1040
+ assert!(
1041
+ asked < *calls.borrow(),
1042
+ "the MISS was cached: a secret that appears later can never be picked up"
1043
+ );
1044
+ credential_is(call_auth(&wire.api(), 1), "LATEKEY01");
1045
+ }
1046
+
1047
+ // The other half of the same rule: a HIT is still cached by default, so the
1048
+ // fix above must not turn every request into a chain walk.
1049
+ #[test]
1050
+ fn cache_true_keeps_a_hit() {
1051
+ let wire = Wire::new();
1052
+ let calls = Rc::new(RefCell::new(0i64));
1053
+ let n = calls.clone();
1054
+
1055
+ let client = sdk(
1056
+ &wire,
1057
+ vec![providers(vec![callable(move |_name| {
1058
+ *n.borrow_mut() += 1;
1059
+ Value::str("STABLEKEY01")
1060
+ })])],
1061
+ );
1062
+
1063
+ for _ in 0..2 {
1064
+ client
1065
+ .direct(jo(vec![("path", Value::str("/thing"))]))
1066
+ .expect("direct");
1067
+ }
1068
+
1069
+ assert_eq!(
1070
+ *calls.borrow(),
1071
+ 1,
1072
+ "a hit must be cached under the default cache: true"
1073
+ );
1074
+ }
1075
+
992
1076
  // An UNCACHED miss after a hit is a revocation: the resolved value must
993
1077
  // stop going out.
994
1078
  #[test]
@@ -1403,6 +1487,18 @@ fn exchange_auth_null_suppresses_and_is_never_retried() {
1403
1487
  "no credential may be sent when auth is suppressed: {}",
1404
1488
  wire.trace()
1405
1489
  );
1490
+
1491
+ // AND NO PURCHASE. resolve() runs before with_refresh's suppression
1492
+ // check, so the refresh token used to go to the token endpoint in a
1493
+ // request body even here. Stopping the retry does not unsend it, and
1494
+ // only the token endpoint can see this.
1495
+ assert_eq!(
1496
+ wire.token().len(),
1497
+ 0,
1498
+ "auth null suppressed the credential but the refresh token was still \
1499
+ POSTed to the exchange endpoint: {}",
1500
+ wire.trace()
1501
+ );
1406
1502
  }
1407
1503
 
1408
1504
  // The exchange with NO system.fetch: the ordinary case, where make_options
@@ -264,18 +264,29 @@ class SecretsFeature extends BaseFeature("secrets", "0.1.0", true) {
264
264
  else withrefresh(ctx, url, fetchdef, inner)
265
265
  }
266
266
 
267
- // One resolution, shared by every concurrent caller. A settled SUCCESS is
267
+ // One resolution, shared by every concurrent caller. A settled HIT is
268
268
  // kept only when caching is on; a FAILURE is never kept, so the next
269
269
  // operation asks the chain again.
270
+ //
271
+ // A MISS is not kept either, however caching is set. That rule is
272
+ // sekreto's, not this feature's: `A miss is never cached: the next read
273
+ // asks again`, in sekreto's own source. Keeping a settled miss here would
274
+ // override that from the layer above, and a secret provisioned after
275
+ // startup - a mounted file, a policy granted a minute late - would never
276
+ // be picked up for the life of the client. `cache` is about caching a
277
+ // HIT; it was never a promise to keep saying no.
270
278
  private def resolve(): Unit = lock.synchronized {
271
279
  if (!this.settled) {
272
- resolveonce()
273
- if (this.docache) this.settled = true
280
+ val hit = resolveonce()
281
+ if (this.docache && hit) this.settled = true
274
282
  }
275
283
  }
276
284
 
277
- private def resolveonce(): Unit = {
278
- if (this.sek == null) return
285
+ // Resolve once, reporting whether a credential came out of it. That
286
+ // boolean is the whole of what resolve() needs to tell a cacheable HIT
287
+ // from a miss it must not keep.
288
+ private def resolveonce(): Boolean = {
289
+ if (this.sek == null) return false
279
290
 
280
291
  // tryget returns None for a MISS and RAISES for an ERROR. That is the
281
292
  // whole miss-vs-error rule, and it is sekreto's, not this feature's.
@@ -288,7 +299,7 @@ class SecretsFeature extends BaseFeature("secrets", "0.1.0", true) {
288
299
  // here - it seats FIRST in the chain as a memory provider, so the
289
300
  // chain HITS while one is set and this branch is unreachable.)
290
301
  this.cred = found.getOrElse("")
291
- return
302
+ return found.isDefined
292
303
  }
293
304
 
294
305
  // Exchanging: what the chain resolved is the REFRESH token, kept for
@@ -302,9 +313,20 @@ class SecretsFeature extends BaseFeature("secrets", "0.1.0", true) {
302
313
  // A starting access token was supplied. Spend it: if it is stale the API
303
314
  // answers with an expiry status and the wrapper buys another, which is
304
315
  // the same path expiry takes anyway.
305
- if ("" != this.cred) return
316
+ if ("" != this.cred) return true
317
+
318
+ // `auth: null` is the documented way to send NO credential, and a
319
+ // purchase is a credential-bearing call: the refresh token goes to the
320
+ // token endpoint in the request body. withrefresh honours suppression
321
+ // for the RETRY, but it runs after this - by then the refresh token has
322
+ // already left the process, and no later check can call it back. The
323
+ // suppression has to be honoured here, before the first purchase, or it
324
+ // only ever half-held.
325
+ if (this.liveopts == null || this.liveopts.get("auth") == null) return false
306
326
 
307
327
  buyonce()
328
+
329
+ true
308
330
  }
309
331
 
310
332
  // Buy a token and try the request again when the API says the current one
@@ -612,6 +612,69 @@ object SecretsTestMain {
612
612
  "out; the wire saw \"" + w.authof(last) + "\"")
613
613
  }
614
614
 
615
+ // A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this
616
+ // feature used to override from the layer above.
617
+ //
618
+ // DEFAULT caching here, which is the whole point: `cache: true` is about
619
+ // holding a HIT, and keeping the settled resolution after a miss meant the
620
+ // chain was never asked again for the life of the client. A secret
621
+ // provisioned after startup (a mounted file, a vault policy granted a
622
+ // minute late) was invisible forever, and the only workaround was giving
623
+ // up hit caching entirely.
624
+ private def testCachedMissIsReasked(): Unit = {
625
+ var present = false
626
+ var calls = 0
627
+ val prov = new CodeProvider(_ => {
628
+ calls += 1
629
+ if (present) Some("LATEKEY01") else None
630
+ }, "late")
631
+
632
+ val w = new Wire()
633
+ val client = secretsClient(w, "feature" -> secretsOpts(jlist(prov)))
634
+
635
+ check("cachedmiss.drive", driveOneCall(client, w),
636
+ "no entity op reached the transport")
637
+ if (w.api().nonEmpty) {
638
+ val first = w.api().head
639
+ check("cachedmiss.nocred", !w.hasauth(first) || "" == w.authof(first),
640
+ "the chain has nothing yet, so no credential should go out")
641
+ }
642
+
643
+ val asked = calls
644
+ check("cachedmiss.asked", 0 < asked, "the chain was never asked")
645
+
646
+ // The secret is provisioned while the client is live.
647
+ present = true
648
+ check("cachedmiss.drive2", driveOneCall(client, w),
649
+ "the second op never reached the transport")
650
+
651
+ check("cachedmiss.reasked", asked < calls,
652
+ "the MISS was cached: a secret that appears later can never be picked up")
653
+ if (w.api().nonEmpty) {
654
+ credentialIs("cachedmiss.late", w.authof(w.api().last), "LATEKEY01")
655
+ }
656
+ }
657
+
658
+ // The other half of the same rule: a HIT is still cached by default, so
659
+ // the fix above must not turn every request into a chain walk.
660
+ private def testCachedHitIsKept(): Unit = {
661
+ var calls = 0
662
+ val prov = new CodeProvider(_ => {
663
+ calls += 1
664
+ Some("STABLEKEY01")
665
+ }, "counting")
666
+
667
+ val w = new Wire()
668
+ val client = secretsClient(w, "feature" -> secretsOpts(jlist(prov)))
669
+
670
+ check("cachedhit.drive", driveOneCall(client, w),
671
+ "no entity op reached the transport")
672
+ check("cachedhit.drive2", driveOneCall(client, w),
673
+ "the second op never reached the transport")
674
+
675
+ eqi("cachedhit.once", 1, calls)
676
+ }
677
+
615
678
  private def testSecretNameConfigurable(): Unit = {
616
679
  val w = new Wire()
617
680
  val client = secretsClient(w,
@@ -899,6 +962,12 @@ object SecretsTestMain {
899
962
  "no credential may be sent when auth is suppressed, got \"" +
900
963
  w.authof(w.api().head) + "\"")
901
964
  }
965
+
966
+ // AND NO PURCHASE. resolve() runs before withrefresh's suppression
967
+ // check, so the refresh token used to go to the token endpoint in a
968
+ // request body even here. Stopping the retry does not unsend it, and
969
+ // only the token endpoint can see this.
970
+ eqi("exchange.authnull.nobuy", 0, w.token().length)
902
971
  }
903
972
 
904
973
  // No refresh token anywhere is an ERROR, not an unauthenticated call.
@@ -945,6 +1014,8 @@ object SecretsTestMain {
945
1014
  "failClosedUnbuildableChain" -> testFailClosedUnbuildableChain,
946
1015
  "transientRecovery" -> testTransientRecovery,
947
1016
  "uncachedMissRetracts" -> testUncachedMissRetracts,
1017
+ "cachedMissIsReasked" -> testCachedMissIsReasked,
1018
+ "cachedHitIsKept" -> testCachedHitIsKept,
948
1019
  "secretNameConfigurable" -> testSecretNameConfigurable,
949
1020
  "sekretoIsLive" -> testSekretoIsLive,
950
1021
  "pluginVocabulary" -> testPluginVocabulary,
@@ -167,18 +167,25 @@ class SecretsFeature extends BaseFeature {
167
167
  // the op — sekreto's miss-vs-error rule: never fall through to an
168
168
  // unauthenticated request because a store was broken.
169
169
  //
170
- // The promise is cleared on REJECTION, and after success when caching is
171
- // off. Holding a settled promise forever would mean a transient vault
172
- // outage poisoned the client permanently every later operation failing
173
- // with the original error long after the vault recovered — and it would
174
- // make the documented `cache: false` a lie, since the chain would never
175
- // be asked a second time.
170
+ // The promise is cleared on REJECTION, after success when caching is off,
171
+ // and after a MISS however caching is set. Holding a settled promise
172
+ // forever would mean a transient vault outage poisoned the client
173
+ // permanently every later operation failing with the original error long
174
+ // after the vault recovered and it would make the documented
175
+ // `cache: false` a lie, since the chain would never be asked a second time.
176
+ //
177
+ // The MISS rule is sekreto's, not this feature's: `A miss is never cached:
178
+ // the next read asks again`, in sekreto's own source. Retaining a settled
179
+ // miss here would override that from the layer above, and a secret
180
+ // provisioned after startup — a mounted file, a policy granted a minute
181
+ // late — would never be picked up for the life of the client. `cache` is
182
+ // about caching a HIT; it was never a promise to keep saying no.
176
183
  resolve(): Promise<void> {
177
184
  if (null == this._resolving) {
178
185
  const inflight = this._resolveonce()
179
186
  .then(
180
- () => {
181
- if (!this._cache) {
187
+ (hit: boolean) => {
188
+ if (!this._cache || !hit) {
182
189
  this._resolving = undefined
183
190
  }
184
191
  },
@@ -194,9 +201,12 @@ class SecretsFeature extends BaseFeature {
194
201
  }
195
202
 
196
203
 
197
- private async _resolveonce(): Promise<void> {
204
+ // Resolve once, reporting whether a credential came out of it. That
205
+ // boolean is the whole of what resolve() needs to tell a cacheable HIT
206
+ // from a miss it must not retain.
207
+ private async _resolveonce(): Promise<boolean> {
198
208
  if (null == this._sekreto) {
199
- return
209
+ return false
200
210
  }
201
211
 
202
212
  const found = await this._sekreto.try(this._secretname)
@@ -208,7 +218,7 @@ class SecretsFeature extends BaseFeature {
208
218
  // resolved value lands where the sync auth path already looks.
209
219
  this._client._options.apikey = found
210
220
  }
211
- return
221
+ return undefined !== found
212
222
  }
213
223
 
214
224
  // Exchanging: what the chain resolved is the REFRESH token, kept for
@@ -222,10 +232,23 @@ class SecretsFeature extends BaseFeature {
222
232
  // A starting access token was supplied. Spend it: if it is stale the
223
233
  // API answers 401 and the transport wrapper buys another, which is
224
234
  // the same path expiry takes anyway.
225
- return
235
+ return true
236
+ }
237
+
238
+ // `auth: null` is the documented way to send NO credential, and a
239
+ // purchase is a credential-bearing call: the refresh token goes to the
240
+ // token endpoint in the request body. _withRefresh honours suppression
241
+ // for the RETRY, but it runs after this — by then the refresh token has
242
+ // already left the process, and no later check can call it back. The
243
+ // suppression has to be honoured here, before the first purchase, or it
244
+ // only ever half-held.
245
+ if (null == this._client.options().auth) {
246
+ return false
226
247
  }
227
248
 
228
249
  this._client._options.apikey = await this._buy()
250
+
251
+ return true
229
252
  }
230
253
 
231
254
 
@@ -260,6 +260,71 @@ describe('secrets', () => {
260
260
  })
261
261
 
262
262
 
263
+ // A MISS IS NOT A CACHEABLE ANSWER — sekreto's own rule, which this
264
+ // feature used to override from the layer above.
265
+ //
266
+ // Default caching here, deliberately: `cache: true` is about holding a
267
+ // HIT, and holding the settled promise after a miss meant the chain was
268
+ // never asked again for the life of the client. A secret provisioned
269
+ // after startup (a mounted file, a vault policy granted a minute late)
270
+ // was invisible forever, and the only workaround was giving up hit
271
+ // caching entirely.
272
+ test('active: a MISS is re-asked, so a late secret is picked up',
273
+ async () => {
274
+ let calls = 0
275
+ const sdk = (SDK as any).test({}, {
276
+ feature: {
277
+ secrets: {
278
+ active: true,
279
+ providers: [{
280
+ lookup(_name: string): string | undefined {
281
+ calls++
282
+ // Absent on the first ask, present on the second.
283
+ return 1 < calls ? 'LATEKEY' : undefined
284
+ },
285
+ describe() { return 'late:test' },
286
+ }],
287
+ },
288
+ },
289
+ })
290
+
291
+ const first = await sdk.prepare({ path: '/' })
292
+ assert.equal(first.headers['authorization'], undefined,
293
+ 'the first resolve missed, so no credential should go out')
294
+
295
+ const second = await sdk.prepare({ path: '/' })
296
+ credentialIs(second.headers['authorization'], 'LATEKEY')
297
+
298
+ assert.ok(1 < calls,
299
+ 'the chain was asked once and the MISS cached: a secret that ' +
300
+ 'appears later can never be picked up')
301
+ })
302
+
303
+
304
+ // The other half of the same rule: a HIT is still cached by default, so
305
+ // the fix above must not turn every request into a chain walk.
306
+ test('active: a HIT is still cached by default', async () => {
307
+ let calls = 0
308
+ const sdk = (SDK as any).test({}, {
309
+ feature: {
310
+ secrets: {
311
+ active: true,
312
+ providers: [{
313
+ lookup(_name: string): string { calls++; return 'KEY' + calls },
314
+ describe() { return 'counting:test' },
315
+ }],
316
+ },
317
+ },
318
+ })
319
+
320
+ await sdk.prepare({ path: '/' })
321
+ await sdk.prepare({ path: '/' })
322
+
323
+ assert.equal(calls, 1,
324
+ 'a hit must be cached under the default cache: true')
325
+ })
326
+
327
+
263
328
  test('active: secret name is configurable', async () => {
264
329
  process.env[ENVPREFIX + 'API_TOKEN'] = 'TOKKEY01'
265
330
  try {
@@ -679,6 +744,14 @@ describe('secrets exchange', () => {
679
744
  assert.equal(stub.api().length, 1, 'a suppressed request must not be retried')
680
745
  assert.equal(stub.api()[0].auth, undefined,
681
746
  'no credential may be sent when auth is suppressed')
747
+
748
+ // AND NO PURCHASE. This is the half the API-call assertions cannot see:
749
+ // resolve() runs before _withRefresh's suppression check, so the
750
+ // refresh token used to go to the token endpoint in a request body
751
+ // even here. Stopping the retry does not unsend it.
752
+ assert.equal(stub.token().length, 0,
753
+ 'auth: null suppressed the credential but the refresh token was ' +
754
+ 'still POSTed to the exchange endpoint')
682
755
  })
683
756
 
684
757