@voxgig/sdkgen 4.32.1 → 4.33.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/helpers/naming.js +1 -1
- package/dist/helpers/naming.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/model/sdkgen.aontu +7 -1
- package/package.json +1 -1
- package/project/.sdk/model/feature/debug.aontu +3 -1
- package/project/.sdk/src/cmp/c/PrepareAuth_c.ts +8 -28
- package/project/.sdk/src/cmp/c/TestClean_c.ts +774 -0
- package/project/.sdk/src/cmp/c/Test_c.ts +3 -0
- package/project/.sdk/src/cmp/c/fragment/Entity.fragment.c +16 -5
- package/project/.sdk/src/cmp/c/fragment/Main.fragment.c +1 -1
- package/project/.sdk/src/cmp/clojure/PrepareAuth_clojure.ts +3 -0
- package/project/.sdk/src/cmp/clojure/TestClean_clojure.ts +473 -0
- package/project/.sdk/src/cmp/clojure/Test_clojure.ts +6 -0
- package/project/.sdk/src/cmp/clojure/fragment/Entity.fragment.clj +18 -8
- package/project/.sdk/src/cmp/cpp/PrepareAuth_cpp.ts +3 -0
- package/project/.sdk/src/cmp/cpp/TestClean_cpp.ts +782 -0
- package/project/.sdk/src/cmp/cpp/TestEntity_cpp.ts +1 -1
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +2 -0
- package/project/.sdk/src/cmp/csharp/PrepareAuth_csharp.ts +3 -0
- package/project/.sdk/src/cmp/csharp/TestClean_csharp.ts +887 -0
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +2 -0
- package/project/.sdk/src/cmp/csharp/fragment/EntityBase.fragment.cs +68 -4
- package/project/.sdk/src/cmp/csharp/fragment/Main.fragment.cs +8 -2
- package/project/.sdk/src/cmp/csharp/fragment/SdkError.fragment.cs +49 -0
- package/project/.sdk/src/cmp/elixir/PrepareAuth_elixir.ts +3 -0
- package/project/.sdk/src/cmp/elixir/Schema_elixir.ts +20 -10
- package/project/.sdk/src/cmp/elixir/TestClean_elixir.ts +666 -0
- package/project/.sdk/src/cmp/elixir/Test_elixir.ts +4 -0
- package/project/.sdk/src/cmp/elixir/fragment/Main.fragment.ex +1 -1
- package/project/.sdk/src/cmp/elixir/fragment/Pipeline.fragment.ex +14 -2
- package/project/.sdk/src/cmp/go/PrepareAuth_go.ts +3 -0
- package/project/.sdk/src/cmp/go/TestClean_go.ts +804 -0
- package/project/.sdk/src/cmp/go/Test_go.ts +3 -0
- package/project/.sdk/src/cmp/go/fragment/Entity.fragment.go +54 -4
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +27 -2
- package/project/.sdk/src/cmp/java/PrepareAuth_java.ts +3 -0
- package/project/.sdk/src/cmp/java/TestClean_java.ts +884 -0
- package/project/.sdk/src/cmp/java/Test_java.ts +2 -0
- package/project/.sdk/src/cmp/java/fragment/EntityBase.fragment.java +56 -11
- package/project/.sdk/src/cmp/java/fragment/SdkError.fragment.java +36 -3
- package/project/.sdk/src/cmp/js/PrepareAuth_js.ts +3 -0
- package/project/.sdk/src/cmp/js/TestClean_js.ts +458 -0
- package/project/.sdk/src/cmp/js/Test_js.ts +2 -0
- package/project/.sdk/src/cmp/js/fragment/EntityBase.fragment.js +5 -4
- package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +11 -2
- package/project/.sdk/src/cmp/js/fragment/SdkError.fragment.js +17 -1
- package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +5 -0
- package/project/.sdk/src/cmp/kotlin/PrepareAuth_kotlin.ts +3 -0
- package/project/.sdk/src/cmp/kotlin/TestClean_kotlin.ts +654 -0
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +3 -0
- package/project/.sdk/src/cmp/kotlin/fragment/EntityBase.fragment.kt +44 -11
- package/project/.sdk/src/cmp/kotlin/fragment/SdkError.fragment.kt +31 -0
- package/project/.sdk/src/cmp/lua/PrepareAuth_lua.ts +3 -0
- package/project/.sdk/src/cmp/lua/TestClean_lua.ts +769 -0
- package/project/.sdk/src/cmp/lua/Test_lua.ts +3 -0
- package/project/.sdk/src/cmp/lua/fragment/Entity.fragment.lua +77 -1
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +49 -2
- package/project/.sdk/src/cmp/ocaml/Entity_ocaml.ts +3 -2
- package/project/.sdk/src/cmp/ocaml/PrepareAuth_ocaml.ts +4 -25
- package/project/.sdk/src/cmp/ocaml/TestClean_ocaml.ts +538 -0
- package/project/.sdk/src/cmp/ocaml/Test_ocaml.ts +5 -0
- package/project/.sdk/src/cmp/ocaml/fragment/RunOp.fragment.ml +16 -4
- package/project/.sdk/src/cmp/perl/PrepareAuth_perl.ts +3 -0
- package/project/.sdk/src/cmp/perl/TestClean_perl.ts +619 -0
- package/project/.sdk/src/cmp/perl/Test_perl.ts +3 -0
- package/project/.sdk/src/cmp/perl/fragment/Entity.fragment.pm +67 -5
- package/project/.sdk/src/cmp/perl/fragment/Main.fragment.pm +13 -1
- package/project/.sdk/src/cmp/php/PrepareAuth_php.ts +3 -0
- package/project/.sdk/src/cmp/php/TestClean_php.ts +809 -0
- package/project/.sdk/src/cmp/php/Test_php.ts +2 -0
- package/project/.sdk/src/cmp/php/fragment/Entity.fragment.php +96 -55
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +15 -2
- package/project/.sdk/src/cmp/py/PrepareAuth_py.ts +3 -0
- package/project/.sdk/src/cmp/py/TestClean_py.ts +549 -0
- package/project/.sdk/src/cmp/py/Test_py.ts +3 -0
- package/project/.sdk/src/cmp/py/fragment/Entity.fragment.py +83 -55
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +19 -3
- package/project/.sdk/src/cmp/rb/PrepareAuth_rb.ts +3 -0
- package/project/.sdk/src/cmp/rb/TestClean_rb.ts +535 -0
- package/project/.sdk/src/cmp/rb/Test_rb.ts +3 -0
- package/project/.sdk/src/cmp/rb/fragment/Entity.fragment.rb +108 -46
- package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +12 -1
- package/project/.sdk/src/cmp/rust/PrepareAuth_rust.ts +9 -45
- package/project/.sdk/src/cmp/rust/TestClean_rust.ts +881 -0
- package/project/.sdk/src/cmp/rust/Test_rust.ts +3 -0
- package/project/.sdk/src/cmp/rust/fragment/Entity.fragment.rs +14 -6
- package/project/.sdk/src/cmp/rust/fragment/Main.fragment.rs +17 -1
- package/project/.sdk/src/cmp/rust/fragment/SdkError.fragment.rs +34 -2
- package/project/.sdk/src/cmp/scala/PrepareAuth_scala.ts +3 -0
- package/project/.sdk/src/cmp/scala/TestClean_scala.ts +608 -0
- package/project/.sdk/src/cmp/scala/Test_scala.ts +3 -0
- package/project/.sdk/src/cmp/scala/fragment/EntityBase.fragment.scala +58 -6
- package/project/.sdk/src/cmp/swift/PrepareAuth_swift.ts +3 -0
- package/project/.sdk/src/cmp/swift/TestClean_swift.ts +671 -0
- package/project/.sdk/src/cmp/swift/Test_swift.ts +3 -0
- package/project/.sdk/src/cmp/swift/fragment/EntityBase.fragment.swift +10 -0
- package/project/.sdk/src/cmp/swift/fragment/Main.fragment.swift +16 -2
- package/project/.sdk/src/cmp/swift/fragment/SdkError.fragment.swift +47 -3
- package/project/.sdk/src/cmp/ts/PrepareAuth_ts.ts +3 -0
- package/project/.sdk/src/cmp/ts/TestClean_ts.ts +465 -0
- package/project/.sdk/src/cmp/ts/Test_ts.ts +2 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityBase.fragment.ts +5 -4
- package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +8 -2
- package/project/.sdk/src/cmp/ts/fragment/SdkError.fragment.ts +20 -2
- package/project/.sdk/src/cmp/zig/PrepareAuth_zig.ts +3 -0
- package/project/.sdk/src/cmp/zig/TestClean_zig.ts +791 -0
- package/project/.sdk/src/cmp/zig/Test_zig.ts +5 -0
- package/project/.sdk/src/cmp/zig/fragment/Build.fragment.zig +19 -0
- package/project/.sdk/src/cmp/zig/fragment/Entity.fragment.zig +14 -5
- package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +1 -1
- package/project/.sdk/tm/c/core/context.c +25 -0
- package/project/.sdk/tm/c/core/error.c +16 -0
- package/project/.sdk/tm/c/core/sdk.h +22 -0
- package/project/.sdk/tm/c/feature/audit.c +2 -0
- package/project/.sdk/tm/c/feature/cost.c +1 -0
- package/project/.sdk/tm/c/feature/debug.c +19 -29
- package/project/.sdk/tm/c/feature/log.c +21 -2
- package/project/.sdk/tm/c/feature/proxy.c +55 -3
- package/project/.sdk/tm/c/feature/secrets.c +7 -0
- package/project/.sdk/tm/c/feature/telemetry.c +2 -0
- package/project/.sdk/tm/c/tests/feature_test.c +2 -2
- package/project/.sdk/tm/c/utility/clean.c +530 -8
- package/project/.sdk/tm/c/utility/done.c +28 -12
- package/project/.sdk/tm/c/utility/make_error.c +4 -3
- package/project/.sdk/tm/c/utility/make_options.c +71 -45
- package/project/.sdk/tm/clojure/feature/secrets/sdk/feature/secrets.clj +15 -0
- package/project/.sdk/tm/clojure/src/sdk/client.clj +20 -4
- package/project/.sdk/tm/clojure/src/sdk/core.clj +319 -35
- package/project/.sdk/tm/clojure/src/sdk/features.clj +68 -30
- package/project/.sdk/tm/clojure/test/sdk/test/feature.clj +4 -2
- package/project/.sdk/tm/clojure/test/sdk/test/pipeline.clj +47 -20
- package/project/.sdk/tm/clojure/test/sdk/test_runner.clj +4 -0
- package/project/.sdk/tm/cpp/core/types.hpp +93 -3
- package/project/.sdk/tm/cpp/feature/audit.hpp +1 -0
- package/project/.sdk/tm/cpp/feature/cost.hpp +1 -0
- package/project/.sdk/tm/cpp/feature/debug.hpp +20 -12
- package/project/.sdk/tm/cpp/feature/log.hpp +31 -9
- package/project/.sdk/tm/cpp/feature/proxy.hpp +52 -6
- package/project/.sdk/tm/cpp/feature/secrets.hpp +13 -0
- package/project/.sdk/tm/cpp/feature/telemetry.hpp +4 -2
- package/project/.sdk/tm/cpp/test/feature_test.cpp +2 -2
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +426 -51
- package/project/.sdk/tm/csharp/core/Context.cs +32 -0
- package/project/.sdk/tm/csharp/core/Utility.cs +2 -0
- package/project/.sdk/tm/csharp/feature/AuditFeature.cs +1 -0
- package/project/.sdk/tm/csharp/feature/CostFeature.cs +7 -5
- package/project/.sdk/tm/csharp/feature/DebugFeature.cs +19 -16
- package/project/.sdk/tm/csharp/feature/FeatureOptions.cs +16 -0
- package/project/.sdk/tm/csharp/feature/LogFeature.cs +4 -1
- package/project/.sdk/tm/csharp/feature/ProxyFeature.cs +26 -5
- package/project/.sdk/tm/csharp/feature/SecretsFeature.cs +16 -0
- package/project/.sdk/tm/csharp/feature/TelemetryFeature.cs +4 -2
- package/project/.sdk/tm/csharp/test/FeatureTest.cs +2 -2
- package/project/.sdk/tm/csharp/utility/Clean.cs +440 -2
- package/project/.sdk/tm/csharp/utility/Done.cs +27 -11
- package/project/.sdk/tm/csharp/utility/MakeError.cs +19 -8
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +119 -29
- package/project/.sdk/tm/csharp/utility/MakeResponse.cs +21 -11
- package/project/.sdk/tm/csharp/utility/Register.cs +1 -0
- package/project/.sdk/tm/elixir/lib/projectname/context.ex +19 -0
- package/project/.sdk/tm/elixir/lib/projectname/entity_base.ex +22 -1
- package/project/.sdk/tm/elixir/lib/projectname/error.ex +24 -0
- package/project/.sdk/tm/elixir/lib/projectname/feature/audit.ex +2 -2
- package/project/.sdk/tm/elixir/lib/projectname/feature/cost.ex +2 -2
- package/project/.sdk/tm/elixir/lib/projectname/feature/debug.ex +13 -13
- package/project/.sdk/tm/elixir/lib/projectname/feature/log.ex +18 -5
- package/project/.sdk/tm/elixir/lib/projectname/feature/proxy.ex +19 -1
- package/project/.sdk/tm/elixir/lib/projectname/feature/secrets.ex +15 -0
- package/project/.sdk/tm/elixir/lib/projectname/feature/telemetry.ex +4 -2
- package/project/.sdk/tm/elixir/lib/projectname/feature.ex +22 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +464 -41
- package/project/.sdk/tm/elixir/test/feature_test.exs +3 -2
- package/project/.sdk/tm/go/core/context.go +42 -0
- package/project/.sdk/tm/go/core/error.go +30 -10
- package/project/.sdk/tm/go/core/utility_type.go +2 -0
- package/project/.sdk/tm/go/feature/audit_feature.go +1 -0
- package/project/.sdk/tm/go/feature/base_feature.go +12 -0
- package/project/.sdk/tm/go/feature/cost_feature.go +2 -2
- package/project/.sdk/tm/go/feature/debug_feature.go +14 -12
- package/project/.sdk/tm/go/feature/log_feature.go +13 -8
- package/project/.sdk/tm/go/feature/proxy_feature.go +26 -6
- package/project/.sdk/tm/go/feature/secrets_feature.go +19 -0
- package/project/.sdk/tm/go/feature/telemetry_feature.go +4 -2
- package/project/.sdk/tm/go/test/feature_test.go +2 -2
- package/project/.sdk/tm/go/utility/clean.go +585 -2
- package/project/.sdk/tm/go/utility/done.go +29 -9
- package/project/.sdk/tm/go/utility/make_error.go +51 -16
- package/project/.sdk/tm/go/utility/make_options.go +77 -36
- package/project/.sdk/tm/go/utility/register.go +12 -0
- package/project/.sdk/tm/java/core/Context.java +29 -0
- package/project/.sdk/tm/java/core/SdkClient.java +4 -2
- package/project/.sdk/tm/java/core/Utility.java +7 -0
- package/project/.sdk/tm/java/feature/AuditFeature.java +6 -0
- package/project/.sdk/tm/java/feature/CostFeature.java +5 -0
- package/project/.sdk/tm/java/feature/DebugFeature.java +25 -14
- package/project/.sdk/tm/java/feature/LogFeature.java +11 -4
- package/project/.sdk/tm/java/feature/ProxyFeature.java +41 -6
- package/project/.sdk/tm/java/feature/SecretsFeature.java +18 -0
- package/project/.sdk/tm/java/feature/TelemetryFeature.java +8 -2
- package/project/.sdk/tm/java/test/FeatureTest.java +2 -2
- package/project/.sdk/tm/java/utility/Clean.java +519 -1
- package/project/.sdk/tm/java/utility/Done.java +1 -1
- package/project/.sdk/tm/java/utility/MakeError.java +5 -1
- package/project/.sdk/tm/java/utility/MakeOptions.java +55 -31
- package/project/.sdk/tm/java/utility/Register.java +4 -0
- package/project/.sdk/tm/js/src/Context.js +5 -1
- package/project/.sdk/tm/js/src/feature/audit/AuditFeature.js +2 -2
- package/project/.sdk/tm/js/src/feature/cost/CostFeature.js +2 -2
- package/project/.sdk/tm/js/src/feature/debug/DebugFeature.js +13 -7
- package/project/.sdk/tm/js/src/feature/log/LogFeature.js +9 -5
- package/project/.sdk/tm/js/src/feature/proxy/ProxyFeature.js +19 -1
- package/project/.sdk/tm/js/src/feature/secrets/SecretsFeature.js +14 -0
- package/project/.sdk/tm/js/src/feature/telemetry/TelemetryFeature.js +4 -2
- package/project/.sdk/tm/js/src/utility/CleanUtility.js +294 -21
- package/project/.sdk/tm/js/src/utility/DoneUtility.js +17 -5
- package/project/.sdk/tm/js/src/utility/MakeErrorUtility.js +18 -2
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -15
- package/project/.sdk/tm/js/src/utility/Utility.js +4 -2
- package/project/.sdk/tm/js/test/feature/harness.js +11 -1
- package/project/.sdk/tm/js/test/feature.test.js +9 -2
- package/project/.sdk/tm/kotlin/core/Context.kt +19 -0
- package/project/.sdk/tm/kotlin/core/SdkClient.kt +9 -2
- package/project/.sdk/tm/kotlin/core/Utility.kt +2 -0
- package/project/.sdk/tm/kotlin/feature/AuditFeature.kt +11 -9
- package/project/.sdk/tm/kotlin/feature/CostFeature.kt +8 -5
- package/project/.sdk/tm/kotlin/feature/DebugFeature.kt +15 -22
- package/project/.sdk/tm/kotlin/feature/LogFeature.kt +8 -4
- package/project/.sdk/tm/kotlin/feature/ProxyFeature.kt +26 -2
- package/project/.sdk/tm/kotlin/feature/SecretsFeature.kt +11 -0
- package/project/.sdk/tm/kotlin/feature/TelemetryFeature.kt +4 -2
- package/project/.sdk/tm/kotlin/test/FeatureTest.kt +2 -2
- package/project/.sdk/tm/kotlin/utility/CoreUtil.kt +447 -11
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +38 -31
- package/project/.sdk/tm/kotlin/utility/Register.kt +1 -0
- package/project/.sdk/tm/lua/core/context.lua +43 -0
- package/project/.sdk/tm/lua/core/error.lua +36 -1
- package/project/.sdk/tm/lua/core/utility_type.lua +4 -0
- package/project/.sdk/tm/lua/feature/audit_feature.lua +2 -2
- package/project/.sdk/tm/lua/feature/cost_feature.lua +2 -2
- package/project/.sdk/tm/lua/feature/debug_feature.lua +21 -17
- package/project/.sdk/tm/lua/feature/log_feature.lua +2 -1
- package/project/.sdk/tm/lua/feature/proxy_feature.lua +23 -1
- package/project/.sdk/tm/lua/feature/secrets_feature.lua +18 -0
- package/project/.sdk/tm/lua/feature/telemetry_feature.lua +4 -2
- package/project/.sdk/tm/lua/test/feature/secrets/secrets_feature_test.lua +3 -2
- package/project/.sdk/tm/lua/test/feature_test.lua +10 -3
- package/project/.sdk/tm/lua/utility/clean.lua +426 -2
- package/project/.sdk/tm/lua/utility/clean_explain.lua +34 -0
- package/project/.sdk/tm/lua/utility/done.lua +1 -7
- package/project/.sdk/tm/lua/utility/make_error.lua +3 -1
- package/project/.sdk/tm/lua/utility/make_options.lua +76 -30
- package/project/.sdk/tm/lua/utility/register.lua +4 -1
- package/project/.sdk/tm/ocaml/Makefile +5 -1
- package/project/.sdk/tm/ocaml/feature/secrets_feature.ml +12 -1
- package/project/.sdk/tm/ocaml/sdk_features.ml +78 -18
- package/project/.sdk/tm/ocaml/sdk_helpers.ml +27 -0
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +304 -26
- package/project/.sdk/tm/ocaml/sdk_types.ml +1 -0
- package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +3 -1
- package/project/.sdk/tm/ocaml/test/t_feature.ml +2 -2
- package/project/.sdk/tm/perl/core/context.pm +27 -0
- package/project/.sdk/tm/perl/core/error.pm +52 -5
- package/project/.sdk/tm/perl/feature/audit_feature.pm +2 -2
- package/project/.sdk/tm/perl/feature/cost_feature.pm +2 -2
- package/project/.sdk/tm/perl/feature/debug_feature.pm +17 -13
- package/project/.sdk/tm/perl/feature/log_feature.pm +3 -1
- package/project/.sdk/tm/perl/feature/proxy_feature.pm +21 -1
- package/project/.sdk/tm/perl/feature/secrets_feature.pm +20 -1
- package/project/.sdk/tm/perl/feature/telemetry_feature.pm +4 -2
- package/project/.sdk/tm/perl/t/feature.t +4 -2
- package/project/.sdk/tm/perl/utility/clean.pm +345 -1
- package/project/.sdk/tm/perl/utility/done.pm +24 -6
- package/project/.sdk/tm/perl/utility/make_error.pm +17 -4
- package/project/.sdk/tm/perl/utility/make_options.pm +33 -14
- package/project/.sdk/tm/php/core/Context.php +24 -1
- package/project/.sdk/tm/php/core/Error.php +34 -3
- package/project/.sdk/tm/php/core/UtilityType.php +4 -0
- package/project/.sdk/tm/php/feature/AuditFeature.php +2 -2
- package/project/.sdk/tm/php/feature/CostFeature.php +2 -2
- package/project/.sdk/tm/php/feature/DebugFeature.php +18 -9
- package/project/.sdk/tm/php/feature/LogFeature.php +5 -2
- package/project/.sdk/tm/php/feature/ProxyFeature.php +20 -1
- package/project/.sdk/tm/php/feature/SecretsFeature.php +18 -0
- package/project/.sdk/tm/php/feature/TelemetryFeature.php +4 -2
- package/project/.sdk/tm/php/test/FeatureTest.php +2 -2
- package/project/.sdk/tm/php/utility/Clean.php +438 -2
- package/project/.sdk/tm/php/utility/Done.php +14 -7
- package/project/.sdk/tm/php/utility/MakeError.php +9 -7
- package/project/.sdk/tm/php/utility/MakeOptions.php +62 -38
- package/project/.sdk/tm/php/utility/Register.php +2 -0
- package/project/.sdk/tm/py/pkg/core/context.py +17 -0
- package/project/.sdk/tm/py/pkg/core/error.py +42 -1
- package/project/.sdk/tm/py/pkg/core/utility_type.py +4 -0
- package/project/.sdk/tm/py/pkg/feature/audit_feature.py +2 -2
- package/project/.sdk/tm/py/pkg/feature/cost_feature.py +2 -2
- package/project/.sdk/tm/py/pkg/feature/debug_feature.py +17 -12
- package/project/.sdk/tm/py/pkg/feature/log_feature.py +2 -1
- package/project/.sdk/tm/py/pkg/feature/proxy_feature.py +18 -1
- package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +12 -0
- package/project/.sdk/tm/py/pkg/feature/telemetry_feature.py +4 -2
- package/project/.sdk/tm/py/pkg/utility/clean.py +311 -1
- package/project/.sdk/tm/py/pkg/utility/done.py +18 -5
- package/project/.sdk/tm/py/pkg/utility/make_error.py +9 -6
- package/project/.sdk/tm/py/pkg/utility/make_options.py +64 -25
- package/project/.sdk/tm/py/pkg/utility/make_response.py +19 -13
- package/project/.sdk/tm/py/pkg/utility/register.py +4 -2
- package/project/.sdk/tm/py/test/feature_harness.py +4 -0
- package/project/.sdk/tm/py/test/test_feature.py +2 -2
- package/project/.sdk/tm/py/test/test_primary_utility.py +1 -0
- package/project/.sdk/tm/rb/core/context.rb +28 -0
- package/project/.sdk/tm/rb/core/error.rb +30 -0
- package/project/.sdk/tm/rb/core/utility_type.rb +1 -1
- package/project/.sdk/tm/rb/feature/audit_feature.rb +2 -2
- package/project/.sdk/tm/rb/feature/cost_feature.rb +2 -2
- package/project/.sdk/tm/rb/feature/debug_feature.rb +15 -12
- package/project/.sdk/tm/rb/feature/log_feature.rb +3 -1
- package/project/.sdk/tm/rb/feature/proxy_feature.rb +25 -1
- package/project/.sdk/tm/rb/feature/secrets_feature.rb +17 -0
- package/project/.sdk/tm/rb/feature/telemetry_feature.rb +4 -2
- package/project/.sdk/tm/rb/test/feature_test.rb +4 -2
- package/project/.sdk/tm/rb/utility/clean.rb +312 -1
- package/project/.sdk/tm/rb/utility/done.rb +15 -5
- package/project/.sdk/tm/rb/utility/make_error.rb +13 -4
- package/project/.sdk/tm/rb/utility/make_options.rb +31 -12
- package/project/.sdk/tm/rb/utility/register.rb +2 -0
- package/project/.sdk/tm/rust/core/context.rs +55 -0
- package/project/.sdk/tm/rust/core/utility_type.rs +17 -0
- package/project/.sdk/tm/rust/feature/audit.rs +2 -0
- package/project/.sdk/tm/rust/feature/cost.rs +3 -2
- package/project/.sdk/tm/rust/feature/debug.rs +16 -16
- package/project/.sdk/tm/rust/feature/log.rs +42 -7
- package/project/.sdk/tm/rust/feature/proxy.rs +48 -2
- package/project/.sdk/tm/rust/feature/secrets.rs +12 -0
- package/project/.sdk/tm/rust/feature/telemetry.rs +2 -0
- package/project/.sdk/tm/rust/tests/feature_test.rs +2 -2
- package/project/.sdk/tm/rust/utility/clean.rs +446 -5
- package/project/.sdk/tm/rust/utility/done.rs +22 -12
- package/project/.sdk/tm/rust/utility/make_error.rs +4 -1
- package/project/.sdk/tm/rust/utility/make_options.rs +73 -19
- package/project/.sdk/tm/scala/Makefile +3 -1
- package/project/.sdk/tm/scala/core/Context.scala +16 -0
- package/project/.sdk/tm/scala/core/SdkClient.scala +14 -4
- package/project/.sdk/tm/scala/core/SdkError.scala +28 -0
- package/project/.sdk/tm/scala/core/Types.scala +3 -0
- package/project/.sdk/tm/scala/core/Utility.scala +2 -0
- package/project/.sdk/tm/scala/feature/AuditFeature.scala +16 -10
- package/project/.sdk/tm/scala/feature/CostFeature.scala +10 -5
- package/project/.sdk/tm/scala/feature/DebugFeature.scala +24 -21
- package/project/.sdk/tm/scala/feature/LogFeature.scala +9 -4
- package/project/.sdk/tm/scala/feature/ProxyFeature.scala +23 -2
- package/project/.sdk/tm/scala/feature/SecretsFeature.scala +14 -0
- package/project/.sdk/tm/scala/feature/TelemetryFeature.scala +9 -2
- package/project/.sdk/tm/scala/sdktest/SdkTestMain.scala +2 -2
- package/project/.sdk/tm/scala/utility/Make.scala +63 -20
- package/project/.sdk/tm/scala/utility/Misc.scala +358 -5
- package/project/.sdk/tm/scala/utility/Register.scala +1 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Context.swift +29 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Utility.swift +2 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/AuditFeature.swift +10 -9
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/CostFeature.swift +7 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/DebugFeature.swift +19 -15
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/FeatureOptions.swift +16 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/LogFeature.swift +4 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/ProxyFeature.swift +20 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/SecretsFeature.swift +13 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TelemetryFeature.swift +4 -2
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeError.swift +15 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +58 -19
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Register.swift +1 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/ResultUtil.swift +391 -4
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/FeatureTest.swift +2 -2
- package/project/.sdk/tm/ts/src/Context.ts +5 -1
- package/project/.sdk/tm/ts/src/feature/audit/AuditFeature.ts +2 -2
- package/project/.sdk/tm/ts/src/feature/cost/CostFeature.ts +2 -2
- package/project/.sdk/tm/ts/src/feature/debug/DebugFeature.ts +13 -7
- package/project/.sdk/tm/ts/src/feature/log/LogFeature.ts +9 -5
- package/project/.sdk/tm/ts/src/feature/proxy/ProxyFeature.ts +19 -1
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +12 -0
- package/project/.sdk/tm/ts/src/feature/telemetry/TelemetryFeature.ts +4 -2
- package/project/.sdk/tm/ts/src/utility/CleanUtility.ts +287 -9
- package/project/.sdk/tm/ts/src/utility/DoneUtility.ts +18 -5
- package/project/.sdk/tm/ts/src/utility/MakeErrorUtility.ts +18 -8
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +38 -16
- package/project/.sdk/tm/ts/src/utility/Utility.ts +4 -2
- package/project/.sdk/tm/ts/test/feature/harness.ts +11 -1
- package/project/.sdk/tm/ts/test/feature.test.ts +9 -2
- package/project/.sdk/tm/zig/core/context.zig +34 -0
- package/project/.sdk/tm/zig/core/error.zig +22 -1
- package/project/.sdk/tm/zig/core/utility.zig +403 -39
- package/project/.sdk/tm/zig/feature/audit.zig +4 -2
- package/project/.sdk/tm/zig/feature/cost.zig +3 -2
- package/project/.sdk/tm/zig/feature/debug.zig +20 -25
- package/project/.sdk/tm/zig/feature/log.zig +3 -1
- package/project/.sdk/tm/zig/feature/proxy.zig +47 -6
- package/project/.sdk/tm/zig/feature/secrets.zig +7 -0
- package/project/.sdk/tm/zig/feature/telemetry.zig +4 -2
- package/project/.sdk/tm/zig/test/feature_test.zig +2 -2
- package/project/sdkgen-package.json +1 -1
- package/src/helpers/naming.ts +1 -1
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Content,
|
|
3
|
+
File,
|
|
4
|
+
cmp,
|
|
5
|
+
configDefinition,
|
|
6
|
+
each,
|
|
7
|
+
entityCollection,
|
|
8
|
+
isAuthSuppressed,
|
|
9
|
+
isHttpBasicAuth,
|
|
10
|
+
resolveAuthIn,
|
|
11
|
+
resolveAuthName,
|
|
12
|
+
} from '@voxgig/sdkgen'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import { cppVarName } from './utility_cpp'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// The canary sweep (see TestClean_ts). cpp has no reflection, so the
|
|
19
|
+
// operations the ts sweep discovers from the client are emitted from the
|
|
20
|
+
// model, each with the path parameters its config points declare, and the
|
|
21
|
+
// transport is scripted through `system.fetch`, the seam a closed options
|
|
22
|
+
// union leaves for it.
|
|
23
|
+
const TestClean = cmp(function TestClean(props: any) {
|
|
24
|
+
const { model } = props.ctx$
|
|
25
|
+
const { target } = props
|
|
26
|
+
|
|
27
|
+
const ProjectName = model.const.Name
|
|
28
|
+
|
|
29
|
+
const auth = {
|
|
30
|
+
suppressed: isAuthSuppressed(model),
|
|
31
|
+
where: resolveAuthIn(model),
|
|
32
|
+
name: 'header' === resolveAuthIn(model)
|
|
33
|
+
? resolveAuthName(model).toLowerCase() : resolveAuthName(model),
|
|
34
|
+
basic: isHttpBasicAuth(model),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const configEntity = configDefinition(model, target.name).def.entity || {}
|
|
38
|
+
|
|
39
|
+
const rank: Record<string, number> = { list: 0, load: 1 }
|
|
40
|
+
const candidates: Candidate[] = []
|
|
41
|
+
each(entityCollection(model))
|
|
42
|
+
.filter((e: any) => false !== e.active)
|
|
43
|
+
.forEach((entity: any) => {
|
|
44
|
+
const ops = Object.keys(entity.op || {})
|
|
45
|
+
.filter((op) => ['list', 'load', 'create', 'update', 'remove'].includes(op))
|
|
46
|
+
.sort((a, b) => (rank[a] ?? 2) - (rank[b] ?? 2))
|
|
47
|
+
for (const op of ops) {
|
|
48
|
+
candidates.push({
|
|
49
|
+
name: entity.name + '.' + op, accessor: cppVarName(entity.name), op,
|
|
50
|
+
params: pointParams(configEntity[entity.name]?.op?.[op]),
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
File({ name: 'clean_test.cpp' }, () => Content(render(ProjectName, auth, candidates)))
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
type Candidate = { name: string, accessor: string, op: string, params: string[] }
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// Every path parameter an operation's points declare, as the generated
|
|
63
|
+
// config carries them (points[].args.params[].name).
|
|
64
|
+
function pointParams(opdef: any): string[] {
|
|
65
|
+
const names: string[] = []
|
|
66
|
+
for (const point of opdef?.points || []) {
|
|
67
|
+
for (const p of point?.args?.params || []) {
|
|
68
|
+
if ('string' === typeof p?.name && !names.includes(p.name)) names.push(p.name)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return names
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function candidate(ProjectName: string, c: Candidate): string {
|
|
76
|
+
const call = 'list' === c.op
|
|
77
|
+
? `auto ents = c.${c.accessor}()->list(m, ctrl);
|
|
78
|
+
Value out = vlist();
|
|
79
|
+
for (const auto& e : ents) out.as_list()->push_back(e->data());
|
|
80
|
+
return out;`
|
|
81
|
+
: `return c.${c.accessor}()->${c.op}(m, ctrl)->data();`
|
|
82
|
+
return ` {"${c.name}", {${c.params.map(cppstr).join(', ')}},
|
|
83
|
+
[](${ProjectName}SDK& c, const Value& m, const Value& ctrl) -> Value {
|
|
84
|
+
${call}
|
|
85
|
+
},
|
|
86
|
+
[](${ProjectName}SDK& c, const Value& m, const Value& callopts) -> std::vector<Value> {
|
|
87
|
+
return c.${c.accessor}()->stream(${cppstr(c.op)}, m, callopts);
|
|
88
|
+
}},`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
function render(
|
|
93
|
+
ProjectName: string,
|
|
94
|
+
auth: { suppressed: boolean, where: string, name: string, basic: boolean },
|
|
95
|
+
candidates: Candidate[],
|
|
96
|
+
): string {
|
|
97
|
+
return `// Generated canary sweep: no credential leaves this SDK in any form.
|
|
98
|
+
// Mirrors test/clean.test.ts in the ts reference. Do not hand-edit.
|
|
99
|
+
|
|
100
|
+
#include <functional>
|
|
101
|
+
#include <iostream>
|
|
102
|
+
#include <stdexcept>
|
|
103
|
+
#include <map>
|
|
104
|
+
#include <string>
|
|
105
|
+
#include <vector>
|
|
106
|
+
|
|
107
|
+
#include "testlib.hpp"
|
|
108
|
+
|
|
109
|
+
using namespace sdk;
|
|
110
|
+
|
|
111
|
+
// Generated: the credential's wire placement is fixed when the SDK is built.
|
|
112
|
+
static const bool AUTH_SUPPRESSED = ${auth.suppressed ? 'true' : 'false'};
|
|
113
|
+
static const std::string AUTH_WHERE = ${cppstr(auth.where)};
|
|
114
|
+
static const std::string AUTH_NAME = ${cppstr(auth.name)};
|
|
115
|
+
|
|
116
|
+
static const std::string CANARY_APIKEY = "CANARY-APIKEY-k9x2m7q4p1";
|
|
117
|
+
static const std::string CANARY_SECRET = "CANARY-SECRET-w3e8r5t2y6";
|
|
118
|
+
static const std::string CANARY_HEADER = "CANARY-HEADER-z1x4c7v0b3";
|
|
119
|
+
static const std::string CANARY_VALUE = "CANARY-VALUE-n5m8b2v9c4";
|
|
120
|
+
|
|
121
|
+
static const std::string MASK = "[redacted]";
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
struct Sink {
|
|
125
|
+
std::string name;
|
|
126
|
+
std::string text;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
// Every form a canary can travel in.
|
|
131
|
+
static std::vector<std::string> canaryForms() {
|
|
132
|
+
std::vector<std::string> out;
|
|
133
|
+
for (const std::string& v : {CANARY_APIKEY, CANARY_SECRET, CANARY_HEADER, CANARY_VALUE}) {
|
|
134
|
+
out.push_back(v);
|
|
135
|
+
out.push_back(util::cleanBase64(v));
|
|
136
|
+
out.push_back(Struct::escurl(Value(v)));
|
|
137
|
+
}
|
|
138
|
+
out.push_back(util::cleanBase64(CANARY_APIKEY + ":" + CANARY_SECRET));
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
static std::vector<std::string> leaks(const std::string& text) {
|
|
144
|
+
std::vector<std::string> out;
|
|
145
|
+
for (const auto& f : canaryForms()) {
|
|
146
|
+
if (std::string::npos != text.find(f)) out.push_back(f);
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
// Header maps keep the caller's spelling; the assertion should not care.
|
|
153
|
+
static Value header(const Value& map, const std::string& name) {
|
|
154
|
+
if (!map.is_map()) return Value::undef();
|
|
155
|
+
std::string lname = name;
|
|
156
|
+
for (auto& c : lname) c = static_cast<char>(std::tolower((unsigned char)c));
|
|
157
|
+
for (const auto& kv : *map.as_map()) {
|
|
158
|
+
std::string k = kv.first;
|
|
159
|
+
for (auto& c : k) c = static_cast<char>(std::tolower((unsigned char)c));
|
|
160
|
+
if (k == lname) return kv.second;
|
|
161
|
+
}
|
|
162
|
+
return Value::undef();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
static bool endsWith(const std::string& s, const std::string& suf) {
|
|
167
|
+
return s.size() >= suf.size() && 0 == s.compare(s.size() - suf.size(), suf.size(), suf);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
static void addForms(std::vector<Sink>& sinks, const std::string& name, const Value& val) {
|
|
172
|
+
sinks.push_back({name + ":json", vs::jsonify(val, 0)});
|
|
173
|
+
sinks.push_back({name + ":string", Struct::stringify(val)});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
static void addError(std::vector<Sink>& sinks, const std::string& name, const SdkErrorPtr& err) {
|
|
178
|
+
sinks.push_back({name + ":what", std::string(err->what())});
|
|
179
|
+
sinks.push_back({name + ":string", err->to_string()});
|
|
180
|
+
addForms(sinks, name + ":value", err->toValue());
|
|
181
|
+
addForms(sinks, name + ":spec", err->spec);
|
|
182
|
+
addForms(sinks, name + ":result", err->result);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
// Captures the serialised context from inside the pipeline: what a hook
|
|
187
|
+
// author would hand to a logger.
|
|
188
|
+
class CaptureFeature : public BaseFeature {
|
|
189
|
+
public:
|
|
190
|
+
std::vector<Sink>* sinks;
|
|
191
|
+
explicit CaptureFeature(std::vector<Sink>* sinks_)
|
|
192
|
+
: BaseFeature("capture", "0.0.1", true), sinks(sinks_) {}
|
|
193
|
+
void preRequest(CtxPtr ctx) override { sinks->push_back({"ctx@PreRequest", ctx->to_string()}); }
|
|
194
|
+
void preResponse(CtxPtr ctx) override { sinks->push_back({"ctx@PreResponse", ctx->to_string()}); }
|
|
195
|
+
void preUnexpected(CtxPtr ctx) override { sinks->push_back({"ctx@PreUnexpected", ctx->to_string()}); }
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
// A feature that throws from inside the pipeline, quoting the request it
|
|
200
|
+
// saw: an exception makeError never handled. Its variant throws again from
|
|
201
|
+
// PreUnexpected, which makeError fires once it has cleaned its own error.
|
|
202
|
+
class ThrowFeature : public BaseFeature {
|
|
203
|
+
public:
|
|
204
|
+
bool unexpected;
|
|
205
|
+
explicit ThrowFeature(bool unexpected_ = false)
|
|
206
|
+
: BaseFeature("throwhook", "0.0.1", true), unexpected(unexpected_) {}
|
|
207
|
+
void preResponse(CtxPtr ctx) override {
|
|
208
|
+
throw std::runtime_error("hook saw " + vs::jsonify(ctx->spec ? ctx->spec->toValue() : Value::undef(), 0));
|
|
209
|
+
}
|
|
210
|
+
void preUnexpected(CtxPtr ctx) override {
|
|
211
|
+
if (unexpected) {
|
|
212
|
+
throw std::runtime_error("hook saw " + vs::jsonify(ctx->spec ? ctx->spec->toValue() : Value::undef(), 0));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
// Features that fail the operation with the SDK's own error, whose code
|
|
219
|
+
// quotes a registered value: one refuses it as rbac does, and records the
|
|
220
|
+
// error PreUnexpected hands a hook; the other throws it.
|
|
221
|
+
class DenyFeature : public BaseFeature {
|
|
222
|
+
public:
|
|
223
|
+
std::vector<Sink>* sinks;
|
|
224
|
+
explicit DenyFeature(std::vector<Sink>* sinks_)
|
|
225
|
+
: BaseFeature("denyhook", "0.0.1", true), sinks(sinks_) {}
|
|
226
|
+
void prePoint(CtxPtr ctx) override {
|
|
227
|
+
ctx->out.pointError = ctx->makeError("denied:" + CANARY_VALUE, "denied");
|
|
228
|
+
}
|
|
229
|
+
void preUnexpected(CtxPtr ctx) override {
|
|
230
|
+
if (ctx->ctrl->err) addError(*sinks, "error", ctx->ctrl->err);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
class RaiseFeature : public BaseFeature {
|
|
235
|
+
public:
|
|
236
|
+
RaiseFeature() : BaseFeature("raisehook", "0.0.1", true) {}
|
|
237
|
+
void preResponse(CtxPtr) override {
|
|
238
|
+
throw std::make_shared<SdkError>("raised:" + CANARY_VALUE, "raised", nullptr);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
// A stream whose producer fails while the caller consumes it, quoting a
|
|
244
|
+
// credential.
|
|
245
|
+
class StreamThrowFeature : public BaseFeature {
|
|
246
|
+
public:
|
|
247
|
+
StreamThrowFeature() : BaseFeature("streamthrow", "0.0.1", true) {}
|
|
248
|
+
void preDone(CtxPtr ctx) override {
|
|
249
|
+
if (!ctx->result) return;
|
|
250
|
+
ctx->result->stream = []() -> std::vector<Value> {
|
|
251
|
+
throw std::runtime_error("stream saw " + CANARY_APIKEY);
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
// A stream that succeeds, so the pipeline's terminal step never runs.
|
|
258
|
+
class StreamOkFeature : public BaseFeature {
|
|
259
|
+
public:
|
|
260
|
+
StreamOkFeature() : BaseFeature("streamok", "0.0.1", true) {}
|
|
261
|
+
void preDone(CtxPtr ctx) override {
|
|
262
|
+
if (!ctx->result) return;
|
|
263
|
+
std::vector<Value> items;
|
|
264
|
+
Value data = ctx->result->resdata;
|
|
265
|
+
if (data.is_list()) {
|
|
266
|
+
for (const auto& item : *data.as_list()) items.push_back(item);
|
|
267
|
+
} else if (!is_nullish(data)) {
|
|
268
|
+
items.push_back(data);
|
|
269
|
+
}
|
|
270
|
+
ctx->result->stream = [items]() { return items; };
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
// A sink callable: records every form of the record it receives.
|
|
276
|
+
static Value capture(std::vector<Sink>* sinks, const std::string& name, int at) {
|
|
277
|
+
vs::Injector fn = [sinks, name, at](vs::Injection&, const Value& args, const std::string&,
|
|
278
|
+
const Value&) -> Value {
|
|
279
|
+
addForms(*sinks, name, vs::getelem(args, Value(int64_t(at))));
|
|
280
|
+
return Value::undef();
|
|
281
|
+
};
|
|
282
|
+
return Value(fn);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
static Value response(int status, const Value& data, const Value& headers) {
|
|
287
|
+
Value h = vmap({{"content-type", Value("application/json")}});
|
|
288
|
+
if (headers.is_map()) {
|
|
289
|
+
for (const auto& kv : *headers.as_map()) map_put(h, kv.first, kv.second);
|
|
290
|
+
}
|
|
291
|
+
Value out = vmap();
|
|
292
|
+
map_put(out, "status", Value(status));
|
|
293
|
+
map_put(out, "statusText", Value(status < 400 ? "OK" : "ERR"));
|
|
294
|
+
map_put(out, "body", Value(vs::jsonify(data, 0)));
|
|
295
|
+
map_put(out, "json", json_thunk(data));
|
|
296
|
+
map_put(out, "headers", h);
|
|
297
|
+
return out;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
struct Scenario {
|
|
302
|
+
std::string name;
|
|
303
|
+
std::function<Value(const std::string&, const Value&)> respond;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
static std::vector<Scenario> scenarios() {
|
|
308
|
+
return {
|
|
309
|
+
{"ok", [](const std::string&, const Value&) {
|
|
310
|
+
return response(200, vmap({{"id", Value("i1")}, {"name", Value("n1")}}),
|
|
311
|
+
vmap({{"x-session-token", Value("RESP-TOKEN-a1b2c3d4e5")}}));
|
|
312
|
+
}},
|
|
313
|
+
{"notfound", [](const std::string&, const Value&) {
|
|
314
|
+
return response(404, vmap({{"error", Value("no such record")}}), Value::undef());
|
|
315
|
+
}},
|
|
316
|
+
{"server", [](const std::string&, const Value&) {
|
|
317
|
+
return response(500, vmap({{"error", Value("boom")}}), Value::undef());
|
|
318
|
+
}},
|
|
319
|
+
{"transport", [](const std::string& url, const Value&) -> Value {
|
|
320
|
+
throw std::make_shared<SdkError>("fetch_fail",
|
|
321
|
+
"socket hang up (URL was: \\"" + url + "\\")", nullptr);
|
|
322
|
+
}},
|
|
323
|
+
{"notjson", [](const std::string&, const Value&) {
|
|
324
|
+
vs::Injector broken = [](vs::Injection&, const Value&, const std::string&,
|
|
325
|
+
const Value&) -> Value {
|
|
326
|
+
throw std::make_shared<SdkError>("json_parse", "Unexpected token < in JSON", nullptr);
|
|
327
|
+
};
|
|
328
|
+
Value out = vmap();
|
|
329
|
+
map_put(out, "status", Value(200));
|
|
330
|
+
map_put(out, "statusText", Value("OK"));
|
|
331
|
+
map_put(out, "body", Value("<html>"));
|
|
332
|
+
map_put(out, "json", Value(broken));
|
|
333
|
+
map_put(out, "headers", vmap());
|
|
334
|
+
return out;
|
|
335
|
+
}},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
static bool hasFeature(const std::string& name) {
|
|
341
|
+
Value fm = Helpers::toMapAny(getp(sharedConfig(), "feature"));
|
|
342
|
+
return fm.is_map() && !getp(fm, name).is_undef();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
static std::shared_ptr<${ProjectName}SDK> makeSdk(const Scenario& scenario, std::vector<Sink>* sinks,
|
|
347
|
+
const Value& cleanopts,
|
|
348
|
+
FeaturePtr extra = nullptr) {
|
|
349
|
+
Value feature = vmap();
|
|
350
|
+
if (hasFeature("log")) {
|
|
351
|
+
// The log feature hands [level, record] to its logger.
|
|
352
|
+
map_put(feature, "log", vmap({{"active", Value(true)}, {"logger", capture(sinks, "log", 1)}}));
|
|
353
|
+
}
|
|
354
|
+
if (hasFeature("debug")) {
|
|
355
|
+
map_put(feature, "debug", vmap({{"active", Value(true)}, {"onEntry", capture(sinks, "debug", 0)}}));
|
|
356
|
+
}
|
|
357
|
+
if (hasFeature("audit")) {
|
|
358
|
+
map_put(feature, "audit", vmap({{"active", Value(true)}, {"sink", capture(sinks, "audit", 0)}}));
|
|
359
|
+
}
|
|
360
|
+
if (hasFeature("telemetry")) {
|
|
361
|
+
map_put(feature, "telemetry", vmap({{"active", Value(true)}, {"exporter", capture(sinks, "telemetry", 0)}}));
|
|
362
|
+
}
|
|
363
|
+
if (hasFeature("cost")) {
|
|
364
|
+
map_put(feature, "cost", vmap({{"active", Value(true)}, {"sink", capture(sinks, "cost", 0)}}));
|
|
365
|
+
}
|
|
366
|
+
if (hasFeature("metrics")) map_put(feature, "metrics", vmap({{"active", Value(true)}}));
|
|
367
|
+
if (hasFeature("clienttrack")) map_put(feature, "clienttrack", vmap({{"active", Value(true)}}));
|
|
368
|
+
|
|
369
|
+
Scenario sc = scenario;
|
|
370
|
+
vs::Injector fetch = [sc](vs::Injection&, const Value& args, const std::string&,
|
|
371
|
+
const Value&) -> Value {
|
|
372
|
+
Value url = vs::getelem(args, Value(int64_t(0)));
|
|
373
|
+
Value fetchdef = vs::getelem(args, Value(int64_t(1)));
|
|
374
|
+
return sc.respond(url.is_string() ? url.as_string() : "", fetchdef);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
Value clean = vmap({{"values", Value(CANARY_VALUE)}});
|
|
378
|
+
if (cleanopts.is_map()) {
|
|
379
|
+
for (const auto& kv : *cleanopts.as_map()) map_put(clean, kv.first, kv.second);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
Value opts = vmap({
|
|
383
|
+
{"apikey", Value(CANARY_APIKEY)},
|
|
384
|
+
{"secret", Value(CANARY_SECRET)},
|
|
385
|
+
{"headers", vmap({{"X-Custom-Token", Value(CANARY_HEADER)}})},
|
|
386
|
+
{"clean", clean},
|
|
387
|
+
{"feature", feature},
|
|
388
|
+
{"system", vmap({{"fetch", Value(fetch)}})},
|
|
389
|
+
});
|
|
390
|
+
auto sdk = std::make_shared<${ProjectName}SDK>(opts);
|
|
391
|
+
sdk->getRootCtx()->utility->featureAdd(sdk->getRootCtx(), std::make_shared<CaptureFeature>(sinks));
|
|
392
|
+
if (extra) sdk->getRootCtx()->utility->featureAdd(sdk->getRootCtx(), extra);
|
|
393
|
+
return sdk;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
struct Candidate {
|
|
398
|
+
std::string name;
|
|
399
|
+
std::vector<std::string> params;
|
|
400
|
+
std::function<Value(${ProjectName}SDK&, const Value&, const Value&)> run;
|
|
401
|
+
std::function<std::vector<Value>(${ProjectName}SDK&, const Value&, const Value&)> stream;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
struct Target {
|
|
406
|
+
int index;
|
|
407
|
+
Value match;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
// Generated from the model: every operation the active entities declare,
|
|
412
|
+
// with the path parameters its points declare.
|
|
413
|
+
static std::vector<Candidate> candidates() {
|
|
414
|
+
return {
|
|
415
|
+
${candidates.map((c) => candidate(ProjectName, c)).join('\n')}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
// The first operation that completes against a plain 200: with no
|
|
421
|
+
// arguments, else with every path parameter its points declare filled in.
|
|
422
|
+
static Target usableOp(const std::vector<Candidate>& cands) {
|
|
423
|
+
vs::Injector fetch = [](vs::Injection&, const Value&, const std::string&, const Value&) -> Value {
|
|
424
|
+
return response(200, vmap({{"id", Value("i1")}}), Value::undef());
|
|
425
|
+
};
|
|
426
|
+
Value opts = vmap({
|
|
427
|
+
{"apikey", Value(CANARY_APIKEY)},
|
|
428
|
+
{"system", vmap({{"fetch", Value(fetch)}})},
|
|
429
|
+
});
|
|
430
|
+
auto plain = std::make_shared<${ProjectName}SDK>(opts);
|
|
431
|
+
for (size_t i = 0; i < cands.size(); i++) {
|
|
432
|
+
Value filled = vmap();
|
|
433
|
+
for (const auto& p : cands[i].params) map_put(filled, p, Value("p1"));
|
|
434
|
+
for (const Value& match : {vmap(), filled}) {
|
|
435
|
+
try {
|
|
436
|
+
cands[i].run(*plain, Struct::clone(match), vmap());
|
|
437
|
+
return {static_cast<int>(i), match};
|
|
438
|
+
} catch (const SdkErrorPtr&) {
|
|
439
|
+
continue;
|
|
440
|
+
} catch (const std::exception&) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {-1, Value::undef()};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
static const char* NOTHING_TO_SWEEP =
|
|
450
|
+
"SKIP: no operation of this SDK completes against a plain 200; nothing to sweep";
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
static SdkErrorPtr drive(${ProjectName}SDK& sdk, const Candidate& cand, const Target& target,
|
|
454
|
+
const Value& ctrl, std::vector<Sink>& sinks) {
|
|
455
|
+
// A caller may keep the record it passed rather than read ctrl.explain.
|
|
456
|
+
Value held = getp(ctrl, "explain");
|
|
457
|
+
SdkErrorPtr err;
|
|
458
|
+
Value out = Value::undef();
|
|
459
|
+
bool got = false;
|
|
460
|
+
try {
|
|
461
|
+
out = cand.run(sdk, Struct::clone(target.match), ctrl);
|
|
462
|
+
got = true;
|
|
463
|
+
} catch (const SdkErrorPtr& e) {
|
|
464
|
+
err = e;
|
|
465
|
+
} catch (const std::exception& e) {
|
|
466
|
+
// Escaped the pipeline raw: swept as it is.
|
|
467
|
+
err = std::make_shared<SdkError>("escaped", e.what(), nullptr);
|
|
468
|
+
}
|
|
469
|
+
if (err) addError(sinks, "error", err);
|
|
470
|
+
if (got) addForms(sinks, "result", out);
|
|
471
|
+
Value explain = getp(ctrl, "explain");
|
|
472
|
+
if (explain.is_map()) addForms(sinks, "explain", explain);
|
|
473
|
+
if (held.is_map() && (!explain.is_map() || held.as_map() != explain.as_map())) {
|
|
474
|
+
addForms(sinks, "explain:held", held);
|
|
475
|
+
}
|
|
476
|
+
return err;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
struct Variant {
|
|
481
|
+
std::string name;
|
|
482
|
+
std::function<Value()> ctrl;
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
static std::vector<Variant> variants() {
|
|
487
|
+
return {
|
|
488
|
+
{"throw", []() { return vmap(); }},
|
|
489
|
+
{"explain", []() { return vmap({{"explain", vmap()}}); }},
|
|
490
|
+
{"nothrow", []() { return vmap({{"throw", Value(false)}, {"explain", vmap()}}); }},
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
static void no_credential_leaves_the_sdk() {
|
|
496
|
+
std::vector<Candidate> cands = candidates();
|
|
497
|
+
Target target = usableOp(cands);
|
|
498
|
+
if (0 > target.index) {
|
|
499
|
+
std::cout << NOTHING_TO_SWEEP << std::endl;
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const Candidate& cand = cands[target.index];
|
|
503
|
+
|
|
504
|
+
std::vector<Sink> sinks;
|
|
505
|
+
std::map<std::string, SdkErrorPtr> errors;
|
|
506
|
+
std::map<std::string, Value> explains;
|
|
507
|
+
|
|
508
|
+
for (const Scenario& scenario : scenarios()) {
|
|
509
|
+
for (const Variant& variant : variants()) {
|
|
510
|
+
auto sdk = makeSdk(scenario, &sinks, Value::undef());
|
|
511
|
+
Value ctrl = variant.ctrl();
|
|
512
|
+
SdkErrorPtr err = drive(*sdk, cand, target, ctrl, sinks);
|
|
513
|
+
std::string key = scenario.name + "/" + variant.name;
|
|
514
|
+
if (err) errors[key] = err;
|
|
515
|
+
Value explain = getp(ctrl, "explain");
|
|
516
|
+
if (explain.is_map()) explains[key] = explain;
|
|
517
|
+
sinks.push_back({"sdk:string", sdk->to_string()});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// A credential mistyped as a map is rejected by validation, whose message
|
|
522
|
+
// quotes the value it rejected.
|
|
523
|
+
SdkErrorPtr rejected;
|
|
524
|
+
try {
|
|
525
|
+
std::make_shared<${ProjectName}SDK>(vmap({
|
|
526
|
+
{"apikey", vmap({{"value", Value(CANARY_APIKEY)}})},
|
|
527
|
+
{"clean", vmap({{"values", Value(CANARY_VALUE)}})},
|
|
528
|
+
}));
|
|
529
|
+
} catch (const SdkErrorPtr& e) {
|
|
530
|
+
rejected = e;
|
|
531
|
+
}
|
|
532
|
+
ASSERT_TRUE((bool)rejected, "a credential mistyped as a map should be rejected");
|
|
533
|
+
if (rejected) addError(sinks, "rejected", rejected);
|
|
534
|
+
|
|
535
|
+
// An exception a feature hook throws, quoting the request, skips makeError;
|
|
536
|
+
// the variant throws again from PreUnexpected. Both run with explain on.
|
|
537
|
+
for (bool unexpected : {false, true}) {
|
|
538
|
+
auto hooked = makeSdk(scenarios()[0], &sinks, Value::undef(), std::make_shared<ThrowFeature>(unexpected));
|
|
539
|
+
SdkErrorPtr hookerr = drive(*hooked, cand, target, vmap({{"explain", vmap()}}), sinks);
|
|
540
|
+
ASSERT_TRUE((bool)hookerr, "the throwing hook should fail the operation");
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// A feature's own error keeps its code, which is cleaned like the message:
|
|
544
|
+
// returned, handed to a hook, thrown by a hook, and cleaned by cleanError.
|
|
545
|
+
auto denier = makeSdk(scenarios()[0], &sinks, Value::undef(), std::make_shared<DenyFeature>(&sinks));
|
|
546
|
+
SdkErrorPtr denied = drive(*denier, cand, target, vmap(), sinks);
|
|
547
|
+
ASSERT_TRUE((bool)denied, "the refusing hook should fail the operation");
|
|
548
|
+
auto raiser = makeSdk(scenarios()[0], &sinks, Value::undef(), std::make_shared<RaiseFeature>());
|
|
549
|
+
SdkErrorPtr raised = drive(*raiser, cand, target, vmap(), sinks);
|
|
550
|
+
ASSERT_TRUE((bool)raised, "the raising hook should fail the operation");
|
|
551
|
+
auto stepped = std::make_shared<SdkError>("stepped:" + CANARY_VALUE, "stepped", nullptr);
|
|
552
|
+
util::cleanError(denier->getRootCtx(), stepped);
|
|
553
|
+
addError(sinks, "stepped", stepped);
|
|
554
|
+
|
|
555
|
+
// Consuming a stream runs inside the same catch path as the operation, and
|
|
556
|
+
// the explain record the caller passed is cleaned however the stream ends.
|
|
557
|
+
const std::vector<std::pair<std::string, FeaturePtr>> streams = {
|
|
558
|
+
{"stream", std::make_shared<StreamThrowFeature>()},
|
|
559
|
+
{"stream-ok", std::make_shared<StreamOkFeature>()},
|
|
560
|
+
{"stream-plain", nullptr},
|
|
561
|
+
};
|
|
562
|
+
for (const auto& [name, extra] : streams) {
|
|
563
|
+
auto streamed = makeSdk(scenarios()[0], &sinks, Value::undef(), extra);
|
|
564
|
+
Value explain = vmap();
|
|
565
|
+
Value callopts = vmap({{"ctrl", vmap({{"explain", explain}})}});
|
|
566
|
+
bool streamraised = false;
|
|
567
|
+
try {
|
|
568
|
+
for (const Value& item : cand.stream(*streamed, Struct::clone(target.match), callopts)) (void)item;
|
|
569
|
+
} catch (const SdkErrorPtr& e) {
|
|
570
|
+
streamraised = true;
|
|
571
|
+
addError(sinks, name, e);
|
|
572
|
+
} catch (const std::exception& e) {
|
|
573
|
+
streamraised = true;
|
|
574
|
+
sinks.push_back({name + ":what", std::string(e.what())});
|
|
575
|
+
}
|
|
576
|
+
ASSERT_TRUE(("stream" == name) == streamraised, name + ": only the failing stream throws");
|
|
577
|
+
ASSERT_TRUE(0 < explain.as_map()->size(), name + ": the explain record was not filled");
|
|
578
|
+
addForms(sinks, name + ":explain", explain);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// A client given no clean block at all masks by the schema defaults.
|
|
582
|
+
Scenario notfoundsc = scenarios()[1];
|
|
583
|
+
vs::Injector barefetch = [notfoundsc](vs::Injection&, const Value& args, const std::string&,
|
|
584
|
+
const Value&) -> Value {
|
|
585
|
+
Value url = vs::getelem(args, Value(int64_t(0)));
|
|
586
|
+
return notfoundsc.respond(url.is_string() ? url.as_string() : "", vs::getelem(args, Value(int64_t(1))));
|
|
587
|
+
};
|
|
588
|
+
auto bare = std::make_shared<${ProjectName}SDK>(vmap({
|
|
589
|
+
{"apikey", Value(CANARY_APIKEY)},
|
|
590
|
+
{"secret", Value(CANARY_SECRET)},
|
|
591
|
+
{"headers", vmap({{"X-Custom-Token", Value(CANARY_HEADER)}})},
|
|
592
|
+
{"system", vmap({{"fetch", Value(barefetch)}})},
|
|
593
|
+
}));
|
|
594
|
+
SdkErrorPtr barerr = drive(*bare, cand, target, vmap(), sinks);
|
|
595
|
+
ASSERT_TRUE((bool)barerr, "the 404 scenario must throw without a clean block");
|
|
596
|
+
|
|
597
|
+
// The raw path returns its failure rather than throwing it.
|
|
598
|
+
Value direct = makeSdk(scenarios()[3], &sinks, Value::undef())->direct(vmap({{"path", Value("raw")}}));
|
|
599
|
+
ASSERT_TRUE(is_false(getp(direct, "ok")), "a transport failure should fail direct()");
|
|
600
|
+
addForms(sinks, "direct", direct);
|
|
601
|
+
|
|
602
|
+
std::string leaked;
|
|
603
|
+
int leakcount = 0;
|
|
604
|
+
for (const Sink& s : sinks) {
|
|
605
|
+
std::vector<std::string> found = leaks(s.text);
|
|
606
|
+
if (found.empty()) continue;
|
|
607
|
+
leakcount++;
|
|
608
|
+
if (!leaked.empty()) leaked += "; ";
|
|
609
|
+
leaked += s.name + " [";
|
|
610
|
+
for (size_t i = 0; i < found.size(); i++) leaked += (0 < i ? ", " : "") + found[i];
|
|
611
|
+
leaked += "]";
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
std::cout << "clean: swept " << sinks.size() << " surface(s), " << leakcount << " leak(s)"
|
|
615
|
+
<< std::endl;
|
|
616
|
+
|
|
617
|
+
ASSERT_EQ(leakcount, 0, "credential leaked through: " + leaked);
|
|
618
|
+
|
|
619
|
+
// The positive half: the slot the credential travelled in is masked, and
|
|
620
|
+
// an unregistered token in a response header is masked by name.
|
|
621
|
+
auto nf = errors.find("notfound/throw");
|
|
622
|
+
ASSERT_TRUE(errors.end() != nf, "the 404 scenario must throw");
|
|
623
|
+
if (errors.end() != nf) {
|
|
624
|
+
SdkErrorPtr notfound = nf->second;
|
|
625
|
+
ASSERT_EQ(notfound->status, 404, "the 404 scenario reports its status");
|
|
626
|
+
Value spec = notfound->spec;
|
|
627
|
+
if (!AUTH_SUPPRESSED) {
|
|
628
|
+
if ("query" == AUTH_WHERE) {
|
|
629
|
+
ASSERT_EQ_VAL(header(getp(spec, "query"), AUTH_NAME), Value(MASK), "query credential masked");
|
|
630
|
+
} else if ("cookie" == AUTH_WHERE) {
|
|
631
|
+
std::string cookie = Struct::stringify(header(getp(spec, "headers"), "cookie"));
|
|
632
|
+
ASSERT_TRUE(std::string::npos != cookie.find(MASK), "cookie: " + cookie);
|
|
633
|
+
} else {
|
|
634
|
+
std::string cred = Struct::stringify(header(getp(spec, "headers"), AUTH_NAME));
|
|
635
|
+
ASSERT_TRUE(endsWith(cred, MASK), AUTH_NAME + ": " + cred);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
ASSERT_EQ_VAL(header(getp(spec, "headers"), "x-custom-token"), Value(MASK),
|
|
639
|
+
"custom token header masked");
|
|
640
|
+
}
|
|
641
|
+
if (denied) ASSERT_TRUE(denied->code == "denied:" + MASK, "refusal code: " + denied->code);
|
|
642
|
+
if (raised) ASSERT_TRUE(raised->code == "raised:" + MASK, "raised code: " + raised->code);
|
|
643
|
+
ASSERT_TRUE(stepped->code == "stepped:" + MASK, "stepped code: " + stepped->code);
|
|
644
|
+
if (barerr) {
|
|
645
|
+
ASSERT_EQ_VAL(header(getp(barerr->spec, "headers"), "x-custom-token"), Value(MASK),
|
|
646
|
+
"no clean block: custom token header masked");
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
auto ex = explains.find("ok/explain");
|
|
650
|
+
Value result = explains.end() == ex ? Value::undef() : getp(ex->second, "result");
|
|
651
|
+
ASSERT_TRUE(result.is_map(), "the explain record should carry the result");
|
|
652
|
+
ASSERT_EQ_VAL(header(getp(result, "headers"), "x-session-token"), Value(MASK),
|
|
653
|
+
"response token header masked");
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
static void the_sweep_can_see_a_leak() {
|
|
658
|
+
std::vector<Candidate> cands = candidates();
|
|
659
|
+
Target target = usableOp(cands);
|
|
660
|
+
if (0 > target.index) {
|
|
661
|
+
std::cout << NOTHING_TO_SWEEP << std::endl;
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
std::vector<Sink> sinks;
|
|
666
|
+
auto sdk = makeSdk(scenarios()[1], &sinks, vmap({{"active", Value(false)}}));
|
|
667
|
+
SdkErrorPtr err = drive(*sdk, cands[target.index], target, vmap(), sinks);
|
|
668
|
+
ASSERT_TRUE((bool)err, "the 404 scenario must throw");
|
|
669
|
+
if (!err) return;
|
|
670
|
+
|
|
671
|
+
int leaked = 0;
|
|
672
|
+
for (const Sink& s : sinks) {
|
|
673
|
+
if (!leaks(s.text).empty()) leaked++;
|
|
674
|
+
}
|
|
675
|
+
ASSERT_TRUE(0 < leaked, "with clean off, nothing showed the canary: the sweep is blind");
|
|
676
|
+
|
|
677
|
+
if (!AUTH_SUPPRESSED) {
|
|
678
|
+
std::string text = vs::jsonify(err->spec, 0);
|
|
679
|
+
ASSERT_TRUE(std::string::npos != text.find(CANARY_APIKEY) ||
|
|
680
|
+
std::string::npos != text.find(util::cleanBase64(CANARY_APIKEY + ":" + CANARY_SECRET)),
|
|
681
|
+
"the raw spec should carry the credential when clean is off");
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Explaining a failure must not cost it its error.
|
|
685
|
+
std::vector<Sink> quiet;
|
|
686
|
+
auto explainer = makeSdk(scenarios()[1], &quiet, vmap({{"active", Value(false)}}));
|
|
687
|
+
SdkErrorPtr explained = drive(*explainer, cands[target.index], target,
|
|
688
|
+
vmap({{"explain", vmap()}}), quiet);
|
|
689
|
+
ASSERT_TRUE(explained && explained->msg == err->msg,
|
|
690
|
+
"with clean off, explain lost the error: " + (explained ? explained->msg : "<none>"));
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
// A registered value used as a property name is masked; names that mask
|
|
695
|
+
// alike are all kept.
|
|
696
|
+
static void a_registered_value_used_as_a_name_is_masked() {
|
|
697
|
+
auto sdk = std::make_shared<${ProjectName}SDK>(vmap({
|
|
698
|
+
{"clean", vmap({{"values", Value("ZZVAL-abc123,ZZVAL-xyz789")}})},
|
|
699
|
+
}));
|
|
700
|
+
Value out = util::clean(sdk->getRootCtx(), vmap({
|
|
701
|
+
{"ZZVAL-abc123", Value(1)}, {"ZZVAL-xyz789", Value(2)}, {"plain", Value(3)},
|
|
702
|
+
}));
|
|
703
|
+
std::vector<std::string> keys;
|
|
704
|
+
for (const auto& kv : *out.as_map()) keys.push_back(kv.first);
|
|
705
|
+
ASSERT_TRUE((keys == std::vector<std::string>{MASK, MASK + "#1", "plain"}),
|
|
706
|
+
"masked names: " + Struct::stringify(out));
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
// The generated config's own clean block is honoured, and left unchanged.
|
|
711
|
+
static void the_generated_configs_own_clean_block_is_honoured() {
|
|
712
|
+
auto client = std::make_shared<${ProjectName}SDK>(vmap());
|
|
713
|
+
UtilityPtr utility = client->getUtility();
|
|
714
|
+
Value config = vmap({{"options", vmap({{"clean", vmap({
|
|
715
|
+
{"keys", Value("zzsens")}, {"values", Value("CONFIG-SEEDED-1")},
|
|
716
|
+
})}})}});
|
|
717
|
+
CtxSpec cs;
|
|
718
|
+
cs.utility = utility;
|
|
719
|
+
cs.options = vmap({{"clean", vmap({{"values", Value("CALLER-SEEDED-2")}})}});
|
|
720
|
+
cs.config = config;
|
|
721
|
+
CtxPtr ctx = utility->makeContext(cs, nullptr);
|
|
722
|
+
ctx->options = utility->makeOptions(ctx);
|
|
723
|
+
ASSERT_EQ_VAL(util::clean(ctx, Value("a CONFIG-SEEDED-1 b CALLER-SEEDED-2")),
|
|
724
|
+
Value("a " + MASK + " b " + MASK), "both seeded values are masked");
|
|
725
|
+
Value out = util::clean(ctx, vmap({{"my_zzsens", Value("x")}, {"other", Value("y")}}));
|
|
726
|
+
ASSERT_EQ_VAL(getp(out, "my_zzsens"), Value(MASK), "the config's key name is sensitive");
|
|
727
|
+
ASSERT_EQ_VAL(getp(out, "other"), Value("y"), "an ordinary name is kept");
|
|
728
|
+
ASSERT_EQ_VAL(Struct::getpath(config, {"options", "clean", "keys"}), Value("zzsens"),
|
|
729
|
+
"the config's keys are left alone");
|
|
730
|
+
ASSERT_EQ_VAL(Struct::getpath(config, {"options", "clean", "values"}), Value("CONFIG-SEEDED-1"),
|
|
731
|
+
"the config's values are left alone");
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
// A feature's name is not a field name: a feature called secrets does not
|
|
736
|
+
// make its settings secret, though a sensitive field inside it still is. An
|
|
737
|
+
// entity block, of per-entity settings or seeded records keyed by entity name
|
|
738
|
+
// and id, is not read at all.
|
|
739
|
+
static void a_feature_name_is_read_as_a_name() {
|
|
740
|
+
auto client = std::make_shared<${ProjectName}SDK>(vmap({
|
|
741
|
+
{"apikey", Value(CANARY_APIKEY)},
|
|
742
|
+
{"feature", vmap({
|
|
743
|
+
{"secrets", vmap({
|
|
744
|
+
{"active", Value(false)}, {"name", Value("ZZNAME-feat123")}, {"token", Value("ZZTOKEN-feat456")},
|
|
745
|
+
})},
|
|
746
|
+
{"test", vmap({
|
|
747
|
+
{"active", Value(false)},
|
|
748
|
+
{"entity", vmap({{"zztoken", vmap({{"ZZTOKEN01", vmap({{"note", Value("PLAINRECORD-t5r3e1w9")}})}})}})},
|
|
749
|
+
})},
|
|
750
|
+
})},
|
|
751
|
+
{"entity", vmap({{"zztoken", vmap({{"alias", vmap({{"zzkey", Value("PLAINALIAS-m2n4b6v8")}})}})}})},
|
|
752
|
+
}));
|
|
753
|
+
CtxPtr ctx = client->getRootCtx();
|
|
754
|
+
ASSERT_EQ_VAL(util::clean(ctx, Value("ZZNAME-feat123 ZZTOKEN-feat456")),
|
|
755
|
+
Value("ZZNAME-feat123 " + MASK), "only the sensitive field is registered");
|
|
756
|
+
ASSERT_EQ_VAL(util::clean(ctx, Value("record PLAINRECORD-t5r3e1w9")),
|
|
757
|
+
Value("record PLAINRECORD-t5r3e1w9"), "a record seeded under an entity block is not registered");
|
|
758
|
+
ASSERT_EQ_VAL(util::clean(ctx, Value("alias PLAINALIAS-m2n4b6v8")),
|
|
759
|
+
Value("alias PLAINALIAS-m2n4b6v8"), "an entity's own settings are not registered");
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
int main() {
|
|
764
|
+
T_RUN(no_credential_leaves_the_sdk);
|
|
765
|
+
T_RUN(the_sweep_can_see_a_leak);
|
|
766
|
+
T_RUN(a_registered_value_used_as_a_name_is_masked);
|
|
767
|
+
T_RUN(the_generated_configs_own_clean_block_is_honoured);
|
|
768
|
+
T_RUN(a_feature_name_is_read_as_a_name);
|
|
769
|
+
return sdktest::summary("clean_test");
|
|
770
|
+
}
|
|
771
|
+
`
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
function cppstr(s: string): string {
|
|
776
|
+
return '"' + String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
export {
|
|
781
|
+
TestClean
|
|
782
|
+
}
|