@voxgig/sdkgen 4.5.3 → 4.6.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/action/check.js +15 -0
- package/dist/action/check.js.map +1 -1
- package/dist/cmp/AgentGuide.js +1 -1
- package/dist/cmp/AgentGuide.js.map +1 -1
- package/dist/cmp/AgentGuideContent.d.ts +1 -1
- package/dist/cmp/AgentGuideContent.js +8 -2
- package/dist/cmp/AgentGuideContent.js.map +1 -1
- package/dist/cmp/Feature.js +17 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/FeatureDocs.d.ts +1 -1
- package/dist/cmp/FeatureDocs.js +6 -1
- package/dist/cmp/FeatureDocs.js.map +1 -1
- package/dist/cmp/ReadmeExplanation.js +3 -1
- package/dist/cmp/ReadmeExplanation.js.map +1 -1
- package/dist/cmp/ReadmeFeatures.js +1 -1
- package/dist/cmp/ReadmeFeatures.js.map +1 -1
- package/dist/cmp/ReadmeRefFeatures.js +1 -1
- package/dist/cmp/ReadmeRefFeatures.js.map +1 -1
- package/dist/helpers/applicability.d.ts +6 -0
- package/dist/helpers/applicability.js +103 -0
- package/dist/helpers/applicability.js.map +1 -0
- package/dist/helpers/collectDeps.js +4 -2
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +2 -1
- package/dist/helpers/serverVars.js +17 -0
- package/dist/helpers/serverVars.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -2
- package/dist/sdkgen.js +9 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.js +7 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +39 -0
- package/package.json +1 -1
- package/project/.sdk/model/feature/feature-index.aon +1 -0
- package/project/.sdk/model/feature/secrets.aon +118 -0
- package/project/.sdk/model/target/ts.aon +8 -1
- package/project/.sdk/src/cmp/c/Config_c.ts +5 -1
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +5 -1
- package/project/.sdk/src/cmp/dart/Config_dart.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Main_elixir.ts +5 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +5 -1
- package/project/.sdk/src/cmp/go/Main_go.ts +6 -2
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +28 -4
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +43 -10
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +5 -5
- package/project/.sdk/src/cmp/java/Config_java.ts +22 -1
- package/project/.sdk/src/cmp/java/Main_java.ts +5 -1
- package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/ReadmeTopQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +23 -4
- package/project/.sdk/src/cmp/java/TestEntity_java.ts +29 -4
- package/project/.sdk/src/cmp/js/Config_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Main_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Package_js.ts +4 -1
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/lean/Config_lean.ts +5 -1
- package/project/.sdk/src/cmp/lua/Config_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Main_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Package_lua.ts +4 -1
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +5 -1
- package/project/.sdk/src/cmp/perl/Main_perl.ts +5 -1
- package/project/.sdk/src/cmp/php/Config_php.ts +5 -1
- package/project/.sdk/src/cmp/php/Main_php.ts +5 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +5 -1
- package/project/.sdk/src/cmp/py/Main_py.ts +5 -1
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +24 -5
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +23 -3
- package/project/.sdk/src/cmp/rb/Config_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/Main_rb.ts +5 -1
- package/project/.sdk/src/cmp/rust/Config_rust.ts +5 -1
- package/project/.sdk/src/cmp/rust/Main_rust.ts +5 -1
- package/project/.sdk/src/cmp/scala/Config_scala.ts +5 -1
- package/project/.sdk/src/cmp/scala/Main_scala.ts +5 -1
- package/project/.sdk/src/cmp/swift/Config_swift.ts +5 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +5 -1
- package/project/.sdk/src/cmp/ts/Main_ts.ts +57 -1
- package/project/.sdk/src/cmp/ts/Package_ts.ts +4 -1
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +15 -3
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +18 -5
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +19 -5
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +67 -7
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +27 -4
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +7 -0
- package/project/.sdk/src/cmp/zig/Config_zig.ts +5 -1
- package/project/.sdk/tm/c/utility/make_options.c +22 -0
- package/project/.sdk/tm/clojure/src/sdk/core.clj +18 -1
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +23 -0
- package/project/.sdk/tm/csharp/test/CustomUtilityTest.cs +15 -0
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +23 -0
- package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +22 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +19 -0
- package/project/.sdk/tm/go/core/context.go +1 -1
- package/project/.sdk/tm/go/feature/cost_feature.go +1 -1
- package/project/.sdk/tm/go/feature/paging_feature.go +5 -5
- package/project/.sdk/tm/go/feature/test_feature.go +12 -5
- package/project/.sdk/tm/go/test/custom_utility_test.go +15 -0
- package/project/.sdk/tm/go/test/feature_corpus_test.go +7 -0
- package/project/.sdk/tm/go/test/runner_test.go +46 -0
- package/project/.sdk/tm/go/test/struct_runner_test.go +7 -7
- package/project/.sdk/tm/go/test/struct_utility_test.go +63 -27
- package/project/.sdk/tm/go/utility/fetcher.go +2 -2
- package/project/.sdk/tm/go/utility/make_options.go +24 -5
- package/project/.sdk/tm/go/utility/make_point.go +1 -1
- package/project/.sdk/tm/go/utility/make_spec.go +17 -1
- package/project/.sdk/tm/go/utility/prepare_auth.go +1 -1
- package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +370 -307
- package/project/.sdk/tm/go/utility/transform_request.go +29 -1
- package/project/.sdk/tm/go/utility/transform_response.go +20 -1
- package/project/.sdk/tm/java/test/CustomUtilityTest.java +10 -0
- package/project/.sdk/tm/java/test/FeatureCorpusTest.java +7 -0
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +6 -0
- package/project/.sdk/tm/java/test/RunnerSupport.java +43 -0
- package/project/.sdk/tm/java/utility/MakeOptions.java +84 -1
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +24 -0
- package/project/.sdk/tm/js/src/utility/StructUtility.js +2076 -1837
- package/project/.sdk/tm/js/test/feature/Corpus.test.js +9 -0
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +21 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +12 -1
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +11 -0
- package/project/.sdk/tm/perl/utility/make_options.pm +18 -0
- package/project/.sdk/tm/php/test/FeatureCorpusTest.php +10 -1
- package/project/.sdk/tm/php/utility/MakeOptions.php +24 -0
- package/project/.sdk/tm/py/pkg/utility/make_options.py +20 -0
- package/project/.sdk/tm/py/test/runner.py +32 -0
- package/project/.sdk/tm/py/test/test_feature_corpus.py +10 -1
- package/project/.sdk/tm/rb/test/feature_corpus_test.rb +9 -1
- package/project/.sdk/tm/rb/utility/make_options.rb +17 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +25 -0
- package/project/.sdk/tm/scala/utility/Make.scala +17 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +21 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +419 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +1221 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +381 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +151 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +42 -0
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +18 -0
- package/project/.sdk/tm/ts/src/utility/StructUtility.ts +1321 -710
- package/project/.sdk/tm/ts/test/feature/Corpus.test.ts +9 -0
- package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +764 -0
- package/project/.sdk/tm/ts/test/omni.test.ts +84 -0
- package/project/.sdk/tm/ts/test/omni.ts +86 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +6 -2
- package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +2 -2
- package/project/.sdk/tm/ts/test/utility.ts +122 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +692 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +238 -0
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +188 -0
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +38 -0
- package/project/.sdk/tm/zig/core/utility.zig +23 -0
- package/project/sdkgen-package.json +2 -1
- package/src/action/check.ts +18 -0
- package/src/cmp/AgentGuide.ts +1 -1
- package/src/cmp/AgentGuideContent.ts +9 -2
- package/src/cmp/Feature.ts +19 -0
- package/src/cmp/FeatureDocs.ts +7 -1
- package/src/cmp/ReadmeExplanation.ts +4 -1
- package/src/cmp/ReadmeFeatures.ts +1 -1
- package/src/cmp/ReadmeRefFeatures.ts +1 -1
- package/src/helpers/applicability.ts +123 -0
- package/src/helpers/collectDeps.ts +5 -1
- package/src/helpers/serverVars.ts +19 -0
- package/src/sdkgen.ts +9 -1
- package/src/utility.ts +10 -1
- package/project/.sdk/tm/ts/test/runner.ts +0 -425
|
@@ -84,7 +84,16 @@ function scriptedFetcher(res) {
|
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
function makeClient(kase) {
|
|
87
|
+
// `test: { active: true }` is the OPTION, not the `test` FEATURE.
|
|
88
|
+
//
|
|
89
|
+
// It says "this client is not live", which is what makes a REQUIRED
|
|
90
|
+
// OpenAPI server variable resolve to a deterministic `test-<name>`
|
|
91
|
+
// rather than refuse to construct (see makeOptions). It installs no
|
|
92
|
+
// transport, so the scripted fetcher below still stands — the FEATURE
|
|
93
|
+
// is transport: 'base' and would shadow it, which is why this cannot
|
|
94
|
+
// just turn the feature on.
|
|
87
95
|
return new SDK({
|
|
96
|
+
test: { active: true },
|
|
88
97
|
feature: kase.feature,
|
|
89
98
|
utility: { fetcher: scriptedFetcher(kase.res || [{ status: 200, body: {} }]) },
|
|
90
99
|
})
|
|
@@ -28,8 +28,24 @@ fun makeOptions(ctx: Context): MutableMap<String, Any?> {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// `auth: null` is the documented way to disable auth outright, and
|
|
32
|
+
// PrepareAuth honours it before it ever reads the apikey. It cannot survive
|
|
33
|
+
// validate: depending on the struct port a stored null is either REPLACED
|
|
34
|
+
// by the optspec default - transmitting the credential the caller withheld
|
|
35
|
+
// - or REJECTED outright. Withhold the key for validate, then put the null
|
|
36
|
+
// back. Same fix as ts/js/go makeOptions.
|
|
37
|
+
//
|
|
38
|
+
// Suppliedness cannot be recovered after validate, hence here, and it must
|
|
39
|
+
// tell an ABSENT auth from a present null: containsKey rather than a null
|
|
40
|
+
// check on the value, which cannot distinguish them.
|
|
41
|
+
val authSuppressed = options.containsKey("auth") && null == options["auth"]
|
|
42
|
+
|
|
31
43
|
var opts = Struct.clone(options) as MutableMap<String, Any?>
|
|
32
44
|
|
|
45
|
+
if (authSuppressed) {
|
|
46
|
+
opts.remove("auth")
|
|
47
|
+
}
|
|
48
|
+
|
|
33
49
|
// Feature add-order. options.feature may be given as an ordered LIST of
|
|
34
50
|
// { name, active, ...opts } entries (the list position IS the order in which
|
|
35
51
|
// features are added), or as a { name: {opts} } map. Normalize a list to a
|
|
@@ -107,6 +123,11 @@ fun makeOptions(ctx: Context): MutableMap<String, Any?> {
|
|
|
107
123
|
val validated = Struct.validate(merged, optspec, vopts)
|
|
108
124
|
opts = validated as MutableMap<String, Any?>
|
|
109
125
|
|
|
126
|
+
// Restore the suppression the optspec default would otherwise erase.
|
|
127
|
+
if (authSuppressed) {
|
|
128
|
+
opts["auth"] = null
|
|
129
|
+
}
|
|
130
|
+
|
|
110
131
|
// Restore system.fetch.
|
|
111
132
|
if (sysFetch != null) {
|
|
112
133
|
val sys = Helpers.toMapAny(opts["system"])
|
|
@@ -260,8 +260,19 @@ def prepareAuth (ctx : Value) : SIO (Value × Option Value) := do
|
|
|
260
260
|
| .map _ => do
|
|
261
261
|
let headers ← gpMap specV "headers"
|
|
262
262
|
let options ← gp ctx "options"
|
|
263
|
+
-- `auth: null` is the documented way to suppress auth outright: NO
|
|
264
|
+
-- authorization header, whatever the apikey says. Without this the
|
|
265
|
+
-- withheld credential goes on the wire.
|
|
266
|
+
--
|
|
267
|
+
-- The ports that run options through validate against an optspec carrying
|
|
268
|
+
-- an `auth` default can use absence as the signal (validate guarantees the
|
|
269
|
+
-- key is present otherwise). lean's makeOptions has no optspec, so `auth`
|
|
270
|
+
-- is ABSENT in the ordinary case and absence must stay the ordinary case.
|
|
271
|
+
-- getpropRaw is the only reader that tells a STORED null from an absent
|
|
272
|
+
-- key - gp collapses both to .noval - so the stored null alone suppresses.
|
|
273
|
+
let authRaw ← getpropRaw options "auth"
|
|
263
274
|
let apikey ← gpS options "apikey"
|
|
264
|
-
if apikey == "" then do
|
|
275
|
+
if authRaw == .null || apikey == "" then do
|
|
265
276
|
dp headers "authorization"
|
|
266
277
|
pure (specV, none)
|
|
267
278
|
else do
|
|
@@ -968,7 +968,16 @@ let make_options_util (ctx : ctx) : value =
|
|
|
968
968
|
| Some u -> List.iter (fun k -> setp u.u_custom k (getp custom_utils k)) (keysof custom_utils)
|
|
969
969
|
| None -> ())
|
|
970
970
|
| _ -> ());
|
|
971
|
+
(* `auth: null` is the documented way to suppress auth outright. validate()
|
|
972
|
+
treats a STORED null as "no value" (getprop returns the alt), so the
|
|
973
|
+
optspec `auth` default would fire and turn the suppression into "use the
|
|
974
|
+
default auth" - transmitting a credential the caller withheld. getprop_raw
|
|
975
|
+
is the only reader that tells a stored Null from an absent key. Withhold
|
|
976
|
+
the key across merge/validate, then restore the null below. *)
|
|
977
|
+
let auth_suppressed =
|
|
978
|
+
(match getprop_raw options "auth" with Null -> true | _ -> false) in
|
|
971
979
|
let opts = match clone options with Map _ as m -> m | _ -> empty_map () in
|
|
980
|
+
let () = if auth_suppressed then ignore (delprop opts (Str "auth")) in
|
|
972
981
|
(* Feature add-order. options.feature may be given as an ordered LIST of
|
|
973
982
|
{name; active; ...opts} entries (list position = add order) or a
|
|
974
983
|
{name => {opts}} map. Normalize a list to a map (so merge/validate/init
|
|
@@ -999,6 +1008,8 @@ let make_options_util (ctx : ctx) : value =
|
|
|
999
1008
|
let merged = merge (ja [empty_map (); cfgopts; opts]) in
|
|
1000
1009
|
let validated = validate merged optspec in
|
|
1001
1010
|
let opts = match validated with Map _ as m -> m | _ -> empty_map () in
|
|
1011
|
+
(* Restore the suppression the optspec default would otherwise erase. *)
|
|
1012
|
+
let () = if auth_suppressed then setp opts "auth" Null in
|
|
1002
1013
|
(* Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
1003
1014
|
Every placeholder must resolve to a non-empty value: from options.server
|
|
1004
1015
|
(user), else the Config default. A placeholder that resolves to "" is a
|
|
@@ -69,7 +69,22 @@ $REGISTRY{make_options} = sub {
|
|
|
69
69
|
# reads options.extend, but clone/validate dropped the instances.
|
|
70
70
|
my $extend_raw = ProjectNameHelpers::gp($options, 'extend');
|
|
71
71
|
|
|
72
|
+
# `auth => undef` is the documented way to disable auth outright, and
|
|
73
|
+
# prepare_auth honours it before it ever reads the apikey. It cannot survive
|
|
74
|
+
# validate: depending on the struct port a stored null is either REPLACED by
|
|
75
|
+
# the optspec default - transmitting the credential the caller withheld - or
|
|
76
|
+
# REJECTED outright. Withhold the key for validate, then put the undef back.
|
|
77
|
+
# Same fix as ts/js/go make_options.
|
|
78
|
+
#
|
|
79
|
+
# Suppliedness cannot be recovered after validate, hence here, and it must
|
|
80
|
+
# tell an ABSENT auth from a present undef: exists rather than defined,
|
|
81
|
+
# which is false for both.
|
|
82
|
+
my $authsuppressed =
|
|
83
|
+
(ref($options) eq 'HASH' && exists $options->{auth} && !defined $options->{auth}) ? 1 : 0;
|
|
84
|
+
|
|
72
85
|
my $opts = Voxgig::Struct::clone($options);
|
|
86
|
+
|
|
87
|
+
delete $opts->{auth} if $authsuppressed && ref($opts) eq 'HASH';
|
|
73
88
|
$opts = {} unless Voxgig::Struct::ismap($opts);
|
|
74
89
|
delete $opts->{extend};
|
|
75
90
|
|
|
@@ -143,6 +158,9 @@ $REGISTRY{make_options} = sub {
|
|
|
143
158
|
my $validated = Voxgig::Struct::validate($merged, $optspec);
|
|
144
159
|
$opts = Voxgig::Struct::ismap($validated) ? $validated : {};
|
|
145
160
|
|
|
161
|
+
# Restore the suppression the optspec default would otherwise erase.
|
|
162
|
+
$opts->{auth} = undef if $authsuppressed;
|
|
163
|
+
|
|
146
164
|
if ($sys_fetch) {
|
|
147
165
|
$opts->{system} = {} unless Voxgig::Struct::ismap($opts->{system});
|
|
148
166
|
$opts->{system}{fetch} = $sys_fetch;
|
|
@@ -91,7 +91,16 @@ class FeatureCorpusTest extends TestCase
|
|
|
91
91
|
*/
|
|
92
92
|
private static function buildClient(array $kase)
|
|
93
93
|
{
|
|
94
|
-
|
|
94
|
+
// 'test' here is the OPTION, not the `test` FEATURE. It says "this
|
|
95
|
+
// client is not live", which is what makes a REQUIRED OpenAPI server
|
|
96
|
+
// variable resolve to a deterministic test-<name> rather than throw
|
|
97
|
+
// at construction (see makeOptions). It installs no transport, so the
|
|
98
|
+
// scripted fetcher still stands - the FEATURE is transport: 'base'
|
|
99
|
+
// and would shadow it.
|
|
100
|
+
$opts = [
|
|
101
|
+
'test' => ['active' => true],
|
|
102
|
+
'utility' => ['fetcher' => self::scriptedFetcher($kase['res'] ?? null)],
|
|
103
|
+
];
|
|
95
104
|
if (isset($kase['feature'])) {
|
|
96
105
|
$opts['feature'] = $kase['feature'];
|
|
97
106
|
}
|
|
@@ -94,12 +94,31 @@ class ProjectNameMakeOptions
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// `auth: null` is the documented way to disable auth outright, and
|
|
98
|
+
// prepareAuth honours it before it ever reads the apikey. It cannot
|
|
99
|
+
// survive validate: depending on the struct port a stored null is
|
|
100
|
+
// either REPLACED by the optspec default - transmitting the
|
|
101
|
+
// credential the caller withheld - or REJECTED outright. Withhold the
|
|
102
|
+
// key for validate, then put the null back. Same fix as ts/js/go
|
|
103
|
+
// makeOptions.
|
|
104
|
+
//
|
|
105
|
+
// Suppliedness cannot be recovered after validate, hence here, and it
|
|
106
|
+
// must tell an ABSENT auth from a present null: array_key_exists
|
|
107
|
+
// rather than isset, which is false for both.
|
|
108
|
+
$authsuppressed = is_array($options)
|
|
109
|
+
&& array_key_exists('auth', $options)
|
|
110
|
+
&& null === $options['auth'];
|
|
111
|
+
|
|
97
112
|
$opts = \Voxgig\Struct\Struct::clone($options);
|
|
98
113
|
$opts = self::to_array_deep($opts);
|
|
99
114
|
if (!is_array($opts)) {
|
|
100
115
|
$opts = [];
|
|
101
116
|
}
|
|
102
117
|
|
|
118
|
+
if ($authsuppressed) {
|
|
119
|
+
unset($opts['auth']);
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
// Feature add-order. options['feature'] may be given as an ordered LIST
|
|
104
123
|
// of ['name'=>..., 'active'=>..., ...] entries (the list position IS the
|
|
105
124
|
// order in which features are added), or as a ['name'=>[opts]] map.
|
|
@@ -164,6 +183,11 @@ class ProjectNameMakeOptions
|
|
|
164
183
|
$opts = [];
|
|
165
184
|
}
|
|
166
185
|
|
|
186
|
+
// Restore the suppression the optspec default would otherwise erase.
|
|
187
|
+
if ($authsuppressed) {
|
|
188
|
+
$opts['auth'] = null;
|
|
189
|
+
}
|
|
190
|
+
|
|
167
191
|
// Reattach the station binding handle held aside above (the feature
|
|
168
192
|
// optspec is `$OPEN`, so the extra keys are legal; they were only
|
|
169
193
|
// kept out of the clone/validate round-trip).
|
|
@@ -65,10 +65,26 @@ def make_options_util(ctx):
|
|
|
65
65
|
if isinstance(options, dict) and options.get("extend") is not None:
|
|
66
66
|
options = {k: v for k, v in options.items() if k != "extend"}
|
|
67
67
|
|
|
68
|
+
# `auth: None` is the documented way to disable auth outright, and
|
|
69
|
+
# prepare_auth honours it before it ever reads the apikey. It cannot
|
|
70
|
+
# survive validate: depending on the struct port a stored null is either
|
|
71
|
+
# REPLACED by the optspec default — transmitting the credential the
|
|
72
|
+
# caller withheld — or REJECTED outright. Withhold the key for validate,
|
|
73
|
+
# then put the null back. Same fix as ts/js/go make_options.
|
|
74
|
+
#
|
|
75
|
+
# Suppliedness cannot be recovered after validate, hence here, and it
|
|
76
|
+
# must tell an ABSENT auth from a present None: only the latter is a
|
|
77
|
+
# suppression.
|
|
78
|
+
authsuppressed = (
|
|
79
|
+
isinstance(options, dict) and "auth" in options and options["auth"] is None)
|
|
80
|
+
|
|
68
81
|
opts = vs.clone(options)
|
|
69
82
|
if not isinstance(opts, dict):
|
|
70
83
|
opts = {}
|
|
71
84
|
|
|
85
|
+
if authsuppressed:
|
|
86
|
+
opts.pop("auth", None)
|
|
87
|
+
|
|
72
88
|
# Feature add-order. options["feature"] may be given as an ordered LIST of
|
|
73
89
|
# {name, active, ...opts} entries (the list position IS the order in which
|
|
74
90
|
# features are added), or as a {name: {opts}} map. Normalize a list to a
|
|
@@ -162,6 +178,10 @@ def make_options_util(ctx):
|
|
|
162
178
|
validated = {}
|
|
163
179
|
opts = validated
|
|
164
180
|
|
|
181
|
+
# Restore the suppression the optspec default would otherwise erase.
|
|
182
|
+
if authsuppressed:
|
|
183
|
+
opts["auth"] = None
|
|
184
|
+
|
|
165
185
|
# Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
166
186
|
# Every placeholder must resolve to a non-empty value: from
|
|
167
187
|
# options["server"] (user), else the config default. A placeholder that
|
|
@@ -101,6 +101,34 @@ class ProjectNameTestRunner:
|
|
|
101
101
|
return True, item.get("reason")
|
|
102
102
|
return False, None
|
|
103
103
|
|
|
104
|
+
@staticmethod
|
|
105
|
+
def live_client_options():
|
|
106
|
+
"""Extra SDK options every LIVE client is constructed with, from
|
|
107
|
+
sdk-test-control.json `test.client.options`.
|
|
108
|
+
|
|
109
|
+
The generated live client knows two things: the base URL (from the
|
|
110
|
+
spec) and the credential (from the environment). Everything else
|
|
111
|
+
about how a particular API wants to be talked to - which features to
|
|
112
|
+
switch on, and with what settings - is a property of THAT API, known
|
|
113
|
+
to the project and to nothing in the toolchain.
|
|
114
|
+
|
|
115
|
+
Merged UNDER the generated fields, so the suite's own
|
|
116
|
+
base/apikey/server values win: this ADDS to the live client, it does
|
|
117
|
+
not redirect it.
|
|
118
|
+
|
|
119
|
+
Reserved fields are stripped HERE rather than at each merge site:
|
|
120
|
+
the generated dict only names a field when the model calls for one,
|
|
121
|
+
so a "base" in this block would face no competing value and would
|
|
122
|
+
silently redirect the whole suite - credential included - to another
|
|
123
|
+
host.
|
|
124
|
+
"""
|
|
125
|
+
ctrl = ProjectNameTestRunner.load_test_control()
|
|
126
|
+
opts = ctrl.get("test", {}).get("client", {}).get("options")
|
|
127
|
+
if not isinstance(opts, dict):
|
|
128
|
+
return {}
|
|
129
|
+
reserved = ("base", "prefix", "suffix", "server", "apikey", "secret")
|
|
130
|
+
return {k: v for k, v in opts.items() if k not in reserved}
|
|
131
|
+
|
|
104
132
|
@staticmethod
|
|
105
133
|
def live_delay_ms():
|
|
106
134
|
"""Per-test live pacing delay (ms); default 500."""
|
|
@@ -161,5 +189,9 @@ def load_test_control():
|
|
|
161
189
|
return ProjectNameTestRunner.load_test_control()
|
|
162
190
|
|
|
163
191
|
|
|
192
|
+
def live_client_options():
|
|
193
|
+
return ProjectNameTestRunner.live_client_options()
|
|
194
|
+
|
|
195
|
+
|
|
164
196
|
def live_delay_ms():
|
|
165
197
|
return ProjectNameTestRunner.live_delay_ms()
|
|
@@ -95,7 +95,16 @@ def _client(kase):
|
|
|
95
95
|
transport: 'base' and REPLACES the transport, so a client in test mode
|
|
96
96
|
would shadow the script.
|
|
97
97
|
"""
|
|
98
|
-
|
|
98
|
+
# "test" here is the OPTION, not the `test` FEATURE. It says "this
|
|
99
|
+
# client is not live", which is what makes a REQUIRED OpenAPI server
|
|
100
|
+
# variable resolve to a deterministic test-<name> rather than raise at
|
|
101
|
+
# construction (see make_options). It installs no transport, so the
|
|
102
|
+
# scripted fetcher still stands - the FEATURE is transport: 'base' and
|
|
103
|
+
# would shadow it, which is why this cannot just turn the feature on.
|
|
104
|
+
opts = {
|
|
105
|
+
"test": {"active": True},
|
|
106
|
+
"utility": {"fetcher": _scripted_fetcher(kase.get("res"))},
|
|
107
|
+
}
|
|
99
108
|
if kase.get("feature") is not None:
|
|
100
109
|
opts["feature"] = kase["feature"]
|
|
101
110
|
return ProjectNameSDK(opts)
|
|
@@ -71,7 +71,15 @@ class FeatureCorpusTest < Minitest::Test
|
|
|
71
71
|
# transport: 'base' and REPLACES the transport, so a client in test mode
|
|
72
72
|
# would shadow the script.
|
|
73
73
|
def build_client(kase)
|
|
74
|
-
|
|
74
|
+
# "test" here is the OPTION, not the `test` FEATURE. It says "this
|
|
75
|
+
# client is not live", which is what makes a REQUIRED OpenAPI server
|
|
76
|
+
# variable resolve to a deterministic test-<name> rather than raise at
|
|
77
|
+
# construction (see make_options). It installs no transport, so the
|
|
78
|
+
# scripted fetcher still stands.
|
|
79
|
+
opts = {
|
|
80
|
+
"test" => { "active" => true },
|
|
81
|
+
"utility" => { "fetcher" => scripted_fetcher(kase["res"]) },
|
|
82
|
+
}
|
|
75
83
|
opts["feature"] = kase["feature"] unless kase["feature"].nil?
|
|
76
84
|
ProjectNameSDK.new(opts)
|
|
77
85
|
end
|
|
@@ -40,9 +40,23 @@ module ProjectNameUtilities
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# `auth: nil` is the documented way to disable auth outright, and
|
|
44
|
+
# prepare_auth honours it before it ever reads the apikey. It cannot
|
|
45
|
+
# survive validate: depending on the struct port a stored null is either
|
|
46
|
+
# REPLACED by the optspec default - transmitting the credential the
|
|
47
|
+
# caller withheld - or REJECTED outright. Withhold the key for validate,
|
|
48
|
+
# then put the nil back. Same fix as ts/js/go make_options.
|
|
49
|
+
#
|
|
50
|
+
# Suppliedness cannot be recovered after validate, hence here, and it
|
|
51
|
+
# must tell an ABSENT auth from a present nil: only the latter is a
|
|
52
|
+
# suppression.
|
|
53
|
+
authsuppressed = options.is_a?(Hash) && options.key?('auth') && options['auth'].nil?
|
|
54
|
+
|
|
43
55
|
opts = VoxgigStruct.clone(options)
|
|
44
56
|
opts = {} unless opts.is_a?(Hash)
|
|
45
57
|
|
|
58
|
+
opts.delete('auth') if authsuppressed
|
|
59
|
+
|
|
46
60
|
# Feature add-order. options["feature"] may be given as an ordered ARRAY of
|
|
47
61
|
# { "name" => ..., "active" => ..., ... } entries (the array position IS the
|
|
48
62
|
# order in which features are added), or as a { "name" => {opts} } map.
|
|
@@ -109,6 +123,9 @@ module ProjectNameUtilities
|
|
|
109
123
|
validated = VoxgigStruct.validate(merged, optspec)
|
|
110
124
|
opts = validated.is_a?(Hash) ? validated : {}
|
|
111
125
|
|
|
126
|
+
# Restore the suppression the optspec default would otherwise erase.
|
|
127
|
+
opts['auth'] = nil if authsuppressed
|
|
128
|
+
|
|
112
129
|
# Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
113
130
|
# Every placeholder must resolve to a non-empty value: from
|
|
114
131
|
# options["server"] (user), else the config default. A placeholder that
|
|
@@ -23,8 +23,28 @@ pub fn make_options_util(ctx: &Rc<Context>) -> Value {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// `auth: null` is the documented way to disable auth outright, and
|
|
27
|
+
// prepare_auth honours it before it ever reads the apikey. It cannot
|
|
28
|
+
// survive validate: depending on the struct port a stored null is either
|
|
29
|
+
// REPLACED by the optspec default - transmitting the credential the
|
|
30
|
+
// caller withheld - or REJECTED outright. Withhold the key for validate,
|
|
31
|
+
// then put the null back. Same fix as ts/js/go make_options.
|
|
32
|
+
//
|
|
33
|
+
// Read the map DIRECTLY rather than through get_prop: get_prop applies
|
|
34
|
+
// the Group A rule and returns the alt for a stored null, so it cannot
|
|
35
|
+
// tell an absent auth from a suppressed one - and only the latter is a
|
|
36
|
+
// suppression.
|
|
37
|
+
let auth_suppressed = match &options {
|
|
38
|
+
Value::Map(m) => matches!(m.borrow().get("auth"), Some(Value::Null)),
|
|
39
|
+
_ => false,
|
|
40
|
+
};
|
|
41
|
+
|
|
26
42
|
let mut opts = vs::clone(&options);
|
|
27
43
|
|
|
44
|
+
if auth_suppressed {
|
|
45
|
+
opts = vs::del_prop(opts, &Value::str("auth"));
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
// Feature add-order. `options.feature` may be an ordered List of
|
|
29
49
|
// { name, active, ...opts } entries (the List position IS the order in
|
|
30
50
|
// which features are added), or a { name: {opts} } map. Normalize a List
|
|
@@ -120,6 +140,11 @@ pub fn make_options_util(ctx: &Rc<Context>) -> Value {
|
|
|
120
140
|
}
|
|
121
141
|
}
|
|
122
142
|
|
|
143
|
+
// Restore the suppression the optspec default would otherwise erase.
|
|
144
|
+
if auth_suppressed {
|
|
145
|
+
setp(&opts, "auth", Value::Null);
|
|
146
|
+
}
|
|
147
|
+
|
|
123
148
|
// Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
124
149
|
// Every placeholder must resolve to a non-empty value: from options.server
|
|
125
150
|
// (user), else the Config default. A placeholder that resolves to "" is a
|
|
@@ -254,8 +254,22 @@ object MakeOptions {
|
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
// `auth: null` is the documented way to suppress auth outright, and
|
|
258
|
+
// prepareAuth honours it before it ever reads the apikey. It cannot survive
|
|
259
|
+
// validate: a stored null reads as "no value", so the optspec `auth`
|
|
260
|
+
// default fires and the suppression becomes "use the default auth" -
|
|
261
|
+
// transmitting the credential the caller withheld. Withhold the key for
|
|
262
|
+
// validate, then put the null back. Same fix as ts/js/go/java makeOptions.
|
|
263
|
+
//
|
|
264
|
+
// Suppliedness cannot be recovered after validate, hence here, and it must
|
|
265
|
+
// tell an ABSENT auth from a present null: containsKey rather than a get()
|
|
266
|
+
// null check, which cannot distinguish them.
|
|
267
|
+
val authSuppressed = options.containsKey("auth") && null == options.get("auth")
|
|
268
|
+
|
|
257
269
|
var opts = Struct.clone(options).asInstanceOf[JMap[String, Object]]
|
|
258
270
|
|
|
271
|
+
if (authSuppressed) opts.remove("auth")
|
|
272
|
+
|
|
259
273
|
// Feature add-order. options.feature may be given as an ordered LIST of
|
|
260
274
|
// { name, active, ...opts } entries (the list position IS the order in
|
|
261
275
|
// which features are added), or as a { name: {opts} } map. Normalize a
|
|
@@ -330,6 +344,9 @@ object MakeOptions {
|
|
|
330
344
|
val validated = Struct.validate(merged, optspec, vopts)
|
|
331
345
|
opts = validated.asInstanceOf[JMap[String, Object]]
|
|
332
346
|
|
|
347
|
+
// Restore the suppression the optspec default would otherwise erase.
|
|
348
|
+
if (authSuppressed) opts.put("auth", null)
|
|
349
|
+
|
|
333
350
|
// Restore system.fetch.
|
|
334
351
|
if (sysFetch != null) {
|
|
335
352
|
val sys = Helpers.toMapAny(opts.get("system"))
|
|
@@ -85,8 +85,24 @@ func makeOptionsUtil(_ ctx: Context) -> VMap {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
// `auth: .null` is the documented way to disable auth outright, and
|
|
89
|
+
// prepareAuth honours it before it ever reads the apikey. It cannot survive
|
|
90
|
+
// validate: depending on the struct port a stored null is either REPLACED
|
|
91
|
+
// by the optspec default - transmitting the credential the caller withheld
|
|
92
|
+
// - or REJECTED outright. Withhold the key for validate, then put the null
|
|
93
|
+
// back. Same fix as ts/js/go makeOptions.
|
|
94
|
+
//
|
|
95
|
+
// `isNull` rather than `isNil`: the latter is also true for Noval, so it
|
|
96
|
+
// cannot tell an ABSENT auth from a suppressed one, and only the latter is
|
|
97
|
+
// a suppression.
|
|
98
|
+
let authSuppressed = options.entries["auth"]?.isNull ?? false
|
|
99
|
+
|
|
88
100
|
let opts = clone(.map(options)).asMap ?? VMap()
|
|
89
101
|
|
|
102
|
+
if authSuppressed {
|
|
103
|
+
opts.entries.removeValue(forKey: "auth")
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
// Feature add-order. options.feature may be given as an ordered LIST of
|
|
91
107
|
// { name, active, ...opts } entries (the list position IS the order in which
|
|
92
108
|
// features are added), or as a { name: {opts} } map. Normalize a list to a
|
|
@@ -124,6 +140,11 @@ func makeOptionsUtil(_ ctx: Context) -> VMap {
|
|
|
124
140
|
let validated = validate(merged, optspec)
|
|
125
141
|
let result = validated.asMap ?? VMap()
|
|
126
142
|
|
|
143
|
+
// Restore the suppression the optspec default would otherwise erase.
|
|
144
|
+
if authSuppressed {
|
|
145
|
+
result.entries["auth"] = .null
|
|
146
|
+
}
|
|
147
|
+
|
|
127
148
|
// Restore system.fetch.
|
|
128
149
|
if !isNil(sysFetch) {
|
|
129
150
|
if let sm = gp(result, "system").asMap {
|