@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
@@ -321,11 +321,19 @@ public class SecretsFeature : BaseFeature
321
321
  // ---------------------------------------------------------------
322
322
  // Resolution.
323
323
 
324
- // One resolution, shared by every concurrent caller. A settled SUCCESS
325
- // is kept only when caching is on (`cache: false` means every resolve
324
+ // One resolution, shared by every concurrent caller. A settled HIT is
325
+ // kept only when caching is on (`cache: false` means every resolve
326
326
  // asks the chain again); a FAILURE is always cleared, so a transient
327
327
  // vault outage never poisons the client permanently - the next
328
328
  // operation asks the chain again.
329
+ //
330
+ // A MISS is cleared too, however caching is set. That rule is
331
+ // sekreto's, not this feature's: `A miss is never cached: the next read
332
+ // asks again`, in sekreto's own source. Keeping a settled miss here
333
+ // would override that from the layer above, and a secret provisioned
334
+ // after startup - a mounted file, a policy granted a minute late -
335
+ // would never be picked up for the life of the client. `cache` is about
336
+ // caching a HIT; it was never a promise to keep saying no.
329
337
  private void Resolve()
330
338
  {
331
339
  if (null != _initerr)
@@ -361,9 +369,10 @@ public class SecretsFeature : BaseFeature
361
369
  }
362
370
 
363
371
  Exception? err = null;
372
+ var hit = false;
364
373
  try
365
374
  {
366
- ResolveOnce();
375
+ hit = ResolveOnce();
367
376
  }
368
377
  catch (Exception ex)
369
378
  {
@@ -373,7 +382,7 @@ public class SecretsFeature : BaseFeature
373
382
  lock (_mu)
374
383
  {
375
384
  call.Err = err;
376
- if (null != err || !_cache)
385
+ if (null != err || !_cache || !hit)
377
386
  {
378
387
  _resolving = null;
379
388
  }
@@ -386,11 +395,14 @@ public class SecretsFeature : BaseFeature
386
395
  }
387
396
  }
388
397
 
389
- private void ResolveOnce()
398
+ // Resolve once, reporting whether a credential came out of it. That
399
+ // bool is the whole of what Resolve() needs to tell a cacheable HIT
400
+ // from a miss it must not keep.
401
+ private bool ResolveOnce()
390
402
  {
391
403
  if (null == _sek)
392
404
  {
393
- return;
405
+ return false;
394
406
  }
395
407
 
396
408
  // TryGet returns null on a MISS and THROWS on a provider error -
@@ -410,7 +422,7 @@ public class SecretsFeature : BaseFeature
410
422
  // HITS while one is set and this branch is unreachable.)
411
423
  _cred = found ?? "";
412
424
  }
413
- return;
425
+ return null != found;
414
426
  }
415
427
 
416
428
  // Exchanging: what the chain resolved is the REFRESH token, kept
@@ -441,10 +453,24 @@ public class SecretsFeature : BaseFeature
441
453
  // stale the API answers with an expiry status and the transport
442
454
  // wrapper buys another, which is the same path expiry takes
443
455
  // anyway.
444
- return;
456
+ return true;
457
+ }
458
+
459
+ // `auth: null` is the documented way to send NO credential, and a
460
+ // purchase is a credential-bearing call: the refresh token goes to
461
+ // the token endpoint in the request body. WithRefresh honours
462
+ // suppression for the RETRY, but it runs after this - by then the
463
+ // refresh token has already left the process, and no later check
464
+ // can call it back. The suppression has to be honoured here, before
465
+ // the first purchase, or it only ever half-held.
466
+ if (AuthSuppressed())
467
+ {
468
+ return false;
445
469
  }
446
470
 
447
471
  Buy();
472
+
473
+ return true;
448
474
  }
449
475
 
450
476
  // ---------------------------------------------------------------
@@ -652,6 +652,82 @@ public class SecretsFeatureTest
652
652
  "out; the wire saw " + last.Auth);
653
653
  }
654
654
 
