@voxgig/sdkgen 4.6.0 → 4.8.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.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/Feature.js +5 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/TestControl.d.ts +4 -0
- package/dist/cmp/TestControl.js +51 -0
- package/dist/cmp/TestControl.js.map +1 -0
- package/dist/helpers/featureSource.d.ts +3 -1
- package/dist/helpers/featureSource.js +105 -0
- package/dist/helpers/featureSource.js.map +1 -1
- package/dist/helpers/opShape.js +8 -11
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/pointPath.d.ts +10 -0
- package/dist/helpers/pointPath.js +54 -0
- package/dist/helpers/pointPath.js.map +1 -0
- package/dist/sdkgen.d.ts +6 -3
- package/dist/sdkgen.js +14 -4
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +2 -1
- package/dist/utility.js +78 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +58 -0
- package/package.json +2 -2
- package/project/.sdk/model/feature/secrets.aon +82 -0
- package/project/.sdk/src/cmp/c/Config_c.ts +7 -8
- package/project/.sdk/src/cmp/c/TestDirect_c.ts +4 -3
- package/project/.sdk/src/cmp/cpp/Main_cpp.ts +2 -1
- package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +4 -3
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Main_csharp.ts +2 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +34 -9
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +29 -5
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -1
- package/project/.sdk/src/cmp/dart/Config_dart.ts +7 -8
- package/project/.sdk/src/cmp/dart/Main_dart.ts +2 -1
- package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +28 -10
- package/project/.sdk/src/cmp/dart/TestEntity_dart.ts +28 -7
- package/project/.sdk/src/cmp/dart/Test_dart.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +9 -8
- package/project/.sdk/src/cmp/go/Config_go.ts +1 -7
- package/project/.sdk/src/cmp/go/Main_go.ts +2 -1
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +5 -4
- package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
- package/project/.sdk/src/cmp/java/Config_java.ts +7 -7
- package/project/.sdk/src/cmp/java/Main_java.ts +2 -1
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +5 -4
- package/project/.sdk/src/cmp/java/Test_java.ts +5 -1
- package/project/.sdk/src/cmp/js/Config_js.ts +7 -8
- package/project/.sdk/src/cmp/js/Main_js.ts +2 -1
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +34 -8
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +35 -5
- package/project/.sdk/src/cmp/js/Test_js.ts +5 -1
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +7 -1
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +7 -7
- package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +2 -1
- package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +5 -4
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/lean/Config_lean.ts +9 -8
- package/project/.sdk/src/cmp/lua/Config_lua.ts +1 -7
- package/project/.sdk/src/cmp/lua/Main_lua.ts +2 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +32 -7
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +24 -4
- package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -1
- package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
- package/project/.sdk/src/cmp/perl/Main_perl.ts +2 -1
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +29 -7
- package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +24 -4
- package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -1
- package/project/.sdk/src/cmp/perl/utility_perl.ts +10 -0
- package/project/.sdk/src/cmp/php/Config_php.ts +1 -7
- package/project/.sdk/src/cmp/php/Main_php.ts +2 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +28 -8
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +28 -4
- package/project/.sdk/src/cmp/php/Test_php.ts +5 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +1 -7
- package/project/.sdk/src/cmp/py/Main_py.ts +2 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +5 -4
- package/project/.sdk/src/cmp/py/Test_py.ts +5 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +1 -7
- package/project/.sdk/src/cmp/rb/Main_rb.ts +2 -1
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +28 -8
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +24 -4
- package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/utility_rb.ts +3 -1
- package/project/.sdk/src/cmp/rust/Main_rust.ts +2 -1
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +35 -7
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +37 -4
- package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -1
- package/project/.sdk/src/cmp/scala/Config_scala.ts +9 -7
- package/project/.sdk/src/cmp/scala/Main_scala.ts +2 -1
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +4 -3
- package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -1
- package/project/.sdk/src/cmp/seneca-provider/Extras_seneca-provider.ts +3 -1
- package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +9 -5
- package/project/.sdk/src/cmp/ts/Config_ts.ts +57 -16
- package/project/.sdk/src/cmp/ts/Main_ts.ts +10 -2
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +15 -7
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +11 -3
- package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -1
- package/project/.sdk/tm/csharp/test/Runner.cs +45 -0
- package/project/.sdk/tm/dart/test/utility.dart +39 -0
- package/project/.sdk/tm/js/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/js/test/utility.js +91 -1
- package/project/.sdk/tm/lua/test/runner.lua +40 -0
- package/project/.sdk/tm/ocaml/test/harness.ml +14 -4
- package/project/.sdk/tm/perl/t/runner.pm +30 -0
- package/project/.sdk/tm/php/test/Runner.php +36 -0
- package/project/.sdk/tm/rb/test/runner.rb +25 -0
- package/project/.sdk/tm/rust/tests/common/mod.rs +32 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +1 -1
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +8 -2
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +29 -5
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +30 -21
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +90 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +48 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/aws.ts +219 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/azuresecrets.ts +144 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/boru.ts +113 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/doppler.ts +77 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +51 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +31 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +54 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/gcpsecrets.ts +118 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/hashicorp.ts +159 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +66 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/infisical.ts +107 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +33 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/onepassword.ts +120 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +176 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +15 -13
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +25 -19
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +1 -1
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +1 -1
- package/project/.sdk/tm/zig/core/utility.zig +1 -1
- package/project/sdkgen-package.json +1 -1
- package/src/cmp/Feature.ts +5 -0
- package/src/cmp/TestControl.ts +64 -0
- package/src/helpers/featureSource.ts +130 -0
- package/src/helpers/opShape.ts +9 -14
- package/src/helpers/pointPath.ts +88 -0
- package/src/sdkgen.ts +18 -0
- package/src/utility.ts +92 -1
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +0 -1221
|
@@ -153,6 +153,51 @@ public static class TestRunner
|
|
|
153
153
|
return _testControl;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// LiveClientOptions returns the extra SDK options every LIVE client is
|
|
157
|
+
// constructed with, read from sdk-test-control.json `test.client.options`.
|
|
158
|
+
//
|
|
159
|
+
// The generated live client knows two things: the base URL (from the
|
|
160
|
+
// spec) and the credential (from the environment). Everything else about
|
|
161
|
+
// how a particular API wants to be talked to - which features to switch
|
|
162
|
+
// on, and with what settings - is a property of THAT API, known to the
|
|
163
|
+
// project and to nothing in the toolchain.
|
|
164
|
+
//
|
|
165
|
+
// Merged UNDER the generated fields, so the suite's own
|
|
166
|
+
// base/apikey/server values win: this ADDS to the live client, it does
|
|
167
|
+
// not redirect it.
|
|
168
|
+
//
|
|
169
|
+
// Reserved fields are stripped HERE rather than at each merge site: the
|
|
170
|
+
// generated dictionary only names a field when the model calls for one,
|
|
171
|
+
// so a "base" in this block would face no competing value and would
|
|
172
|
+
// silently redirect the whole suite - credential included - to another
|
|
173
|
+
// host.
|
|
174
|
+
private static readonly string[] LiveReserved =
|
|
175
|
+
{ "base", "prefix", "suffix", "server", "apikey", "secret" };
|
|
176
|
+
|
|
177
|
+
public static Dictionary<string, object?> LiveClientOptions()
|
|
178
|
+
{
|
|
179
|
+
var ctrl = LoadTestControl();
|
|
180
|
+
if (!ctrl.TryGetValue("test", out var testRaw) ||
|
|
181
|
+
testRaw is not Dictionary<string, object?> test ||
|
|
182
|
+
!test.TryGetValue("client", out var clientRaw) ||
|
|
183
|
+
clientRaw is not Dictionary<string, object?> client ||
|
|
184
|
+
!client.TryGetValue("options", out var optsRaw) ||
|
|
185
|
+
optsRaw is not Dictionary<string, object?> opts)
|
|
186
|
+
{
|
|
187
|
+
return new Dictionary<string, object?>();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
var out_ = new Dictionary<string, object?>();
|
|
191
|
+
foreach (var kv in opts)
|
|
192
|
+
{
|
|
193
|
+
if (Array.IndexOf(LiveReserved, kv.Key) < 0)
|
|
194
|
+
{
|
|
195
|
+
out_[kv.Key] = kv.Value;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out_;
|
|
199
|
+
}
|
|
200
|
+
|
|
156
201
|
// IsControlSkipped checks sdk-test-control.json for a skip entry.
|
|
157
202
|
// Returns (skip, reason).
|
|
158
203
|
public static (bool, string) IsControlSkipped(string kind, string name, string mode)
|
|
@@ -143,6 +143,45 @@ bool skipIfMissingIds(T t, Map setup, List<String> requiredKeys) {
|
|
|
143
143
|
|
|
144
144
|
// Per-test live pacing delay (ms). Read from sdk-test-control.json
|
|
145
145
|
// `test.live.delayMs`; defaults to 500ms if absent or invalid.
|
|
146
|
+
// Extra SDK options every LIVE client is constructed with, read from
|
|
147
|
+
// sdk-test-control.json `test.client.options`.
|
|
148
|
+
//
|
|
149
|
+
// The generated live client knows two things: the base URL (from the spec)
|
|
150
|
+
// and the credential (from the environment). Everything else about how a
|
|
151
|
+
// particular API wants to be talked to - which features to switch on, and
|
|
152
|
+
// with what settings - is a property of THAT API, known to the project and
|
|
153
|
+
// to nothing in the toolchain.
|
|
154
|
+
//
|
|
155
|
+
// Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
156
|
+
// values win: this ADDS to the live client, it does not redirect it.
|
|
157
|
+
//
|
|
158
|
+
// Reserved fields are stripped HERE rather than at each merge site: the
|
|
159
|
+
// generated map only names a field when the model calls for one, so a
|
|
160
|
+
// 'base' in this block would face no competing value and would silently
|
|
161
|
+
// redirect the whole suite - credential included - to another host.
|
|
162
|
+
const List<String> liveReserved = [
|
|
163
|
+
'base', 'prefix', 'suffix', 'server', 'apikey', 'secret'
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
Map<String, dynamic> liveClientOptions() {
|
|
167
|
+
final ctrl = loadTestControl();
|
|
168
|
+
final t = ctrl['test'];
|
|
169
|
+
if (t is! Map) return <String, dynamic>{};
|
|
170
|
+
final c = t['client'];
|
|
171
|
+
if (c is! Map) return <String, dynamic>{};
|
|
172
|
+
final opts = c['options'];
|
|
173
|
+
if (opts is! Map) return <String, dynamic>{};
|
|
174
|
+
|
|
175
|
+
final out = <String, dynamic>{};
|
|
176
|
+
opts.forEach((k, v) {
|
|
177
|
+
if (!liveReserved.contains(k)) {
|
|
178
|
+
out['$k'] = v;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
146
185
|
int liveDelayMs() {
|
|
147
186
|
final ctrl = loadTestControl();
|
|
148
187
|
final t = ctrl['test'];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"_doc": "Per-SDK test control. Lists tests/operations to skip in unit and live modes; tunes per-test pacing. Edit by hand. Loaded by js/test/utility.js.",
|
|
4
|
+
"test": {
|
|
5
|
+
"skip": {
|
|
6
|
+
"live": {
|
|
7
|
+
"direct": [],
|
|
8
|
+
"entityOp": []
|
|
9
|
+
},
|
|
10
|
+
"unit": {
|
|
11
|
+
"direct": [],
|
|
12
|
+
"entityOp": []
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"live": {
|
|
16
|
+
"delayMs": 500
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* for creating test data, transformations, validations, and environment overrides.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
const Fs = require('node:fs')
|
|
9
|
+
const Path = require('node:path')
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
// Creates a new step data structure within the data model
|
|
9
13
|
function makeStepData(dm, stepname) {
|
|
10
14
|
dm.s[stepname] = {
|
|
@@ -62,11 +66,97 @@ function envOverride(m) {
|
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
|
|
69
|
+
// Loads sdk-test-control.json (cached). Returns an empty-skip object if
|
|
70
|
+
// the file is missing or unparsable so tests never crash on a bad config.
|
|
71
|
+
let _testControlCache = null
|
|
72
|
+
|
|
73
|
+
function loadTestControl() {
|
|
74
|
+
if (_testControlCache) return _testControlCache
|
|
75
|
+
const ctrlPath = Path.resolve(__dirname, '../test/sdk-test-control.json')
|
|
76
|
+
try {
|
|
77
|
+
_testControlCache = JSON.parse(Fs.readFileSync(ctrlPath, 'utf8'))
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
_testControlCache = {
|
|
81
|
+
version: 1,
|
|
82
|
+
test: { skip: { live: { direct: [], entityOp: [] }, unit: { direct: [], entityOp: [] } } }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return _testControlCache
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
// Extra SDK options every LIVE client is constructed with, read from
|
|
90
|
+
// sdk-test-control.json `test.client.options`.
|
|
91
|
+
//
|
|
92
|
+
// The generated live client knows two things: the base URL (from the spec)
|
|
93
|
+
// and the credential (from the environment). Everything else about how a
|
|
94
|
+
// particular API wants to be talked to - which features to switch on, and
|
|
95
|
+
// with what settings - is a property of THAT API, known to the project and
|
|
96
|
+
// to nothing in the toolchain. So it lives in the file the project owns and
|
|
97
|
+
// describes, where it can be read and reviewed. Secrets still come from the
|
|
98
|
+
// environment (the providers this block names read them).
|
|
99
|
+
//
|
|
100
|
+
// Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
101
|
+
// values win - this adds to the live client, it does not redirect it.
|
|
102
|
+
//
|
|
103
|
+
// That contract is enforced HERE rather than left to each merge site: the
|
|
104
|
+
// generated object only names a field when the model calls for one, so a
|
|
105
|
+
// `base` in this block would face no competing value and would silently
|
|
106
|
+
// redirect the whole suite - credential included - to another host. The
|
|
107
|
+
// reserved fields are stripped once, where the block is read, so every
|
|
108
|
+
// caller gets the same guarantee whether or not it happens to emit them.
|
|
109
|
+
const LIVE_RESERVED = ['base', 'prefix', 'suffix', 'server', 'apikey', 'secret']
|
|
110
|
+
|
|
111
|
+
function liveClientOptions() {
|
|
112
|
+
const ctrl = loadTestControl()
|
|
113
|
+
const opts = ctrl && ctrl.test && ctrl.test.client && ctrl.test.client.options
|
|
114
|
+
|
|
115
|
+
if (null == opts || 'object' !== typeof opts) {
|
|
116
|
+
return {}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const out = {}
|
|
120
|
+
for (const key of Object.keys(opts)) {
|
|
121
|
+
if (!LIVE_RESERVED.includes(key)) {
|
|
122
|
+
out[key] = opts[key]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return out
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
// Per-test live pacing delay (ms). Read from sdk-test-control.json
|
|
131
|
+
// `test.live.delayMs`; defaults to 500ms if absent or invalid.
|
|
132
|
+
function liveDelayMs() {
|
|
133
|
+
const ctrl = loadTestControl()
|
|
134
|
+
const v = ctrl && ctrl.test && ctrl.test.live && ctrl.test.live.delayMs
|
|
135
|
+
return ('number' === typeof v && v >= 0) ? v : 500
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
// afterEach hook helper for live pacing. Generated tests register this via
|
|
141
|
+
// `afterEach(liveDelay(<envVar>))`; it sleeps `liveDelayMs()` only when the
|
|
142
|
+
// SDK's *_TEST_LIVE env var is set.
|
|
143
|
+
function liveDelay(liveEnvVar) {
|
|
144
|
+
return async () => {
|
|
145
|
+
if ('TRUE' === process.env[liveEnvVar]) {
|
|
146
|
+
await new Promise(r => setTimeout(r, liveDelayMs()))
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
65
151
|
module.exports = {
|
|
66
152
|
makeStepData,
|
|
67
153
|
makeMatch,
|
|
68
154
|
makeReqdata,
|
|
69
155
|
makeValid,
|
|
70
156
|
makeCtrl,
|
|
71
|
-
envOverride
|
|
157
|
+
envOverride,
|
|
158
|
+
loadTestControl,
|
|
159
|
+
liveClientOptions,
|
|
160
|
+
liveDelayMs,
|
|
161
|
+
liveDelay
|
|
72
162
|
}
|
|
@@ -146,6 +146,46 @@ function runner.is_control_skipped(kind, name, mode)
|
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
|
|
149
|
+
-- Extra SDK options every LIVE client is constructed with, read from
|
|
150
|
+
-- sdk-test-control.json `test.client.options`.
|
|
151
|
+
--
|
|
152
|
+
-- The generated live client knows two things: the base URL (from the spec)
|
|
153
|
+
-- and the credential (from the environment). Everything else about how a
|
|
154
|
+
-- particular API wants to be talked to - which features to switch on, and
|
|
155
|
+
-- with what settings - is a property of THAT API, known to the project and
|
|
156
|
+
-- to nothing in the toolchain.
|
|
157
|
+
--
|
|
158
|
+
-- Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
159
|
+
-- values win: this ADDS to the live client, it does not redirect it.
|
|
160
|
+
--
|
|
161
|
+
-- Reserved fields are stripped HERE rather than at each merge site: the
|
|
162
|
+
-- generated table only names a field when the model calls for one, so a
|
|
163
|
+
-- "base" in this block would face no competing value and would silently
|
|
164
|
+
-- redirect the whole suite - credential included - to another host.
|
|
165
|
+
local LIVE_RESERVED = {
|
|
166
|
+
base = true, prefix = true, suffix = true,
|
|
167
|
+
server = true, apikey = true, secret = true,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function runner.live_client_options()
|
|
171
|
+
local ctrl = runner.load_test_control()
|
|
172
|
+
local test = ctrl.test
|
|
173
|
+
if type(test) ~= "table" then return {} end
|
|
174
|
+
local client = test.client
|
|
175
|
+
if type(client) ~= "table" then return {} end
|
|
176
|
+
local opts = client.options
|
|
177
|
+
if type(opts) ~= "table" then return {} end
|
|
178
|
+
|
|
179
|
+
local out = {}
|
|
180
|
+
for k, v in pairs(opts) do
|
|
181
|
+
if not LIVE_RESERVED[k] then
|
|
182
|
+
out[k] = v
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
return out
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
|
|
149
189
|
-- Per-test live pacing delay (ms); default 500.
|
|
150
190
|
function runner.live_delay_ms()
|
|
151
191
|
local ctrl = runner.load_test_control()
|
|
@@ -93,14 +93,24 @@ let make_client ?(server : server option) ?(mode = "test") ?(base = "http://api.
|
|
|
93
93
|
rootctx.c_op <- new_operation (jo [("name", Str "root"); ("entity", Str "_")]);
|
|
94
94
|
client.cl_rootctx <- Some rootctx;
|
|
95
95
|
List.iter (fun (name, opts) ->
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
(* `netsim` is a test-only network simulator implemented in
|
|
97
|
+
Sdk_features, not a model feature, so it never appears in the
|
|
98
|
+
generated config and has_feature rejects it. Construct it directly:
|
|
99
|
+
without this every netsim-driven test (retry backoff, timeout,
|
|
100
|
+
and the metrics/telemetry/audit error paths) silently runs against
|
|
101
|
+
an unsimulated transport and sees a plain 200. *)
|
|
102
|
+
let ftr =
|
|
103
|
+
if name = "netsim" then Some (Sdk_features.netsim_feature ())
|
|
104
|
+
else if has_feature name then Some (Sdk_config.make_feature name)
|
|
105
|
+
else None in
|
|
106
|
+
match ftr with
|
|
107
|
+
| None -> ()
|
|
108
|
+
| Some ftr ->
|
|
98
109
|
let fopts = jo [("active", Bool true)] in
|
|
99
110
|
(match opts with Map _ -> List.iter (fun k -> setp fopts k (getp opts k)) (keysof opts) | _ -> ());
|
|
100
111
|
setp (getp client.cl_options "feature") name fopts;
|
|
101
112
|
ftr.f_init rootctx fopts;
|
|
102
|
-
client.cl_features <- client.cl_features @ [ftr]
|
|
103
|
-
end) features;
|
|
113
|
+
client.cl_features <- client.cl_features @ [ftr]) features;
|
|
104
114
|
feature_hook_util rootctx "PostConstruct";
|
|
105
115
|
{ h_base = base; h_headers = hheaders; h_client = client; h_utility = utility; h_rootctx = rootctx }
|
|
106
116
|
|
|
@@ -129,6 +129,36 @@ sub is_control_skipped {
|
|
|
129
129
|
return (0, undef);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
# Extra SDK options every LIVE client is constructed with, read from
|
|
133
|
+
# sdk-test-control.json `test.client.options`.
|
|
134
|
+
#
|
|
135
|
+
# The generated live client knows two things: the base URL (from the spec)
|
|
136
|
+
# and the credential (from the environment). Everything else about how a
|
|
137
|
+
# particular API wants to be talked to - which features to switch on, and
|
|
138
|
+
# with what settings - is a property of THAT API, known to the project and
|
|
139
|
+
# to nothing in the toolchain.
|
|
140
|
+
#
|
|
141
|
+
# Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
142
|
+
# values win: this ADDS to the live client, it does not redirect it.
|
|
143
|
+
#
|
|
144
|
+
# Reserved fields are stripped HERE rather than at each merge site: the
|
|
145
|
+
# generated hash only names a field when the model calls for one, so a
|
|
146
|
+
# "base" in this block would face no competing value and would silently
|
|
147
|
+
# redirect the whole suite - credential included - to another host.
|
|
148
|
+
my %LIVE_RESERVED = map { $_ => 1 }
|
|
149
|
+
qw(base prefix suffix server apikey secret);
|
|
150
|
+
|
|
151
|
+
sub live_client_options {
|
|
152
|
+
my $ctrl = load_test_control();
|
|
153
|
+
my $opts = ProjectNameHelpers::gpath($ctrl, 'test.client.options');
|
|
154
|
+
return {} unless Voxgig::Struct::ismap($opts);
|
|
155
|
+
my %out;
|
|
156
|
+
for my $k (keys %$opts) {
|
|
157
|
+
$out{$k} = $opts->{$k} unless $LIVE_RESERVED{$k};
|
|
158
|
+
}
|
|
159
|
+
return \%out;
|
|
160
|
+
}
|
|
161
|
+
|
|
132
162
|
# Per-test live pacing delay (ms); default 500.
|
|
133
163
|
sub live_delay_ms {
|
|
134
164
|
my $ctrl = load_test_control();
|
|
@@ -138,6 +138,42 @@ class ProjectNameTestRunner
|
|
|
138
138
|
return [false, null];
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Extra SDK options every LIVE client is constructed with, read from
|
|
143
|
+
* sdk-test-control.json `test.client.options`.
|
|
144
|
+
*
|
|
145
|
+
* The generated live client knows two things: the base URL (from the
|
|
146
|
+
* spec) and the credential (from the environment). Everything else
|
|
147
|
+
* about how a particular API wants to be talked to - which features to
|
|
148
|
+
* switch on, and with what settings - is a property of THAT API, known
|
|
149
|
+
* to the project and to nothing in the toolchain.
|
|
150
|
+
*
|
|
151
|
+
* Merged UNDER the generated fields, so the suite's own
|
|
152
|
+
* base/apikey/server values win: this ADDS to the live client, it does
|
|
153
|
+
* not redirect it.
|
|
154
|
+
*
|
|
155
|
+
* Reserved fields are stripped HERE rather than at each merge site: the
|
|
156
|
+
* generated array only names a field when the model calls for one, so a
|
|
157
|
+
* "base" in this block would face no competing value and would silently
|
|
158
|
+
* redirect the whole suite - credential included - to another host.
|
|
159
|
+
*/
|
|
160
|
+
public static function live_client_options(): array
|
|
161
|
+
{
|
|
162
|
+
$ctrl = self::load_test_control();
|
|
163
|
+
$opts = $ctrl['test']['client']['options'] ?? null;
|
|
164
|
+
if (!is_array($opts)) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
$reserved = ['base', 'prefix', 'suffix', 'server', 'apikey', 'secret'];
|
|
168
|
+
$out = [];
|
|
169
|
+
foreach ($opts as $k => $v) {
|
|
170
|
+
if (!in_array($k, $reserved, true)) {
|
|
171
|
+
$out[$k] = $v;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return $out;
|
|
175
|
+
}
|
|
176
|
+
|
|
141
177
|
/** Per-test live pacing delay (ms); default 500. */
|
|
142
178
|
public static function live_delay_ms(): int
|
|
143
179
|
{
|
|
@@ -101,6 +101,31 @@ module ProjectNameTestRunner
|
|
|
101
101
|
[false, nil]
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
+
# Extra SDK options every LIVE client is constructed with, read from
|
|
105
|
+
# sdk-test-control.json `test.client.options`.
|
|
106
|
+
#
|
|
107
|
+
# The generated live client knows two things: the base URL (from the spec)
|
|
108
|
+
# and the credential (from the environment). Everything else about how a
|
|
109
|
+
# particular API wants to be talked to - which features to switch on, and
|
|
110
|
+
# with what settings - is a property of THAT API, known to the project and
|
|
111
|
+
# to nothing in the toolchain.
|
|
112
|
+
#
|
|
113
|
+
# Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
114
|
+
# values win: this ADDS to the live client, it does not redirect it.
|
|
115
|
+
#
|
|
116
|
+
# Reserved fields are stripped HERE rather than at each merge site: the
|
|
117
|
+
# generated hash only names a field when the model calls for one, so a
|
|
118
|
+
# "base" in this block would face no competing value and would silently
|
|
119
|
+
# redirect the whole suite - credential included - to another host.
|
|
120
|
+
LIVE_RESERVED = %w[base prefix suffix server apikey secret].freeze
|
|
121
|
+
|
|
122
|
+
def self.live_client_options
|
|
123
|
+
ctrl = load_test_control
|
|
124
|
+
opts = ctrl.dig('test', 'client', 'options')
|
|
125
|
+
return {} unless opts.is_a?(Hash)
|
|
126
|
+
opts.reject { |k, _v| LIVE_RESERVED.include?(k) }
|
|
127
|
+
end
|
|
128
|
+
|
|
104
129
|
# Per-test live pacing delay (ms); default 500.
|
|
105
130
|
def self.live_delay_ms
|
|
106
131
|
ctrl = load_test_control
|
|
@@ -93,6 +93,38 @@ pub fn is_control_skipped(kind: &str, name: &str, mode: &str) -> (bool, String)
|
|
|
93
93
|
(false, String::new())
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/// Extra SDK options every LIVE client is constructed with, read from
|
|
97
|
+
/// sdk-test-control.json `test.client.options`.
|
|
98
|
+
///
|
|
99
|
+
/// The generated live client knows two things: the base URL (from the spec)
|
|
100
|
+
/// and the credential (from the environment). Everything else about how a
|
|
101
|
+
/// particular API wants to be talked to - which features to switch on, and
|
|
102
|
+
/// with what settings - is a property of THAT API, known to the project and
|
|
103
|
+
/// to nothing in the toolchain.
|
|
104
|
+
///
|
|
105
|
+
/// Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
106
|
+
/// values win: this ADDS to the live client, it does not redirect it.
|
|
107
|
+
///
|
|
108
|
+
/// Reserved fields are stripped HERE rather than at each merge site: the
|
|
109
|
+
/// generated map only names a field when the model calls for one, so a
|
|
110
|
+
/// "base" in this block would face no competing value and would silently
|
|
111
|
+
/// redirect the whole suite - credential included - to another host.
|
|
112
|
+
pub const LIVE_RESERVED: [&str; 6] =
|
|
113
|
+
["base", "prefix", "suffix", "server", "apikey", "secret"];
|
|
114
|
+
|
|
115
|
+
pub fn live_client_options() -> Value {
|
|
116
|
+
let ctrl = load_test_control();
|
|
117
|
+
let out = Value::empty_map();
|
|
118
|
+
if let Value::Map(m) = get_spec(&ctrl, &["test", "client", "options"]) {
|
|
119
|
+
for (k, v) in m.borrow().iter() {
|
|
120
|
+
if !LIVE_RESERVED.contains(&k.as_str()) {
|
|
121
|
+
setp(&out, k, v.clone());
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
out
|
|
126
|
+
}
|
|
127
|
+
|
|
96
128
|
/// Configured per-test live delay in ms; default 500.
|
|
97
129
|
pub fn live_delay_ms() -> i64 {
|
|
98
130
|
let ctrl = load_test_control();
|
|
@@ -78,7 +78,7 @@ pub fn make_options_util(ctx: &Rc<Context>) -> Value {
|
|
|
78
78
|
("base", Value::str("http://localhost:8000")),
|
|
79
79
|
("prefix", Value::str("")),
|
|
80
80
|
("suffix", Value::str("")),
|
|
81
|
-
("auth", jo(vec![("prefix", Value::str(""))])),
|
|
81
|
+
("auth", jo(vec![("prefix", Value::str("")), ("basic", Value::Bool(false))])),
|
|
82
82
|
("headers", jo(vec![("`$CHILD`", Value::str("`$STRING`"))])),
|
|
83
83
|
(
|
|
84
84
|
"allow",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/Sekreto.ts)
|
|
2
|
-
// Source: https://github.com/voxgig/sekreto @
|
|
2
|
+
// Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
|
|
3
3
|
// License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
|
|
4
4
|
// sekreto: one interface for secrets, wherever they live.
|
|
5
5
|
//
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
// This file is CANONICAL. Every other port is a translation of it, and
|
|
12
12
|
// spec/sekreto.json is the behavioural contract they all run.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// The REGISTRY, never './Providers'. Importing the barrel here is what
|
|
15
|
+
// made every provider kind reachable from the core: the chain needs
|
|
16
|
+
// `makeprovider`, and the barrel's edge dragged AWS request signing and
|
|
17
|
+
// seven HTTP clients in behind it. The registry knows only the kinds
|
|
18
|
+
// something actually imported. See docs/design/plugin-providers.md.
|
|
19
|
+
import { Provider, ProviderSpec } from './provider/support'
|
|
20
|
+
import { makeprovider } from './provider/Registry'
|
|
15
21
|
|
|
16
22
|
/** A secret name: dot-separated lowercase segments, e.g. `api.token`. */
|
|
17
23
|
export type Name = string
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/Sigv4.ts)
|
|
2
|
-
// Source: https://github.com/voxgig/sekreto @
|
|
2
|
+
// Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
|
|
3
3
|
// License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
|
|
4
4
|
// AWS Signature Version 4, hand-rolled.
|
|
5
5
|
//
|
|
@@ -14,7 +14,28 @@
|
|
|
14
14
|
// carry known-answer cases that all ten ports must reproduce bit-for-bit,
|
|
15
15
|
// and lets the integration mock recompute the signature server-side.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
// node:crypto is loaded ON FIRST USE, not at import time.
|
|
18
|
+
//
|
|
19
|
+
// Providers.ts imports sigv4 for the AWS providers, and Sekreto.ts imports
|
|
20
|
+
// Providers — so a top-level `node:crypto` here put it in the module graph
|
|
21
|
+
// of every sekreto consumer, including one that never signs anything.
|
|
22
|
+
// Deferring keeps this module pure until an AWS provider actually runs.
|
|
23
|
+
//
|
|
24
|
+
// require(), not `await import()`: these helpers are synchronous and are
|
|
25
|
+
// called from synchronous signing code. The package is CommonJS.
|
|
26
|
+
function crypto(): typeof import('node:crypto') {
|
|
27
|
+
try {
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
|
+
return require('node:crypto')
|
|
30
|
+
} catch (err: any) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
'sekreto: AWS request signing needs node:crypto, which this runtime ' +
|
|
33
|
+
'does not provide: ' +
|
|
34
|
+
err.message,
|
|
35
|
+
{ cause: err },
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
18
39
|
|
|
19
40
|
export type Sigv4Input = {
|
|
20
41
|
method: string
|
|
@@ -39,11 +60,11 @@ export type Sigv4Input = {
|
|
|
39
60
|
export type Sigv4Output = Record<string, string>
|
|
40
61
|
|
|
41
62
|
function sha256hex(text: string): string {
|
|
42
|
-
return createHash('sha256').update(text, 'utf8').digest('hex')
|
|
63
|
+
return crypto().createHash('sha256').update(text, 'utf8').digest('hex')
|
|
43
64
|
}
|
|
44
65
|
|
|
45
66
|
function hmac(key: Buffer | string, text: string): Buffer {
|
|
46
|
-
return createHmac('sha256', key).update(text, 'utf8').digest()
|
|
67
|
+
return crypto().createHmac('sha256', key).update(text, 'utf8').digest()
|
|
47
68
|
}
|
|
48
69
|
|
|
49
70
|
/** RFC 3986 escaping, which is stricter than encodeURIComponent: AWS
|
|
@@ -128,7 +149,10 @@ export function sigv4(input: Sigv4Input): Sigv4Output {
|
|
|
128
149
|
const kregion = hmac(kdate, input.region)
|
|
129
150
|
const kservice = hmac(kregion, input.service)
|
|
130
151
|
const ksigning = hmac(kservice, 'aws4_request')
|
|
131
|
-
const signature =
|
|
152
|
+
const signature = crypto()
|
|
153
|
+
.createHmac('sha256', ksigning)
|
|
154
|
+
.update(stringtosign, 'utf8')
|
|
155
|
+
.digest('hex')
|
|
132
156
|
|
|
133
157
|
const out: Sigv4Output = {
|
|
134
158
|
authorization:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/index.ts)
|
|
2
|
-
// Source: https://github.com/voxgig/sekreto @
|
|
2
|
+
// Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
|
|
3
3
|
// License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
|
|
4
4
|
// @voxgig/sekreto - one interface for secrets, wherever they live.
|
|
5
5
|
|
|
@@ -18,25 +18,34 @@ export {
|
|
|
18
18
|
|
|
19
19
|
export type { Name, SekretoOptions } from './Sekreto'
|
|
20
20
|
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
// THE CORE SURFACE. Deliberately does NOT re-export the eleven provider
|
|
22
|
+
// kinds that need something of their runtime: pulling one through this
|
|
23
|
+
// file would make all of them reachable and put AWS request signing in
|
|
24
|
+
// every build, which is the thing the split removes.
|
|
25
|
+
//
|
|
26
|
+
// `env` and `memory` are here because they import nothing at all, and a
|
|
27
|
+
// chain with nowhere to read from is not usable or testable.
|
|
28
|
+
//
|
|
29
|
+
// Everything else registers itself when its module is imported:
|
|
30
|
+
//
|
|
31
|
+
// import '@voxgig/sekreto/provider/dotenv'
|
|
32
|
+
//
|
|
33
|
+
// or, for the old all-in behaviour, `from '@voxgig/sekreto/Providers'`.
|
|
34
|
+
// See docs/design/plugin-providers.md.
|
|
35
|
+
export { envprovider } from './provider/env'
|
|
36
|
+
export { memoryprovider } from './provider/memory'
|
|
37
|
+
|
|
38
|
+
// A pure validator, no platform dependency - kept on the core surface
|
|
39
|
+
// because callers validate an address before configuring a provider.
|
|
40
|
+
export { checkaddr } from './provider/addr'
|
|
41
|
+
|
|
42
|
+
export { makeprovider, register, registered, kinds } from './provider/Registry'
|
|
43
|
+
export type { ProviderDefinition } from './provider/Registry'
|
|
38
44
|
|
|
39
|
-
export type { Provider, ProviderSpec } from './
|
|
45
|
+
export type { Provider, ProviderSpec } from './provider/support'
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
// `sigv4` is NOT on the core surface: it is the node:crypto edge, and
|
|
48
|
+
// only the two aws providers use it. Import it from the module that
|
|
49
|
+
// needs it - `@voxgig/sekreto/provider/aws` - or from the full-set
|
|
50
|
+
// barrel. Re-exporting it here would put request signing in every
|
|
51
|
+
// build again, which is the thing the split removes.
|