@voxgig/sdkgen 4.32.1 → 4.34.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/copies.d.ts +21 -0
- package/dist/action/copies.js +146 -0
- package/dist/action/copies.js.map +1 -0
- package/dist/action/doctor.d.ts +15 -2
- package/dist/action/doctor.js +169 -23
- package/dist/action/doctor.js.map +1 -1
- package/dist/action/edition.js +6 -2
- package/dist/action/edition.js.map +1 -1
- package/dist/action/feature.js +6 -2
- package/dist/action/feature.js.map +1 -1
- package/dist/action/package.js +28 -10
- package/dist/action/package.js.map +1 -1
- package/dist/action/remove.js +2 -0
- package/dist/action/remove.js.map +1 -1
- package/dist/action/resolve.d.ts +1 -0
- package/dist/action/resolve.js +10 -2
- package/dist/action/resolve.js.map +1 -1
- package/dist/action/target.js +6 -2
- package/dist/action/target.js.map +1 -1
- package/dist/helpers/naming.js +1 -1
- package/dist/helpers/naming.js.map +1 -1
- package/dist/sdkgen.d.ts +2 -1
- package/dist/sdkgen.js +36 -3
- package/dist/sdkgen.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/action/copies.ts +219 -0
- package/src/action/doctor.ts +247 -21
- package/src/action/edition.ts +10 -2
- package/src/action/feature.ts +11 -2
- package/src/action/package.ts +31 -10
- package/src/action/remove.ts +4 -0
- package/src/action/resolve.ts +16 -3
- package/src/action/target.ts +10 -2
- package/src/helpers/naming.ts +1 -1
- package/src/sdkgen.ts +45 -5
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ModelEntity
|
|
3
|
+
} from '@voxgig/apidef'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
cmp,
|
|
7
|
+
configDefinition,
|
|
8
|
+
each,
|
|
9
|
+
File,
|
|
10
|
+
Content,
|
|
11
|
+
entityCollection,
|
|
12
|
+
targetFeatures,
|
|
13
|
+
isAuthSuppressed,
|
|
14
|
+
isHttpBasicAuth,
|
|
15
|
+
resolveAuthIn,
|
|
16
|
+
resolveAuthName,
|
|
17
|
+
} from '@voxgig/sdkgen'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import { cIdent, cVarName } from './utility_c'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
// A custom action is not a vtable slot the sweep can call by name.
|
|
24
|
+
const CRUD = ['list', 'load', 'create', 'update', 'remove']
|
|
25
|
+
|
|
26
|
+
const DIAGNOSTIC = ['log', 'debug', 'audit', 'telemetry', 'cost', 'metrics', 'clienttrack']
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
// The canary sweep (twin of TestClean_ts). C is statically typed, so the
|
|
30
|
+
// operation candidates the ts sweep finds by reflection are enumerated here
|
|
31
|
+
// at generation time, each with the path parameters its config points
|
|
32
|
+
// declare; the sweep still DRIVES them to find the first that completes.
|
|
33
|
+
const TestClean = cmp(function TestClean(props: any) {
|
|
34
|
+
const { model } = props.ctx$
|
|
35
|
+
const { target } = props
|
|
36
|
+
|
|
37
|
+
const Name = model.const.Name
|
|
38
|
+
const ident = cIdent(model)
|
|
39
|
+
|
|
40
|
+
const auth = {
|
|
41
|
+
suppressed: isAuthSuppressed(model),
|
|
42
|
+
where: resolveAuthIn(model),
|
|
43
|
+
name: 'header' === resolveAuthIn(model)
|
|
44
|
+
? resolveAuthName(model).toLowerCase() : resolveAuthName(model),
|
|
45
|
+
basic: isHttpBasicAuth(model),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const features = Object.keys(targetFeatures(model, target))
|
|
49
|
+
.filter((name) => DIAGNOSTIC.includes(name))
|
|
50
|
+
.sort()
|
|
51
|
+
|
|
52
|
+
const configEntity = configDefinition(model, target.name).def.entity || {}
|
|
53
|
+
|
|
54
|
+
const candidates: Candidate[] = []
|
|
55
|
+
const entities = each(entityCollection(model)).filter((e: any) => false !== e.active)
|
|
56
|
+
each(entities, (entity: ModelEntity) => {
|
|
57
|
+
const evar = cVarName(entity.name)
|
|
58
|
+
const ops = Object.keys((entity as any).op || {})
|
|
59
|
+
.filter((op) => CRUD.includes(op))
|
|
60
|
+
.sort((a, b) => CRUD.indexOf(a) - CRUD.indexOf(b))
|
|
61
|
+
for (const op of ops) {
|
|
62
|
+
candidates.push({
|
|
63
|
+
name: entity.name + '.' + op, fn: 'drive_' + evar + '_' + op, evar, op,
|
|
64
|
+
params: pointParams(configEntity[entity.name]?.op?.[op]),
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
File({ name: 'clean_test.c' }, () => {
|
|
70
|
+
Content(render({ Name, ident, auth, features, candidates }))
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
type Candidate = { name: string, fn: string, evar: string, op: string, params: string[] }
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// Every path parameter an operation's points declare, as the generated
|
|
79
|
+
// config carries them (points[].args.params[].name).
|
|
80
|
+
function pointParams(opdef: any): string[] {
|
|
81
|
+
const names: string[] = []
|
|
82
|
+
for (const point of opdef?.points || []) {
|
|
83
|
+
for (const p of point?.args?.params || []) {
|
|
84
|
+
if ('string' === typeof p?.name && !names.includes(p.name)) names.push(p.name)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return names
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
function render(spec: {
|
|
92
|
+
Name: string,
|
|
93
|
+
ident: string,
|
|
94
|
+
auth: { suppressed: boolean, where: string, name: string, basic: boolean },
|
|
95
|
+
features: string[],
|
|
96
|
+
candidates: Candidate[],
|
|
97
|
+
}): string {
|
|
98
|
+
const { Name, ident, auth, features, candidates } = spec
|
|
99
|
+
|
|
100
|
+
const drivers = candidates.map((c) => 'list' === c.op
|
|
101
|
+
? `static PNError* ${c.fn}(${Name}SDK* sdk, voxgig_value* mtch, voxgig_value* ctrl, voxgig_value** out) {
|
|
102
|
+
PNError* err = NULL;
|
|
103
|
+
Entity* e = ${ident}_${c.evar}(sdk, NULL);
|
|
104
|
+
Entity** items = e->vt->list(e, mtch, ctrl, &err);
|
|
105
|
+
if (err) return err;
|
|
106
|
+
voxgig_value* list = v_list();
|
|
107
|
+
for (size_t i = 0; items && items[i]; i++) {
|
|
108
|
+
voxgig_list_push(voxgig_as_list(list), items[i]->vt->data(items[i], NULL));
|
|
109
|
+
}
|
|
110
|
+
*out = list;
|
|
111
|
+
return NULL;
|
|
112
|
+
}
|
|
113
|
+
`
|
|
114
|
+
: `static PNError* ${c.fn}(${Name}SDK* sdk, voxgig_value* mtch, voxgig_value* ctrl, voxgig_value** out) {
|
|
115
|
+
PNError* err = NULL;
|
|
116
|
+
Entity* e = ${ident}_${c.evar}(sdk, NULL);
|
|
117
|
+
Entity* r = e->vt->${c.op}(e, mtch, ctrl, &err);
|
|
118
|
+
if (err) return err;
|
|
119
|
+
*out = r ? r->vt->data(r, NULL) : v_undef();
|
|
120
|
+
return NULL;
|
|
121
|
+
}
|
|
122
|
+
`).join('\n') + '\n' + candidates.map((c) =>
|
|
123
|
+
`static voxgig_value* ${c.fn}_stream(${Name}SDK* sdk, voxgig_value* mtch, voxgig_value* callopts, PNError** err) {
|
|
124
|
+
return ${c.evar}_stream(${ident}_${c.evar}(sdk, NULL), "${c.op}", mtch, callopts, err);
|
|
125
|
+
}
|
|
126
|
+
`).join('\n')
|
|
127
|
+
|
|
128
|
+
const table = candidates.map((c) => ` { "${c.name}", ${c.fn}, ${c.fn}_stream, { ${
|
|
129
|
+
c.params.map((p) => '"' + cstr(p) + '", ').join('')}NULL } },`).join('\n')
|
|
130
|
+
|
|
131
|
+
return `// Generated canary sweep (see TestClean_c): no credential leaves the SDK
|
|
132
|
+
// in any form, and the sweep can see one when clean is switched off.
|
|
133
|
+
|
|
134
|
+
#include "ctest.h"
|
|
135
|
+
|
|
136
|
+
#include <ctype.h>
|
|
137
|
+
#include <stdint.h>
|
|
138
|
+
#include <stdio.h>
|
|
139
|
+
#include <stdlib.h>
|
|
140
|
+
#include <string.h>
|
|
141
|
+
#include <strings.h>
|
|
142
|
+
|
|
143
|
+
// Generated: the credential's wire placement is fixed when the SDK is built.
|
|
144
|
+
static const bool AUTH_SUPPRESSED = ${auth.suppressed};
|
|
145
|
+
static const char* AUTH_WHERE = "${cstr(auth.where)}";
|
|
146
|
+
static const char* AUTH_NAME = "${cstr(auth.name)}";
|
|
147
|
+
|
|
148
|
+
// The diagnostic features this SDK ships.
|
|
149
|
+
static const char* FEATURES[] = { ${features.map((f) => '"' + f + '"').join(', ')}${0 < features.length ? ', ' : ''}NULL };
|
|
150
|
+
|
|
151
|
+
static const char* CANARY_APIKEY = "CANARY-APIKEY-k9x2m7q4p1";
|
|
152
|
+
static const char* CANARY_SECRET = "CANARY-SECRET-w3e8r5t2y6";
|
|
153
|
+
static const char* CANARY_HEADER = "CANARY-HEADER-z1x4c7v0b3";
|
|
154
|
+
static const char* CANARY_VALUE = "CANARY-VALUE-n5m8b2v9c4";
|
|
155
|
+
|
|
156
|
+
static const char* MASK = "[redacted]";
|
|
157
|
+
|
|
158
|
+
// The sweep's own encoders: a leak of an encoded form must not hide behind
|
|
159
|
+
// the SDK's encoder.
|
|
160
|
+
static char* b64(const char* in) {
|
|
161
|
+
static const char ALPHABET[] =
|
|
162
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
163
|
+
size_t n = strlen(in);
|
|
164
|
+
char* out = (char*)malloc((n + 2) / 3 * 4 + 1);
|
|
165
|
+
size_t o = 0;
|
|
166
|
+
for (size_t i = 0; i < n; i += 3) {
|
|
167
|
+
unsigned int v = (unsigned char)in[i] << 16;
|
|
168
|
+
if (i + 1 < n) v |= (unsigned int)(unsigned char)in[i + 1] << 8;
|
|
169
|
+
if (i + 2 < n) v |= (unsigned int)(unsigned char)in[i + 2];
|
|
170
|
+
out[o++] = ALPHABET[(v >> 18) & 0x3f];
|
|
171
|
+
out[o++] = ALPHABET[(v >> 12) & 0x3f];
|
|
172
|
+
out[o++] = (i + 1 < n) ? ALPHABET[(v >> 6) & 0x3f] : '=';
|
|
173
|
+
out[o++] = (i + 2 < n) ? ALPHABET[v & 0x3f] : '=';
|
|
174
|
+
}
|
|
175
|
+
out[o] = '\\0';
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static char* pct(const char* in) {
|
|
180
|
+
size_t n = strlen(in);
|
|
181
|
+
char* out = (char*)malloc(n * 3 + 1);
|
|
182
|
+
size_t o = 0;
|
|
183
|
+
for (size_t i = 0; i < n; i++) {
|
|
184
|
+
unsigned char c = (unsigned char)in[i];
|
|
185
|
+
if (isalnum(c) || strchr("-_.!~*'()", c)) {
|
|
186
|
+
out[o++] = (char)c;
|
|
187
|
+
} else {
|
|
188
|
+
o += (size_t)sprintf(out + o, "%%%02X", c);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
out[o] = '\\0';
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Every form a canary can travel in.
|
|
196
|
+
static const char* FORMS[16];
|
|
197
|
+
static size_t NFORMS = 0;
|
|
198
|
+
|
|
199
|
+
static void build_forms(void) {
|
|
200
|
+
const char* canaries[4] = { CANARY_APIKEY, CANARY_SECRET, CANARY_HEADER, CANARY_VALUE };
|
|
201
|
+
for (int i = 0; i < 4; i++) {
|
|
202
|
+
FORMS[NFORMS++] = canaries[i];
|
|
203
|
+
FORMS[NFORMS++] = b64(canaries[i]);
|
|
204
|
+
FORMS[NFORMS++] = pct(canaries[i]);
|
|
205
|
+
}
|
|
206
|
+
char pair[256];
|
|
207
|
+
snprintf(pair, sizeof(pair), "%s:%s", CANARY_APIKEY, CANARY_SECRET);
|
|
208
|
+
FORMS[NFORMS++] = b64(pair);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
typedef struct {
|
|
212
|
+
const char* name;
|
|
213
|
+
char* text;
|
|
214
|
+
} Sink;
|
|
215
|
+
|
|
216
|
+
static Sink* SINKS = NULL;
|
|
217
|
+
static size_t NSINKS = 0;
|
|
218
|
+
static size_t CAPSINKS = 0;
|
|
219
|
+
|
|
220
|
+
static void push(const char* name, char* text) {
|
|
221
|
+
if (NSINKS == CAPSINKS) {
|
|
222
|
+
CAPSINKS = CAPSINKS ? CAPSINKS * 2 : 64;
|
|
223
|
+
SINKS = (Sink*)realloc(SINKS, CAPSINKS * sizeof(Sink));
|
|
224
|
+
}
|
|
225
|
+
SINKS[NSINKS].name = name;
|
|
226
|
+
SINKS[NSINKS].text = text ? text : strdup("");
|
|
227
|
+
NSINKS++;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static void push_value(const char* name, voxgig_value* val) {
|
|
231
|
+
push(name, voxgig_jsonify(val, NULL));
|
|
232
|
+
push(name, voxgig_stringify(val, -1));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
static void push_error(const char* name, PNError* err) {
|
|
236
|
+
push(name, strdup(err->msg ? err->msg : ""));
|
|
237
|
+
push(name, pn_error_str(err));
|
|
238
|
+
push(name, voxgig_jsonify(err->spec, NULL));
|
|
239
|
+
push(name, voxgig_jsonify(err->result, NULL));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
static voxgig_value* capture_fn(void* ud, voxgig_value* arg) {
|
|
243
|
+
push_value((const char*)ud, arg);
|
|
244
|
+
return v_undef();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Captures the serialised context from inside the pipeline: what a hook
|
|
248
|
+
// author would hand to a logger.
|
|
249
|
+
typedef struct {
|
|
250
|
+
Feature base;
|
|
251
|
+
} CaptureFeature;
|
|
252
|
+
|
|
253
|
+
static const char* capture_name(Feature* f) { (void)f; return "capture"; }
|
|
254
|
+
static bool capture_active(Feature* f) { (void)f; return true; }
|
|
255
|
+
static voxgig_value* capture_add_options(Feature* f) { (void)f; return NULL; }
|
|
256
|
+
static void capture_init(Feature* f, Context* ctx, voxgig_value* options) {
|
|
257
|
+
(void)f; (void)ctx; (void)options;
|
|
258
|
+
}
|
|
259
|
+
static void capture_hook(Feature* f, const char* name, Context* ctx) {
|
|
260
|
+
(void)f;
|
|
261
|
+
if (0 == strcmp(name, "PreRequest") || 0 == strcmp(name, "PreResponse") ||
|
|
262
|
+
0 == strcmp(name, "PreUnexpected")) {
|
|
263
|
+
push("ctx", context_str(ctx));
|
|
264
|
+
push_value("ctx", context_to_value(ctx));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
static const FeatureVT CAPTURE_VT = {
|
|
269
|
+
capture_name, capture_active, capture_add_options, capture_init, capture_hook, NULL,
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// A feature that fails the operation from inside the pipeline, quoting the
|
|
273
|
+
// request it saw. A C hook has no error return, so it fails the result: an
|
|
274
|
+
// error make_error receives from a hook, not from the pipeline. For the same
|
|
275
|
+
// reason there is no variant failing in PreUnexpected: make_error has built
|
|
276
|
+
// and cleaned the error it returns before that hook runs.
|
|
277
|
+
static const char* throw_name(Feature* f) { (void)f; return "throwhook"; }
|
|
278
|
+
static void throw_hook(Feature* f, const char* name, Context* ctx) {
|
|
279
|
+
(void)f;
|
|
280
|
+
if (0 != strcmp(name, "PreResponse") || !ctx->result) return;
|
|
281
|
+
char* spec = voxgig_jsonify(ctx->spec ? spec_to_value(ctx->spec) : v_undef(), NULL);
|
|
282
|
+
char msg[4096];
|
|
283
|
+
snprintf(msg, sizeof(msg), "hook saw %s", spec ? spec : "");
|
|
284
|
+
ctx->result->err = context_make_error(ctx, "hook", msg);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static const FeatureVT THROW_VT = {
|
|
288
|
+
throw_name, capture_active, capture_add_options, capture_init, throw_hook, NULL,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// A feature that refuses the operation with the SDK's own error, as rbac
|
|
292
|
+
// does, whose code quotes a registered value; it records the error
|
|
293
|
+
// PreUnexpected hands a hook.
|
|
294
|
+
static const char* deny_name(Feature* f) { (void)f; return "denyhook"; }
|
|
295
|
+
static void deny_hook(Feature* f, const char* name, Context* ctx) {
|
|
296
|
+
(void)f;
|
|
297
|
+
if (0 == strcmp(name, "PrePoint")) {
|
|
298
|
+
char code[128];
|
|
299
|
+
snprintf(code, sizeof(code), "denied:%s", CANARY_VALUE);
|
|
300
|
+
ctx_out_set_point_err(ctx, context_make_error(ctx, code, "denied"));
|
|
301
|
+
} else if (0 == strcmp(name, "PreUnexpected") && ctx->ctrl && ctx->ctrl->err) {
|
|
302
|
+
push_error("error", ctx->ctrl->err);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static const FeatureVT DENY_VT = {
|
|
307
|
+
deny_name, capture_active, capture_add_options, capture_init, deny_hook, NULL,
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// A stream that succeeds, so the pipeline's terminal step never runs. A C
|
|
311
|
+
// stream producer has no error channel, so no stream fails.
|
|
312
|
+
static voxgig_value* streamok_items(void* ud) {
|
|
313
|
+
voxgig_value* data = (voxgig_value*)ud;
|
|
314
|
+
voxgig_value* out = v_list();
|
|
315
|
+
if (voxgig_is_list(data)) {
|
|
316
|
+
voxgig_list* l = voxgig_as_list(data);
|
|
317
|
+
for (size_t i = 0; i < l->len; i++) {
|
|
318
|
+
voxgig_list_push(voxgig_as_list(out), voxgig_retain(l->items[i]));
|
|
319
|
+
}
|
|
320
|
+
} else if (!v_is_noval(data) && !v_is_null(data)) {
|
|
321
|
+
voxgig_list_push(voxgig_as_list(out), voxgig_retain(data));
|
|
322
|
+
}
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static const char* streamok_name(Feature* f) { (void)f; return "streamok"; }
|
|
327
|
+
static void streamok_hook(Feature* f, const char* name, Context* ctx) {
|
|
328
|
+
(void)f;
|
|
329
|
+
if (0 != strcmp(name, "PreDone") || !ctx->result) return;
|
|
330
|
+
ctx->result->stream = streamok_items;
|
|
331
|
+
ctx->result->stream_ud = v_share(ctx->result->resdata);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
static const FeatureVT STREAMOK_VT = {
|
|
335
|
+
streamok_name, capture_active, capture_add_options, capture_init, streamok_hook, NULL,
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
enum { SC_OK = 0, SC_NOTFOUND, SC_SERVER, SC_TRANSPORT, SC_NOTJSON, SC_COUNT };
|
|
339
|
+
static const char* SC_NAMES[] = { "ok", "notfound", "server", "transport", "notjson" };
|
|
340
|
+
|
|
341
|
+
static voxgig_value* response(int status, voxgig_value* data, const char* hk, const char* hv) {
|
|
342
|
+
voxgig_value* headers = cmap(1, "content-type", v_str("application/json"));
|
|
343
|
+
if (hk) setp(headers, hk, v_str(hv));
|
|
344
|
+
return cmap(5,
|
|
345
|
+
"status", v_num((double)status),
|
|
346
|
+
"statusText", v_str(status < 400 ? "OK" : "ERR"),
|
|
347
|
+
"headers", headers,
|
|
348
|
+
"body", v_str(voxgig_jsonify(data, NULL)),
|
|
349
|
+
"json", json_thunk(data));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
static voxgig_value* respond(int sc, const char* url) {
|
|
353
|
+
switch (sc) {
|
|
354
|
+
case SC_OK:
|
|
355
|
+
return response(200, cmap(2, "id", v_str("i1"), "name", v_str("n1")),
|
|
356
|
+
"x-session-token", "RESP-TOKEN-a1b2c3d4e5");
|
|
357
|
+
case SC_NOTFOUND:
|
|
358
|
+
return response(404, cmap(1, "error", v_str("no such record")), NULL, NULL);
|
|
359
|
+
case SC_SERVER:
|
|
360
|
+
return response(500, cmap(1, "error", v_str("boom")), NULL, NULL);
|
|
361
|
+
case SC_TRANSPORT: {
|
|
362
|
+
char msg[2048];
|
|
363
|
+
snprintf(msg, sizeof(msg), "socket hang up (URL was: \\"%s\\")", url);
|
|
364
|
+
return cmap(1, "__err__", v_str(msg));
|
|
365
|
+
}
|
|
366
|
+
default:
|
|
367
|
+
return cmap(5,
|
|
368
|
+
"status", v_num(200),
|
|
369
|
+
"statusText", v_str("OK"),
|
|
370
|
+
"headers", v_map(),
|
|
371
|
+
"body", v_str("<html>"),
|
|
372
|
+
"json", json_thunk(v_undef()));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// The transport seam: system.fetch is called with [url, fetchdef].
|
|
377
|
+
static voxgig_value* transport_fn(void* ud, voxgig_value* args) {
|
|
378
|
+
int sc = (int)(intptr_t)ud;
|
|
379
|
+
const char* url = "";
|
|
380
|
+
if (voxgig_is_list(args) && 0 < voxgig_as_list(args)->len) {
|
|
381
|
+
voxgig_value* u = voxgig_as_list(args)->items[0];
|
|
382
|
+
if (voxgig_is_string(u)) url = voxgig_as_string(u);
|
|
383
|
+
}
|
|
384
|
+
return respond(sc, url);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
static ${Name}SDK* make_sdk(int sc, voxgig_value* cleanopts, Feature* extra) {
|
|
388
|
+
voxgig_value* feature = v_map();
|
|
389
|
+
for (size_t i = 0; FEATURES[i]; i++) {
|
|
390
|
+
const char* name = FEATURES[i];
|
|
391
|
+
voxgig_value* fopts = cmap(1, "active", v_bool(true));
|
|
392
|
+
if (0 == strcmp(name, "log")) setp(fopts, "logger", vfn(capture_fn, (void*)"log"));
|
|
393
|
+
else if (0 == strcmp(name, "debug")) setp(fopts, "onEntry", vfn(capture_fn, (void*)"debug"));
|
|
394
|
+
else if (0 == strcmp(name, "audit")) setp(fopts, "sink", vfn(capture_fn, (void*)"audit"));
|
|
395
|
+
else if (0 == strcmp(name, "telemetry")) setp(fopts, "exporter", vfn(capture_fn, (void*)"telemetry"));
|
|
396
|
+
else if (0 == strcmp(name, "cost")) setp(fopts, "sink", vfn(capture_fn, (void*)"cost"));
|
|
397
|
+
setp(feature, name, fopts);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
voxgig_value* clean = cmap(1, "values", v_str(CANARY_VALUE));
|
|
401
|
+
if (voxgig_is_map(cleanopts)) {
|
|
402
|
+
voxgig_map* m = voxgig_as_map(cleanopts);
|
|
403
|
+
for (size_t i = 0; i < m->len; i++) {
|
|
404
|
+
setp(clean, m->entries[i].key, voxgig_retain(m->entries[i].value));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
${Name}SDK* sdk = ${ident}_sdk_new(cmap(6,
|
|
409
|
+
"apikey", v_str(CANARY_APIKEY),
|
|
410
|
+
"secret", v_str(CANARY_SECRET),
|
|
411
|
+
"headers", cmap(1, "X-Custom-Token", v_str(CANARY_HEADER)),
|
|
412
|
+
"clean", clean,
|
|
413
|
+
"feature", feature,
|
|
414
|
+
"system", cmap(1, "fetch", vfn(transport_fn, (void*)(intptr_t)sc))));
|
|
415
|
+
|
|
416
|
+
// C options are pure data, so the extension feature is added after
|
|
417
|
+
// construction (the \`extend\` option of the ts client).
|
|
418
|
+
CaptureFeature* cf = (CaptureFeature*)calloc(1, sizeof(CaptureFeature));
|
|
419
|
+
cf->base.vt = &CAPTURE_VT;
|
|
420
|
+
sdk_features_push(sdk, (Feature*)cf);
|
|
421
|
+
if (extra) sdk_features_push(sdk, extra);
|
|
422
|
+
|
|
423
|
+
return sdk;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
typedef PNError* (*Drive)(${Name}SDK* sdk, voxgig_value* mtch, voxgig_value* ctrl, voxgig_value** out);
|
|
427
|
+
typedef voxgig_value* (*Streamer)(${Name}SDK* sdk, voxgig_value* mtch, voxgig_value* callopts, PNError** err);
|
|
428
|
+
|
|
429
|
+
${drivers}
|
|
430
|
+
// Generated: every CRUD operation of every active entity, list and load
|
|
431
|
+
// first (they need no body), with the path parameters its points declare.
|
|
432
|
+
static const struct { const char* name; Drive fn; Streamer stream; const char* params[16]; } CANDIDATES[] = {
|
|
433
|
+
${table}
|
|
434
|
+
{ NULL, NULL, NULL, { NULL } },
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
typedef struct {
|
|
438
|
+
Drive fn;
|
|
439
|
+
Streamer stream;
|
|
440
|
+
voxgig_value* mtch;
|
|
441
|
+
} Target;
|
|
442
|
+
|
|
443
|
+
// The first operation that completes against a plain 200: with no
|
|
444
|
+
// arguments, else with every path parameter its points declare filled in.
|
|
445
|
+
static bool usable_op(Target* target) {
|
|
446
|
+
${Name}SDK* plain = ${ident}_sdk_new(cmap(2,
|
|
447
|
+
"apikey", v_str(CANARY_APIKEY),
|
|
448
|
+
"system", cmap(1, "fetch", vfn(transport_fn, (void*)(intptr_t)SC_OK))));
|
|
449
|
+
for (size_t i = 0; CANDIDATES[i].name; i++) {
|
|
450
|
+
voxgig_value* filled = v_map();
|
|
451
|
+
for (size_t p = 0; CANDIDATES[i].params[p]; p++) {
|
|
452
|
+
setp(filled, CANDIDATES[i].params[p], v_str("p1"));
|
|
453
|
+
}
|
|
454
|
+
voxgig_value* tries[2] = { v_map(), filled };
|
|
455
|
+
for (int t = 0; t < 2; t++) {
|
|
456
|
+
voxgig_value* out = NULL;
|
|
457
|
+
PNError* err = CANDIDATES[i].fn(plain, voxgig_clone(tries[t]), NULL, &out);
|
|
458
|
+
if (!err) {
|
|
459
|
+
target->fn = CANDIDATES[i].fn;
|
|
460
|
+
target->stream = CANDIDATES[i].stream;
|
|
461
|
+
target->mtch = tries[t];
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
static PNError* drive(${Name}SDK* sdk, Target* target, voxgig_value* ctrl) {
|
|
470
|
+
// A caller may keep the record it passed rather than read ctrl.explain.
|
|
471
|
+
voxgig_value* held = ctrl ? getp(ctrl, "explain") : NULL;
|
|
472
|
+
voxgig_value* out = NULL;
|
|
473
|
+
PNError* err = target->fn(sdk, voxgig_clone(target->mtch), ctrl, &out);
|
|
474
|
+
if (err) {
|
|
475
|
+
push_error("error", err);
|
|
476
|
+
} else {
|
|
477
|
+
push_value("result", out ? out : v_undef());
|
|
478
|
+
}
|
|
479
|
+
voxgig_value* explain = ctrl ? getp(ctrl, "explain") : NULL;
|
|
480
|
+
if (v_is_map(explain)) push_value("explain", explain);
|
|
481
|
+
if (v_is_map(held) && held != explain) push_value("explain:held", held);
|
|
482
|
+
return err;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Header maps keep the caller's spelling; the assertion should not care.
|
|
486
|
+
static const char* header(voxgig_value* map, const char* name) {
|
|
487
|
+
if (!voxgig_is_map(map)) return NULL;
|
|
488
|
+
voxgig_map* m = voxgig_as_map(map);
|
|
489
|
+
for (size_t i = 0; i < m->len; i++) {
|
|
490
|
+
if (0 == strcasecmp(m->entries[i].key, name)) {
|
|
491
|
+
voxgig_value* v = m->entries[i].value;
|
|
492
|
+
return voxgig_is_string(v) ? voxgig_as_string(v) : voxgig_stringify(v, -1);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return NULL;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
static size_t leaks(const char* text, char* found, size_t cap) {
|
|
499
|
+
size_t n = 0;
|
|
500
|
+
found[0] = '\\0';
|
|
501
|
+
for (size_t i = 0; i < NFORMS; i++) {
|
|
502
|
+
if (strstr(text, FORMS[i])) {
|
|
503
|
+
if (n) strncat(found, ", ", cap - strlen(found) - 1);
|
|
504
|
+
strncat(found, FORMS[i], cap - strlen(found) - 1);
|
|
505
|
+
n++;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return n;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
static bool ends_with(const char* s, const char* suffix) {
|
|
512
|
+
size_t sl = strlen(s);
|
|
513
|
+
size_t xl = strlen(suffix);
|
|
514
|
+
return sl >= xl && 0 == strcmp(s + sl - xl, suffix);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
int main(void) {
|
|
518
|
+
build_forms();
|
|
519
|
+
|
|
520
|
+
Target target;
|
|
521
|
+
if (!usable_op(&target)) {
|
|
522
|
+
printf("SKIP: no operation of this SDK completes against a plain 200; nothing to sweep\\n");
|
|
523
|
+
return 0;
|
|
524
|
+
}
|
|
525
|
+
Target* op = ⌖
|
|
526
|
+
|
|
527
|
+
PNError* notfound = NULL;
|
|
528
|
+
voxgig_value* explained = NULL;
|
|
529
|
+
|
|
530
|
+
for (int sc = 0; sc < SC_COUNT; sc++) {
|
|
531
|
+
for (int variant = 0; variant < 3; variant++) {
|
|
532
|
+
${Name}SDK* sdk = make_sdk(sc, NULL, NULL);
|
|
533
|
+
voxgig_value* explain = v_map();
|
|
534
|
+
voxgig_value* ctrl = NULL;
|
|
535
|
+
if (1 == variant) ctrl = cmap(1, "explain", explain);
|
|
536
|
+
if (2 == variant) ctrl = cmap(2, "throw", v_bool(false), "explain", explain);
|
|
537
|
+
PNError* err = drive(sdk, op, ctrl);
|
|
538
|
+
if (SC_NOTFOUND == sc && 0 == variant) notfound = err;
|
|
539
|
+
if (SC_OK == sc && 1 == variant) explained = explain;
|
|
540
|
+
(void)SC_NAMES;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// A credential mistyped as a map. The C validator defaults rather than
|
|
545
|
+
// rejects, so what the constructor produced is swept instead: a string
|
|
546
|
+
// quoting the value, cleaned the way a validation message is.
|
|
547
|
+
${Name}SDK* mistyped = ${ident}_sdk_new(cmap(2,
|
|
548
|
+
"apikey", cmap(1, "value", v_str(CANARY_APIKEY)),
|
|
549
|
+
"clean", cmap(1, "values", v_str(CANARY_VALUE))));
|
|
550
|
+
{
|
|
551
|
+
char quoted[256];
|
|
552
|
+
snprintf(quoted, sizeof(quoted), "apikey: expected string, got {\\"value\\":\\"%s\\"}",
|
|
553
|
+
CANARY_APIKEY);
|
|
554
|
+
push("mistyped:quoted", clean_str(sdk_get_root_ctx(mistyped), quoted));
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// An error a feature hook raises, quoting the request, with explain on.
|
|
558
|
+
Feature* thrower = (Feature*)calloc(1, sizeof(CaptureFeature));
|
|
559
|
+
thrower->vt = &THROW_VT;
|
|
560
|
+
PNError* hookerr = drive(make_sdk(SC_OK, NULL, thrower), op, cmap(1, "explain", v_map()));
|
|
561
|
+
CHECK(hookerr != NULL, "the throwing hook should fail the operation");
|
|
562
|
+
|
|
563
|
+
// The explain record a stream call is passed is cleaned however the stream
|
|
564
|
+
// ends: from a feature's producer, or materialised by done.
|
|
565
|
+
for (int s = 0; s < 2; s++) {
|
|
566
|
+
const char* name = 0 == s ? "stream-ok" : "stream-plain";
|
|
567
|
+
Feature* extra = NULL;
|
|
568
|
+
if (0 == s) {
|
|
569
|
+
extra = (Feature*)calloc(1, sizeof(CaptureFeature));
|
|
570
|
+
extra->vt = &STREAMOK_VT;
|
|
571
|
+
}
|
|
572
|
+
voxgig_value* explain = v_map();
|
|
573
|
+
PNError* serr = NULL;
|
|
574
|
+
op->stream(make_sdk(SC_OK, NULL, extra), voxgig_clone(op->mtch),
|
|
575
|
+
cmap(1, "ctrl", cmap(1, "explain", explain)), &serr);
|
|
576
|
+
char label[64];
|
|
577
|
+
snprintf(label, sizeof(label), "%s: only a failing stream raises", name);
|
|
578
|
+
CHECK(NULL == serr, label);
|
|
579
|
+
snprintf(label, sizeof(label), "%s: the explain record was not filled", name);
|
|
580
|
+
CHECK(0 < voxgig_as_map(explain)->len, label);
|
|
581
|
+
push_value(0 == s ? "stream-ok:explain" : "stream-plain:explain", explain);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// A feature's own error keeps its code, which is cleaned like the message:
|
|
585
|
+
// returned, handed to a hook, and cleaned where a step's error skips
|
|
586
|
+
// make_error.
|
|
587
|
+
Feature* denier = (Feature*)calloc(1, sizeof(CaptureFeature));
|
|
588
|
+
denier->vt = &DENY_VT;
|
|
589
|
+
PNError* denied = drive(make_sdk(SC_OK, NULL, denier), op, NULL);
|
|
590
|
+
CHECK(denied != NULL, "the refusing hook should fail the operation");
|
|
591
|
+
char steppedcode[128];
|
|
592
|
+
snprintf(steppedcode, sizeof(steppedcode), "stepped:%s", CANARY_VALUE);
|
|
593
|
+
PNError* stepped = pn_error_new(steppedcode, "stepped");
|
|
594
|
+
clean_error_util(sdk_get_root_ctx(mistyped), stepped);
|
|
595
|
+
push("stepped", pn_error_str(stepped));
|
|
596
|
+
|
|
597
|
+
// A client given no clean block at all masks by the schema defaults.
|
|
598
|
+
${Name}SDK* bare = ${ident}_sdk_new(cmap(4,
|
|
599
|
+
"apikey", v_str(CANARY_APIKEY),
|
|
600
|
+
"secret", v_str(CANARY_SECRET),
|
|
601
|
+
"headers", cmap(1, "X-Custom-Token", v_str(CANARY_HEADER)),
|
|
602
|
+
"system", cmap(1, "fetch", vfn(transport_fn, (void*)(intptr_t)SC_NOTFOUND))));
|
|
603
|
+
PNError* barerr = drive(bare, op, NULL);
|
|
604
|
+
CHECK(barerr != NULL, "the 404 scenario must throw without a clean block");
|
|
605
|
+
|
|
606
|
+
// The raw path returns its failure rather than an error.
|
|
607
|
+
PNError* directerr = NULL;
|
|
608
|
+
voxgig_value* direct = sdk_direct(make_sdk(SC_TRANSPORT, NULL, NULL),
|
|
609
|
+
cmap(1, "path", v_str("raw")), &directerr);
|
|
610
|
+
bool directok = true;
|
|
611
|
+
CHECK(NULL == directerr && get_bool(direct, "ok", &directok) && !directok,
|
|
612
|
+
"a transport failure should fail direct()");
|
|
613
|
+
push_value("direct", direct);
|
|
614
|
+
|
|
615
|
+
size_t nleaks = 0;
|
|
616
|
+
char found[4096];
|
|
617
|
+
for (size_t i = 0; i < NSINKS; i++) {
|
|
618
|
+
if (leaks(SINKS[i].text, found, sizeof(found))) {
|
|
619
|
+
fprintf(stderr, "credential leaked through: %s [%s]\\n", SINKS[i].name, found);
|
|
620
|
+
nleaks++;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
printf("clean: swept %zu surface(s), %zu leak(s)\\n", NSINKS, nleaks);
|
|
625
|
+
CHECK(0 == nleaks, "a credential leaked (see above)");
|
|
626
|
+
|
|
627
|
+
// The positive half: the slot the credential travelled in is masked, and
|
|
628
|
+
// an unregistered token in a response header is masked by name.
|
|
629
|
+
CHECK(notfound != NULL, "the 404 scenario must throw");
|
|
630
|
+
if (notfound) {
|
|
631
|
+
CHECK_INT_EQ(to_int(getp(notfound->result, "status")), 404, "the 404 error carries its status");
|
|
632
|
+
voxgig_value* headers = getp(notfound->spec, "headers");
|
|
633
|
+
if (!AUTH_SUPPRESSED) {
|
|
634
|
+
if (0 == strcmp(AUTH_WHERE, "query")) {
|
|
635
|
+
CHECK_STR_EQ(header(getp(notfound->spec, "query"), AUTH_NAME), MASK, "the query credential is masked");
|
|
636
|
+
} else if (0 == strcmp(AUTH_WHERE, "cookie")) {
|
|
637
|
+
const char* cookie = header(headers, "cookie");
|
|
638
|
+
CHECK(cookie && strstr(cookie, MASK), "the cookie credential is masked");
|
|
639
|
+
} else {
|
|
640
|
+
const char* cred = header(headers, AUTH_NAME);
|
|
641
|
+
CHECK(cred && ends_with(cred, MASK), "the header credential is masked");
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
CHECK_STR_EQ(header(headers, "x-custom-token"), MASK, "a custom token header is masked by name");
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
{
|
|
648
|
+
char want[64];
|
|
649
|
+
snprintf(want, sizeof(want), "denied:%s", MASK);
|
|
650
|
+
CHECK_STR_EQ(denied ? denied->code : NULL, want, "a feature's own error code is masked");
|
|
651
|
+
snprintf(want, sizeof(want), "stepped:%s", MASK);
|
|
652
|
+
CHECK_STR_EQ(stepped->code, want, "clean_error masks the code");
|
|
653
|
+
}
|
|
654
|
+
CHECK_STR_EQ(barerr ? header(getp(barerr->spec, "headers"), "x-custom-token") : NULL, MASK,
|
|
655
|
+
"a client with no clean block masks by the schema defaults");
|
|
656
|
+
|
|
657
|
+
CHECK(explained != NULL && voxgig_is_map(getp(explained, "result")),
|
|
658
|
+
"the explain record should carry the result");
|
|
659
|
+
if (explained) {
|
|
660
|
+
CHECK_STR_EQ(header(getp(getp(explained, "result"), "headers"), "x-session-token"), MASK,
|
|
661
|
+
"a response token header is masked by name");
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// The negative control: with clean switched off the canary MUST show, or
|
|
665
|
+
// the sweep is blind.
|
|
666
|
+
size_t before = NSINKS;
|
|
667
|
+
${Name}SDK* raw = make_sdk(SC_NOTFOUND, cmap(1, "active", v_bool(false)), NULL);
|
|
668
|
+
PNError* rawerr = drive(raw, op, NULL);
|
|
669
|
+
CHECK(rawerr != NULL, "the 404 scenario must throw with clean off");
|
|
670
|
+
size_t shown = 0;
|
|
671
|
+
for (size_t i = before; i < NSINKS; i++) {
|
|
672
|
+
if (leaks(SINKS[i].text, found, sizeof(found))) shown++;
|
|
673
|
+
}
|
|
674
|
+
CHECK(0 < shown, "with clean off, nothing showed the canary: the sweep is blind");
|
|
675
|
+
if (rawerr && !AUTH_SUPPRESSED) {
|
|
676
|
+
char* text = voxgig_jsonify(rawerr->spec, NULL);
|
|
677
|
+
char pair[256];
|
|
678
|
+
snprintf(pair, sizeof(pair), "%s:%s", CANARY_APIKEY, CANARY_SECRET);
|
|
679
|
+
char* pairb64 = b64(pair);
|
|
680
|
+
CHECK(strstr(text, CANARY_APIKEY) || strstr(text, pairb64),
|
|
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
|
+
{
|
|
686
|
+
voxgig_value* out = NULL;
|
|
687
|
+
PNError* explained = op->fn(make_sdk(SC_NOTFOUND, cmap(1, "active", v_bool(false)), NULL),
|
|
688
|
+
voxgig_clone(op->mtch), cmap(1, "explain", v_map()), &out);
|
|
689
|
+
CHECK_STR_EQ(explained ? explained->msg : NULL, rawerr ? rawerr->msg : NULL,
|
|
690
|
+
"with clean off, explain lost the error");
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// A registered value used as a property name is masked; names that mask
|
|
694
|
+
// alike are all kept.
|
|
695
|
+
${Name}SDK* named = ${ident}_sdk_new(cmap(1,
|
|
696
|
+
"clean", cmap(1, "values", v_str("ZZVAL-abc123,ZZVAL-xyz789"))));
|
|
697
|
+
voxgig_value* renamed = clean_util(sdk_get_root_ctx(named), cmap(3,
|
|
698
|
+
"ZZVAL-abc123", v_num(1), "ZZVAL-xyz789", v_num(2), "plain", v_num(3)));
|
|
699
|
+
voxgig_map* rm = voxgig_as_map(renamed);
|
|
700
|
+
CHECK(3 == rm->len, "every masked name is kept");
|
|
701
|
+
if (3 == rm->len) {
|
|
702
|
+
char alt[64];
|
|
703
|
+
snprintf(alt, sizeof(alt), "%s#1", MASK);
|
|
704
|
+
CHECK_STR_EQ(rm->entries[0].key, MASK, "a registered value used as a name is masked");
|
|
705
|
+
CHECK_STR_EQ(rm->entries[1].key, alt, "a colliding masked name takes a counter");
|
|
706
|
+
CHECK_STR_EQ(rm->entries[2].key, "plain", "an ordinary name is kept");
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// The generated config's own clean block is honoured, and left unchanged.
|
|
710
|
+
{
|
|
711
|
+
voxgig_value* config = cmap(1, "options", cmap(1, "clean", cmap(2,
|
|
712
|
+
"keys", v_str("zzsens"), "values", v_str("CONFIG-SEEDED-1"))));
|
|
713
|
+
CtxSpec cs;
|
|
714
|
+
memset(&cs, 0, sizeof(cs));
|
|
715
|
+
cs.options = cmap(1, "clean", cmap(1, "values", v_str("CALLER-SEEDED-2")));
|
|
716
|
+
cs.config = config;
|
|
717
|
+
Context* cctx = make_context_util(cs, NULL);
|
|
718
|
+
cctx->options = make_options_util(cctx);
|
|
719
|
+
char want[128];
|
|
720
|
+
snprintf(want, sizeof(want), "a %s b %s", MASK, MASK);
|
|
721
|
+
CHECK_STR_EQ(clean_str(cctx, "a CONFIG-SEEDED-1 b CALLER-SEEDED-2"), want,
|
|
722
|
+
"the config's and the caller's values are both masked");
|
|
723
|
+
voxgig_value* out = clean_util(cctx, cmap(2, "my_zzsens", v_str("x"), "other", v_str("y")));
|
|
724
|
+
CHECK_STR_EQ(get_str(out, "my_zzsens"), MASK, "the config's key name is sensitive");
|
|
725
|
+
CHECK_STR_EQ(get_str(out, "other"), "y", "an ordinary name is kept");
|
|
726
|
+
voxgig_value* cfgclean = getpath2(config, "options", "clean");
|
|
727
|
+
CHECK_STR_EQ(get_str(cfgclean, "keys"), "zzsens", "the config's keys are left alone");
|
|
728
|
+
CHECK_STR_EQ(get_str(cfgclean, "values"), "CONFIG-SEEDED-1",
|
|
729
|
+
"the config's values are left alone");
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// A feature's name is not a field name: a feature called secrets does not
|
|
733
|
+
// make its settings secret, though a sensitive field inside it still is. An
|
|
734
|
+
// entity block, of per-entity settings or seeded records keyed by entity
|
|
735
|
+
// name and id, is not read at all.
|
|
736
|
+
{
|
|
737
|
+
${Name}SDK* featured = ${ident}_sdk_new(cmap(3,
|
|
738
|
+
"apikey", v_str(CANARY_APIKEY),
|
|
739
|
+
"feature", cmap(2,
|
|
740
|
+
"secrets", cmap(3,
|
|
741
|
+
"active", v_bool(false),
|
|
742
|
+
"name", v_str("ZZNAME-feat123"),
|
|
743
|
+
"token", v_str("ZZTOKEN-feat456")),
|
|
744
|
+
"test", cmap(2,
|
|
745
|
+
"active", v_bool(false),
|
|
746
|
+
"entity", cmap(1, "zztoken", cmap(1, "ZZTOKEN01",
|
|
747
|
+
cmap(1, "note", v_str("PLAINRECORD-t5r3e1w9")))))),
|
|
748
|
+
"entity", cmap(1, "zztoken", cmap(1, "alias",
|
|
749
|
+
cmap(1, "zzkey", v_str("PLAINALIAS-m2n4b6v8"))))));
|
|
750
|
+
Context* fctx = sdk_get_root_ctx(featured);
|
|
751
|
+
char want[128];
|
|
752
|
+
snprintf(want, sizeof(want), "ZZNAME-feat123 %s", MASK);
|
|
753
|
+
CHECK_STR_EQ(clean_str(fctx, "ZZNAME-feat123 ZZTOKEN-feat456"), want,
|
|
754
|
+
"only the sensitive field of a feature is registered");
|
|
755
|
+
CHECK_STR_EQ(clean_str(fctx, "record PLAINRECORD-t5r3e1w9"), "record PLAINRECORD-t5r3e1w9",
|
|
756
|
+
"a record seeded under an entity block is not registered");
|
|
757
|
+
CHECK_STR_EQ(clean_str(fctx, "alias PLAINALIAS-m2n4b6v8"), "alias PLAINALIAS-m2n4b6v8",
|
|
758
|
+
"an entity's own settings are not registered");
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
TEST_SUMMARY("clean");
|
|
762
|
+
}
|
|
763
|
+
`
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
function cstr(s: string): string {
|
|
768
|
+
return String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
export {
|
|
773
|
+
TestClean
|
|
774
|
+
}
|