655
+ // A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this
656
+ // feature used to override from the layer above.
657
+ //
658
+ // DEFAULT caching here, which is the whole point: `cache: true` is
659
+ // about holding a HIT, and keeping the settled resolution after a miss
660
+ // meant the chain was never asked again for the life of the client. A
661
+ // secret provisioned after startup (a mounted file, a vault policy
662
+ // granted a minute late) was invisible forever, and the only workaround
663
+ // was giving up hit caching entirely.
664
+ [Fact]
665
+ public void CachedMissIsReasked()
666
+ {
667
+ var present = false;
668
+ var calls = 0;
669
+ var late = new ProbeProvider
670
+ {
671
+ Fn = _ =>
672
+ {
673
+ calls++;
674
+ return present ? "LATEKEY01" : null;
675
+ },
676
+ };
677
+
678
+ var w = new Wire();
679
+ var client = SecretsClient(w, new Dictionary<string, object?>
680
+ {
681
+ ["feature"] = ProviderOpts(late, null),
682
+ });
683
+
684
+ DriveEntityOp(client, w);
685
+ var first = w.Api()[0];
686
+ Assert.True(!first.HasAuth || "" == first.Auth,
687
+ "the chain has nothing yet, so no credential should go out");
688
+
689
+ var asked = calls;
690
+ Assert.True(0 < asked);
691
+
692
+ // The secret is provisioned while the client is live.
693
+ present = true;
694
+
695
+ DriveEntityOp(client, w);
696
+ CredentialIs(w.Api()[w.Api().Count - 1].Auth, "LATEKEY01");
697
+
698
+ Assert.True(asked < calls,
699
+ "the MISS was cached: a secret that appears later can never be picked up");
700
+ }
701
+
702
+ // The other half of the same rule: a HIT is still cached by default, so
703
+ // the fix above must not turn every request into a chain walk.
704
+ [Fact]
705
+ public void CachedHitIsKept()
706
+ {
707
+ var calls = 0;
708
+ var counting = new ProbeProvider
709
+ {
710
+ Fn = _ =>
711
+ {
712
+ calls++;
713
+ return "STABLEKEY01";
714
+ },
715
+ };
716
+
717
+ var w = new Wire();
718
+ var client = SecretsClient(w, new Dictionary<string, object?>
719
+ {
720
+ ["feature"] = ProviderOpts(counting, null),
721
+ });
722
+
723
+ DriveEntityOp(client, w);
724
+ DriveEntityOp(client, w);
725
+
726
+ Assert.True(1 == calls,
727
+ "a hit must be cached under the default cache: true, chain asked " +
728
+ calls + " times");
729
+ }
730
+
655
731
  [Fact]
656
732
  public void CacheFalseAsksTheChainOnEveryResolve()
657
733
  {
@@ -1455,6 +1531,15 @@ public class SecretsFeatureTest
1455
1531
  Assert.False(w.Api()[0].HasAuth,
1456
1532
  "no credential may be sent when auth is suppressed, got " +
1457
1533
  w.Api()[0].Auth);
1534
+
1535
+ // AND NO PURCHASE. Resolve() runs before WithRefresh's
1536
+ // suppression check, so the refresh token used to go to the
1537
+ // token endpoint in a request body even here. Stopping the
1538
+ // retry does not unsend it, and only the token endpoint can
1539
+ // see this.
1540
+ Assert.True(0 == w.Token().Count,
1541
+ "auth null suppressed the credential but the refresh token was " +
1542
+ "still POSTed to the exchange endpoint");
1458
1543
  }
1459
1544
  finally
