diff --git a/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java b/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java index f553ca61b0..2f473b6233 100644 --- a/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java +++ b/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java @@ -1760,6 +1760,17 @@ public void prefixedFunctionsInExpressions() throws Exception { assertLog(runtime.allLogs(), ".*Hello, world!.*"); } + @Test + public void sensitiveFunction() throws Exception { + deploy("sensitiveFunction"); + + save(ProcessConfiguration.builder().build()); + + run(); + + assertLog(runtime.allLogs(), ".*" + Pattern.quote("The '******' is masked now") + ".*"); + } + private void deploy(String name) throws URISyntaxException, IOException { runtime.deploy(name); } diff --git a/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/functions/TestFunction.java b/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/functions/TestFunction.java index 794c8c54a4..133b100179 100644 --- a/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/functions/TestFunction.java +++ b/runtime/v2/runner-test/src/test/java/com/walmartlabs/concord/runtime/v2/runner/functions/TestFunction.java @@ -1,5 +1,25 @@ package com.walmartlabs.concord.runtime.v2.runner.functions; +/*- + * ***** + * Concord + * ----- + * Copyright (C) 2017 - 2025 Walmart Inc. + * ----- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ===== + */ + import com.walmartlabs.concord.runtime.v2.sdk.ELFunction; import javax.inject.Named; diff --git a/runtime/v2/runner-test/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/sensitiveFunction/concord.yml b/runtime/v2/runner-test/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/sensitiveFunction/concord.yml new file mode 100644 index 0000000000..adfb344deb --- /dev/null +++ b/runtime/v2/runner-test/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/sensitiveFunction/concord.yml @@ -0,0 +1,6 @@ +flows: + default: + - set: + regularValue: "regularValue" + secretValue: "${sensitive(regularValue)}" + - log: "The 'regularValue' is masked now" diff --git a/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/el/functions/MarkAsSensitiveFunction.java b/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/el/functions/MarkAsSensitiveFunction.java new file mode 100644 index 0000000000..265b02a172 --- /dev/null +++ b/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/el/functions/MarkAsSensitiveFunction.java @@ -0,0 +1,59 @@ +package com.walmartlabs.concord.runtime.v2.runner.el.functions; + +/*- + * ***** + * Concord + * ----- + * Copyright (C) 2017 - 2025 Walmart Inc. + * ----- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ===== + */ + +import com.walmartlabs.concord.runtime.v2.sdk.ELFunction; +import com.walmartlabs.concord.runtime.v2.sdk.SensitiveDataHolder; + +import javax.inject.Inject; + +import static java.util.Objects.requireNonNull; + +public class MarkAsSensitiveFunction { + + private static SensitiveDataHolder sensitiveData; + + @Inject + public MarkAsSensitiveFunction(SensitiveDataHolder sensitiveData) { + MarkAsSensitiveFunction.sensitiveData = requireNonNull(sensitiveData); + } + + @ELFunction + public static String sensitive(Object v) { + if (MarkAsSensitiveFunction.sensitiveData == null) { + throw new IllegalStateException("MaskFunction must be initialized first"); + } + + if (v == null) { + return null; + } + + if (v instanceof String s) { + if (s.isBlank()) { + return s; + } + sensitiveData.add(s); + return s; + } + + throw new IllegalArgumentException("Only string values can be masked. Got a " + v.getClass() + " instead"); + } +} diff --git a/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/guice/ExpressionSupportModule.java b/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/guice/ExpressionSupportModule.java index 2371b2f15a..35139a4e22 100644 --- a/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/guice/ExpressionSupportModule.java +++ b/runtime/v2/runner/src/main/java/com/walmartlabs/concord/runtime/v2/runner/guice/ExpressionSupportModule.java @@ -27,9 +27,9 @@ import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; import com.walmartlabs.concord.runtime.v2.runner.el.DefaultExpressionEvaluator; -import com.walmartlabs.concord.runtime.v2.sdk.ELFunction; import com.walmartlabs.concord.runtime.v2.runner.el.FunctionHolder; import com.walmartlabs.concord.runtime.v2.runner.el.functions.*; +import com.walmartlabs.concord.runtime.v2.sdk.ELFunction; import com.walmartlabs.concord.runtime.v2.sdk.ExpressionEvaluator; import java.lang.reflect.Modifier; @@ -84,6 +84,7 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { binder.bind(HasVariableFunction.class).asEagerSingleton(); binder.bind(IsDebugFunction.class).asEagerSingleton(); binder.bind(IsDryRunFunction.class).asEagerSingleton(); + binder.bind(MarkAsSensitiveFunction.class).asEagerSingleton(); binder.bind(OrDefaultFunction.class).asEagerSingleton(); binder.bind(ThrowFunction.class).asEagerSingleton(); binder.bind(UuidFunction.class).asEagerSingleton();