Skip to content

Commit df20e6d

Browse files
authored
feat(sdk): add CLI and integration tests (#64)
Add a simple CLI and set up the platform so we can run e2e tests against it. Also includes a fix for using encrypted metadata (#67). The correct transform is ``` encryptedMetadata = base64(string({ "iv": base64(iv), "ciphertext": base64(ciphertext) }) ```
1 parent e1da325 commit df20e6d

File tree

15 files changed

+502
-157
lines changed

15 files changed

+502
-157
lines changed

.github/workflows/checks.yaml

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ jobs:
3030

3131
mavenverify:
3232
runs-on: ubuntu-latest
33-
if: always()
3433
needs:
3534
- pr
3635
steps:
@@ -52,8 +51,127 @@ jobs:
5251
BUF_INPUT_HTTPS_USERNAME: opentdf-bot
5352
BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }}
5453

54+
platform-integration:
55+
runs-on: ubuntu-22.04
56+
needs:
57+
- pr
58+
steps:
59+
- name: Checkout Java SDK
60+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
61+
- uses: bufbuild/buf-setup-action@382440cdb8ec7bc25a68d7b4711163d95f7cc3aa
62+
with:
63+
github_token: ${{ secrets.GITHUB_TOKEN }}
64+
- name: Set up JDK
65+
uses: actions/setup-java@5896cecc08fd8a1fbdfaf517e29b571164b031f7
66+
with:
67+
java-version: "11"
68+
distribution: "adopt"
69+
server-id: github
70+
- name: Build java SDK
71+
run: |
72+
mvn --batch-mode clean install -DskipTests
73+
env:
74+
BUF_INPUT_HTTPS_USERNAME: opentdf-bot
75+
BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }}
76+
- name: Check out platform
77+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
78+
with:
79+
repository: opentdf/platform
80+
ref: main
81+
path: platform
82+
- name: Set up go
83+
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
84+
with:
85+
go-version: "1.22.3"
86+
check-latest: false
87+
cache-dependency-path: |
88+
platform/service/go.sum
89+
platform/examples/go.sum
90+
platform/protocol/go/go.sum
91+
platform/sdk/go.sum
92+
- run: go mod download
93+
working-directory: platform
94+
- run: go mod verify
95+
working-directory: platform
96+
- name: Create keys
97+
run: |
98+
.github/scripts/init-temp-keys.sh
99+
cp opentdf-dev.yaml opentdf.yaml
100+
sudo chmod -R 777 ./keys
101+
working-directory: platform
102+
- name: Trust the locally issued cert
103+
run: |
104+
keytool \
105+
-importcert \
106+
-storepass changeit \
107+
-noprompt \
108+
-file localhost.crt \
109+
-keystore $JAVA_HOME/lib/security/cacerts \
110+
-alias localhost-for-tests
111+
working-directory: platform/keys
112+
- name: Bring the services up
113+
run: docker compose up -d --wait --wait-timeout 240
114+
working-directory: platform
115+
- name: Provision keycloak
116+
run: go run ./service provision keycloak
117+
working-directory: platform
118+
- name: Provision fixtures
119+
run: go run ./service provision fixtures
120+
working-directory: platform
121+
- name: Start server in background
122+
uses: JarvusInnovations/background-action@2428e7b970a846423095c79d43f759abf979a635
123+
with:
124+
run: |
125+
go run ./service start
126+
wait-on: |
127+
tcp:localhost:8080
128+
log-output-if: true
129+
wait-for: 90s
130+
working-directory: platform
131+
- name: Get grpcurl
132+
run: go install github.com/fullstorydev/grpcurl/cmd/[email protected]
133+
- name: Make sure that the platform is up
134+
run: |
135+
grpcurl -plaintext localhost:8080 list && \
136+
grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey
137+
- name: Validate the SDK through the command line interface
138+
run: |
139+
printf 'here is some data to encrypt' > data
140+
141+
java -jar target/cmdline.jar \
142+
--client-id=opentdf-sdk \
143+
--client-secret=secret \
144+
--platform-endpoint=localhost:8080 \
145+
-i \
146+
encrypt --kas-url=localhost:8080 -f data -m 'here is some metadata' > test.tdf
147+
148+
java -jar target/cmdline.jar \
149+
--client-id=opentdf-sdk \
150+
--client-secret=secret \
151+
--platform-endpoint=localhost:8080 \
152+
-i \
153+
decrypt -f test.tdf > decrypted
154+
155+
java -jar target/cmdline.jar \
156+
--client-id=opentdf-sdk \
157+
--client-secret=secret \
158+
--platform-endpoint=localhost:8080 \
159+
-i \
160+
metadata -f test.tdf > metadata
161+
162+
if ! diff -q data decrypted; then
163+
printf 'decrypted data is incorrect [%s]' "$(< decrypted)"
164+
exit 1
165+
fi
166+
167+
if [ "$(< metadata)" != 'here is some metadata' ]; then
168+
printf 'metadata is incorrect [%s]\n' "$(< metadata)"
169+
exit 1
170+
fi
171+
working-directory: cmdline
55172
ci:
56173
needs:
174+
- platform-integration
57175
- mavenverify
58176
- pr
59177
runs-on: ubuntu-latest

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
protocol/src/main/protogen
22
/.idea/
3-
/protocol/target/
4-
/sdk/target/
3+
target/
54
.vscode/
65
.DS_Store

