Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions dd-smoke-tests/appsec/lambda-sca/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
id 'dd-trace-java.module.smoke-test'
}

description = 'Lambda SCA reachability smoke test'

dependencies {
compileOnly project(':dd-trace-api')
implementation group: 'com.amazonaws', name: 'aws-lambda-java-core', version: '1.2.3'
runtimeOnly group: 'com.github.junrar', name: 'junrar', version: '7.5.5'
testImplementation project(':dd-smoke-tests')
}

// Launch with the runtime classpath: Junrar must retain its own JAR code source for SCA.
tasks.withType(Test).configureEach {
dependsOn tasks.named('classes')
jvmArgumentProviders.add(new CommandLineArgumentProvider() {
@Override
Iterable<String> asArguments() {
return ["-Ddatadog.smoketest.lambda.classpath=${sourceSets.main.runtimeClasspath.asPath}"]
}
})
}
128 changes: 128 additions & 0 deletions dd-smoke-tests/appsec/lambda-sca/gradle.lockfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
# To regenerate this file, run: ./gradlew :dd-smoke-tests:appsec:lambda-sca:dependencies --write-locks
cafe.cryptography:curve25519-elisabeth:0.1.0=testRuntimeClasspath
cafe.cryptography:ed25519-elisabeth:0.1.0=testRuntimeClasspath
ch.qos.logback:logback-classic:1.2.13=testCompileClasspath,testRuntimeClasspath
ch.qos.logback:logback-core:1.2.13=testCompileClasspath,testRuntimeClasspath
com.amazonaws:aws-lambda-java-core:1.2.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.blogspot.mydailyjava:weak-lock-free:0.17=testCompileClasspath,testRuntimeClasspath
com.datadoghq.okhttp3:okhttp:3.12.15=testCompileClasspath,testRuntimeClasspath
com.datadoghq.okio:okio:1.17.6=testCompileClasspath,testRuntimeClasspath
com.datadoghq:dd-instrument-java:0.0.6=testCompileClasspath,testRuntimeClasspath
com.datadoghq:dd-javac-plugin-client:0.2.2=testCompileClasspath,testRuntimeClasspath
com.datadoghq:java-dogstatsd-client:4.4.5=testRuntimeClasspath
com.datadoghq:sketches-java:0.8.3=testRuntimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.10.3=testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-api:3.4.2=testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport-zerodep:3.4.2=testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport:3.4.2=testCompileClasspath,testRuntimeClasspath
com.github.javaparser:javaparser-core:3.25.6=codenarc
com.github.jnr:jffi:1.3.15=testRuntimeClasspath
com.github.jnr:jnr-a64asm:1.0.0=testRuntimeClasspath
com.github.jnr:jnr-constants:0.10.4=testRuntimeClasspath
com.github.jnr:jnr-enxio:0.32.20=testRuntimeClasspath
com.github.jnr:jnr-ffi:2.2.19=testRuntimeClasspath
com.github.jnr:jnr-posix:3.1.22=testRuntimeClasspath
com.github.jnr:jnr-unixsocket:0.38.25=testRuntimeClasspath
com.github.jnr:jnr-x86asm:1.0.2=testRuntimeClasspath
com.github.junrar:junrar:7.5.5=runtimeClasspath,testRuntimeClasspath
com.github.spotbugs:spotbugs-annotations:4.10.4=compileClasspath,spotbugs
com.github.spotbugs:spotbugs:4.10.4=spotbugs
com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.14.0=spotbugs
com.google.errorprone:error_prone_annotations:2.47.0=testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.48.0=spotbugs
com.google.guava:failureaccess:1.0.3=testCompileClasspath,testRuntimeClasspath
com.google.guava:guava:33.6.0-jre=testCompileClasspath,testRuntimeClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=testCompileClasspath,testRuntimeClasspath
com.google.j2objc:j2objc-annotations:3.1=testCompileClasspath,testRuntimeClasspath
com.google.re2j:re2j:1.8=testRuntimeClasspath
com.squareup.moshi:moshi:1.11.0=testCompileClasspath,testRuntimeClasspath
com.squareup.okhttp3:logging-interceptor:3.12.12=testCompileClasspath,testRuntimeClasspath
com.squareup.okhttp3:okhttp:3.12.12=testCompileClasspath,testRuntimeClasspath
com.squareup.okio:okio:1.17.5=testCompileClasspath,testRuntimeClasspath
com.thoughtworks.qdox:qdox:1.12.1=codenarc
commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.21.0=spotbugs
de.thetaphi:forbiddenapis:3.11=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
io.sqreen:libsqreen:17.5.0=testRuntimeClasspath
javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath
jaxen:jaxen:2.0.6=spotbugs
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.18.12=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.18.12=testCompileClasspath,testRuntimeClasspath
net.java.dev.jna:jna-platform:5.8.0=testRuntimeClasspath
net.java.dev.jna:jna:5.13.0=testCompileClasspath,testRuntimeClasspath
net.sf.saxon:Saxon-HE:12.10=spotbugs
org.apache.ant:ant-antlr:1.10.14=codenarc
org.apache.ant:ant-junit:1.10.14=codenarc
org.apache.bcel:bcel:6.12.0=spotbugs
org.apache.commons:commons-compress:1.24.0=testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-lang3:3.20.0=spotbugs
org.apache.commons:commons-text:1.15.0=spotbugs
org.apache.logging.log4j:log4j-api:2.26.1=spotbugs
org.apache.logging.log4j:log4j-core:2.26.1=spotbugs
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testRuntimeClasspath
org.codehaus.groovy:groovy-ant:3.0.23=codenarc
org.codehaus.groovy:groovy-docgenerator:3.0.23=codenarc
org.codehaus.groovy:groovy-groovydoc:3.0.23=codenarc
org.codehaus.groovy:groovy-json:3.0.23=codenarc
org.codehaus.groovy:groovy-json:3.0.25=testCompileClasspath,testRuntimeClasspath
org.codehaus.groovy:groovy-templates:3.0.23=codenarc
org.codehaus.groovy:groovy-xml:3.0.23=codenarc
org.codehaus.groovy:groovy:3.0.23=codenarc
org.codehaus.groovy:groovy:3.0.25=testCompileClasspath,testRuntimeClasspath
org.codenarc:CodeNarc:3.7.0=codenarc
org.dom4j:dom4j:2.2.0=spotbugs
org.gmetrics:GMetrics:2.1.0=codenarc
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
org.hamcrest:hamcrest:3.0=testCompileClasspath,testRuntimeClasspath
org.jctools:jctools-core-jdk11:4.0.6=testRuntimeClasspath
org.jctools:jctools-core:4.0.6=testRuntimeClasspath
org.jetbrains:annotations:17.0.0=testCompileClasspath,testRuntimeClasspath
org.jspecify:jspecify:1.0.0=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.14.1=testRuntimeClasspath
org.junit.platform:junit-platform-runner:1.14.1=testRuntimeClasspath
org.junit.platform:junit-platform-suite-api:1.14.1=testRuntimeClasspath
org.junit.platform:junit-platform-suite-commons:1.14.1=testRuntimeClasspath
org.junit:junit-bom:5.14.1=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:4.4.0=testRuntimeClasspath
org.msgpack:msgpack-core:0.8.24=testRuntimeClasspath
org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:9.10.1=spotbugs
org.ow2.asm:asm-analysis:9.7.1=testRuntimeClasspath
org.ow2.asm:asm-commons:9.10.1=spotbugs
org.ow2.asm:asm-commons:9.7.1=testRuntimeClasspath
org.ow2.asm:asm-tree:9.10.1=spotbugs
org.ow2.asm:asm-tree:9.7.1=testRuntimeClasspath
org.ow2.asm:asm-util:9.10.1=spotbugs
org.ow2.asm:asm-util:9.7.1=testRuntimeClasspath
org.ow2.asm:asm:9.10.1=spotbugs,testCompileClasspath,testRuntimeClasspath
org.rnorth.duct-tape:duct-tape:1.0.8=testCompileClasspath,testRuntimeClasspath
org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.30=compileClasspath
org.slf4j:slf4j-api:1.7.36=runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.17=spotbugsSlf4j
org.slf4j:slf4j-api:2.0.18=spotbugs
org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j
org.spockframework:spock-bom:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
org.spockframework:spock-core:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
org.tabletest:tabletest-junit:1.2.2=testCompileClasspath,testRuntimeClasspath
org.tabletest:tabletest-parser:1.2.1=testCompileClasspath,testRuntimeClasspath
org.testcontainers:testcontainers:1.21.4=testCompileClasspath,testRuntimeClasspath
org.xmlresolver:xmlresolver:5.3.3=spotbugs
empty=annotationProcessor,spotbugsPlugins,testAnnotationProcessor
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package datadog.smoketest.lambda;

