Skip to content

Commit 20a0420

Browse files
l46kokcopybara-github
authored andcommitted
Add code for Exercise 7 Codelabs
PiperOrigin-RevId: 630195206
1 parent 27a9ecd commit 20a0420

8 files changed

Lines changed: 300 additions & 4 deletions

File tree

codelab/src/main/codelab/BUILD.bazel

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ java_library(
99
name = "codelab",
1010
srcs = glob(["*.java"]),
1111
deps = [
12-
"@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep
13-
"@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep
14-
"@maven//:com_google_guava_guava", # unuseddeps: keep
1512
"//common", # unuseddeps: keep
1613
"//common:compiler_common", # unuseddeps: keep
1714
"//common:proto_json_adapter", # unuseddeps: keep
1815
"//common/types", # unuseddeps: keep
1916
"//common/types:type_providers", # unuseddeps: keep
2017
"//compiler", # unuseddeps: keep
2118
"//compiler:compiler_builder", # unuseddeps: keep
19+
"//parser:macro", # unuseddeps: keep
2220
"//runtime", # unuseddeps: keep
21+
"@maven//:com_google_api_grpc_proto_google_common_protos", # unuseddeps: keep
22+
"@maven//:com_google_guava_guava", # unuseddeps: keep
23+
"@maven//:com_google_protobuf_protobuf_java", # unuseddeps: keep
2324
"@maven//:com_google_protobuf_protobuf_java_util", # unuseddeps: keep
24-
#
2525
],
2626
)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package codelab;
16+
17+
import com.google.rpc.context.AttributeContext.Request;
18+
import dev.cel.common.CelAbstractSyntaxTree;
19+
import dev.cel.common.CelValidationException;
20+
import dev.cel.common.types.SimpleType;
21+
import dev.cel.compiler.CelCompiler;
22+
import dev.cel.compiler.CelCompilerFactory;
23+
import dev.cel.runtime.CelEvaluationException;
24+
import dev.cel.runtime.CelRuntime;
25+
import dev.cel.runtime.CelRuntimeFactory;
26+
import java.util.Map;
27+
28+
/**
29+
* Exercise7 introduces macros for dealing with repeated fields and maps.
30+
*
31+
* <p>Determine whether the `jwt.extra_claims` has at least one key that starts with the `group`
32+
* prefix, and ensure that all group-like keys have list values containing only strings that end
33+
* with '@acme.co`.
34+
*/
35+
final class Exercise7 {
36+
37+
/**
38+
* Compiles the input expression.
39+
*
40+
* @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic
41+
* errors.
42+
*/
43+
CelAbstractSyntaxTree compile(String expression) {
44+
CelCompiler celCompiler =
45+
CelCompilerFactory.standardCelCompilerBuilder()
46+
.addVar("jwt", SimpleType.DYN)
47+
// Set the macros here for `all`, `filter` and `exists`.
48+
.setResultType(SimpleType.BOOL)
49+
.build();
50+
51+
try {
52+
return celCompiler.compile(expression).getAst();
53+
} catch (CelValidationException e) {
54+
throw new IllegalArgumentException("Failed to compile expression.", e);
55+
}
56+
}
57+
58+
/** Evaluates the compiled AST with the user provided parameter values. */
59+
Object eval(CelAbstractSyntaxTree ast, Map<String, ?> parameterValues) {
60+
CelRuntime celRuntime =
61+
CelRuntimeFactory.standardCelRuntimeBuilder()
62+
.addMessageTypes(Request.getDescriptor())
63+
.build();
64+
65+
try {
66+
CelRuntime.Program program = celRuntime.createProgram(ast);
67+
return program.eval(parameterValues);
68+
} catch (CelEvaluationException e) {
69+
throw new IllegalArgumentException("Evaluation error has occurred.", e);
70+
}
71+
}
72+
}