1460
1545
  {
@@ -361,10 +361,18 @@ defmodule ProjectName.Feature.Secrets do
361
361
 
362
362
  # ---- resolution ----------------------------------------------------------
363
363
 
364
- # One resolution. A settled SUCCESS is kept only when caching is on
364
+ # One resolution. A settled HIT is kept only when caching is on
365
365
  # (`cache: false` means every resolve asks the chain again); a FAILURE is
366
366
  # never kept, so a transient vault outage cannot poison the client
367
367
  # permanently - the next operation asks the chain again.
368
+ #
369
+ # A MISS is not kept either, however caching is set. That rule is
370
+ # sekreto's, not this feature's: `A miss is never cached: the next read
371
+ # asks again`, in sekreto's own source. Keeping a settled miss here would
372
+ # override that from the layer above, and a secret provisioned after
373
+ # startup - a mounted file, a policy granted a minute late - would never
374
+ # be picked up for the life of the client. `cache` is about caching a
375
+ # HIT; it was never a promise to keep saying no.
368
376
  def resolve(f) do
369
377
  initerr = S.getprop(f, "_initerr")
370
378
 
@@ -433,7 +441,8 @@ defmodule ProjectName.Feature.Secrets do
433
441
  # - it seats FIRST in the chain as a memory provider, so the chain
434
442
  # HITS while one is set and the miss branch is unreachable.)
435
443
  S.setprop(f, "_cred", tostr(found))
436
- keep(f)
444
+ # Only a HIT is kept: see resolve/1.
445
+ if found != nil, do: keep(f)
437
446
  :ok
438
447
  else
439
448
  # Exchanging: what the chain resolved is the REFRESH token, kept for
@@ -451,6 +460,12 @@ defmodule ProjectName.Feature.Secrets do
451
460
  keep(f)
452
461
  :ok
453
462
  else
463
+ # NO SUPPRESSION CHECK HERE, and that is deliberate: elixir's
464
+ # transport/5 already returns before resolve/1 when `auth: nil`, so
465
+ # a suppressed request never reaches this purchase at all. Every
466
+ # other target guards the purchase itself, because their transports
467
+ # resolve first. One rule, one place - and here that place is the
468
+ # transport.
454
469
  case buy(f, x) do
455
470
  {:ok, _token} ->
456
471
  keep(f)
@@ -631,6 +631,47 @@ defmodule ProjectName.SecretsTest do
631
631
  auth_is(Enum.at(api(r), 1), "KEY2")
632
632
  end
633
633
 
634
+ # A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this
635
+ # feature used to override from the layer above.
636
+ #
637
+ # DEFAULT caching here, which is the whole point: `cache: true` is about
638
+ # holding a HIT (the test below pins that half), and keeping the settled
639
+ # resolution after a miss meant the chain was never asked again for the
640
+ # life of the client. A secret provisioned after startup (a mounted
641
+ # file, a vault policy granted a minute late) was invisible forever.
642
+ test "active: a cached MISS is re-asked, so a late secret is picked up" do
643
+ n = :counters.new(1, [])
644
+ present = :counters.new(1, [])
645
+
646
+ late = %{
647
+ lookup: fn _ ->
648
+ :counters.add(n, 1, 1)
649
+ if :counters.get(present, 1) > 0, do: "LATEKEY01", else: nil
650
+ end,
651
+ describe: fn -> "late:test" end
652
+ }
653
+
654
+ r = recorder()
655
+ client = sdk(r, [{"feature", secrets([{"providers", providers([late])}])}])
656
+
657
+ ProjectName.direct(client, S.jm(["path", "/one"]))
658
+ assert Enum.at(api(r), 0).auth == nil,
659
+ "the chain has nothing yet, so no credential should go out"
660
+
661
+ asked = :counters.get(n, 1)
662
+ assert asked > 0
663
+
664
+ # The secret is provisioned while the client is live.
665
+ :counters.add(present, 1, 1)
666
+
667
+ ProjectName.direct(client, S.jm(["path", "/two"]))
668
+
669
+ assert :counters.get(n, 1) > asked,
670
+ "the MISS was cached: a secret that appears later can never be picked up"
671
+
672
+ auth_is(Enum.at(api(r), 1), "LATEKEY01")
673
+ end
674
+
634
675
  test "active: caching on asks the chain once" do
635
676
  n = :counters.new(1, [])
636
677
  counting = %{
@@ -265,10 +265,18 @@ func (f *SecretsFeature) Init(ctx *core.Context, options map[string]any) {
265
265
  }
266
266
 
267
267
  // resolve runs one resolution, shared by every concurrent caller. A
268
- // settled SUCCESS is kept only when caching is on (`cache: false` means
269
- // every resolve asks the chain again); a FAILURE is always cleared, so a
268
+ // settled HIT is kept only when caching is on (`cache: false` means every
269
+ // resolve asks the chain again); a FAILURE is always cleared, so a
270
270
  // transient vault outage never poisons the client permanently - the next
271
271
  // operation asks the chain again.
272
+ //
273
+ // A MISS is cleared too, however caching is set. That rule is sekreto's,
274
+ // not this feature's: `A miss is never cached: the next read asks again`,
275
+ // in sekreto's own source. Retaining a settled miss here would override
276
+ // that from the layer above, and a secret provisioned after startup - a
277
+ // mounted file, a policy granted a minute late - would never be picked up
278
+ // for the life of the client. `cache` is about caching a HIT; it was never
279
+ // a promise to keep saying no.
272
280
  func (f *SecretsFeature) resolve() error {
273
281
  if nil != f.initerr {
274
282
  return f.initerr
@@ -284,11 +292,11 @@ func (f *SecretsFeature) resolve() error {
284
292
  f.resolving = call
285
293
  f.mu.Unlock()
286
294
 
287
- err := f.resolveonce()
295
+ hit, err := f.resolveonce()
288
296
 
289
297
  f.mu.Lock()
290
298
  call.err = err
291
- if nil != err || !f.cache {
299
+ if nil != err || !f.cache || !hit {
292
300
  f.resolving = nil
293
301
  }
294
302
  f.mu.Unlock()
@@ -297,16 +305,19 @@ func (f *SecretsFeature) resolve() error {
297
305
  return err
298
306
  }
299
307
 
300
- func (f *SecretsFeature) resolveonce() error {
308
+ // resolveonce resolves once, reporting whether a credential came out of it.
309
+ // That bool is the whole of what resolve() needs to tell a cacheable HIT
310
+ // from a miss it must not retain.
311
+ func (f *SecretsFeature) resolveonce() (bool, error) {
301
312
  if nil == f.sek {
302
- return nil
313
+ return false, nil
303
314
  }
304
315
 
305
316
  found, has, err := f.sek.Try(f.secretname)
306
317
  if nil != err {
307
318
  // A provider ERROR fails the op (via the transport gate); only a
308
319
  // MISS falls through.
309
- return err
320
+ return false, err
310
321
  }
311
322
 
312
323
  if nil == f.exchange {
@@ -323,7 +334,7 @@ func (f *SecretsFeature) resolveonce() error {
323
334
  f.cred = ""
324
335
  }
325
336
  f.mu.Unlock()
326
- return nil
337
+ return has, nil
327
338
  }
328
339
 
329
340
  // Exchanging: what the chain resolved is the REFRESH token, kept for
@@ -350,11 +361,22 @@ func (f *SecretsFeature) resolveonce() error {
350
361
  // A starting access token was supplied. Spend it: if it is stale
351
362
  // the API answers with an expiry status and the transport wrapper
352
363
  // buys another, which is the same path expiry takes anyway.
353
- return nil
364
+ return true, nil
365
+ }
366
+
367
+ // `auth: nil` is the documented way to send NO credential, and a
368
+ // purchase is a credential-bearing call: the refresh token goes to the
369
+ // token endpoint in the request body. withrefresh honours suppression
370
+ // for the RETRY, but it runs after this - by then the refresh token has
371
+ // already left the process, and no later check can call it back. The
372
+ // suppression has to be honoured here, before the first purchase, or it
373
+ // only ever half-held.
374
+ if nil == f.liveopts["auth"] {
375
+ return false, nil
354
376
  }
355
377
 
356
378
  _, err = f.buy()
357
- return err
379
+ return nil == err, err
358
380
  }
359
381
 
360
382
  // transport wraps whatever transport was current at Init.
@@ -488,6 +488,89 @@ func TestSecretsChain(t *testing.T) {
488
488
  })
489
489
  }
490
490
 
491
+ // A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this
492
+ // feature used to override from the layer above.
493
+ //
494
+ // DEFAULT caching here, which is the whole point: `cache: true` is about
495
+ // holding a HIT, and holding the settled resolution after a miss meant the
496
+ // chain was never asked again for the life of the client. A secret
497
+ // provisioned after startup (a mounted file, a vault policy granted a
498
+ // minute late) was invisible forever, and the only workaround was giving up
499
+ // hit caching entirely.
500
+ func TestSecretsCachedMissIsReasked(t *testing.T) {
501
+ var mu sync.Mutex
502
+ calls := 0
503
+
504
+ w := makewire()
505
+ client := secretsClient(w, map[string]any{
506
+ "feature": map[string]any{"secrets": map[string]any{
507
+ "active": true,
508
+ "providers": []any{
509
+ &customProvider{
510
+ lookup: func(name string) (string, bool, error) {
511
+ mu.Lock()
512
+ defer mu.Unlock()
513
+ calls++
514
+ // Absent on the first ask, present on the second.
515
+ if 1 < calls {
516
+ return "LATEKEY01", true, nil
517
+ }
518
+ return "", false, nil
519
+ },
520
+ },
521
+ },
522
+ }},
523
+ })
524
+
525
+ driveEntityOp(t, client, w)
526
+ if first := w.api()[0]; first.has && "" != first.auth {
527
+ t.Fatalf("the first resolve missed, so no credential should go out; got %q", first.auth)
528
+ }
529
+
530
+ driveEntityOp(t, client, w)
531
+ credentialIs(t, w.api()[len(w.api())-1].auth, "LATEKEY01")
532
+
533
+ mu.Lock()
534
+ defer mu.Unlock()
535
+ if 1 >= calls {
536
+ t.Fatal("the chain was asked once and the MISS cached: a secret " +
537
+ "that appears later can never be picked up")
538
+ }
539
+ }
540
+
541
+ // The other half of the same rule: a HIT is still cached by default, so the
542
+ // fix above must not turn every request into a chain walk.
543
+ func TestSecretsCachedHitIsKept(t *testing.T) {
544
+ var mu sync.Mutex
545
+ calls := 0
546
+
547
+ w := makewire()
548
+ client := secretsClient(w, map[string]any{
549
+ "feature": map[string]any{"secrets": map[string]any{
550
+ "active": true,
551
+ "providers": []any{
552
+ &customProvider{
553
+ lookup: func(name string) (string, bool, error) {
554
+ mu.Lock()
555
+ defer mu.Unlock()
556
+ calls++
557
+ return "STABLEKEY01", true, nil
558
+ },
559
+ },
560
+ },
561
+ }},
562
+ })
563
+
564
+ driveEntityOp(t, client, w)
565
+ driveEntityOp(t, client, w)
566
+
567
+ mu.Lock()
568
+ defer mu.Unlock()
569
+ if 1 != calls {
570
+ t.Fatalf("a hit must be cached under the default cache: true, chain asked %d times", calls)
571
+ }
572
+ }
573
+
491
574
  // customProvider is a sekreto.Provider built in code (the interface is
492
575
  // structural: Lookup + Describe).
493
576
  type customProvider struct {
@@ -538,6 +621,39 @@ func TestSecretsExchange(t *testing.T) {
538
621
  credentialIs(t, api[1].auth, "ACCESS02")
539
622
  })
540
623
 
624
+ // `auth: nil` SUPPRESSES THE PURCHASE, not just the retry.
625
+ //
626
+ // resolve() runs before withrefresh's suppression check, so the refresh
627
+ // token used to go to the token endpoint in a request body even here.
628
+ // Stopping the retry does not unsend it - this asserts on the token
629
+ // endpoint, which is the half the API-call assertions cannot see.
630
+ t.Run("auth nil buys no token at all", func(t *testing.T) {
631
+ os.Setenv(envprefix+"REFRESH_TOKEN", "REFRESH01")
632
+ defer os.Unsetenv(envprefix + "REFRESH_TOKEN")
633
+
634
+ w := makewire()
635
+ w.apistatus = []int{401}
636
+
637
+ client := secretsClient(w, map[string]any{
638
+ "auth": nil,
639
+ "feature": secretsOpts(map[string]any{
640
+ "name": "refresh_token",
641
+ "exchange": map[string]any{"active": true},
642
+ }),
643
+ })
644
+
645
+ driveEntityOp(t, client, w)
646
+
647
+ if 0 != len(w.token()) {
648
+ t.Fatalf("auth nil suppressed the credential but the refresh "+
649
+ "token was still POSTed to the exchange endpoint (%d calls)",
650
+ len(w.token()))
651
+ }
652
+ if call := w.api()[0]; call.has {
653
+ t.Fatalf("no credential may be sent when auth is suppressed, got %q", call.auth)
654
+ }
655
+ })
656
+
541
657
  t.Run("test mode buys nothing and needs no token endpoint", func(t *testing.T) {
542
658
  os.Setenv(envprefix+"REFRESH_TOKEN", "REFRESH01")
543
659
  defer os.Unsetenv(envprefix + "REFRESH_TOKEN")
@@ -325,10 +325,18 @@ public class SecretsFeature extends BaseFeature {
325
325
  }
326
326
 
327
327
  // resolve runs one resolution, shared by every concurrent caller. A
328
- // settled SUCCESS is kept only when caching is on (`cache: false` means
329
- // every resolve asks the chain again); a FAILURE is always cleared, so a
328
+ // settled HIT is kept only when caching is on (`cache: false` means every
329
+ // resolve asks the chain again); a FAILURE is always cleared, so a
330
330
  // transient vault outage never poisons the client permanently - the next
331
331
  // operation asks the chain again.
332
+ //
333
+ // A MISS is cleared too, however caching is set. That rule is sekreto's,
334
+ // not this feature's: `A miss is never cached: the next read asks again`,
335
+ // in sekreto's own source. Keeping a settled miss here would override
336
+ // that from the layer above, and a secret provisioned after startup - a
337
+ // mounted file, a policy granted a minute late - would never be picked up
338
+ // for the life of the client. `cache` is about caching a HIT; it was
339
+ // never a promise to keep saying no.
332
340
  private void resolve() {
333
341
  SecretsCall call;
334
342
  boolean mine = false;
@@ -353,8 +361,9 @@ public class SecretsFeature extends BaseFeature {
353
361
  }
354
362
 
355
363
  RuntimeException err = null;
364
+ boolean hit = false;
356
365
  try {
357
- resolveonce();
366
+ hit = resolveonce();
358
367
  }
359
368
  catch (RuntimeException e) {
360
369
  err = e;
@@ -362,7 +371,7 @@ public class SecretsFeature extends BaseFeature {
362
371
 
363
372
  synchronized (this.lock) {
364
373
  call.err = err;
365
- if (err != null || !this.cache) {
374
+ if (err != null || !this.cache || !hit) {
366
375
  this.resolving = null;
367
376
  }
368
377
  }
@@ -373,9 +382,12 @@ public class SecretsFeature extends BaseFeature {
373
382
  }
374
383
  }
375
384
 
376
- private void resolveonce() {
385
+ // resolveonce resolves once, reporting whether a credential came out of
386
+ // it. That boolean is the whole of what resolve() needs to tell a
387
+ // cacheable HIT from a miss it must not keep.
388
+ private boolean resolveonce() {
377
389
  if (this.sek == null) {
378
- return;
390
+ return false;
379
391
  }
380
392
 
381
393
  // tryget: null is a MISS (the chain had nothing), an exception is an
@@ -392,7 +404,7 @@ public class SecretsFeature extends BaseFeature {
392
404
  // unreachable.)
393
405
  this.cred = found == null ? "" : found;
394
406
  }
395
- return;
407
+ return found != null;
396
408
  }
397
409
 
398
410
  // Exchanging: what the chain resolved is the REFRESH token, kept for
@@ -416,10 +428,23 @@ public class SecretsFeature extends BaseFeature {
416
428
  // A starting access token was supplied. Spend it: if it is stale the
417
429
  // API answers with an expiry status and the transport wrapper buys
418
430
  // another, which is the same path expiry takes anyway.
419
- return;
431
+ return true;
432
+ }
433
+
434
+ // `auth: null` is the documented way to send NO credential, and a
435
+ // purchase is a credential-bearing call: the refresh token goes to the
436
+ // token endpoint in the request body. withrefresh honours suppression
437
+ // for the RETRY, but it runs after this - by then the refresh token has
438
+ // already left the process, and no later check can call it back. The
439
+ // suppression has to be honoured here, before the first purchase, or it
440
+ // only ever half-held.
441
+ if (this.liveopts.get("auth") == null) {
442
+ return false;
420
443
  }
421
444
 
422
445
  buy();
446
+
447
+ return true;
423
448
  }
424
449
 
425
450
  // withrefresh buys a token and tries the request again when the API says
@@ -760,6 +760,62 @@ public class SecretsFeatureTest {
760
760
  + " the wire saw \"" + last.auth + "\"");
761
761
  }
762
762
 
763
+ // A MISS IS NOT A CACHEABLE ANSWER - sekreto's own rule, which this
764
+ // feature used to override from the layer above.
765
+ //
766
+ // DEFAULT caching here, which is the whole point: `cache: true` is about
767
+ // holding a HIT, and keeping the settled resolution after a miss meant
768
+ // the chain was never asked again for the life of the client. A secret
769
+ // provisioned after startup (a mounted file, a vault policy granted a
770
+ // minute late) was invisible forever, and the only workaround was giving
771
+ // up hit caching entirely.
772
+ @Test
773
+ public void active_aCachedMissIsReasked() {
774
+ final boolean[] present = {false};
775
+ final int[] calls = {0};
776
+ Wire wire = new Wire();
777
+ ProjectNameSDK client = liveClient(wire, secretsOpts(
778
+ List.of(new TestProvider((name) -> {
779
+ calls[0]++;
780
+ return present[0] ? "LATEKEY01" : null;
781
+ }))));
782
+
783
+ client.direct(map("path", "/one"));
784
+ Call first = wire.api().get(0);
785
+ assertFalse(first.has && !"".equals(first.auth),
786
+ "the chain has nothing yet, so no credential should go out");
787
+
788
+ int asked = calls[0];
789
+ assertTrue(0 < asked);
790
+
791
+ // The secret is provisioned while the client is live.
792
+ present[0] = true;
793
+ client.direct(map("path", "/two"));
794
+
795
+ credentialIs(wire.api().get(wire.api().size() - 1).auth, "LATEKEY01");
796
+ assertTrue(asked < calls[0],
797
+ "the MISS was cached: a secret that appears later can never be picked up");
798
+ }
799
+
800
+ // The other half of the same rule: a HIT is still cached by default, so
801
+ // the fix above must not turn every request into a chain walk.
802
+ @Test
803
+ public void active_aCachedHitIsKept() {
804
+ final int[] calls = {0};
805
+ Wire wire = new Wire();
806
+ ProjectNameSDK client = liveClient(wire, secretsOpts(
807
+ List.of(new TestProvider((name) -> {
808
+ calls[0]++;
809
+ return "STABLEKEY01";
810
+ }))));
811
+
812
+ client.direct(map("path", "/one"));
813
+ client.direct(map("path", "/two"));
814
+
815
+ assertEquals(1, calls[0],
816
+ "a hit must be cached under the default cache: true");
817
+ }
818
+
763
819
  // `auth: null` - the documented way to disable auth outright, which
764
820
  // prepareAuth honours before it ever reads the apikey.
765
821
  //
@@ -966,6 +1022,14 @@ public class SecretsFeatureTest {
966
1022
  assertFalse(wire.api().get(0).has,
967
1023
  "no credential may be sent when auth is suppressed, got \""
968
1024
  + wire.api().get(0).auth + "\"");
1025
+
1026
+ // AND NO PURCHASE. resolve() runs before withrefresh's suppression
1027
+ // check, so the refresh token used to go to the token endpoint in a
1028
+ // request body even here. Stopping the retry does not unsend it, and
1029
+ // only the token endpoint can see this.
1030
+ assertEquals(0, wire.token().size(),
1031
+ "auth null suppressed the credential but the refresh token was still"
1032
+ + " POSTed to the exchange endpoint");
969
1033
  }
970
1034
 
971
1035
  @Test