@voxgig/sdkgen 4.32.0 → 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/Response.js +14 -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/js/test/utility/PrimaryUtility.test.js +25 -0
- 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/Response.ts +14 -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/ts/test/utility/PrimaryUtility.test.ts +25 -0
- 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,666 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cmp,
|
|
3
|
+
each,
|
|
4
|
+
File,
|
|
5
|
+
Content,
|
|
6
|
+
isAuthSuppressed,
|
|
7
|
+
isHttpBasicAuth,
|
|
8
|
+
resolveAuthIn,
|
|
9
|
+
resolveAuthName,
|
|
10
|
+
} from '@voxgig/sdkgen'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
elixirString,
|
|
15
|
+
} from './utility_elixir'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// The canary sweep, the elixir port of TestClean_ts.ts: see that component.
|
|
19
|
+
const TestClean = cmp(function TestClean(props: any) {
|
|
20
|
+
const { model } = props.ctx$
|
|
21
|
+
const { entity } = props
|
|
22
|
+
|
|
23
|
+
const auth = {
|
|
24
|
+
suppressed: isAuthSuppressed(model),
|
|
25
|
+
where: resolveAuthIn(model),
|
|
26
|
+
name: 'header' === resolveAuthIn(model)
|
|
27
|
+
? resolveAuthName(model).toLowerCase() : resolveAuthName(model),
|
|
28
|
+
basic: isHttpBasicAuth(model),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
File({ name: 'clean_test.exs' }, () => Content(render(model, entity, auth)))
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const OP_ORDER: Record<string, number> = { list: 0, load: 1 }
|
|
36
|
+
const OPS = ['list', 'load', 'create', 'update', 'remove']
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// The path parameters an operation's points declare, as the runtime config
|
|
40
|
+
// carries them under points[].args.params.
|
|
41
|
+
function pointParams(opdef: any): string[] {
|
|
42
|
+
const names: string[] = []
|
|
43
|
+
for (const point of each(opdef?.points || [])) {
|
|
44
|
+
if (false === point?.a) continue
|
|
45
|
+
for (const arg of each(point?.g?.params || [])) {
|
|
46
|
+
if (false !== arg?.a && 'string' === typeof arg?.n && !names.includes(arg.n)) {
|
|
47
|
+
names.push(arg.n)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return names
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// The operations to try, list and load first: a required path parameter is
|
|
56
|
+
// what usually stops a candidate, and the read ops need none.
|
|
57
|
+
function candidates(Name: string, entity: any[]): string {
|
|
58
|
+
const rows: { rank: number, text: string }[] = []
|
|
59
|
+
each(entity, (e: any) => {
|
|
60
|
+
for (const op of Object.keys(e.op || {})) {
|
|
61
|
+
if (!OPS.includes(op)) continue
|
|
62
|
+
rows.push({
|
|
63
|
+
rank: OP_ORDER[op] ?? 2,
|
|
64
|
+
text: ` {${elixirString(e.name + '.' + op)}, fn sdk -> ${Name}.${e.name}(sdk) end,
|
|
65
|
+
fn ent, match, ctrl -> ${Name}.Entity.${e.Name}.${op}(ent, args(match), ctrl) end,
|
|
66
|
+
[${pointParams(e.op[op]).map((p) => elixirString(p)).join(', ')}]}`,
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
rows.sort((a, b) => a.rank - b.rank)
|
|
71
|
+
return rows.map((r) => r.text).join(',\n')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function render(model: any, entity: any[], auth: {
|
|
76
|
+
suppressed: boolean, where: string, name: string, basic: boolean
|
|
77
|
+
}): string {
|
|
78
|
+
const Name = model.const.Name
|
|
79
|
+
|
|
80
|
+
return `# ${Name} SDK canary sweep (generated by @voxgig/sdkgen).
|
|
81
|
+
#
|
|
82
|
+
# Every credential slot holds a distinctive value, every diagnostic feature
|
|
83
|
+
# this SDK ships is switched on with a capturing sink, a real operation runs
|
|
84
|
+
# through every outcome, and every string that leaves the SDK is searched for
|
|
85
|
+
# the canaries and their encoded forms. It also proves its own sensitivity:
|
|
86
|
+
# with clean switched off the canary MUST show.
|
|
87
|
+
#
|
|
88
|
+
# A struct node inspects as a handle, so the SDK's own records (the error's
|
|
89
|
+
# result and spec, the explain record, every sink record, the context's
|
|
90
|
+
# to_data) are also read through the struct JSON; a raw client, entity or
|
|
91
|
+
# context node is not, since that is a dump of the heap rather than a
|
|
92
|
+
# serialisation the SDK performs.
|
|
93
|
+
|
|
94
|
+
defmodule ${Name}.CleanTest do
|
|
95
|
+
use ExUnit.Case
|
|
96
|
+
|
|
97
|
+
alias Voxgig.Struct, as: S
|
|
98
|
+
alias ${Name}.Helpers, as: H
|
|
99
|
+
alias ${Name}.FeatureHarness, as: FH
|
|
100
|
+
|
|
101
|
+
# Generated: the credential's wire placement is fixed when the SDK is built.
|
|
102
|
+
@auth %{suppressed: ${auth.suppressed}, where: ${elixirString(auth.where)},
|
|
103
|
+
name: ${elixirString(auth.name)}, basic: ${auth.basic}}
|
|
104
|
+
|
|
105
|
+
@canary %{
|
|
106
|
+
apikey: "CANARY-APIKEY-k9x2m7q4p1",
|
|
107
|
+
secret: "CANARY-SECRET-w3e8r5t2y6",
|
|
108
|
+
header: "CANARY-HEADER-z1x4c7v0b3",
|
|
109
|
+
value: "CANARY-VALUE-n5m8b2v9c4"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@mask "[redacted]"
|
|
113
|
+
|
|
114
|
+
# Every form a canary can travel in.
|
|
115
|
+
defp forms_of do
|
|
116
|
+
Enum.flat_map(Map.values(@canary), fn v -> [v, Base.encode64(v), S.escurl(v)] end) ++
|
|
117
|
+
[Base.encode64(@canary.apikey <> ":" <> @canary.secret)]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
defp leaks(text), do: Enum.filter(forms_of(), &String.contains?(text, &1))
|
|
121
|
+
|
|
122
|
+
# Header maps keep the caller's spelling; the assertion should not care.
|
|
123
|
+
defp header(m, name) do
|
|
124
|
+
if S.ismap(m) do
|
|
125
|
+
Enum.find_value(H.entries(m), fn {k, v} ->
|
|
126
|
+
if String.downcase(to_string(k)) == String.downcase(name), do: v
|
|
127
|
+
end)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
defp push(name, kind, f) do
|
|
132
|
+
try do
|
|
133
|
+
[%{name: name <> ":" <> kind, text: to_string(f.())}]
|
|
134
|
+
rescue
|
|
135
|
+
_ -> []
|
|
136
|
+
catch
|
|
137
|
+
_, _ -> []
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Every default print of a value, as a sink each.
|
|
142
|
+
defp forms(name, val) do
|
|
143
|
+
push(name, "inspect", fn -> inspect(val, limit: :infinity, printable_limit: :infinity) end) ++
|
|
144
|
+
push(name, "raw", fn -> inspect(val, structs: false, limit: :infinity, printable_limit: :infinity) end) ++
|
|
145
|
+
if is_exception(val) do
|
|
146
|
+
push(name, "message", fn -> Exception.message(val) end) ++
|
|
147
|
+
push(name, "format", fn -> Exception.format(:error, val) end) ++
|
|
148
|
+
push(name, "json", fn -> S.jsonify(val) end)
|
|
149
|
+
else
|
|
150
|
+
[]
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# The SDK's own data, through the struct JSON as well.
|
|
155
|
+
defp data_forms(name, node) do
|
|
156
|
+
forms(name, node) ++
|
|
157
|
+
push(name, "json", fn -> S.jsonify(node) end) ++
|
|
158
|
+
push(name, "stringify", fn -> S.stringify(node) end)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
defp error_forms(e) do
|
|
162
|
+
forms("error", e) ++
|
|
163
|
+
if match?(%${Name}.Error{}, e) do
|
|
164
|
+
data_forms("error.result", e.result) ++ data_forms("error.spec", e.spec)
|
|
165
|
+
else
|
|
166
|
+
[]
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
defp result_forms(out) do
|
|
171
|
+
cond do
|
|
172
|
+
S.ismap(out) and S.getprop(out, "_client") != nil ->
|
|
173
|
+
forms("result", out) ++ data_forms("result.data", S.getprop(out, "_data"))
|
|
174
|
+
|
|
175
|
+
S.islist(out) ->
|
|
176
|
+
forms("result", out)
|
|
177
|
+
|
|
178
|
+
true ->
|
|
179
|
+
data_forms("result", out)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
defp add(sinks, items), do: Enum.each(items, fn s -> S.setprop(sinks, S.size(sinks), s) end)
|
|
184
|
+
defp sink_list(sinks), do: Enum.map(H.entries(sinks), &elem(&1, 1))
|
|
185
|
+
|
|
186
|
+
# Captures the serialised context from inside the pipeline: what a hook
|
|
187
|
+
# author would hand to a logger.
|
|
188
|
+
defp capture_feature(sinks) do
|
|
189
|
+
cap = fn hook ->
|
|
190
|
+
fn ctx ->
|
|
191
|
+
add(sinks, forms("ctx@" <> hook, ctx))
|
|
192
|
+
add(sinks, data_forms("ctxdata@" <> hook, ${Name}.Context.to_data(ctx)))
|
|
193
|
+
nil
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
S.jm([
|
|
198
|
+
"name", "capture", "version", "0.0.1", "active", true, "options", S.jm([]),
|
|
199
|
+
"init", fn _ctx, _opts -> nil end,
|
|
200
|
+
"PreRequest", cap.("PreRequest"),
|
|
201
|
+
"PreResponse", cap.("PreResponse"),
|
|
202
|
+
"PreUnexpected", cap.("PreUnexpected")
|
|
203
|
+
])
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
defp response(status, data, headers) do
|
|
207
|
+
h = S.jm(["content-type", "application/json"])
|
|
208
|
+
Enum.each(headers, fn {k, v} -> S.setprop(h, k, v) end)
|
|
209
|
+
|
|
210
|
+
S.jm([
|
|
211
|
+
"status", status,
|
|
212
|
+
"statusText", if(status < 400, do: "OK", else: "ERR"),
|
|
213
|
+
"headers", h,
|
|
214
|
+
"body", S.jsonify(data),
|
|
215
|
+
"json", fn -> data end
|
|
216
|
+
])
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
defp scenarios do
|
|
220
|
+
[
|
|
221
|
+
{"ok",
|
|
222
|
+
fn _url, _fd ->
|
|
223
|
+
{response(200, S.jm(["id", "i1", "name", "n1"]), [{"x-session-token", "RESP-TOKEN-a1b2c3d4e5"}]), nil}
|
|
224
|
+
end},
|
|
225
|
+
{"notfound", fn _url, _fd -> {response(404, S.jm(["error", "no such record"]), []), nil} end},
|
|
226
|
+
{"server", fn _url, _fd -> {response(500, S.jm(["error", "boom"]), []), nil} end},
|
|
227
|
+
{"transport",
|
|
228
|
+
fn url, _fd ->
|
|
229
|
+
{nil, ${Name}.Error.new("transport", "socket hang up (URL was: \\"" <> url <> "\\")")}
|
|
230
|
+
end},
|
|
231
|
+
{"notjson",
|
|
232
|
+
fn _url, _fd ->
|
|
233
|
+
{S.jm([
|
|
234
|
+
"status", 200, "statusText", "OK", "headers", S.jm([]), "body", "<html>",
|
|
235
|
+
"json", fn -> raise "Unexpected token < in JSON" end
|
|
236
|
+
]), nil}
|
|
237
|
+
end}
|
|
238
|
+
]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
defp make_sdk(respond, sinks, cleanopts, extra \\\\ []) do
|
|
242
|
+
capture = fn name -> fn rec -> add(sinks, data_forms(name, rec)) end end
|
|
243
|
+
feature = S.jm([])
|
|
244
|
+
|
|
245
|
+
on = fn name, kvs ->
|
|
246
|
+
if FH.has_feature(name), do: S.setprop(feature, name, S.jm(["active", true] ++ kvs))
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
on.("log", ["logger", capture.("log")])
|
|
250
|
+
on.("debug", ["onEntry", capture.("debug")])
|
|
251
|
+
on.("audit", ["sink", capture.("audit")])
|
|
252
|
+
on.("telemetry", ["exporter", capture.("telemetry")])
|
|
253
|
+
on.("cost", ["sink", capture.("cost")])
|
|
254
|
+
on.("metrics", [])
|
|
255
|
+
on.("clienttrack", [])
|
|
256
|
+
|
|
257
|
+
clean = S.jm(["values", @canary.value])
|
|
258
|
+
Enum.each(cleanopts, fn {k, v} -> S.setprop(clean, k, v) end)
|
|
259
|
+
|
|
260
|
+
${Name}.new(
|
|
261
|
+
S.jm([
|
|
262
|
+
"apikey", @canary.apikey,
|
|
263
|
+
"secret", @canary.secret,
|
|
264
|
+
"headers", S.jm(["X-Custom-Token", @canary.header]),
|
|
265
|
+
"clean", clean,
|
|
266
|
+
"feature", feature,
|
|
267
|
+
"extend", S.jt([capture_feature(sinks) | extra]),
|
|
268
|
+
"utility", S.jm(["fetcher", fn _ctx, url, fd -> respond.(url, fd) end])
|
|
269
|
+
])
|
|
270
|
+
)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# A fresh struct node of the match, since an operation may keep what it is
|
|
274
|
+
# given.
|
|
275
|
+
defp args(match), do: S.jm(Enum.flat_map(match, fn {k, v} -> [k, v] end))
|
|
276
|
+
|
|
277
|
+
# The operations this SDK generated, read ops first.
|
|
278
|
+
defp candidates do
|
|
279
|
+
[
|
|
280
|
+
${candidates(Name, entity)}
|
|
281
|
+
]
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# The first operation that completes against a plain 200: with no
|
|
285
|
+
# arguments, else with every path parameter its points declare filled in.
|
|
286
|
+
defp usable_op do
|
|
287
|
+
plain =
|
|
288
|
+
${Name}.new(
|
|
289
|
+
S.jm([
|
|
290
|
+
"apikey", @canary.apikey,
|
|
291
|
+
"utility", S.jm(["fetcher", fn _c, _u, _f -> {response(200, S.jm(["id", "i1"]), []), nil} end])
|
|
292
|
+
])
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
Enum.find_value(candidates(), fn {name, acc, op, params} ->
|
|
296
|
+
filled = Map.new(params, fn p -> {p, "p1"} end)
|
|
297
|
+
|
|
298
|
+
Enum.find_value([%{}, filled], fn match ->
|
|
299
|
+
try do
|
|
300
|
+
op.(acc.(plain), match, S.jm([]))
|
|
301
|
+
{name, acc, op, match}
|
|
302
|
+
rescue
|
|
303
|
+
_ -> nil
|
|
304
|
+
catch
|
|
305
|
+
_, _ -> nil
|
|
306
|
+
end
|
|
307
|
+
end)
|
|
308
|
+
end)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# A feature that raises from inside the pipeline, quoting the request it
|
|
312
|
+
# saw: an error make_error never handled.
|
|
313
|
+
defp throw_feature(unexpected) do
|
|
314
|
+
saw = fn ctx -> "hook saw " <> S.jsonify(S.getprop(ctx, "spec")) end
|
|
315
|
+
|
|
316
|
+
S.jm([
|
|
317
|
+
"name", "throwhook", "version", "0.0.1", "active", true, "options", S.jm([]),
|
|
318
|
+
"init", fn _ctx, _opts -> nil end,
|
|
319
|
+
"PreResponse", fn ctx -> raise saw.(ctx) end,
|
|
320
|
+
# Fired from the operation's rescue, before its cleaning.
|
|
321
|
+
"PreUnexpected", fn ctx -> if unexpected, do: raise(saw.(ctx)) end
|
|
322
|
+
])
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# A stream that fails while the caller iterates it, quoting a credential.
|
|
326
|
+
defp stream_feature do
|
|
327
|
+
S.jm([
|
|
328
|
+
"name", "streamthrow", "version", "0.0.1", "active", true, "options", S.jm([]),
|
|
329
|
+
"init", fn _ctx, _opts -> nil end,
|
|
330
|
+
"PreDone", fn ctx ->
|
|
331
|
+
S.setprop(S.getprop(ctx, "result"), "stream",
|
|
332
|
+
fn -> Stream.map([1], fn _ -> raise "stream saw " <> @canary.apikey end) end)
|
|
333
|
+
end
|
|
334
|
+
])
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# A stream that succeeds, yielding the result's items.
|
|
338
|
+
defp stream_ok_feature do
|
|
339
|
+
S.jm([
|
|
340
|
+
"name", "streamok", "version", "0.0.1", "active", true, "options", S.jm([]),
|
|
341
|
+
"init", fn _ctx, _opts -> nil end,
|
|
342
|
+
"PreDone", fn ctx ->
|
|
343
|
+
result = S.getprop(ctx, "result")
|
|
344
|
+
rd = S.getprop(result, "resdata")
|
|
345
|
+
items = if S.islist(rd), do: Enum.map(H.entries(rd), &elem(&1, 1)), else: List.wrap(rd)
|
|
346
|
+
S.setprop(result, "stream", fn -> items end)
|
|
347
|
+
end
|
|
348
|
+
])
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# The target operation, streamed through its entity.
|
|
352
|
+
defp stream_of(sdk, {name, acc, _op, match}, callopts) do
|
|
353
|
+
ent = acc.(sdk)
|
|
354
|
+
mod = S.getprop(ent, "_module")
|
|
355
|
+
mod.stream(ent, List.last(String.split(name, ".")), S.jm(["reqmatch", args(match)]), callopts)
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Features that fail the operation with the SDK's own error, whose code
|
|
359
|
+
# quotes a registered value: one refuses it as rbac does, and records the
|
|
360
|
+
# error PreUnexpected hands a hook; the other raises.
|
|
361
|
+
defp deny_feature(sinks) do
|
|
362
|
+
S.jm([
|
|
363
|
+
"name", "denyhook", "version", "0.0.1", "active", true, "options", S.jm([]),
|
|
364
|
+
"init", fn _ctx, _opts -> nil end,
|
|
365
|
+
"PrePoint", fn ctx ->
|
|
366
|
+
err = ${Name}.Context.make_error(ctx, "denied:" <> @canary.value, "denied")
|
|
367
|
+
S.setprop(S.getprop(ctx, "out"), "point", err)
|
|
368
|
+
end,
|
|
369
|
+
"PreUnexpected", fn ctx ->
|
|
370
|
+
add(sinks, error_forms(S.getprop(S.getprop(ctx, "ctrl"), "err")))
|
|
371
|
+
nil
|
|
372
|
+
end
|
|
373
|
+
])
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
defp raise_feature do
|
|
377
|
+
S.jm([
|
|
378
|
+
"name", "raisehook", "version", "0.0.1", "active", true, "options", S.jm([]),
|
|
379
|
+
"init", fn _ctx, _opts -> nil end,
|
|
380
|
+
"PreResponse", fn _ctx -> raise ${Name}.Error.new("raised:" <> @canary.value, "raised") end
|
|
381
|
+
])
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
defp drive(sdk, {_name, acc, op, match}, ctrl, sinks) do
|
|
385
|
+
ent = acc.(sdk)
|
|
386
|
+
# A caller may keep the record it passed rather than read ctrl.explain.
|
|
387
|
+
held = S.getprop(ctrl, "explain")
|
|
388
|
+
|
|
389
|
+
{out, err} =
|
|
390
|
+
try do
|
|
391
|
+
{op.(ent, match, ctrl), nil}
|
|
392
|
+
rescue
|
|
393
|
+
e -> {nil, e}
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
if err != nil, do: add(sinks, error_forms(err))
|
|
397
|
+
if out != nil, do: add(sinks, result_forms(out))
|
|
398
|
+
explain = S.getprop(ctrl, "explain")
|
|
399
|
+
if explain != nil, do: add(sinks, data_forms("explain", explain))
|
|
400
|
+
if held != nil and held != explain, do: add(sinks, data_forms("explain:held", held))
|
|
401
|
+
err
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
@no_target "no operation of this SDK completes against a plain 200; nothing to sweep"
|
|
405
|
+
|
|
406
|
+
# ExUnit has no runtime skip, so a sweep with nothing to drive says so.
|
|
407
|
+
test "no credential leaves the SDK in any form" do
|
|
408
|
+
case usable_op() do
|
|
409
|
+
nil -> IO.puts("SKIP no credential leaves the SDK in any form: " <> @no_target)
|
|
410
|
+
target -> sweep(target)
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
test "the sweep can see a leak: clean switched off shows the credential" do
|
|
415
|
+
case usable_op() do
|
|
416
|
+
nil -> IO.puts("SKIP the sweep can see a leak: " <> @no_target)
|
|
417
|
+
target -> sweep_blind(target)
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
defp sweep(target) do
|
|
422
|
+
sinks = S.jt([])
|
|
423
|
+
|
|
424
|
+
variants = [
|
|
425
|
+
{"throw", fn -> S.jm([]) end},
|
|
426
|
+
{"explain", fn -> S.jm(["explain", S.jm([])]) end},
|
|
427
|
+
{"nothrow", fn -> S.jm(["throw", false, "explain", S.jm([])]) end}
|
|
428
|
+
]
|
|
429
|
+
|
|
430
|
+
{errors, explains} =
|
|
431
|
+
Enum.reduce(scenarios(), {%{}, %{}}, fn {sname, respond}, acc ->
|
|
432
|
+
Enum.reduce(variants, acc, fn {vname, mkctrl}, {errors, explains} ->
|
|
433
|
+
sdk = make_sdk(respond, sinks, [])
|
|
434
|
+
ctrl = mkctrl.()
|
|
435
|
+
err = drive(sdk, target, ctrl, sinks)
|
|
436
|
+
add(sinks, forms("sdk", sdk))
|
|
437
|
+
key = sname <> "/" <> vname
|
|
438
|
+
errors = if err != nil, do: Map.put(errors, key, err), else: errors
|
|
439
|
+
ex = S.getprop(ctrl, "explain")
|
|
440
|
+
explains = if ex != nil, do: Map.put(explains, key, ex), else: explains
|
|
441
|
+
{errors, explains}
|
|
442
|
+
end)
|
|
443
|
+
end)
|
|
444
|
+
|
|
445
|
+
# A credential mistyped as a map is rejected by validation, whose message
|
|
446
|
+
# quotes the value it rejected.
|
|
447
|
+
rejected =
|
|
448
|
+
try do
|
|
449
|
+
${Name}.new(S.jm(["apikey", S.jm(["value", @canary.apikey]), "clean", S.jm(["values", @canary.value])]))
|
|
450
|
+
nil
|
|
451
|
+
rescue
|
|
452
|
+
e -> e
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
assert rejected != nil, "a credential mistyped as a map should be rejected"
|
|
456
|
+
add(sinks, forms("rejected", rejected))
|
|
457
|
+
|
|
458
|
+
# An error a feature hook raises, quoting the request, skips make_error.
|
|
459
|
+
[{_name, ok} | _] = scenarios()
|
|
460
|
+
|
|
461
|
+
for unexpected <- [false, true] do
|
|
462
|
+
hooked = make_sdk(ok, sinks, [], [throw_feature(unexpected)])
|
|
463
|
+
err = drive(hooked, target, S.jm(["explain", S.jm([])]), sinks)
|
|
464
|
+
assert err != nil, "the throwing hook should fail the operation"
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
# Iterating a stream runs through the same cleaning path as the operation,
|
|
468
|
+
# and the explain record the caller passed is cleaned however it ends.
|
|
469
|
+
for {name, extra} <- [{"stream", [stream_feature()]}, {"stream-ok", [stream_ok_feature()]}, {"stream-plain", []}] do
|
|
470
|
+
explain = S.jm([])
|
|
471
|
+
callopts = S.jm(["ctrl", S.jm(["explain", explain])])
|
|
472
|
+
|
|
473
|
+
streamerr =
|
|
474
|
+
try do
|
|
475
|
+
Enum.to_list(stream_of(make_sdk(ok, sinks, [], extra), target, callopts))
|
|
476
|
+
nil
|
|
477
|
+
rescue
|
|
478
|
+
e -> e
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
assert (name == "stream") == (streamerr != nil), name <> ": only the failing stream raises"
|
|
482
|
+
if streamerr != nil, do: add(sinks, forms(name, streamerr))
|
|
483
|
+
assert S.size(explain) > 0, name <> ": the explain record was not filled"
|
|
484
|
+
add(sinks, data_forms(name <> ":explain", explain))
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# A feature's own error keeps its code, which is cleaned like the message:
|
|
488
|
+
# returned, handed to a hook, raised by a hook, and nested in a record.
|
|
489
|
+
denied = drive(make_sdk(ok, sinks, [], [deny_feature(sinks)]), target, S.jm([]), sinks)
|
|
490
|
+
assert denied != nil, "the refusing hook should fail the operation"
|
|
491
|
+
raised = drive(make_sdk(ok, sinks, [], [raise_feature()]), target, S.jm([]), sinks)
|
|
492
|
+
assert raised != nil, "the raising hook should fail the operation"
|
|
493
|
+
|
|
494
|
+
nested =
|
|
495
|
+
${Name}.Utility.clean_impl(${Name}.get_root_ctx(make_sdk(ok, sinks, [])),
|
|
496
|
+
S.jm(["err", ${Name}.Error.new("nested:" <> @canary.value, "nested")]))
|
|
497
|
+
|
|
498
|
+
add(sinks, data_forms("nested", nested))
|
|
499
|
+
|
|
500
|
+
# A client given no clean block at all masks by the schema defaults.
|
|
501
|
+
[_ok, {_nf, notfound_respond} | _] = scenarios()
|
|
502
|
+
|
|
503
|
+
bare =
|
|
504
|
+
${Name}.new(
|
|
505
|
+
S.jm([
|
|
506
|
+
"apikey", @canary.apikey,
|
|
507
|
+
"secret", @canary.secret,
|
|
508
|
+
"headers", S.jm(["X-Custom-Token", @canary.header]),
|
|
509
|
+
"utility", S.jm(["fetcher", fn _ctx, url, fd -> notfound_respond.(url, fd) end])
|
|
510
|
+
])
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
barerr = drive(bare, target, S.jm([]), sinks)
|
|
514
|
+
assert barerr != nil, "the 404 scenario must fail without a clean block"
|
|
515
|
+
|
|
516
|
+
# The raw path returns its failure rather than raising it.
|
|
517
|
+
[_ok, _nf, _server, {_tr, transport_respond} | _] = scenarios()
|
|
518
|
+
direct = ${Name}.direct(make_sdk(transport_respond, sinks, []), S.jm(["path", "raw"]))
|
|
519
|
+
assert S.getprop(direct, "ok") == false, "a transport failure should fail direct()"
|
|
520
|
+
add(sinks, forms("direct", S.getprop(direct, "err")))
|
|
521
|
+
|
|
522
|
+
all = sink_list(sinks)
|
|
523
|
+
leaked = Enum.filter(all, fn s -> leaks(s.text) != [] end)
|
|
524
|
+
|
|
525
|
+
IO.puts("clean: swept #{length(all)} surface(s), #{length(leaked)} leak(s)")
|
|
526
|
+
|
|
527
|
+
assert leaked == [],
|
|
528
|
+
"credential leaked through: " <>
|
|
529
|
+
Enum.map_join(leaked, "; ", fn s -> s.name <> " [" <> Enum.join(leaks(s.text), ", ") <> "]" end)
|
|
530
|
+
|
|
531
|
+
# The positive half: the slot the credential travelled in is masked, and
|
|
532
|
+
# an unregistered token in a response header is masked by name.
|
|
533
|
+
notfound = errors["notfound/throw"]
|
|
534
|
+
assert notfound != nil, "the 404 scenario must throw"
|
|
535
|
+
assert match?(%${Name}.Error{}, notfound), "the 404 error is an SDK error"
|
|
536
|
+
assert ${Name}.Error.status(notfound) == 404
|
|
537
|
+
spec = notfound.spec
|
|
538
|
+
|
|
539
|
+
unless @auth.suppressed do
|
|
540
|
+
case @auth.where do
|
|
541
|
+
"query" ->
|
|
542
|
+
assert header(S.getprop(spec, "query"), @auth.name) == @mask
|
|
543
|
+
|
|
544
|
+
"cookie" ->
|
|
545
|
+
assert String.contains?(to_string(header(S.getprop(spec, "headers"), "cookie")), @mask)
|
|
546
|
+
|
|
547
|
+
_ ->
|
|
548
|
+
assert String.ends_with?(to_string(header(S.getprop(spec, "headers"), @auth.name)), @mask)
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
assert header(S.getprop(spec, "headers"), "x-custom-token") == @mask
|
|
553
|
+
assert denied.code == "denied:" <> @mask
|
|
554
|
+
assert raised.code == "raised:" <> @mask
|
|
555
|
+
assert S.getpath(nested, "err.code") == "nested:" <> @mask
|
|
556
|
+
assert header(S.getprop(barerr.spec, "headers"), "x-custom-token") == @mask
|
|
557
|
+
|
|
558
|
+
explained = explains["ok/explain"]
|
|
559
|
+
result = if explained != nil, do: S.getprop(explained, "result"), else: nil
|
|
560
|
+
assert S.ismap(result), "the explain record should carry the result"
|
|
561
|
+
assert header(S.getprop(result, "headers"), "x-session-token") == @mask
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
defp sweep_blind(target) do
|
|
565
|
+
sinks = S.jt([])
|
|
566
|
+
[_ok, {_name, notfound} | _] = scenarios()
|
|
567
|
+
sdk = make_sdk(notfound, sinks, [{"active", false}])
|
|
568
|
+
err = drive(sdk, target, S.jm([]), sinks)
|
|
569
|
+
assert err != nil
|
|
570
|
+
|
|
571
|
+
# Explaining a failure must not cost it its error.
|
|
572
|
+
explained =
|
|
573
|
+
drive(make_sdk(notfound, S.jt([]), [{"active", false}]), target, S.jm(["explain", S.jm([])]), S.jt([]))
|
|
574
|
+
|
|
575
|
+
assert explained != nil and Exception.message(explained) == Exception.message(err),
|
|
576
|
+
"with clean off, explain lost the error"
|
|
577
|
+
|
|
578
|
+
assert Enum.any?(sink_list(sinks), fn s -> leaks(s.text) != [] end),
|
|
579
|
+
"with clean off, nothing showed the canary: the sweep is blind"
|
|
580
|
+
|
|
581
|
+
unless @auth.suppressed do
|
|
582
|
+
text = S.jsonify(err.spec)
|
|
583
|
+
|
|
584
|
+
assert String.contains?(text, @canary.apikey) or
|
|
585
|
+
String.contains?(text, Base.encode64(@canary.apikey <> ":" <> @canary.secret)),
|
|
586
|
+
"the raw spec should carry the credential when clean is off"
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
test "a registered value used as a property name is masked, collisions kept" do
|
|
591
|
+
cfg = ${Name}.Utility.make_clean_config(S.jm(["keys", "key,secret,token"]))
|
|
592
|
+
ctx = S.jm(["options", S.jm(["__derived__", S.jm(["clean", cfg])])])
|
|
593
|
+
${Name}.Utility.clean_add_impl(ctx, "ZZVAL-abc123")
|
|
594
|
+
${Name}.Utility.clean_add_impl(ctx, "ZZVAL-xyz789")
|
|
595
|
+
out = ${Name}.Utility.clean_impl(ctx, S.jm(["ZZVAL-abc123", 1, "ZZVAL-xyz789", 2, "plain", 3]))
|
|
596
|
+
assert S.getprop(out, @mask) == 1
|
|
597
|
+
assert S.getprop(out, @mask <> "#1") == 2
|
|
598
|
+
assert S.getprop(out, "plain") == 3
|
|
599
|
+
assert "ZZVAL-abc123" not in S.keysof(out)
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# A feature's name is not a field name: a feature called secrets does not
|
|
603
|
+
# make its settings secret, though a sensitive field inside it still is. An
|
|
604
|
+
# entity block, of entity settings or seeded records, is not read at all.
|
|
605
|
+
test "a feature's name is read as a name" do
|
|
606
|
+
record = S.jm(["zztoken", S.jm(["ZZTOKEN01", S.jm(["note", "PLAINRECORD-t5r3e1w9"])])])
|
|
607
|
+
|
|
608
|
+
client =
|
|
609
|
+
${Name}.new(
|
|
610
|
+
S.jm([
|
|
611
|
+
"apikey", @canary.apikey,
|
|
612
|
+
"feature",
|
|
613
|
+
S.jm([
|
|
614
|
+
"secrets", S.jm(["active", false, "name", "ZZNAME-feat123", "token", "ZZTOKEN-feat456"]),
|
|
615
|
+
"test", S.jm(["active", false, "entity", record])
|
|
616
|
+
]),
|
|
617
|
+
"entity", S.jm(["zztoken", S.jm(["alias", S.jm(["zzkey", "PLAINALIAS-m2n4b6v8"])])])
|
|
618
|
+
])
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
ctx = ${Name}.get_root_ctx(client)
|
|
622
|
+
assert ${Name}.Utility.clean_impl(ctx, "ZZNAME-feat123 ZZTOKEN-feat456") == "ZZNAME-feat123 " <> @mask
|
|
623
|
+
assert ${Name}.Utility.clean_impl(ctx, "record PLAINRECORD-t5r3e1w9") == "record PLAINRECORD-t5r3e1w9"
|
|
624
|
+
assert ${Name}.Utility.clean_impl(ctx, "alias PLAINALIAS-m2n4b6v8") == "alias PLAINALIAS-m2n4b6v8"
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
test "the generated config's own clean block is honoured" do
|
|
628
|
+
config = S.jm(["options", S.jm(["clean", S.jm(["keys", "zzsens", "values", "CONFIG-SEEDED-1"])])])
|
|
629
|
+
ctx = S.jm(["config", config, "options", S.jm(["clean", S.jm(["values", "CALLER-SEEDED-2"])])])
|
|
630
|
+
cctx = S.jm(["options", ${Name}.Utility.make_options_impl(ctx)])
|
|
631
|
+
|
|
632
|
+
assert ${Name}.Utility.clean_impl(cctx, "a CONFIG-SEEDED-1 b CALLER-SEEDED-2") ==
|
|
633
|
+
"a " <> @mask <> " b " <> @mask
|
|
634
|
+
|
|
635
|
+
out = ${Name}.Utility.clean_impl(cctx, S.jm(["my_zzsens", "x", "other", "y"]))
|
|
636
|
+
assert S.getprop(out, "my_zzsens") == @mask
|
|
637
|
+
assert S.getprop(out, "other") == "y"
|
|
638
|
+
assert S.getpath(config, "options.clean.keys") == "zzsens"
|
|
639
|
+
assert S.getpath(config, "options.clean.values") == "CONFIG-SEEDED-1"
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
test "clean_add_sensitive registers every scalar under a sensitive name, at any depth" do
|
|
643
|
+
cfg = ${Name}.Utility.make_clean_config(S.jm(["keys", "key,secret,token"]))
|
|
644
|
+
ctx = S.jm(["options", S.jm(["__derived__", S.jm(["clean", cfg])])])
|
|
645
|
+
|
|
646
|
+
${Name}.Utility.clean_add_sensitive(ctx, S.jm([
|
|
647
|
+
"apikey", S.jm(["value", "NESTED-SECRET-1"]),
|
|
648
|
+
"headers", S.jm(["X-Api-Token", S.jt(["LISTED-SECRET-2"])]),
|
|
649
|
+
"secret", 123456789,
|
|
650
|
+
"name", "not-a-secret"
|
|
651
|
+
]))
|
|
652
|
+
|
|
653
|
+
values = Enum.map(H.entries(S.getprop(cfg, "values")), &elem(&1, 1))
|
|
654
|
+
assert "NESTED-SECRET-1" in values
|
|
655
|
+
assert "LISTED-SECRET-2" in values
|
|
656
|
+
assert "123456789" in values
|
|
657
|
+
refute "not-a-secret" in values
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
`
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
export {
|
|
665
|
+
TestClean
|
|
666
|
+
}
|
|
@@ -8,6 +8,7 @@ import { cmp, each, Folder, File, Content, entityCollection } from '@voxgig/sdkg
|
|
|
8
8
|
|
|
9
9
|
import { TestEntity } from './TestEntity_elixir'
|
|
10
10
|
import { TestDirect } from './TestDirect_elixir'
|
|
11
|
+
import { TestClean } from './TestClean_elixir'
|
|
11
12
|
import { ReadmeExamplesTest } from './ReadmeExamplesTest_elixir'
|
|
12
13
|
|
|
13
14
|
|
|
@@ -39,6 +40,9 @@ end
|
|
|
39
40
|
TestDirect({ target, entity })
|
|
40
41
|
})
|
|
41
42
|
|
|
43
|
+
// The canary sweep (test/clean_test.exs), picked up by `mix test`.
|
|
44
|
+
TestClean({ target, entity })
|
|
45
|
+
|
|
42
46
|
// Validate the documented elixir examples in the README/REFERENCE docs.
|
|
43
47
|
ReadmeExamplesTest({ target })
|
|
44
48
|
})
|
|
@@ -209,7 +209,7 @@ defmodule ProjectName do
|
|
|
209
209
|
|
|
210
210
|
cond do
|
|
211
211
|
fetch_err != nil ->
|
|
212
|
-
S.jm(["ok", false, "err", fetch_err])
|
|
212
|
+
S.jm(["ok", false, "err", Utility.clean(ctx, fetch_err)])
|
|
213
213
|
|
|
214
214
|
fetched == nil ->
|
|
215
215
|
S.jm(["ok", false, "err", Context.make_error(ctx, "direct_no_response", "response: undefined")])
|