codelab/src/main/codelab/solutions/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ java_library(
1616
"//common/types:type_providers",
1717
"//compiler",
1818
"//compiler:compiler_builder",
19+
"//parser:macro",
1920
"//runtime",
2021
"@maven//:com_google_api_grpc_proto_google_common_protos",
2122
"@maven//:com_google_guava_guava",
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package codelab.solutions;
16+
17+
import com.google.rpc.context.AttributeContext.Request;
18+
import dev.cel.common.CelAbstractSyntaxTree;
19+
import dev.cel.common.CelValidationException;
20+
import dev.cel.common.types.SimpleType;
21+
import dev.cel.compiler.CelCompiler;
22+
import dev.cel.compiler.CelCompilerFactory;
23+
import dev.cel.parser.CelStandardMacro;
24+
import dev.cel.runtime.CelEvaluationException;
25+
import dev.cel.runtime.CelRuntime;
26+
import dev.cel.runtime.CelRuntimeFactory;
27+
import java.util.Map;
28+
29+
/**
30+
* Exercise7 introduces macros for dealing with repeated fields and maps.
31+
*
32+
* <p>Determine whether the `jwt.extra_claims` has at least one key that starts with the `group`
33+
* prefix, and ensure that all group-like keys have list values containing only strings that end
34+
* with '@acme.co`.
35+
*/
36+
final class Exercise7 {
37+
38+
/**
39+
* Compiles the input expression.
40+
*
41+
* @throws IllegalArgumentException If the expression is malformed due to syntactic or semantic
42+
* errors.
43+
*/
44+
CelAbstractSyntaxTree compile(String expression) {
45+
CelCompiler celCompiler =
46+
CelCompilerFactory.standardCelCompilerBuilder()
47+
.addVar("jwt", SimpleType.DYN)
48+
.setStandardMacros(
49+
CelStandardMacro.ALL, CelStandardMacro.FILTER, CelStandardMacro.EXISTS)
50+
.setResultType(SimpleType.BOOL)
51+
.build();
52+
53+
try {
54+
return celCompiler.compile(expression).getAst();
55+
} catch (CelValidationException e) {
56+
throw new IllegalArgumentException("Failed to compile expression.", e);
57+
}
58+
}
59+
60+
/** Evaluates the compiled AST with the user provided parameter values. */
61+
Object eval(CelAbstractSyntaxTree ast, Map<String, ?> parameterValues) {
62+
CelRuntime celRuntime =
63+
CelRuntimeFactory.standardCelRuntimeBuilder()
64+
.addMessageTypes(Request.getDescriptor())
65+
.build();
66+
67+
try {
68+
CelRuntime.Program program = celRuntime.createProgram(ast);
69+
return program.eval(parameterValues);
70+
} catch (CelEvaluationException e) {
71+
throw new IllegalArgumentException("Evaluation error has occurred.", e);
72+
}
73+
}
74+
}

codelab/src/test/codelab/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ java_test(
100100
],
101101
)
102102

