@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
@@ -0,0 +1,797 @@
1
+ // Secret access via a vendored @voxgig/sekreto provider chain, and the
2
+ // access-token exchange some APIs require on top of it. The c port of
3
+ // tm/ts/src/feature/secrets/SecretsFeature.ts, following the GO port's
4
+ // structure (tm/go/feature/secrets_feature.go) - same contract, c idiom.
5
+ //
6
+ // The SDK's `apikey` option keeps exactly its old meaning: an explicit
7
+ // credential given in code. This feature makes it ONE SOURCE among several
8
+ // rather than the only one: when active, the apikey is resolved through a
9
+ // sekreto chain in which the explicit option (when set) is the FIRST
10
+ // provider - a `memory` store named `options` - so an explicit value always
11
+ // wins, by sekreto's own first-hit rule rather than by special-case logic.
12
+ //
13
+ // MISS vs ERROR (sekreto's invariant): a provider MISS falls through - the
14
+ // op proceeds, unauthenticated if nothing else supplies a credential. A
15
+ // provider ERROR (unreachable vault, bad creds) must FAIL the op: a broken
16
+ // vault never degrades into an unauthenticated request.
17
+ //
18
+ // WHERE RESOLUTION HAPPENS, and why it is not the PreSpec hook. c's hook
19
+ // slot is `void (*hook)(Feature*, const char*, Context*)` (core/sdk.h): a
20
+ // hook cannot fail an operation the way ts's awaited rejection can - and
21
+ // sdk_direct / sdk_graphql run no feature hooks at all (Main.fragment.c's
22
+ // sdk_raw_request calls utility_fetch directly). So, exactly as in go and
23
+ // rust, resolution happens at the TRANSPORT SEAM: `Utility.fetcher`, the
24
+ // one place every wire path crosses (entity ops through make_request,
25
+ // the raw paths through sdk_raw_request, both reading the client's one
26
+ // Utility). The wrapper refuses to send while the last resolution stands
27
+ // failed, which is fail-closed for the entity pipeline and the raw paths
28
+ // alike, with one implementation.
29
+ //
30
+ // WHERE THE CREDENTIAL LIVES, and why it is not the options map. The ts
31
+ // reference writes `options.apikey`; this port does NOT. prepare_auth
32
+ // builds the header from the client's options on every request, and this
33
+ // feature rewrites that header at the seam from a value it holds itself -
34
+ // same construction, same suppression rules - so `sdk_options_map` stays
35
+ // exactly what the caller passed, and the raw paths and the entity path
36
+ // cannot disagree about it. (go's structural rule, kept here for the same
37
+ // reason even though c is single threaded.)
38
+ //
39
+ // EXCHANGE: some APIs will not take a long-lived credential at all. What
40
+ // the chain resolves is then a REFRESH token, which buys a short-lived
41
+ // ACCESS token from a token endpoint (`exchange.path`, relative to
42
+ // options.base); the access token is what every request carries, and when
43
+ // a response status in `exchange.statuses` (401) says it is spent the
44
+ // wrapper buys another and retries the same request once. Test mode buys
45
+ // nothing and answers with a deterministic fake token.
46
+ //
47
+ // THE c-SPECIFIC SEAMS, stated because the parity table cannot check them:
48
+ //
49
+ // * A live provider object cannot travel in the options: voxgig_value is
50
+ // a closed union (UNDEF|NULL|BOOL|INT|DOUBLE|STRING|LIST|MAP|FUNC|
51
+ // SENTINEL), so go's `providers: [&customProvider{}]` has no c spelling.
52
+ // The answer is the `custom` pseudo-kind: a providers entry that is a
53
+ // FUNC, or a map `{ kind: "custom", lookup: <FUNC>, name?: "..." }`,
54
+ // bridged by a sek_provider whose lookup calls the FUNC through
55
+ // call_vfn - the same shape options.system.fetch and the retry
56
+ // feature's injected sleep already use. The FUNC is handed the secret
57
+ // NAME and answers a STRING (a hit), Noval/Null (a MISS - the chain
58
+ // continues) or a map `{ "__err__": "..." }` (an ERROR - the operation
59
+ // fails). Conflating the last two is the failure this library exists
60
+ // to prevent.
61
+ //
62
+ // * The c core ships no HTTP client (utility/fetcher.c). The exchange
63
+ // therefore uses options.system.fetch when supplied - the seam every
64
+ // live c request already lives under - and otherwise
65
+ // `secrets_rawfetch`, which lives in the GENERATED feature/secrets/
66
+ // kinds.c: a libcurl round-trip when a plugin group is active, a
67
+ // transport error that says so when none is (see Config_c; the
68
+ // generated kinds.mk beside it is what links libcurl on the same
69
+ // condition).
70
+ //
71
+ // * sek_new is documented NOT REENTRANT (a file-scope slot for the
72
+ // duration of the call). It runs once, in the client constructor,
73
+ // which is single threaded by core/context.c's own declaration; the
74
+ // same declaration is what lets this port drop go's mutex / in-flight
75
+ // promise apparatus. The pool a chain is built from is never freed:
76
+ // the c SDK is never-free (core/sdk.h "MEMORY MODEL"), and plugin's
77
+ // C port holds its declarations in a process arena regardless.
78
+
79
+ #include "sdk.h"
80
+
81
+ #include "secrets.h"
82
+
83
+ #include "sekreto.h"
84
+
85
+ #include <stddef.h>
86
+ #include <stdio.h>
87
+ #include <stdlib.h>
88
+ #include <string.h>
89
+
90
+ // The exchange transport of last resort, defined in the GENERATED
91
+ // feature/secrets/kinds.c (Config_c) - libcurl when a plugin group is
92
+ // active, a "no transport" error otherwise. Prototyped here rather than in
93
+ // sdk.h because core/ must not know a gated feature's internals.
94
+ voxgig_value* secrets_rawfetch(Context* ctx, const char* url,
95
+ voxgig_value* fetchdef, PNError** err);
96
+
97
+ typedef struct {
98
+ const char* path;
99
+ const char* method;
100
+ const char* request;
101
+ const char* response;
102
+ int64_t* statuses;
103
+ size_t nstatuses;
104
+ int64_t retries;
105
+ } SecretsExchange;
106
+
107
+ typedef struct {
108
+ int64_t resolves; // chain resolutions that completed (hit or miss)
109
+ int64_t buys; // token purchases (test mode included)
110
+ int64_t refused; // requests the fail-closed gate refused to send
111
+ } SecretsTrack;
112
+
113
+ typedef struct {
114
+ Feature base;
115
+ char* name;
116
+ bool active;
117
+ voxgig_value* add_opts;
118
+ voxgig_value* options;
119
+
120
+ ProjectNameSDK* client;
121
+ // The LIVE options map (root ctx options): read for `apikey` and `auth`,
122
+ // never written.
123
+ voxgig_value* liveopts;
124
+
125
+ const char* secretname;
126
+ bool cache;
127
+
128
+ sek_pool* pool;
129
+ sek_sekreto* sek;
130
+
131
+ // sekreto's own message when construction failed; the gate reads it.
132
+ char* initerr;
133
+
134
+ // The RESOLVED credential (the access token when exchanging), held here
135
+ // and injected at the seam - never written into the options map.
136
+ char* cred;
137
+ // A cached resolution stands (cache: true only); a FAILURE never sets it,
138
+ // so the next request asks the chain again.
139
+ bool resolved;
140
+
141
+ SecretsExchange* exchange;
142
+ char* refresh;
143
+
144
+ SecretsTrack track;
145
+ } SecretsFeature;
146
+
147
+ typedef struct {
148
+ Fetcher* inner;
149
+ SecretsFeature* f;
150
+ } SecretsState;
151
+
152
+ // ---- the custom-provider bridge --------------------------------------------
153
+
154
+ typedef struct {
155
+ voxgig_value* fn;
156
+ sek_pool* pool;
157
+ } CustomData;
158
+
159
+ static sek_err custom_lookup(sek_provider* self, const char* name, char** out) {
160
+ CustomData* d = (CustomData*)self->data;
161
+ voxgig_value* got = call_vfn(d->fn, v_str(name));
162
+ *out = NULL;
163
+ if (voxgig_is_string(got)) {
164
+ *out = sek_strdup(d->pool, voxgig_as_string(got));
165
+ return NULL;
166
+ }
167
+ if (voxgig_is_map(got)) {
168
+ const char* emsg = get_str(got, "__err__");
169
+ if (NULL != emsg) return sek_strdup(d->pool, emsg);
170
+ }
171
+ // Noval, Null, or anything that is not a value: a MISS.
172
+ return NULL;
173
+ }
174
+
175
+ static const char* custom_describe(sek_provider* self) {
176
+ (void)self;
177
+ return "custom";
178
+ }
179
+
180
+ static sek_provider* custom_provider(sek_pool* pool, voxgig_value* fn) {
181
+ CustomData* d = (CustomData*)sek_alloc(pool, sizeof(CustomData));
182
+ d->fn = v_share(fn);
183
+ d->pool = pool;
184
+ return sek_provider_new(pool, custom_lookup, custom_describe, d);
185
+ }
186
+
187
+ // ---- options map -> sek_spec ------------------------------------------------
188
+
189
+ // The spec's own key names paired with where each lands in a sek_spec - the
190
+ // same table upstream's providers.c keeps (specof), because the two
191
+ // directions must not drift. Strings only, as upstream reads them; `values`,
192
+ // `kv` and `auth` are not strings and are handled below.
193
+ typedef struct {
194
+ const char* key;
195
+ size_t at;
196
+ } SpecField;
197
+
198
+ #define SF(name, member) {name, offsetof(sek_spec, member)}
199
+ #define SAF(name, member) {name, offsetof(sek_authspec, member)}
200
+
201
+ static const SpecField SPECFIELDS[] = {
202
+ SF("kind", kind), SF("name", name), SF("prefix", prefix), SF("file", file),
203
+ SF("dir", dir), SF("addr", addr), SF("token", token), SF("mount", mount),
204
+ SF("vaultnamespace", vaultnamespace), SF("command", command),
205
+ SF("profile", profile), SF("backend", backend), SF("reason", reason),
206
+ SF("namespace", namespace_), SF("home", home), SF("region", region),
207
+ SF("keyid", keyid), SF("secret", secret), SF("session", session),
208
+ SF("project", project), SF("vault", vault), SF("tenant", tenant),
209
+ SF("clientid", clientid), SF("clientsecret", clientsecret),
210
+ SF("loginaddr", loginaddr), SF("imdsaddr", imdsaddr),
211
+ SF("metadataaddr", metadataaddr), SF("apiversion", apiversion),
212
+ SF("config", config), SF("environment", environment), SF("path", path),
213
+ };
214
+
215
+ static const SpecField AUTHFIELDS[] = {
216
+ SAF("method", method), SAF("mount", mount), SAF("role", role), SAF("jwt", jwt),
217
+ SAF("jwtfile", jwtfile), SAF("roleid", roleid), SAF("secretid", secretid),
218
+ };
219
+
220
+ // A providers entry that is a map, as a spec. Answers false, with the
221
+ // refusal in *why, when the map says `custom` but carries no callable.
222
+ static bool spec_of_map(sek_pool* pool, voxgig_value* m, sek_spec* spec, const char** why) {
223
+ *spec = sek_spec_new(NULL);
224
+ *why = NULL;
225
+
226
+ const char* kind = get_str(m, "kind");
227
+ if (NULL != kind && 0 == strcmp(kind, "custom")) {
228
+ voxgig_value* lookup = getp(m, "lookup");
229
+ if (!voxgig_is_func(lookup)) {
230
+ *why = "a `custom` provider needs a `lookup` callable";
231
+ return false;
232
+ }
233
+ spec->provider = custom_provider(pool, lookup);
234
+ const char* name = get_str(m, "name");
235
+ if (NULL != name && '\0' != name[0]) spec->name = sek_own(pool, name);
236
+ return true;
237
+ }
238
+
239
+ for (size_t i = 0; i < sizeof(SPECFIELDS) / sizeof(SPECFIELDS[0]); i++) {
240
+ const char* held = get_str(m, SPECFIELDS[i].key);
241
+ if (NULL != held) {
242
+ *(const char**)((char*)spec + SPECFIELDS[i].at) = sek_own(pool, held);
243
+ }
244
+ }
245
+
246
+ voxgig_value* values = getp(m, "values");
247
+ if (voxgig_is_map(values)) {
248
+ voxgig_map* vm = voxgig_as_map(values);
249
+ spec->values = sek_map_new(pool);
250
+ for (size_t i = 0; i < vm->len; i++) {
251
+ voxgig_value* held = vm->entries[i].value;
252
+ char* text = voxgig_is_string(held) ? strdup(voxgig_as_string(held))
253
+ : voxgig_stringify(held, 0);
254
+ sek_map_set(spec->values, vm->entries[i].key, sek_own(pool, text));
255
+ free(text);
256
+ }
257
+ }
258
+
259
+ voxgig_value* kv = getp(m, "kv");
260
+ if (voxgig_is_number(kv)) {
261
+ spec->kv = (int)to_int(kv);
262
+ spec->haskv = 1;
263
+ }
264
+
265
+ voxgig_value* auth = getp(m, "auth");
266
+ if (voxgig_is_map(auth)) {
267
+ sek_authspec* use = (sek_authspec*)sek_alloc(pool, sizeof(sek_authspec));
268
+ for (size_t i = 0; i < sizeof(AUTHFIELDS) / sizeof(AUTHFIELDS[0]); i++) {
269
+ const char* held = get_str(auth, AUTHFIELDS[i].key);
270
+ if (NULL != held) {
271
+ *(const char**)((char*)use + AUTHFIELDS[i].at) = sek_own(pool, held);
272
+ }
273
+ }
274
+ spec->auth = use;
275
+ }
276
+
277
+ return true;
278
+ }
279
+
280
+ // ---- credential injection ---------------------------------------------------
281
+
282
+ // Write the resolved credential into THIS request's authorization header,
283
+ // the way prepare_auth builds it (same options auth.prefix, same
284
+ // suppression rule), so the two cannot drift.
285
+ //
286
+ // `auth: null` is the documented way to send NO credential, and
287
+ // prepare_auth honours it by removing the header; so does this, and it
288
+ // never writes one - which is what keeps the exchange from transmitting
289
+ // exactly the credential the caller suppressed on a retry. An EMPTY
290
+ // credential leaves prepare_auth's header alone: nothing was resolved, so
291
+ // there is nothing to inject and nothing to retract that prepare_auth did
292
+ // not already decide.
293
+ static void secrets_reauth(SecretsFeature* f, voxgig_value* fetchdef) {
294
+ voxgig_value* headers = getp(fetchdef, "headers");
295
+ if (!voxgig_is_map(headers)) return;
296
+
297
+ voxgig_value* auth = getp(f->liveopts, "auth");
298
+ if (v_is_noval(auth) || v_is_null(auth)) {
299
+ voxgig_value* k = voxgig_new_string("authorization");
300
+ voxgig_delprop(headers, k);
301
+ voxgig_release(k);
302
+ return;
303
+ }
304
+
305
+ if (NULL == f->cred || '\0' == f->cred[0]) return;
306
+
307
+ const char* prefix = get_str(auth, "prefix");
308
+ if (NULL == prefix || '\0' == prefix[0]) {
309
+ setp(headers, "authorization", v_str(f->cred));
310
+ } else {
311
+ size_t n = strlen(prefix) + 1 + strlen(f->cred) + 1;
312
+ char* buf = (char*)malloc(n);
313
+ snprintf(buf, n, "%s %s", prefix, f->cred);
314
+ setp(headers, "authorization", v_str(buf));
315
+ free(buf);
316
+ }
317
+ }
318
+
319
+ static void secrets_setcred(SecretsFeature* f, const char* value) {
320
+ free(f->cred);
321
+ f->cred = strdup(NULL == value ? "" : value);
322
+ }
323
+
324
+ // ---- the exchange -----------------------------------------------------------
325
+
326
+ // Buy an access token with the refresh token. Answers sekreto-style: a
327
+ // pool-owned message, or NULL for success with the token in f->cred.
328
+ static const char* secrets_buy(SecretsFeature* f, Context* ctx) {
329
+ SecretsExchange* x = f->exchange;
330
+
331
+ // TEST MODE BUYS NOTHING. The test feature replaces the transport so no
332
+ // request leaves the process; an exchange here would be the one HTTP
333
+ // call it could not stop, and it would need a live token endpoint for a
334
+ // suite whose whole point is not needing one. A deterministic,
335
+ // obviously-fake token instead - the same answer make_options gives a
336
+ // required server variable, for the same reason.
337
+ if (0 != strcmp(f->client->mode, "live")) {
338
+ size_t n = 5 + strlen(x->response) + 1;
339
+ char* fake = (char*)malloc(n);
340
+ snprintf(fake, n, "test-%s", x->response);
341
+ secrets_setcred(f, fake);
342
+ free(fake);
343
+ f->track.buys++;
344
+ return NULL;
345
+ }
346
+
347
+ if (NULL == f->refresh || '\0' == f->refresh[0]) {
348
+ return sek_fmt(f->pool,
349
+ "secrets: no refresh token: the provider chain has no '%s', and "
350
+ "feature.secrets.exchange.refresh is unset", f->secretname);
351
+ }
352
+
353
+ voxgig_value* options = sdk_options_map(f->client);
354
+
355
+ // The token endpoint is RELATIVE to the base, which already carries
356
+ // whatever account or tenant segment the server URL declares.
357
+ const char* base = get_str(options, "base");
358
+ base = base ? base : "";
359
+ size_t blen = strlen(base);
360
+ while (0 < blen && '/' == base[blen - 1]) blen--;
361
+ const char* path = x->path;
362
+ while ('/' == path[0]) path++;
363
+ char* url = sek_fmt(f->pool, "%.*s/%s", (int)blen, base, path);
364
+
365
+ // The body is MARSHALLED, never concatenated: a refresh token (or a
366
+ // configured request-field name) carrying a quote, backslash or newline
367
+ // must arrive as that literal value, not as malformed JSON. sekreto's
368
+ // own JSON writer does it.
369
+ sek_json* body = sek_json_obj(f->pool);
370
+ sek_json_set(f->pool, body, x->request, sek_json_str(f->pool, f->refresh));
371
+ char* bodytext = sek_json_stringify(f->pool, body);
372
+
373
+ voxgig_value* fetchdef = cmap(3,
374
+ "method", v_str(x->method),
375
+ "headers", cmap(1, "content-type", v_str("application/json")),
376
+ "body", v_str(bodytext));
377
+
378
+ // Deliberately NOT the SDK transport. The transport is what this feature
379
+ // wraps, and sending the token request back through it would recurse on
380
+ // the first expiry - and would route the exchange through the test mock,
381
+ // which knows nothing about it. options.system.fetch when the caller
382
+ // supplied one (the seam every live c request already uses), else the
383
+ // bundled transport of last resort from the generated kinds.c.
384
+ voxgig_value* sys_fetch = getpath2(options, "system", "fetch");
385
+ voxgig_value* res;
386
+ if (voxgig_is_func(sys_fetch)) {
387
+ res = call_vfn(sys_fetch, clist(2, v_str(url), v_share(fetchdef)));
388
+ const char* emsg = get_str(res, "__err__");
389
+ if (NULL != emsg) return sek_strdup(f->pool, emsg);
390
+ } else {
391
+ PNError* ferr = NULL;
392
+ res = secrets_rawfetch(ctx, url, fetchdef, &ferr);
393
+ if (NULL != ferr) return sek_strdup(f->pool, ferr->msg ? ferr->msg : "secrets: transport failed");
394
+ }
395
+
396
+ int64_t status = to_int(getp(res, "status"));
397
+ if (200 > status || 300 <= status) {
398
+ return sek_fmt(f->pool, "secrets: token exchange failed: %lld from %s",
399
+ (long long)status, url);
400
+ }
401
+
402
+ voxgig_value* jf = getp(res, "json");
403
+ voxgig_value* parsed;
404
+ if (voxgig_is_func(jf)) {
405
+ parsed = call_json(jf);
406
+ } else {
407
+ voxgig_value* raw = getp(res, "body");
408
+ parsed = voxgig_is_string(raw) ? json_parse(voxgig_as_string(raw)) : raw;
409
+ }
410
+
411
+ const char* token = get_str(parsed, x->response);
412
+ if (NULL == token || '\0' == token[0]) {
413
+ return sek_fmt(f->pool, "secrets: token exchange returned no '%s' field from %s",
414
+ x->response, url);
415
+ }
416
+
417
+ secrets_setcred(f, token);
418
+ f->track.buys++;
419
+ return NULL;
420
+ }
421
+
422
+ static bool secrets_spent(SecretsFeature* f, voxgig_value* res) {
423
+ int64_t status;
424
+ if (!fres_status(res, &status)) return false;
425
+ for (size_t i = 0; i < f->exchange->nstatuses; i++) {
426
+ if (f->exchange->statuses[i] == status) return true;
427
+ }
428
+ return false;
429
+ }
430
+
431
+ // ---- resolution -------------------------------------------------------------
432
+
433
+ // One resolution. A settled SUCCESS is kept only when caching is on
434
+ // (`cache: false` means every request asks the chain again, and sekreto's
435
+ // own cache is off with it); a FAILURE is never kept, so a transient vault
436
+ // outage never poisons the client - the next request asks again. Answers
437
+ // the provider's own message, or NULL.
438
+ static const char* secrets_resolve(SecretsFeature* f, Context* ctx) {
439
+ if (NULL != f->initerr) return f->initerr;
440
+ if (f->cache && f->resolved) return NULL;
441
+ if (NULL == f->sek) return NULL;
442
+
443
+ char* found = NULL;
444
+ sek_err err = sek_try(f->sek, f->secretname, &found);
445
+ if (NULL != err) {
446
+ // A provider ERROR fails the op (via the transport gate); only a MISS
447
+ // falls through.
448
+ return err;
449
+ }
450
+ f->track.resolves++;
451
+
452
+ if (NULL == f->exchange) {
453
+ // A hit is the credential. An UNCACHED miss after an earlier hit is a
454
+ // revocation: the chain now says no provider has the secret, so the
455
+ // resolved value must not keep going out on the wire. (An explicit
456
+ // apikey OPTION is never lost here - it seats FIRST in the chain as a
457
+ // memory provider, so the chain HITS while one is set.)
458
+ secrets_setcred(f, found);
459
+ f->resolved = true;
460
+ return NULL;
461
+ }
462
+
463
+ // Exchanging: what the chain resolved is the REFRESH token, kept for
464
+ // every later purchase. A miss is not fatal here - an explicit `apikey`
465
+ // may already hold a usable access token, and the API is what gets to
466
+ // say whether it does.
467
+ free(f->refresh);
468
+ f->refresh = strdup(found ? found : "");
469
+
470
+ if ('\0' == f->cred[0]) {
471
+ // A starting access token supplied as the OPTION: read from the frozen
472
+ // options map (no feature ever writes it).
473
+ const char* held = get_str(f->liveopts, "apikey");
474
+ if (NULL != held && '\0' != held[0]) secrets_setcred(f, held);
475
+ }
476
+ if ('\0' != f->cred[0]) {
477
+ // Spend it: if it is stale the API answers with an expiry status and
478
+ // the wrapper buys another, which is the same path expiry takes anyway.
479
+ f->resolved = true;
480
+ return NULL;
481
+ }
482
+
483
+ const char* berr = secrets_buy(f, ctx);
484
+ if (NULL != berr) return berr;
485
+ f->resolved = true;
486
+ return NULL;
487
+ }
488
+
489
+ // ---- the transport wrapper --------------------------------------------------
490
+
491
+ static voxgig_value* secrets_fetch(Fetcher* self, Context* ctx, const char* url,
492
+ voxgig_value* fetchdef, PNError** err) {
493
+ SecretsState* st = (SecretsState*)self->state;
494
+ SecretsFeature* f = st->f;
495
+ *err = NULL;
496
+
497
+ // FAIL-CLOSED, at the ONE seam every wire path crosses. Entity ops,
498
+ // sdk_direct, sdk_graphql and the exchange retries all come through
499
+ // here, so resolving HERE is what gives the raw paths - which run no
500
+ // feature hooks at all - the same credential the entity pipeline gets.
501
+ // A construction failure (initerr) or a provider ERROR refuses the
502
+ // request with sekreto's own message - never an unauthenticated send.
503
+ if (NULL != f->initerr) {
504
+ f->track.refused++;
505
+ *err = context_make_error(ctx, "secrets_init", f->initerr);
506
+ return NULL;
507
+ }
508
+ const char* rerr = secrets_resolve(f, ctx);
509
+ if (NULL != rerr) {
510
+ f->track.refused++;
511
+ *err = context_make_error(ctx, "secrets_resolve", rerr);
512
+ return NULL;
513
+ }
514
+
515
+ // Inject the resolved credential into THIS request's header (the header
516
+ // was built by prepare_auth from the options apikey; the chain-resolved
517
+ // value lives in feature state instead).
518
+ secrets_reauth(f, fetchdef);
519
+
520
+ if (NULL == f->exchange) {
521
+ return st->inner->fn(st->inner, ctx, url, fetchdef, err);
522
+ }
523
+
524
+ // `auth: null` is a deliberately unauthenticated request: a refusal of it
525
+ // is not an expired token and cannot be fixed by buying one.
526
+ voxgig_value* auth = getp(f->liveopts, "auth");
527
+ if (v_is_noval(auth) || v_is_null(auth)) {
528
+ return st->inner->fn(st->inner, ctx, url, fetchdef, err);
529
+ }
530
+
531
+ int64_t max = f->exchange->retries;
532
+ int64_t attempt = 0;
533
+ for (;;) {
534
+ // The credential THIS attempt goes out with, captured before it leaves:
535
+ // it is what tells a stale refusal apart from a fresh one.
536
+ char* used = strdup(f->cred);
537
+
538
+ PNError* e = NULL;
539
+ voxgig_value* out = st->inner->fn(st->inner, ctx, url, fetchdef, &e);
540
+
541
+ if (NULL != e || attempt >= max || !secrets_spent(f, out)) {
542
+ free(used);
543
+ *err = e;
544
+ return out;
545
+ }
546
+
547
+ // A token bought since this attempt left (single threaded, so only by
548
+ // a nested request from a callback) is spent before another is bought:
549
+ // a second exchange for a token that is already fresh is wasted, and
550
+ // on a provider that invalidates the previous credential on issuance
551
+ // it breaks this request's own retry.
552
+ if ('\0' == f->cred[0] || 0 == strcmp(f->cred, used)) {
553
+ const char* berr = secrets_buy(f, ctx);
554
+ if (NULL != berr) {
555
+ // The purchase failed: answer with the API's own refusal rather
556
+ // than this one. The caller asked for data, and the refusal is
557
+ // the more useful of the two - the exchange error is a symptom.
558
+ free(used);
559
+ return out;
560
+ }
561
+ }
562
+ free(used);
563
+
564
+ secrets_reauth(f, fetchdef);
565
+ attempt++;
566
+ }
567
+ }
568
+
569
+ // ---- the feature ------------------------------------------------------------
570
+
571
+ static const char* secrets_name(Feature* f) { return ((SecretsFeature*)f)->name; }
572
+ static bool secrets_active(Feature* f) { return ((SecretsFeature*)f)->active; }
573
+ static voxgig_value* secrets_add_options(Feature* f) { return ((SecretsFeature*)f)->add_opts; }
574
+
575
+ static void secrets_fail(SecretsFeature* f, const char* msg) {
576
+ // The FIRST failure stands: it names the entry the caller has to fix.
577
+ if (NULL == f->initerr) f->initerr = strdup(msg);
578
+ }
579
+
580
+ // Init is sync by feature contract: build the chain, never look anything up
581
+ // here.
582
+ static void secrets_init(Feature* fb, Context* ctx, voxgig_value* options) {
583
+ SecretsFeature* f = (SecretsFeature*)fb;
584
+ f->options = options;
585
+ f->active = fopt_bool(options, "active", false);
586
+ if (!f->active) return;
587
+
588
+ f->client = ctx->client;
589
+ f->liveopts = ctx->options;
590
+
591
+ // WRAP FIRST. The fail-closed gate needs the seam whatever happens
592
+ // below - a chain that fails to build must still refuse to send - so the
593
+ // wrapper is installed before anything here can fail, and the exchange
594
+ // (when on) additionally needs to SEE responses: expiry is only ever
595
+ // discovered from one, and this is the one place a response can be seen
596
+ // and the request tried again.
597
+ Utility* util = context_util(ctx);
598
+ SecretsState* st = (SecretsState*)calloc(1, sizeof(SecretsState));
599
+ st->inner = util->fetcher;
600
+ st->f = f;
601
+ Fetcher* wrapped = (Fetcher*)calloc(1, sizeof(Fetcher));
602
+ wrapped->fn = secrets_fetch;
603
+ wrapped->state = st;
604
+ util->fetcher = wrapped;
605
+
606
+ f->secretname = fopt_str(options, "name", "apikey");
607
+ f->cache = fopt_bool(options, "cache", true);
608
+ f->pool = sek_pool_new();
609
+
610
+ // Exchange config, normalised once. NULL when off, so every later
611
+ // decision is a NULL check.
612
+ voxgig_value* xopts = fopt_map(options, "exchange");
613
+ if (fopt_bool(xopts, "active", false)) {
614
+ SecretsExchange* x = (SecretsExchange*)calloc(1, sizeof(SecretsExchange));
615
+ x->path = fopt_str(xopts, "path", "auth/token");
616
+ x->method = fopt_str(xopts, "method", "POST");
617
+ x->request = fopt_str(xopts, "request", "refresh_token");
618
+ x->response = fopt_str(xopts, "response", "access_token");
619
+ x->retries = fopt_int(xopts, "retries", 1);
620
+ voxgig_value* sl = fopt_list(xopts, "statuses");
621
+ if (voxgig_is_list(sl) && 0 < voxgig_as_list(sl)->len) {
622
+ voxgig_list* l = voxgig_as_list(sl);
623
+ x->statuses = (int64_t*)calloc(l->len, sizeof(int64_t));
624
+ for (size_t i = 0; i < l->len; i++) {
625
+ if (voxgig_is_number(l->items[i])) x->statuses[x->nstatuses++] = to_int(l->items[i]);
626
+ }
627
+ }
628
+ if (0 == x->nstatuses) {
629
+ x->statuses = (int64_t*)calloc(1, sizeof(int64_t));
630
+ x->statuses[0] = 401;
631
+ x->nstatuses = 1;
632
+ }
633
+ f->exchange = x;
634
+ }
635
+
636
+ // The explicit credential, when set, is the first store in the chain.
637
+ //
638
+ // WHICH option that is depends on the exchange. Without one, the secret
639
+ // being resolved IS the credential the transport sends, so `apikey` is
640
+ // it. With one, the secret is a REFRESH token and `apikey` means the
641
+ // opposite thing - an access token the caller already holds - so the
642
+ // explicit seat belongs to `exchange.refresh`, and apikey is left alone
643
+ // to serve as the starting access token (see secrets_resolve).
644
+ //
645
+ // Read DIRECTLY, not through fopt_str, which answers its default for an
646
+ // empty string: an explicitly EMPTY apikey means "defer to the chain".
647
+ const char* explicit = NULL;
648
+ if (NULL == f->exchange) {
649
+ explicit = get_str(f->liveopts, "apikey");
650
+ } else {
651
+ explicit = get_str(xopts, "refresh");
652
+ }
653
+
654
+ size_t cap = 4;
655
+ size_t count = 0;
656
+ sek_spec* specs = (sek_spec*)calloc(cap, sizeof(sek_spec));
657
+ #define SPEC_PUSH(s) do { \
658
+ if (count == cap) { cap *= 2; specs = (sek_spec*)realloc(specs, cap * sizeof(sek_spec)); } \
659
+ specs[count++] = (s); \
660
+ } while (0)
661
+
662
+ if (NULL != explicit && '\0' != explicit[0]) {
663
+ char* key = NULL;
664
+ sek_err kerr = sek_envkey(f->pool, f->secretname, "", &key);
665
+ if (NULL != kerr) {
666
+ secrets_fail(f, kerr);
667
+ } else {
668
+ sek_spec seat = sek_spec_new("memory");
669
+ seat.name = "options";
670
+ seat.values = sek_map_new(f->pool);
671
+ sek_map_set(seat.values, key, sek_own(f->pool, explicit));
672
+ SPEC_PUSH(seat);
673
+ }
674
+ }
675
+
676
+ voxgig_value* providers = fopt_list(options, "providers");
677
+ if (voxgig_is_list(providers)) {
678
+ voxgig_list* pl = voxgig_as_list(providers);
679
+ for (size_t i = 0; i < pl->len; i++) {
680
+ voxgig_value* p = pl->items[i];
681
+ if (voxgig_is_func(p)) {
682
+ // A provider already built (as built as c can spell it): joins
683
+ // the chain as it is.
684
+ sek_spec live = sek_spec_new(NULL);
685
+ live.provider = custom_provider(f->pool, p);
686
+ SPEC_PUSH(live);
687
+ } else if (voxgig_is_map(p)) {
688
+ sek_spec spec;
689
+ const char* why = NULL;
690
+ if (spec_of_map(f->pool, p, &spec, &why)) {
691
+ SPEC_PUSH(spec);
692
+ } else {
693
+ char* shown = voxgig_stringify(p, 0);
694
+ secrets_fail(f, sek_fmt(f->pool,
695
+ "sekreto: not a provider or a provider spec: %s (%s)", shown, why));
696
+ free(shown);
697
+ }
698
+ } else {
699
+ // FAIL CLOSED, never drop. An entry that is neither a callable nor
700
+ // a spec map (a bare "hashicorp" where a spec was meant, a number,
701
+ // a null) must not leave the chain quietly shorter than the
702
+ // options say: sekreto's own wording lands in the init-failure
703
+ // gate, which refuses to send. A loop that skipped the entry would
704
+ // SHORTEN the chain instead of failing it - a misconfigured
705
+ // providers list then sends ordinary unauthenticated requests, the
706
+ // exact fail-open the gate exists to prevent.
707
+ char* shown = voxgig_stringify(p, 0);
708
+ secrets_fail(f, sek_fmt(f->pool,
709
+ "sekreto: not a provider or a provider spec: %s", shown));
710
+ free(shown);
711
+ }
712
+ }
713
+ }
714
+ #undef SPEC_PUSH
715
+
716
+ if (NULL == f->initerr) {
717
+ // The plugin DEFINITIONS the model selected for this feature, from the
718
+ // generated feature/secrets/kinds.c through core/config.c's accessor.
719
+ // Upstream sekreto's contract since the registry was retired: a kind
720
+ // not passed here is unknown to this Sekreto, so the model's choice of
721
+ // plugin groups IS the SDK's provider vocabulary.
722
+ size_t ndefs = 0;
723
+ void** defs = feature_plugins("secrets", &ndefs);
724
+
725
+ sek_options sopts;
726
+ memset(&sopts, 0, sizeof(sopts));
727
+ sopts.providers = specs;
728
+ sopts.count = count;
729
+ sopts.plugins = (Definition**)defs;
730
+ sopts.plugincount = ndefs;
731
+ sopts.nocache = f->cache ? 0 : 1;
732
+
733
+ sek_sekreto* sek = NULL;
734
+ sek_err serr = sek_new(f->pool, &sopts, &sek);
735
+ if (NULL != serr) {
736
+ // Init cannot fail the construction the way ts's throwing init does;
737
+ // the transport gate refuses to send instead, which keeps a
738
+ // misconfigured chain fail-closed rather than silently
739
+ // unauthenticated.
740
+ secrets_fail(f, serr);
741
+ } else {
742
+ f->sek = sek;
743
+ }
744
+ }
745
+ }
746
+
747
+ static void secrets_hook(Feature* f, const char* name, Context* ctx) {
748
+ (void)f; (void)name; (void)ctx;
749
+ }
750
+
751
+ static voxgig_value* secrets_track(Feature* fb) {
752
+ SecretsFeature* f = (SecretsFeature*)fb;
753
+ return cmap(3,
754
+ "resolves", v_num((double)f->track.resolves),
755
+ "buys", v_num((double)f->track.buys),
756
+ "refused", v_num((double)f->track.refused));
757
+ }
758
+
759
+ static const FeatureVT SECRETS_VT = {
760
+ secrets_name, secrets_active, secrets_add_options, secrets_init, secrets_hook,
761
+ secrets_track,
762
+ };
763
+
764
+ Feature* feature_secrets_new(void) {
765
+ SecretsFeature* f = (SecretsFeature*)calloc(1, sizeof(SecretsFeature));
766
+ f->base.vt = &SECRETS_VT;
767
+ f->name = strdup("secrets");
768
+ f->active = true; // overridden by init from options
769
+ f->add_opts = NULL;
770
+ f->options = voxgig_new_undef();
771
+ f->cred = strdup("");
772
+ f->refresh = strdup("");
773
+ return (Feature*)f;
774
+ }
775
+
776
+ // ---- accessors (secrets.h) --------------------------------------------------
777
+
778
+ Feature* sdk_feature_secrets(ProjectNameSDK* sdk) {
779
+ if (NULL == sdk) return NULL;
780
+ for (size_t i = 0; i < sdk->features_len; i++) {
781
+ Feature* f = sdk->features[i];
782
+ if (0 == strcmp(f->vt->name(f), "secrets")) return f;
783
+ }
784
+ return NULL;
785
+ }
786
+
787
+ struct sek_sekreto* feature_secrets_sekreto(Feature* f) {
788
+ return NULL == f ? NULL : ((SecretsFeature*)f)->sek;
789
+ }
790
+
791
+ const char* feature_secrets_credential(Feature* f) {
792
+ return NULL == f ? "" : ((SecretsFeature*)f)->cred;
793
+ }
794
+
795
+ const char* feature_secrets_initerr(Feature* f) {
796
+ return NULL == f ? NULL : ((SecretsFeature*)f)->initerr;
797
+ }