Skip to content

Commit

Permalink
feat(core): secret function added taking environment starting with "S…
Browse files Browse the repository at this point in the history
…ECRETS_"

closes #1679
  • Loading branch information
brian-mulier-p committed Jul 3, 2023
1 parent 16fe7a2 commit dd4e958
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 0 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ subprojects {
// configure en_US default locale for tests
systemProperty 'user.language', 'en'
systemProperty 'user.country', 'US'

environment 'SECRETS_MY_SECRET', "{\"secretKey\":\"secretValue\"}".bytes.encodeBase64().toString()
}

testlogger {
Expand Down
65 changes: 65 additions & 0 deletions core/src/main/java/io/kestra/core/secret/SecretExtension.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.kestra.core.secret;

import io.pebbletemplates.pebble.extension.*;
import io.pebbletemplates.pebble.operator.BinaryOperator;
import io.pebbletemplates.pebble.operator.UnaryOperator;
import io.pebbletemplates.pebble.tokenParser.TokenParser;
import io.micronaut.context.annotation.Requires;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

@Singleton
public class SecretExtension extends AbstractExtension {
@Inject
private SecretFunction secretFunction;

@Override
public List<TokenParser> getTokenParsers() {
return null;
}

@Override
public List<UnaryOperator> getUnaryOperators() {
return null;
}

@Override
public List<BinaryOperator> getBinaryOperators() {
return null;
}

@Override
public Map<String, Filter> getFilters() {
return null;
}

@Override
public Map<String, Test> getTests() {
return null;
}

@Override
public Map<String, Function> getFunctions() {
Map<String, Function> tests = new HashMap<>();

tests.put("secret", secretFunction);

return tests;
}

@Override
public Map<String, Object> getGlobalVariables() {
return null;
}

@Override
public List<NodeVisitorFactory> getNodeVisitors() {
return null;
}
}


42 changes: 42 additions & 0 deletions core/src/main/java/io/kestra/core/secret/SecretFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.kestra.core.secret;

import io.kestra.core.exceptions.IllegalVariableEvaluationException;
import io.pebbletemplates.pebble.error.PebbleException;
import io.pebbletemplates.pebble.extension.Function;
import io.pebbletemplates.pebble.template.EvaluationContext;
import io.pebbletemplates.pebble.template.PebbleTemplate;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import java.util.List;
import java.util.Map;

@Singleton
public class SecretFunction implements Function {
@Inject
private SecretService secretService;

@Override
public List<String> getArgumentNames() {
return List.of("key");
}

@Override
public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
String key = getSecretKey(args, self, lineNumber);

try {
return secretService.findSecret(key);
} catch (IllegalVariableEvaluationException e) {
throw new PebbleException(e, e.getMessage(), lineNumber, self.getName());
}
}

protected String getSecretKey(Map<String, Object> args, PebbleTemplate self, int lineNumber) {
if (!args.containsKey("key")) {
throw new PebbleException(null, "The 'secret' function expects an argument 'key'.", lineNumber, self.getName());
}

return (String) args.get("key");
}
}
17 changes: 17 additions & 0 deletions core/src/main/java/io/kestra/core/secret/SecretService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.kestra.core.secret;

import io.kestra.core.exceptions.IllegalVariableEvaluationException;
import jakarta.inject.Singleton;

import java.util.Base64;
import java.util.Optional;

@Singleton
public class SecretService {
public String findSecret(String key) throws IllegalVariableEvaluationException {
String environmentVariable = Optional.ofNullable(System.getenv("SECRETS_" + key.toUpperCase()))
.orElseThrow(() -> new IllegalVariableEvaluationException("Unable to find secret '" + key + "'. " +
"You should add it in your environment variables as 'SECRETS_" + key.toUpperCase()+"' with base64-encoded value."));
return new String(Base64.getDecoder().decode(environmentVariable));
}
}
38 changes: 38 additions & 0 deletions core/src/test/java/io/kestra/core/secret/SecretFunctionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.kestra.core.secret;

import io.kestra.core.exceptions.IllegalVariableEvaluationException;
import io.kestra.core.models.executions.Execution;
import io.kestra.core.runners.AbstractMemoryRunnerTest;
import io.kestra.core.runners.RunnerUtils;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.concurrent.TimeoutException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

@MicronautTest
public class SecretFunctionTest extends AbstractMemoryRunnerTest {
@Inject
private RunnerUtils runnerUtils;
@Inject
private SecretService secretService;

@Test
void getSecret() throws TimeoutException {
Execution execution = runnerUtils.runOne("io.kestra.tests", "secrets");
assertThat(execution.getTaskRunList().get(0).getOutputs().get("value"), is("secretValue"));
}

@Test
void getUnknownSecret() {
IllegalVariableEvaluationException exception = Assertions.assertThrows(IllegalVariableEvaluationException.class, () ->
secretService.findSecret("unknown_secret_key")
);

assertThat(exception.getMessage(), is("Unable to find secret 'unknown_secret_key'. You should add it in your environment variables as 'SECRETS_UNKNOWN_SECRET_KEY' with base64-encoded value."));
}
}
7 changes: 7 additions & 0 deletions core/src/test/resources/flows/valids/secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
id: secrets
namespace: io.kestra.tests

tasks:
- id: get-secret
type: io.kestra.core.tasks.debugs.Return
format: "{{json(secret('my_secret')).secretKey}}"

0 comments on commit dd4e958

Please sign in to comment.