import com.amazonaws.services.lambda.runtime.Context;
import com.sun.net.httpserver.HttpServer;
import datadog.trace.api.GlobalTracer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;

/** Drives a real streaming Lambda handler and stubs the extension's invocation protocol. */
public final class LambdaScaApplication {
public static void main(String[] args) throws Exception {
HttpServer server =
HttpServer.create(new InetSocketAddress("127.0.0.1", Integer.parseInt(args[0])), 0);
// Invocation instrumentation calls the extension while the /invoke request is still running.
server.setExecutor(Executors.newCachedThreadPool());
server.createContext(
"/lambda/start-invocation",
exchange -> {
exchange.getResponseHeaders().add("x-datadog-trace-id", "123");
exchange.getResponseHeaders().add("x-datadog-span-id", "456");
exchange.getResponseHeaders().add("x-datadog-sampling-priority", "1");
exchange.sendResponseHeaders(200, -1);
exchange.close();
});
server.createContext(
"/lambda/end-invocation",
exchange -> {
System.out.println(
"LAMBDA_END "
+ exchange.getRequestHeaders().getFirst("lambda-runtime-aws-request-id"));
exchange.sendResponseHeaders(200, -1);
exchange.close();
});
// The setter belongs to the agent's isolated classloader, not the fixture's classpath.
GlobalTracer.get()
.getClass()
.getClassLoader()
.loadClass("datadog.trace.lambda.LambdaHandler")
.getMethod("setExtensionBaseUrl", String.class)
.invoke(null, "http://127.0.0.1:" + server.getAddress().getPort());
// This endpoint only loads the class. The test waits for advisory telemetry before invoking it.
server.createContext(
"/load-dependency",
exchange -> {
try {
Class.forName("com.github.junrar.LocalFolderExtractor");
exchange.sendResponseHeaders(200, -1);
} catch (ClassNotFoundException failure) {
failure.printStackTrace();
exchange.sendResponseHeaders(500, -1);
} finally {
exchange.close();
}
});
LambdaScaHandler handler = new LambdaScaHandler();
server.createContext(
"/invoke/",
exchange -> {
String invocation = exchange.getRequestURI().getPath().substring("/invoke/".length());
Context context =
(Context)
Proxy.newProxyInstance(
Context.class.getClassLoader(),
new Class<?>[] {Context.class},
(proxy, method, arguments) -> {
switch (method.getName()) {
case "getAwsRequestId":
return invocation;
case "getRemainingTimeInMillis":
return 30_000;
case "getMemoryLimitInMB":
return 1024;
case "equals":
return proxy == arguments[0];
case "hashCode":
return System.identityHashCode(proxy);
case "toString":
return "LambdaContext[requestId=" + invocation + "]";
default:
return null;
}
});
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
handler.handleRequest(
new ByteArrayInputStream(invocation.getBytes(StandardCharsets.UTF_8)),
output,
context);
byte[] response = output.toByteArray();
exchange.sendResponseHeaders(200, response.length);
exchange.getResponseBody().write(response);
} catch (Exception failure) {
failure.printStackTrace();
exchange.sendResponseHeaders(500, -1);
} finally {
exchange.close();
}
});
server.start();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package datadog.smoketest.lambda;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;

/** Calls the watched method inside an instrumented Lambda invocation. */
public final class LambdaScaHandler implements RequestStreamHandler {
@Override
public void handleRequest(InputStream input, OutputStream output, Context context)
throws IOException {
try {
warmInvocation();
output.write("OK".getBytes(StandardCharsets.UTF_8));
} catch (ReflectiveOperationException failure) {
throw new IOException(failure);
}
}

private static void warmInvocation() throws ReflectiveOperationException {
Class<?> extractor = Class.forName("com.github.junrar.LocalFolderExtractor");
Constructor<?> constructor = extractor.getDeclaredConstructor(File.class);
constructor.setAccessible(true);
Object instance = constructor.newInstance(new File(System.getProperty("java.io.tmpdir")));
Method method =
extractor.getDeclaredMethod(
"createDirectory", Class.forName("com.github.junrar.rarfile.FileHeader"));
method.setAccessible(true);
try {
// LambdaScaSmokeTest asserts the exact line of this call; update it if this line moves.
method.invoke(instance, (Object) null);
} catch (InvocationTargetException failure) {
// Reaching method entry is sufficient; no archive extraction or filesystem write is needed.
if (!(failure.getCause() instanceof NullPointerException)) {
throw failure;
}
}
}
}
Loading
Loading