103+
java_test(
104+
name = "Exercise7Test",
105+
srcs = ["Exercise7Test.java"],
106+
tags = ["notap"],
107+
test_class = "codelab.Exercise7Test",
108+
deps = [
109+
"//:java_truth",
110+
"//codelab",
111+
"//common",
112+
"@maven//:com_google_guava_guava",
113+
"@maven//:com_google_testparameterinjector_test_parameter_injector",
114+
"@maven//:junit_junit",
115+
],
116+
)
117+
103118
test_suite(
104119
name = "exercise_test_suite",
105120
tags = ["notap"],
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package codelab;
16+
17+
import static com.google.common.truth.Truth.assertThat;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.common.collect.ImmutableMap;
21+
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
22+
import dev.cel.common.CelAbstractSyntaxTree;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
26+
@RunWith(TestParameterInjector.class)
27+
public final class Exercise7Test {
28+
private final Exercise7 exercise7 = new Exercise7();
29+
30+
@Test
31+
public void evaluate_checkJwtClaimsWithMacro_evaluatesToTrue() {
32+
String expression =
33+
"jwt.extra_claims.exists(c, c.startsWith('group'))"
34+
+ " && jwt.extra_claims"
35+
+ ".filter(c, c.startsWith('group'))"
36+
+ ".all(c, jwt.extra_claims[c]"
37+
+ ".all(g, g.endsWith('@acme.co')))";
38+
ImmutableMap<String, Object> jwt =
39+
ImmutableMap.of(
40+
"sub",
41+
"serviceAccount:delegate@acme.co",
42+
"aud",
43+
"my-project",
44+
"iss",
45+
"auth.acme.com:12350",
46+
"extra_claims",
47+
ImmutableMap.of("group1", ImmutableList.of("admin@acme.co", "analyst@acme.co")),
48+
"labels",
49+
ImmutableList.of("metadata", "prod", "pii"),
50+
"groupN",
51+
ImmutableList.of("forever@acme.co"));
52+
CelAbstractSyntaxTree ast = exercise7.compile(expression);
53+
54+
// Evaluate a complex-ish JWT with two groups that satisfy the criteria.
55+
// Output: true.
56+
boolean evaluatedResult = (boolean) exercise7.eval(ast, ImmutableMap.of("jwt", jwt));
57+
58+
assertThat(evaluatedResult).isTrue();
59+
}
60+
}

codelab/src/test/codelab/solutions/BUILD.bazel

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,17 @@ java_test(
9393
"@maven//:junit_junit",
9494
],
9595
)
96+
97+
java_test(
98+
name = "Exercise7Test",
99+
srcs = ["Exercise7Test.java"],
100+
test_class = "codelab.solutions.Exercise7Test",
101+
deps = [
102+
"//:java_truth",
103+
"//codelab:solutions",
104+
"//common",
105+
"@maven//:com_google_guava_guava",
106+
"@maven//:com_google_testparameterinjector_test_parameter_injector",
107+
"@maven//:junit_junit",
108+
],
109+
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package codelab.solutions;
16+
17+
import static com.google.common.truth.Truth.assertThat;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.common.collect.ImmutableMap;
21+
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
22+
import dev.cel.common.CelAbstractSyntaxTree;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
26+
@RunWith(TestParameterInjector.class)
27+
public final class Exercise7Test {
28+
private final Exercise7 exercise7 = new Exercise7();
29+
30+
@Test
31+
public void evaluate_checkJwtClaimsWithMacro_evaluatesToTrue() {
32+
String expression =
33+
"jwt.extra_claims.exists(c, c.startsWith('group'))"
34+
+ " && jwt.extra_claims"
35+
+ ".filter(c, c.startsWith('group'))"
36+
+ ".all(c, jwt.extra_claims[c]"
37+
+ ".all(g, g.endsWith('@acme.co')))";
38+
ImmutableMap<String, Object> jwt =
39+
ImmutableMap.of(
40+
"sub",
41+
"serviceAccount:delegate@acme.co",
42+
"aud",
43+
"my-project",
44+
"iss",
45+
"auth.acme.com:12350",
46+
"extra_claims",
47+
ImmutableMap.of("group1", ImmutableList.of("admin@acme.co", "analyst@acme.co")),
48+
"labels",
49+
ImmutableList.of("metadata", "prod", "pii"),
50+
"groupN",
51+
ImmutableList.of("forever@acme.co"));
52+
CelAbstractSyntaxTree ast = exercise7.compile(expression);
53+
54+
// Evaluate a complex-ish JWT with two groups that satisfy the criteria.
55+
// Output: true.
56+
boolean evaluatedResult = (boolean) exercise7.eval(ast, ImmutableMap.of("jwt", jwt));
57+
58+
assertThat(evaluatedResult).isTrue();
59+
}
60+
}

0 commit comments

Comments
 (0)