cmdline/pom.xml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>io.opentdf.platform</groupId>
8+
<artifactId>sdk-pom</artifactId>
9+
<version>0.1.0-SNAPSHOT</version>
10+
</parent>
11+
<artifactId>cmdline</artifactId>
12+
<properties>
13+
<maven.compiler.source>11</maven.compiler.source>
14+
<maven.compiler.target>11</maven.compiler.target>
15+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
16+
</properties>
17+
<build>
18+
<plugins>
19+
<plugin>
20+
<groupId>org.apache.maven.plugins</groupId>
21+
<artifactId>maven-assembly-plugin</artifactId>
22+
<version>3.7.1</version>
23+
<executions>
24+
<execution>
25+
<phase>package</phase>
26+
<goals>
27+
<goal>single</goal>
28+
</goals>
29+
</execution>
30+
</executions>
31+
<configuration>
32+
<descriptorRefs>
33+
<descriptorRef>jar-with-dependencies</descriptorRef>
34+
</descriptorRefs>
35+
<finalName>cmdline</finalName>
36+
<appendAssemblyId>false</appendAssemblyId>
37+
<archive>
38+
<manifest>
39+
<mainClass>io.opentdf.platform.TDF</mainClass>
40+
</manifest>
41+
</archive>
42+
</configuration>
43+
</plugin>
44+
</plugins>
45+
</build>
46+
<dependencies>
47+
<dependency>
48+
<groupId>info.picocli</groupId>
49+
<artifactId>picocli</artifactId>
50+
<version>4.7.6</version>
51+
</dependency>
52+
<dependency>
53+
<groupId>io.opentdf.platform</groupId>
54+
<artifactId>sdk</artifactId>
55+
<version>0.1.0-SNAPSHOT</version>
56+
</dependency>
57+
</dependencies>
58+
</project>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package io.opentdf.platform;
2+
3+
import io.opentdf.platform.sdk.Config;
4+
import io.opentdf.platform.sdk.SDK;
5+
import io.opentdf.platform.sdk.SDKBuilder;
6+
import io.opentdf.platform.sdk.TDF;
7+
import picocli.CommandLine;
8+
import picocli.CommandLine.Option;
9+
10+
import javax.crypto.BadPaddingException;
11+
import javax.crypto.IllegalBlockSizeException;
12+
import javax.crypto.NoSuchPaddingException;
13+
import java.io.BufferedInputStream;
14+
import java.io.BufferedOutputStream;
15+
import java.io.ByteArrayOutputStream;
16+
import java.io.File;
17+
import java.io.FileInputStream;
18+
import java.io.IOException;
19+
import java.io.PrintWriter;
20+
import java.io.StringWriter;
21+
import java.nio.channels.FileChannel;
22+
import java.nio.file.Path;
23+
import java.nio.file.StandardOpenOption;
24+
import java.security.InvalidAlgorithmParameterException;
25+
import java.security.InvalidKeyException;
26+
import java.security.NoSuchAlgorithmException;
27+
import java.util.ArrayList;
28+
import java.util.List;
29+
import java.util.Optional;
30+
import java.util.function.Consumer;
31+
32+
@CommandLine.Command(name = "tdf")
33+
class Command {
34+
35+
@Option(names = {"--client-secret"}, required = true)
36+
private String clientSecret;
37+
38+
@Option(names = {"-i", "--insecure-connection"}, defaultValue = "false")
39+
private boolean insecure;
40+
41+
@Option(names = {"--client-id"}, required = true)
42+
private String clientId;
43+
44+
@Option(names = {"-p", "--platform-endpoint"}, required = true)
45+
private String platformEndpoint;
46+
47+
@CommandLine.Command(name = "encrypt")
48+
void encrypt(
49+
@Option(names = {"-f", "--file"}, defaultValue = Option.NULL_VALUE) Optional<File> file,
50+
@Option(names = {"-k", "--kas-url"}, required = true) List<String> kas,
51+
@Option(names = {"-m", "--metadata"}, defaultValue = Option.NULL_VALUE) Optional<String> metadata) throws IOException {
52+
53+
var sdk = buildSDK();
54+
var kasInfos = kas.stream().map(k -> {
55+
var ki = new Config.KASInfo();
56+
ki.URL = k;
57+
return ki;
58+
}).toArray(Config.KASInfo[]::new);
59+
60+
List<Consumer<Config.TDFConfig>> configs = new ArrayList<>();
61+
configs.add(Config.withKasInformation(kasInfos));
62+
metadata.map(Config::withMetaData).ifPresent(configs::add);
63+
64+
var tdfConfig = Config.newTDFConfig(configs.toArray(Consumer[]::new));
65+
try (var in = file.isEmpty() ? new BufferedInputStream(System.in) : new FileInputStream(file.get())) {
66+
try (var out = new BufferedOutputStream(System.out)) {
67+
new TDF().createTDF(in, out, tdfConfig, sdk.getServices().kas());
68+
}
69+
}
70+
}
71+
72+
private SDK buildSDK() {
73+
return new SDKBuilder()
74+
.platformEndpoint(platformEndpoint)
75+
.clientSecret(clientId, clientSecret)
76+
.useInsecurePlaintextConnection(insecure)
77+
.build();
78+
}
79+
80+
@CommandLine.Command(name = "decrypt")
81+
void decrypt(@Option(names = {"-f", "--file"}, required = true) Path tdfPath) throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
82+
var sdk = buildSDK();
83+
try (var in = FileChannel.open(tdfPath, StandardOpenOption.READ)) {
84+
try (var stdout = new BufferedOutputStream(System.out)) {
85+
var reader = new TDF().loadTDF(in, sdk.getServices().kas());
86+
reader.readPayload(stdout);
87+
}
88+
}
89+
}
90+
@CommandLine.Command(name = "metadata")
91+
void readMetadata(@Option(names = {"-f", "--file"}, required = true) Path tdfPath) throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
92+
var sdk = buildSDK();
93+
94+
try (var in = FileChannel.open(tdfPath, StandardOpenOption.READ)) {
95+
try (var stdout = new PrintWriter(System.out)) {
96+
var reader = new TDF().loadTDF(in, sdk.getServices().kas());
97+
stdout.write(reader.getMetadata() == null ? "" : reader.getMetadata());
98+
}
99+
}
100+
}
101+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.opentdf.platform;
2+
3+
import picocli.CommandLine;
4+
5+
public class TDF {
6+
public static void main(String[] args) {
7+
var result = new CommandLine(new Command()).execute(args);
8+
System.exit(result);
9+
}
10+
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<modules>
2323
<module>protocol</module>
2424
<module>sdk</module>
25+
<module>cmdline</module>
2526
</modules>
2627
<dependencyManagement>
2728
<dependencies>

sdk/pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
<dependency>
5050
<groupId>io.grpc</groupId>
5151
<artifactId>grpc-netty-shaded</artifactId>
52-
<scope>runtime</scope>
5352
</dependency>
5453
<dependency>
5554
<groupId>io.grpc</groupId>

0 commit comments

Comments
 (0)