@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,791 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cmp,
|
|
3
|
+
configDefinition,
|
|
4
|
+
each,
|
|
5
|
+
File,
|
|
6
|
+
Content,
|
|
7
|
+
entityClassName,
|
|
8
|
+
entityCollection,
|
|
9
|
+
isAuthSuppressed,
|
|
10
|
+
isHttpBasicAuth,
|
|
11
|
+
resolveAuthIn,
|
|
12
|
+
resolveAuthName,
|
|
13
|
+
} from '@voxgig/sdkgen'
|
|
14
|
+
|
|
15
|
+
import { zigVarName } from './utility_zig'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// The canary sweep, the zig port of TestClean_ts.ts: see that component.
|
|
19
|
+
// Each operation carries the path parameters its config points declare.
|
|
20
|
+
const TestClean = cmp(function TestClean(props: any) {
|
|
21
|
+
const { model } = props.ctx$
|
|
22
|
+
const { target } = props
|
|
23
|
+
|
|
24
|
+
const auth = {
|
|
25
|
+
suppressed: isAuthSuppressed(model),
|
|
26
|
+
where: resolveAuthIn(model),
|
|
27
|
+
name: 'header' === resolveAuthIn(model)
|
|
28
|
+
? resolveAuthName(model).toLowerCase() : resolveAuthName(model),
|
|
29
|
+
basic: isHttpBasicAuth(model),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const entityColl = entityCollection(model)
|
|
33
|
+
const rank: Record<string, number> = { list: 0, load: 1 }
|
|
34
|
+
const configEntity = configDefinition(model, target.name).def.entity || {}
|
|
35
|
+
|
|
36
|
+
const candidates: Candidate[] = []
|
|
37
|
+
each(entityColl)
|
|
38
|
+
.filter((e: any) => false !== e.active)
|
|
39
|
+
.forEach((e: any) => {
|
|
40
|
+
const method = zigVarName(e.name)
|
|
41
|
+
const cls = entityClassName(e, entityColl)
|
|
42
|
+
Object.keys(e.op || {})
|
|
43
|
+
.filter((op) => ['list', 'load', 'create', 'update', 'remove'].includes(op))
|
|
44
|
+
.sort((a, b) => ((rank[a] ?? 2) - (rank[b] ?? 2)) || a.localeCompare(b))
|
|
45
|
+
.forEach((op) => candidates.push({
|
|
46
|
+
method, mod: method, cls, op, params: pointParams(configEntity[e.name]?.op?.[op]),
|
|
47
|
+
}))
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
File({ name: 'clean_test.' + target.ext }, () => Content(render(auth, candidates)))
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
type Candidate = { method: string, mod: string, cls: string, op: string, params: string[] }
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// Every path parameter an operation's points declare, as the generated
|
|
58
|
+
// config carries them (points[].args.params[].name).
|
|
59
|
+
function pointParams(opdef: any): string[] {
|
|
60
|
+
const names: string[] = []
|
|
61
|
+
for (const point of opdef?.points || []) {
|
|
62
|
+
for (const p of point?.args?.params || []) {
|
|
63
|
+
if ('string' === typeof p?.name && !names.includes(p.name)) names.push(p.name)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return names
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
function zigbool(b: boolean): string {
|
|
71
|
+
return b ? 'true' : 'false'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function zigstr(s: string): string {
|
|
76
|
+
return '"' + String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
function candidateFn(c: Candidate): string {
|
|
81
|
+
const name = 'try_' + c.method + '_' + c.op
|
|
82
|
+
const call = 'client.' + c.method + '(vnull()).' + c.op + '(mtch, ctrl)'
|
|
83
|
+
if ('list' === c.op) {
|
|
84
|
+
return `
|
|
85
|
+
fn ${name}(client: *sdk.SDK, mtch: Value, ctrl: Value) Outcome {
|
|
86
|
+
switch (${call}) {
|
|
87
|
+
.ok => |ents| {
|
|
88
|
+
const records = h.olist();
|
|
89
|
+
for (ents) |e| records.array.append(e.asEntity().data(null)) catch {};
|
|
90
|
+
return .{ .ok = true, .err = null, .result = records };
|
|
91
|
+
},
|
|
92
|
+
.err => |e| return .{ .ok = false, .err = e, .result = vnull() },
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`
|
|
96
|
+
}
|
|
97
|
+
return `
|
|
98
|
+
fn ${name}(client: *sdk.SDK, mtch: Value, ctrl: Value) Outcome {
|
|
99
|
+
switch (${call}) {
|
|
100
|
+
.ok => |ent| return .{ .ok = true, .err = null, .result = ent.asEntity().data(null) },
|
|
101
|
+
.err => |e| return .{ .ok = false, .err = e, .result = vnull() },
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
function streamFn(c: Candidate): string {
|
|
109
|
+
return `
|
|
110
|
+
fn stream_${c.method}_${c.op}(client: *sdk.SDK, mtch: Value, callopts: Value) []Value {
|
|
111
|
+
return client.${c.method}(vnull()).stream("${c.op}", mtch, callopts);
|
|
112
|
+
}
|
|
113
|
+
`
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
function render(auth: {
|
|
118
|
+
suppressed: boolean, where: string, name: string, basic: boolean
|
|
119
|
+
}, candidates: Candidate[]): string {
|
|
120
|
+
return `// The canary sweep: every credential slot holds a distinctive value, every
|
|
121
|
+
// diagnostic feature this SDK ships is switched on with a capturing sink, a
|
|
122
|
+
// real operation runs through every outcome, and every string that leaves
|
|
123
|
+
// the SDK is searched for the canaries and their encoded forms. It also
|
|
124
|
+
// proves its own sensitivity: with clean switched off the canary MUST show.
|
|
125
|
+
|
|
126
|
+
const std = @import("std");
|
|
127
|
+
const sdk = @import("sdk");
|
|
128
|
+
const fh = @import("fh.zig");
|
|
129
|
+
const h = sdk.h;
|
|
130
|
+
const Value = sdk.Value;
|
|
131
|
+
const testing = std.testing;
|
|
132
|
+
|
|
133
|
+
fn vnull() Value {
|
|
134
|
+
return Value{ .null = {} };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fn fmt(comptime f: []const u8, args: anytype) []const u8 {
|
|
138
|
+
return std.fmt.allocPrint(h.A(), f, args) catch "";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Generated: the credential's wire placement is fixed when the SDK is built.
|
|
142
|
+
const AUTH = .{
|
|
143
|
+
.suppressed = ${zigbool(auth.suppressed)},
|
|
144
|
+
.where = ${zigstr(auth.where)},
|
|
145
|
+
.name = ${zigstr(auth.name)},
|
|
146
|
+
.basic = ${zigbool(auth.basic)},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const CANARY_APIKEY = "CANARY-APIKEY-k9x2m7q4p1";
|
|
150
|
+
const CANARY_SECRET = "CANARY-SECRET-w3e8r5t2y6";
|
|
151
|
+
const CANARY_HEADER = "CANARY-HEADER-z1x4c7v0b3";
|
|
152
|
+
const CANARY_VALUE = "CANARY-VALUE-n5m8b2v9c4";
|
|
153
|
+
|
|
154
|
+
const MASK = "[redacted]";
|
|
155
|
+
|
|
156
|
+
fn base64_std(text: []const u8) []const u8 {
|
|
157
|
+
const enc = std.base64.standard.Encoder;
|
|
158
|
+
const buf = h.A().alloc(u8, enc.calcSize(text.len)) catch return "";
|
|
159
|
+
return enc.encode(buf, text);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Every form a canary can travel in.
|
|
163
|
+
fn forms() [][]const u8 {
|
|
164
|
+
var out: std.ArrayList([]const u8) = .empty;
|
|
165
|
+
for ([_][]const u8{ CANARY_APIKEY, CANARY_SECRET, CANARY_HEADER, CANARY_VALUE }) |v| {
|
|
166
|
+
out.append(h.A(), v) catch {};
|
|
167
|
+
out.append(h.A(), base64_std(v)) catch {};
|
|
168
|
+
out.append(h.A(), h.esc_url(v)) catch {};
|
|
169
|
+
}
|
|
170
|
+
out.append(h.A(), base64_std(fmt("{s}:{s}", .{ CANARY_APIKEY, CANARY_SECRET }))) catch {};
|
|
171
|
+
return out.toOwnedSlice(h.A()) catch &.{};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const Surface = struct { name: []const u8, text: []const u8 };
|
|
175
|
+
|
|
176
|
+
const Sinks = struct {
|
|
177
|
+
items: std.ArrayList(Surface) = .empty,
|
|
178
|
+
|
|
179
|
+
fn push(self: *Sinks, name: []const u8, text: []const u8) void {
|
|
180
|
+
self.items.append(h.A(), .{ .name = name, .text = text }) catch {};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// A record's JSON, and its stringified form.
|
|
184
|
+
fn value(self: *Sinks, name: []const u8, v: Value) void {
|
|
185
|
+
self.push(fmt("{s}:json", .{name}), h.jsonify_compact(v));
|
|
186
|
+
self.push(fmt("{s}:string", .{name}), h.stringify(v));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
fn err(self: *Sinks, name: []const u8, e: *sdk.h.SdkError) void {
|
|
190
|
+
self.push(fmt("{s}:msg", .{name}), e.msg);
|
|
191
|
+
self.push(fmt("{s}:format", .{name}), fmt("{f}", .{e.*}));
|
|
192
|
+
self.push(fmt("{s}:json", .{name}), e.to_json());
|
|
193
|
+
self.push(fmt("{s}:spec", .{name}), h.jsonify_compact(e.spec));
|
|
194
|
+
self.push(fmt("{s}:result", .{name}), h.jsonify_compact(e.result));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
fn ctx(self: *Sinks, name: []const u8, c: *sdk.Context) void {
|
|
198
|
+
self.push(fmt("{s}:json", .{name}), c.to_json());
|
|
199
|
+
self.push(fmt("{s}:format", .{name}), fmt("{f}", .{c.*}));
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// A sink callback (audit sink, telemetry exporter, debug onEntry, cost sink)
|
|
204
|
+
// that records each record's forms under its name.
|
|
205
|
+
const Capture = struct {
|
|
206
|
+
sinks: *Sinks,
|
|
207
|
+
name: []const u8,
|
|
208
|
+
|
|
209
|
+
fn call(p: *anyopaque, _: std.mem.Allocator, arg: Value) anyerror!Value {
|
|
210
|
+
const self: *Capture = @ptrCast(@alignCast(p));
|
|
211
|
+
self.sinks.value(self.name, arg);
|
|
212
|
+
return vnull();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
fn make(sinks: *Sinks, name: []const u8) Value {
|
|
216
|
+
const s = h.A().create(Capture) catch unreachable;
|
|
217
|
+
s.* = .{ .sinks = sinks, .name = name };
|
|
218
|
+
return h.callable(@ptrCast(s), call);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Captures the serialised context from inside the pipeline: what a hook
|
|
223
|
+
// author would hand to a logger.
|
|
224
|
+
const CaptureFeature = struct {
|
|
225
|
+
name: []const u8 = "capture",
|
|
226
|
+
sinks: *Sinks,
|
|
227
|
+
|
|
228
|
+
fn make(sinks: *Sinks) sdk.Feature {
|
|
229
|
+
const self = h.A().create(CaptureFeature) catch unreachable;
|
|
230
|
+
self.* = .{ .sinks = sinks };
|
|
231
|
+
return .{ .ptr = @ptrCast(self), .vtable = &vtable };
|
|
232
|
+
}
|
|
233
|
+
fn self_of(p: *anyopaque) *CaptureFeature {
|
|
234
|
+
return @ptrCast(@alignCast(p));
|
|
235
|
+
}
|
|
236
|
+
fn vname(p: *anyopaque) []const u8 {
|
|
237
|
+
return self_of(p).name;
|
|
238
|
+
}
|
|
239
|
+
fn vactive(_: *anyopaque) bool {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
fn vaddopts(_: *anyopaque) Value {
|
|
243
|
+
return vnull();
|
|
244
|
+
}
|
|
245
|
+
fn vinit(_: *anyopaque, _: *sdk.Context, _: Value) void {}
|
|
246
|
+
fn vdispatch(p: *anyopaque, hook: []const u8, c: *sdk.Context) void {
|
|
247
|
+
const self = self_of(p);
|
|
248
|
+
if (std.mem.eql(u8, hook, "PreRequest") or
|
|
249
|
+
std.mem.eql(u8, hook, "PreResponse") or
|
|
250
|
+
std.mem.eql(u8, hook, "PreUnexpected"))
|
|
251
|
+
{
|
|
252
|
+
self.sinks.ctx(fmt("ctx@{s}", .{hook}), c);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const vtable = sdk.Feature.VTable{
|
|
256
|
+
.name = vname,
|
|
257
|
+
.active = vactive,
|
|
258
|
+
.add_options = vaddopts,
|
|
259
|
+
.init = vinit,
|
|
260
|
+
.dispatch = vdispatch,
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// A feature that fails the operation from inside the pipeline, quoting the
|
|
265
|
+
// request it saw. A zig hook has no error return, so it fails the result:
|
|
266
|
+
// an error make_error receives from a hook, not from the pipeline. For the
|
|
267
|
+
// same reason there is no variant failing in PreUnexpected: make_error has
|
|
268
|
+
// built and cleaned the error it returns before that hook runs.
|
|
269
|
+
const ThrowFeature = struct {
|
|
270
|
+
var instance: u8 = 0;
|
|
271
|
+
|
|
272
|
+
fn make() sdk.Feature {
|
|
273
|
+
return .{ .ptr = @ptrCast(&instance), .vtable = &vtable };
|
|
274
|
+
}
|
|
275
|
+
fn vname(_: *anyopaque) []const u8 {
|
|
276
|
+
return "throwhook";
|
|
277
|
+
}
|
|
278
|
+
fn vactive(_: *anyopaque) bool {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
fn vaddopts(_: *anyopaque) Value {
|
|
282
|
+
return vnull();
|
|
283
|
+
}
|
|
284
|
+
fn vinit(_: *anyopaque, _: *sdk.Context, _: Value) void {}
|
|
285
|
+
fn vdispatch(_: *anyopaque, hook: []const u8, c: *sdk.Context) void {
|
|
286
|
+
if (!std.mem.eql(u8, hook, "PreResponse")) return;
|
|
287
|
+
const res = c.result orelse return;
|
|
288
|
+
const spec: Value = if (c.spec) |sp| sp.to_value() else vnull();
|
|
289
|
+
res.err = c.make_error("hook", fmt("hook saw {s}", .{h.jsonify_compact(spec)}));
|
|
290
|
+
}
|
|
291
|
+
const vtable = sdk.Feature.VTable{
|
|
292
|
+
.name = vname,
|
|
293
|
+
.active = vactive,
|
|
294
|
+
.add_options = vaddopts,
|
|
295
|
+
.init = vinit,
|
|
296
|
+
.dispatch = vdispatch,
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// A stream that succeeds, so the pipeline's terminal step never runs. A zig
|
|
301
|
+
// stream producer has no error channel, so no stream fails.
|
|
302
|
+
const StreamOkFeature = struct {
|
|
303
|
+
var instance: u8 = 0;
|
|
304
|
+
|
|
305
|
+
fn make() sdk.Feature {
|
|
306
|
+
return .{ .ptr = @ptrCast(&instance), .vtable = &vtable };
|
|
307
|
+
}
|
|
308
|
+
fn vname(_: *anyopaque) []const u8 {
|
|
309
|
+
return "streamok";
|
|
310
|
+
}
|
|
311
|
+
fn vactive(_: *anyopaque) bool {
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
fn vaddopts(_: *anyopaque) Value {
|
|
315
|
+
return vnull();
|
|
316
|
+
}
|
|
317
|
+
fn vinit(_: *anyopaque, _: *sdk.Context, _: Value) void {}
|
|
318
|
+
fn items(p: *anyopaque) []Value {
|
|
319
|
+
const res: *sdk.SdkResult = @ptrCast(@alignCast(p));
|
|
320
|
+
return switch (res.resdata) {
|
|
321
|
+
.array => |l| l.data.items,
|
|
322
|
+
.null => &.{},
|
|
323
|
+
else => blk: {
|
|
324
|
+
const one = h.A().alloc(Value, 1) catch break :blk &.{};
|
|
325
|
+
one[0] = res.resdata;
|
|
326
|
+
break :blk one;
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
fn vdispatch(_: *anyopaque, hook: []const u8, c: *sdk.Context) void {
|
|
331
|
+
if (!std.mem.eql(u8, hook, "PreDone")) return;
|
|
332
|
+
const res = c.result orelse return;
|
|
333
|
+
res.stream = .{ .ctx = @ptrCast(res), .call = items };
|
|
334
|
+
}
|
|
335
|
+
const vtable = sdk.Feature.VTable{
|
|
336
|
+
.name = vname,
|
|
337
|
+
.active = vactive,
|
|
338
|
+
.add_options = vaddopts,
|
|
339
|
+
.init = vinit,
|
|
340
|
+
.dispatch = vdispatch,
|
|
341
|
+
};
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// A feature that refuses the operation with the SDK's own error, as rbac
|
|
345
|
+
// does, whose code quotes a registered value; it records the error
|
|
346
|
+
// PreUnexpected hands a hook.
|
|
347
|
+
const DenyFeature = struct {
|
|
348
|
+
sinks: *Sinks,
|
|
349
|
+
|
|
350
|
+
fn make(sinks: *Sinks) sdk.Feature {
|
|
351
|
+
const self = h.A().create(DenyFeature) catch unreachable;
|
|
352
|
+
self.* = .{ .sinks = sinks };
|
|
353
|
+
return .{ .ptr = @ptrCast(self), .vtable = &vtable };
|
|
354
|
+
}
|
|
355
|
+
fn self_of(p: *anyopaque) *DenyFeature {
|
|
356
|
+
return @ptrCast(@alignCast(p));
|
|
357
|
+
}
|
|
358
|
+
fn vname(_: *anyopaque) []const u8 {
|
|
359
|
+
return "denyhook";
|
|
360
|
+
}
|
|
361
|
+
fn vactive(_: *anyopaque) bool {
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
fn vaddopts(_: *anyopaque) Value {
|
|
365
|
+
return vnull();
|
|
366
|
+
}
|
|
367
|
+
fn vinit(_: *anyopaque, _: *sdk.Context, _: Value) void {}
|
|
368
|
+
fn vdispatch(p: *anyopaque, hook: []const u8, c: *sdk.Context) void {
|
|
369
|
+
if (std.mem.eql(u8, hook, "PrePoint")) {
|
|
370
|
+
const e = c.make_error(fmt("denied:{s}", .{CANARY_VALUE}), "denied");
|
|
371
|
+
c.out_set("point", sdk.OutVal{ .err = e });
|
|
372
|
+
} else if (std.mem.eql(u8, hook, "PreUnexpected")) {
|
|
373
|
+
if (c.ctrl.err) |e| self_of(p).sinks.err("error", e);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const vtable = sdk.Feature.VTable{
|
|
377
|
+
.name = vname,
|
|
378
|
+
.active = vactive,
|
|
379
|
+
.add_options = vaddopts,
|
|
380
|
+
.init = vinit,
|
|
381
|
+
.dispatch = vdispatch,
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// ---- scenarios: what the transport answers ------------------------------
|
|
386
|
+
|
|
387
|
+
const Scenario = enum { ok, notfound, server, transport, notjson };
|
|
388
|
+
|
|
389
|
+
fn response(status: i64, data: Value, headers: Value) Value {
|
|
390
|
+
const hh = h.omap();
|
|
391
|
+
h.setp(hh, "content-type", h.vstr("application/json"));
|
|
392
|
+
if (headers == .object) {
|
|
393
|
+
var it = headers.object.iterator();
|
|
394
|
+
while (it.next()) |kv| h.setp(hh, kv.key_ptr.*, kv.value_ptr.*);
|
|
395
|
+
}
|
|
396
|
+
return h.jo(&.{
|
|
397
|
+
.{ "status", h.vnum(status) },
|
|
398
|
+
.{ "statusText", h.vstr(if (status < 400) "OK" else "ERR") },
|
|
399
|
+
.{ "headers", hh },
|
|
400
|
+
.{ "json", h.json_thunk(data) },
|
|
401
|
+
.{ "body", h.vstr(h.jsonify_compact(data)) },
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
fn notJsonThunk(_: *anyopaque, _: std.mem.Allocator, _: Value) anyerror!Value {
|
|
406
|
+
return error.NotJson;
|
|
407
|
+
}
|
|
408
|
+
var notjson_dummy: u8 = 0;
|
|
409
|
+
|
|
410
|
+
// The system.fetch seam: (url, fetchdef) -> transport-shaped response, or a
|
|
411
|
+
// map carrying __err__ for a transport failure.
|
|
412
|
+
const Transport = struct {
|
|
413
|
+
scenario: Scenario,
|
|
414
|
+
|
|
415
|
+
fn call(p: *anyopaque, _: std.mem.Allocator, arg: Value) anyerror!Value {
|
|
416
|
+
const self: *Transport = @ptrCast(@alignCast(p));
|
|
417
|
+
const url = h.scalar_str(h.get_elem(arg, h.vnum(0), vnull()));
|
|
418
|
+
return switch (self.scenario) {
|
|
419
|
+
.ok => response(200, h.jo(&.{ .{ "id", h.vstr("i1") }, .{ "name", h.vstr("n1") } }),
|
|
420
|
+
h.jo(&.{.{ "x-session-token", h.vstr("RESP-TOKEN-a1b2c3d4e5") }})),
|
|
421
|
+
.notfound => response(404, h.jo(&.{.{ "error", h.vstr("no such record") }}), vnull()),
|
|
422
|
+
.server => response(500, h.jo(&.{.{ "error", h.vstr("boom") }}), vnull()),
|
|
423
|
+
.transport => h.jo(&.{.{ "__err__", h.vstr(fmt("socket hang up (URL was: \\"{s}\\")", .{url})) }}),
|
|
424
|
+
.notjson => h.jo(&.{
|
|
425
|
+
.{ "status", h.vnum(200) },
|
|
426
|
+
.{ "statusText", h.vstr("OK") },
|
|
427
|
+
.{ "headers", h.omap() },
|
|
428
|
+
.{ "json", h.callable(@ptrCast(¬json_dummy), notJsonThunk) },
|
|
429
|
+
.{ "body", h.vstr("<html>") },
|
|
430
|
+
}),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
fn make(scenario: Scenario) Value {
|
|
435
|
+
const s = h.A().create(Transport) catch unreachable;
|
|
436
|
+
s.* = .{ .scenario = scenario };
|
|
437
|
+
return h.callable(@ptrCast(s), call);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
fn makeSdk(scenario: Scenario, sinks: *Sinks, clean_active: bool, extra: ?sdk.Feature) *sdk.SDK {
|
|
442
|
+
const feature = h.omap();
|
|
443
|
+
if (fh.fh_has_feature("log")) h.setp(feature, "log", h.jo(&.{.{ "active", h.vbool(true) }}));
|
|
444
|
+
if (fh.fh_has_feature("debug")) h.setp(feature, "debug", h.jo(&.{
|
|
445
|
+
.{ "active", h.vbool(true) },
|
|
446
|
+
.{ "onEntry", Capture.make(sinks, "debug") },
|
|
447
|
+
}));
|
|
448
|
+
if (fh.fh_has_feature("audit")) h.setp(feature, "audit", h.jo(&.{
|
|
449
|
+
.{ "active", h.vbool(true) },
|
|
450
|
+
.{ "sink", Capture.make(sinks, "audit") },
|
|
451
|
+
}));
|
|
452
|
+
if (fh.fh_has_feature("telemetry")) h.setp(feature, "telemetry", h.jo(&.{
|
|
453
|
+
.{ "active", h.vbool(true) },
|
|
454
|
+
.{ "exporter", Capture.make(sinks, "telemetry") },
|
|
455
|
+
}));
|
|
456
|
+
if (fh.fh_has_feature("cost")) h.setp(feature, "cost", h.jo(&.{
|
|
457
|
+
.{ "active", h.vbool(true) },
|
|
458
|
+
.{ "sink", Capture.make(sinks, "cost") },
|
|
459
|
+
}));
|
|
460
|
+
if (fh.fh_has_feature("metrics")) h.setp(feature, "metrics", h.jo(&.{.{ "active", h.vbool(true) }}));
|
|
461
|
+
if (fh.fh_has_feature("clienttrack")) h.setp(feature, "clienttrack", h.jo(&.{.{ "active", h.vbool(true) }}));
|
|
462
|
+
|
|
463
|
+
const clean = h.jo(&.{.{ "values", h.vstr(CANARY_VALUE) }});
|
|
464
|
+
if (!clean_active) h.setp(clean, "active", h.vbool(false));
|
|
465
|
+
|
|
466
|
+
const options = h.jo(&.{
|
|
467
|
+
.{ "apikey", h.vstr(CANARY_APIKEY) },
|
|
468
|
+
.{ "secret", h.vstr(CANARY_SECRET) },
|
|
469
|
+
.{ "headers", h.jo(&.{.{ "X-Custom-Token", h.vstr(CANARY_HEADER) }}) },
|
|
470
|
+
.{ "clean", clean },
|
|
471
|
+
.{ "feature", feature },
|
|
472
|
+
.{ "system", h.jo(&.{.{ "fetch", Transport.make(scenario) }}) },
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
if (extra) |f| return sdk.SDK.new_with(options, &.{ CaptureFeature.make(sinks), f });
|
|
476
|
+
return sdk.SDK.new_with(options, &.{CaptureFeature.make(sinks)});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ---- the candidate operations, from the model ---------------------------
|
|
480
|
+
|
|
481
|
+
const Outcome = struct {
|
|
482
|
+
ok: bool,
|
|
483
|
+
err: ?*sdk.h.SdkError,
|
|
484
|
+
result: Value,
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
const Candidate = *const fn (client: *sdk.SDK, mtch: Value, ctrl: Value) Outcome;
|
|
488
|
+
const Streamer = *const fn (client: *sdk.SDK, mtch: Value, callopts: Value) []Value;
|
|
489
|
+
${candidates.map(candidateFn).join('')}${candidates.map(streamFn).join('')}
|
|
490
|
+
const CandidateDef = struct { run: Candidate, stream: Streamer, params: []const []const u8 };
|
|
491
|
+
|
|
492
|
+
// Generated: every CRUD operation of every active entity, with the path
|
|
493
|
+
// parameters its points declare.
|
|
494
|
+
const CANDIDATES = [_]CandidateDef{${candidates.map((c) => '\n .{ .run = try_' + c.method + '_' + c.op +
|
|
495
|
+
', .stream = stream_' + c.method + '_' + c.op +
|
|
496
|
+
', .params = &.{' + c.params.map(zigstr).join(', ') + '} },').join('')}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
const Target = struct { run: Candidate, stream: Streamer, mtch: Value };
|
|
500
|
+
|
|
501
|
+
// The first operation that completes against a plain 200: with no
|
|
502
|
+
// arguments, else with every path parameter its points declare filled in.
|
|
503
|
+
fn usableOp() ?Target {
|
|
504
|
+
for (CANDIDATES) |cand| {
|
|
505
|
+
const filled = h.omap();
|
|
506
|
+
for (cand.params) |p| h.setp(filled, p, h.vstr("p1"));
|
|
507
|
+
for ([_]Value{ h.omap(), filled }) |mtch| {
|
|
508
|
+
const plain = sdk.SDK.new(h.jo(&.{
|
|
509
|
+
.{ "apikey", h.vstr(CANARY_APIKEY) },
|
|
510
|
+
.{ "system", h.jo(&.{.{ "fetch", Transport.make(.ok) }}) },
|
|
511
|
+
}));
|
|
512
|
+
if (cand.run(plain, h.clone(mtch), h.omap()).ok) {
|
|
513
|
+
return .{ .run = cand.run, .stream = cand.stream, .mtch = mtch };
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const NOTHING_TO_SWEEP = "SKIP: no operation of this SDK completes against a plain 200; nothing to sweep\\n";
|
|
521
|
+
|
|
522
|
+
fn drive(client: *sdk.SDK, target: Target, ctrl: Value, sinks: *Sinks) ?*sdk.h.SdkError {
|
|
523
|
+
// A caller may keep the record it passed rather than read ctrl.explain.
|
|
524
|
+
const held = h.getp(ctrl, "explain");
|
|
525
|
+
const out = target.run(client, h.clone(target.mtch), ctrl);
|
|
526
|
+
if (out.err) |e| sinks.err("error", e);
|
|
527
|
+
if (out.ok) sinks.value("result", out.result);
|
|
528
|
+
const explain = h.getp(ctrl, "explain");
|
|
529
|
+
if (explain == .object) sinks.value("explain", explain);
|
|
530
|
+
if (held == .object and (explain != .object or held.object != explain.object)) {
|
|
531
|
+
sinks.value("explain:held", held);
|
|
532
|
+
}
|
|
533
|
+
return out.err;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
fn leaks(text: []const u8) [][]const u8 {
|
|
537
|
+
var found: std.ArrayList([]const u8) = .empty;
|
|
538
|
+
for (forms()) |f| {
|
|
539
|
+
if (std.mem.indexOf(u8, text, f) != null) found.append(h.A(), f) catch {};
|
|
540
|
+
}
|
|
541
|
+
return found.toOwnedSlice(h.A()) catch &.{};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Header maps keep the caller's spelling; the assertion should not care.
|
|
545
|
+
fn header(map: Value, name: []const u8) ?[]const u8 {
|
|
546
|
+
if (map != .object) return null;
|
|
547
|
+
var it = map.object.iterator();
|
|
548
|
+
while (it.next()) |kv| {
|
|
549
|
+
if (std.ascii.eqlIgnoreCase(kv.key_ptr.*, name)) {
|
|
550
|
+
return switch (kv.value_ptr.*) {
|
|
551
|
+
.string => |s| s,
|
|
552
|
+
else => null,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const Variant = enum { throw, explain, nothrow };
|
|
560
|
+
|
|
561
|
+
fn ctrlFor(v: Variant) Value {
|
|
562
|
+
return switch (v) {
|
|
563
|
+
.throw => h.omap(),
|
|
564
|
+
.explain => h.jo(&.{.{ "explain", h.omap() }}),
|
|
565
|
+
.nothrow => h.jo(&.{ .{ "throw", h.vbool(false) }, .{ "explain", h.omap() } }),
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
test "clean: no credential leaves the SDK in any form" {
|
|
570
|
+
const target = usableOp() orelse {
|
|
571
|
+
std.debug.print(NOTHING_TO_SWEEP, .{});
|
|
572
|
+
return error.SkipZigTest;
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
var sinks = Sinks{};
|
|
576
|
+
var notfound: ?*sdk.h.SdkError = null;
|
|
577
|
+
var explained: Value = vnull();
|
|
578
|
+
|
|
579
|
+
for ([_]Scenario{ .ok, .notfound, .server, .transport, .notjson }) |scenario| {
|
|
580
|
+
for ([_]Variant{ .throw, .explain, .nothrow }) |variant| {
|
|
581
|
+
const client = makeSdk(scenario, &sinks, true, null);
|
|
582
|
+
const ctrl = ctrlFor(variant);
|
|
583
|
+
const err = drive(client, target, ctrl, &sinks);
|
|
584
|
+
if (scenario == .notfound and variant == .throw) notfound = err;
|
|
585
|
+
if (scenario == .ok and variant == .explain) explained = h.getp(ctrl, "explain");
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// A credential mistyped as a map. The zig validator's failure is not
|
|
590
|
+
// raised (make_options keeps its input), so what the constructor produced
|
|
591
|
+
// is swept instead: a string quoting the value, cleaned the way a
|
|
592
|
+
// validation message is.
|
|
593
|
+
const mistyped = sdk.SDK.new(h.jo(&.{
|
|
594
|
+
.{ "apikey", h.jo(&.{.{ "value", h.vstr(CANARY_APIKEY) }}) },
|
|
595
|
+
.{ "clean", h.jo(&.{.{ "values", h.vstr(CANARY_VALUE) }}) },
|
|
596
|
+
}));
|
|
597
|
+
sinks.push("mistyped:quoted", sdk.utilmod.clean_str_util(
|
|
598
|
+
mistyped.get_root_ctx(),
|
|
599
|
+
fmt("apikey: expected string, got {{\\"value\\":\\"{s}\\"}}", .{CANARY_APIKEY}),
|
|
600
|
+
));
|
|
601
|
+
|
|
602
|
+
// An error a feature hook raises, quoting the request, with explain on.
|
|
603
|
+
const hooked = makeSdk(.ok, &sinks, true, ThrowFeature.make());
|
|
604
|
+
const hookerr = drive(hooked, target, h.jo(&.{.{ "explain", h.omap() }}), &sinks);
|
|
605
|
+
try testing.expect(hookerr != null);
|
|
606
|
+
|
|
607
|
+
// The explain record a stream call is passed is cleaned however the
|
|
608
|
+
// stream ends: from a feature's producer, or materialised by done. A zig
|
|
609
|
+
// stream hands no error back, so the record is what is asserted on.
|
|
610
|
+
for ([_]?sdk.Feature{ StreamOkFeature.make(), null }, [_][]const u8{ "stream-ok", "stream-plain" }) |extra, name| {
|
|
611
|
+
const explain = h.omap();
|
|
612
|
+
const callopts = h.jo(&.{.{ "ctrl", h.jo(&.{.{ "explain", explain }}) }});
|
|
613
|
+
_ = target.stream(makeSdk(.ok, &sinks, true, extra), h.clone(target.mtch), callopts);
|
|
614
|
+
try testing.expect(0 < explain.object.count());
|
|
615
|
+
sinks.value(fmt("{s}:explain", .{name}), explain);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// A feature's own error keeps its code, which is cleaned like the
|
|
619
|
+
// message: returned, and handed to a hook.
|
|
620
|
+
const denied = drive(makeSdk(.ok, &sinks, true, DenyFeature.make(&sinks)), target, h.omap(), &sinks);
|
|
621
|
+
try testing.expect(denied != null);
|
|
622
|
+
|
|
623
|
+
// A client given no clean block at all masks by the schema defaults.
|
|
624
|
+
const bare = sdk.SDK.new(h.jo(&.{
|
|
625
|
+
.{ "apikey", h.vstr(CANARY_APIKEY) },
|
|
626
|
+
.{ "secret", h.vstr(CANARY_SECRET) },
|
|
627
|
+
.{ "headers", h.jo(&.{.{ "X-Custom-Token", h.vstr(CANARY_HEADER) }}) },
|
|
628
|
+
.{ "system", h.jo(&.{.{ "fetch", Transport.make(.notfound) }}) },
|
|
629
|
+
}));
|
|
630
|
+
const barerr = drive(bare, target, h.omap(), &sinks);
|
|
631
|
+
try testing.expect(barerr != null);
|
|
632
|
+
|
|
633
|
+
// The raw path returns its failure rather than an error.
|
|
634
|
+
const direct = makeSdk(.transport, &sinks, true, null).direct(h.jo(&.{.{ "path", h.vstr("raw") }}));
|
|
635
|
+
try testing.expect(h.getp(direct, "ok") == .bool and !h.getp(direct, "ok").bool);
|
|
636
|
+
sinks.value("direct", direct);
|
|
637
|
+
|
|
638
|
+
var leaked: usize = 0;
|
|
639
|
+
for (sinks.items.items) |s| {
|
|
640
|
+
const found = leaks(s.text);
|
|
641
|
+
if (0 < found.len) {
|
|
642
|
+
leaked += 1;
|
|
643
|
+
std.debug.print("clean: credential leaked through {s}: {s}\\n", .{ s.name, found[0] });
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
std.debug.print("clean: swept {d} surface(s), {d} leak(s)\\n", .{ sinks.items.items.len, leaked });
|
|
648
|
+
|
|
649
|
+
try testing.expect(0 < sinks.items.items.len);
|
|
650
|
+
try testing.expect(leaked == 0);
|
|
651
|
+
|
|
652
|
+
// The positive half: the slot the credential travelled in is masked, and
|
|
653
|
+
// an unregistered token in a response header is masked by name.
|
|
654
|
+
const nf = notfound orelse {
|
|
655
|
+
std.debug.print("clean: the 404 scenario must fail\\n", .{});
|
|
656
|
+
try testing.expect(false);
|
|
657
|
+
return;
|
|
658
|
+
};
|
|
659
|
+
try testing.expect(h.to_int(h.getp(nf.result, "status")) == 404);
|
|
660
|
+
const spec = nf.spec;
|
|
661
|
+
if (!AUTH.suppressed) {
|
|
662
|
+
if (std.mem.eql(u8, AUTH.where, "query")) {
|
|
663
|
+
try testing.expect(std.mem.eql(u8, header(h.getp(spec, "query"), AUTH.name) orelse "", MASK));
|
|
664
|
+
} else if (std.mem.eql(u8, AUTH.where, "cookie")) {
|
|
665
|
+
const cookie = header(h.getp(spec, "headers"), "cookie") orelse "";
|
|
666
|
+
try testing.expect(std.mem.indexOf(u8, cookie, MASK) != null);
|
|
667
|
+
} else {
|
|
668
|
+
const cred = header(h.getp(spec, "headers"), AUTH.name) orelse "";
|
|
669
|
+
try testing.expect(std.mem.endsWith(u8, cred, MASK));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
try testing.expect(std.mem.eql(u8, header(h.getp(spec, "headers"), "x-custom-token") orelse "", MASK));
|
|
673
|
+
try testing.expectEqualStrings("denied:" ++ MASK, denied.?.code);
|
|
674
|
+
try testing.expectEqualStrings(MASK, header(h.getp(barerr.?.spec, "headers"), "x-custom-token") orelse "");
|
|
675
|
+
|
|
676
|
+
try testing.expect(h.getp(explained, "result") == .object);
|
|
677
|
+
try testing.expect(std.mem.eql(u8, header(h.getp(h.getp(explained, "result"), "headers"), "x-session-token") orelse "", MASK));
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
test "clean: the sweep can see a leak: clean switched off shows the credential" {
|
|
681
|
+
const target = usableOp() orelse {
|
|
682
|
+
std.debug.print(NOTHING_TO_SWEEP, .{});
|
|
683
|
+
return error.SkipZigTest;
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
var sinks = Sinks{};
|
|
687
|
+
const client = makeSdk(.notfound, &sinks, false, null);
|
|
688
|
+
const err = drive(client, target, h.omap(), &sinks);
|
|
689
|
+
try testing.expect(err != null);
|
|
690
|
+
|
|
691
|
+
var seen: usize = 0;
|
|
692
|
+
for (sinks.items.items) |s| {
|
|
693
|
+
if (0 < leaks(s.text).len) seen += 1;
|
|
694
|
+
}
|
|
695
|
+
try testing.expect(0 < seen);
|
|
696
|
+
|
|
697
|
+
if (!AUTH.suppressed) {
|
|
698
|
+
const text = h.jsonify_compact(err.?.spec);
|
|
699
|
+
const basic = base64_std(fmt("{s}:{s}", .{ CANARY_APIKEY, CANARY_SECRET }));
|
|
700
|
+
try testing.expect(std.mem.indexOf(u8, text, CANARY_APIKEY) != null or
|
|
701
|
+
std.mem.indexOf(u8, text, basic) != null);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Explaining a failure must not cost it its error.
|
|
705
|
+
var quiet = Sinks{};
|
|
706
|
+
const explained = drive(makeSdk(.notfound, &quiet, false, null), target,
|
|
707
|
+
h.jo(&.{.{ "explain", h.omap() }}), &quiet);
|
|
708
|
+
try testing.expect(explained != null);
|
|
709
|
+
try testing.expectEqualStrings(err.?.msg, explained.?.msg);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
test "clean: a registered value used as a property name is masked, collisions kept" {
|
|
713
|
+
const client = sdk.SDK.new(h.jo(&.{
|
|
714
|
+
.{ "clean", h.jo(&.{.{ "values", h.vstr("ZZVAL-abc123,ZZVAL-xyz789") }}) },
|
|
715
|
+
}));
|
|
716
|
+
const out = sdk.utilmod.clean_util(client.get_root_ctx(), h.jo(&.{
|
|
717
|
+
.{ "ZZVAL-abc123", h.vnum(1) },
|
|
718
|
+
.{ "ZZVAL-xyz789", h.vnum(2) },
|
|
719
|
+
.{ "plain", h.vnum(3) },
|
|
720
|
+
}));
|
|
721
|
+
try testing.expect(out == .object);
|
|
722
|
+
var keys: std.ArrayList([]const u8) = .empty;
|
|
723
|
+
var it = out.object.iterator();
|
|
724
|
+
while (it.next()) |kv| keys.append(h.A(), kv.key_ptr.*) catch {};
|
|
725
|
+
try testing.expectEqual(@as(usize, 3), keys.items.len);
|
|
726
|
+
try testing.expectEqualStrings(MASK, keys.items[0]);
|
|
727
|
+
try testing.expectEqualStrings(MASK ++ "#1", keys.items[1]);
|
|
728
|
+
try testing.expectEqualStrings("plain", keys.items[2]);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
test "clean: the generated config's own clean block is honoured" {
|
|
732
|
+
const utility = sdk.test_sdk(vnull(), vnull()).get_utility();
|
|
733
|
+
const config = h.jo(&.{.{ "options", h.jo(&.{.{ "clean", h.jo(&.{
|
|
734
|
+
.{ "keys", h.vstr("zzsens") },
|
|
735
|
+
.{ "values", h.vstr("CONFIG-SEEDED-1") },
|
|
736
|
+
}) }}) }});
|
|
737
|
+
const ctx = utility.make_context(sdk.CtxSpec{
|
|
738
|
+
.utility = utility,
|
|
739
|
+
.options = h.jo(&.{.{ "clean", h.jo(&.{.{ "values", h.vstr("CALLER-SEEDED-2") }}) }}),
|
|
740
|
+
.config = config,
|
|
741
|
+
}, null);
|
|
742
|
+
ctx.options = utility.make_options(ctx);
|
|
743
|
+
try testing.expectEqualStrings("a " ++ MASK ++ " b " ++ MASK,
|
|
744
|
+
sdk.utilmod.clean_str_util(ctx, "a CONFIG-SEEDED-1 b CALLER-SEEDED-2"));
|
|
745
|
+
const out = sdk.utilmod.clean_util(ctx, h.jo(&.{ .{ "my_zzsens", h.vstr("x") }, .{ "other", h.vstr("y") } }));
|
|
746
|
+
try testing.expectEqualStrings(MASK, h.get_str(out, "my_zzsens") orelse "");
|
|
747
|
+
try testing.expectEqualStrings("y", h.get_str(out, "other") orelse "");
|
|
748
|
+
const cfgclean = h.getp(h.getp(config, "options"), "clean");
|
|
749
|
+
try testing.expectEqualStrings("zzsens", h.get_str(cfgclean, "keys") orelse "");
|
|
750
|
+
try testing.expectEqualStrings("CONFIG-SEEDED-1", h.get_str(cfgclean, "values") orelse "");
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// A feature's name is not a field name: a feature called secrets does not
|
|
754
|
+
// make its settings secret, though a sensitive field inside it still is. An
|
|
755
|
+
// entity block, of per-entity settings or seeded records keyed by entity name
|
|
756
|
+
// and id, is not read at all.
|
|
757
|
+
test "clean: a feature's name is read as a name" {
|
|
758
|
+
const client = sdk.SDK.new(h.jo(&.{
|
|
759
|
+
.{ "apikey", h.vstr(CANARY_APIKEY) },
|
|
760
|
+
.{ "feature", h.jo(&.{
|
|
761
|
+
.{ "secrets", h.jo(&.{
|
|
762
|
+
.{ "active", h.vbool(false) },
|
|
763
|
+
.{ "name", h.vstr("ZZNAME-feat123") },
|
|
764
|
+
.{ "token", h.vstr("ZZTOKEN-feat456") },
|
|
765
|
+
}) },
|
|
766
|
+
.{ "test", h.jo(&.{
|
|
767
|
+
.{ "active", h.vbool(false) },
|
|
768
|
+
.{ "entity", h.jo(&.{.{ "zztoken", h.jo(&.{.{ "ZZTOKEN01", h.jo(&.{
|
|
769
|
+
.{ "note", h.vstr("PLAINRECORD-t5r3e1w9") },
|
|
770
|
+
}) }}) }}) },
|
|
771
|
+
}) },
|
|
772
|
+
}) },
|
|
773
|
+
.{ "entity", h.jo(&.{.{ "zztoken", h.jo(&.{.{ "alias", h.jo(&.{
|
|
774
|
+
.{ "zzkey", h.vstr("PLAINALIAS-m2n4b6v8") },
|
|
775
|
+
}) }}) }}) },
|
|
776
|
+
}));
|
|
777
|
+
const ctx = client.get_root_ctx();
|
|
778
|
+
try testing.expectEqualStrings("ZZNAME-feat123 " ++ MASK,
|
|
779
|
+
sdk.utilmod.clean_str_util(ctx, "ZZNAME-feat123 ZZTOKEN-feat456"));
|
|
780
|
+
try testing.expectEqualStrings("record PLAINRECORD-t5r3e1w9",
|
|
781
|
+
sdk.utilmod.clean_str_util(ctx, "record PLAINRECORD-t5r3e1w9"));
|
|
782
|
+
try testing.expectEqualStrings("alias PLAINALIAS-m2n4b6v8",
|
|
783
|
+
sdk.utilmod.clean_str_util(ctx, "alias PLAINALIAS-m2n4b6v8"));
|
|
784
|
+
}
|
|
785
|
+
`
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
export {
|
|
790
|
+
TestClean
|
|
791
|
+
}
|