-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test asm standalone from appsec extension
- Loading branch information
1 parent
8095baa
commit a42e4ad
Showing
7 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
function dt_decode_headers_from_httpbin($response) | ||
{ | ||
$data = json_decode($response, true); | ||
if (!$data || !isset($data['headers'])) { | ||
echo 'Invalid response:' . PHP_EOL; | ||
var_dump($response); | ||
return []; | ||
} | ||
$headers = []; | ||
foreach ($data['headers'] as $key => $value) { | ||
$headers[strtolower($key)] = mb_convert_encoding($value, 'ISO-8859-1', 'UTF-8'); | ||
} | ||
return $headers; | ||
} | ||
|
||
function dt_dump_headers_from_httpbin(array $headers, array $whitelist) | ||
{ | ||
foreach ($headers as $key => $value) { | ||
if (!in_array($key, $whitelist, true)) { | ||
continue; | ||
} | ||
echo $key . ': ' . $value . PHP_EOL; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
<?php | ||
|
||
class RequestReplayer | ||
{ | ||
/** | ||
* @var string | ||
*/ | ||
public $endpoint; | ||
|
||
/** | ||
* @var int | ||
*/ | ||
public $flushInterval; | ||
|
||
/** | ||
* @var int | ||
*/ | ||
public $maxIteration; | ||
|
||
public function __construct() | ||
{ | ||
$this->endpoint = sprintf( | ||
'http://%s:%d', | ||
getenv('DD_AGENT_HOST') ?: 'request-replayer', | ||
getenv('DD_TRACE_AGENT_PORT') ?: '80' | ||
); | ||
|
||
$this->flushInterval = getenv('DD_TRACE_AGENT_FLUSH_INTERVAL') | ||
? (int) getenv('DD_TRACE_AGENT_FLUSH_INTERVAL') * 100 | ||
: 50000; | ||
|
||
$this->maxIteration = (strncasecmp(PHP_OS, "WIN", 3) === 0) ? 500 : 200; | ||
} | ||
|
||
public function waitForFlush() | ||
{ | ||
usleep($this->flushInterval * 2); | ||
} | ||
|
||
public function waitForRequest($matcher) | ||
{ | ||
$i = 0; | ||
do { | ||
if ($i++ == $this->maxIteration) { | ||
throw new Exception("wait for replay timeout"); | ||
} | ||
usleep($this->flushInterval); | ||
|
||
$requests = $this->replayAllRequests(); | ||
if (is_array($requests)) { | ||
foreach ($requests as $request) { | ||
if ($matcher($request)) { | ||
return $request; | ||
} | ||
} | ||
} | ||
} while (true); | ||
} | ||
|
||
public function waitForDataAndReplay($ignoreTelemetry = true) | ||
{ | ||
$i = 0; | ||
do { | ||
if ($i++ == $this->maxIteration) { | ||
throw new Exception("wait for replay timeout"); | ||
} | ||
usleep($this->flushInterval); | ||
} while (empty($data = $this->replayRequest($ignoreTelemetry))); | ||
return $data; | ||
} | ||
|
||
public function replayRequest($ignoreTelemetry = false) | ||
{ | ||
// Request replayer now returns as many requests as were sent during a session. | ||
// For the scope of the tests, we are returning the very first one. | ||
$allRequests = $this->replayAllRequests(); | ||
if ($allRequests && $ignoreTelemetry) { | ||
$allRequests = array_values(array_filter($allRequests, function ($v) { return $v["uri"] != '/telemetry/proxy/api/v2/apmtelemetry'; })); | ||
} | ||
return $allRequests ? $allRequests[0] : []; | ||
} | ||
|
||
public function replayAllRequests() | ||
{ | ||
return json_decode(file_get_contents($this->endpoint . '/replay', false, stream_context_create([ | ||
"http" => [ | ||
"header" => "X-Datadog-Test-Session-Token: " . ini_get("datadog.trace.agent_test_session_token"), | ||
], | ||
])), true); | ||
} | ||
|
||
public function replayHeaders($showOnly = []) | ||
{ | ||
$request = $this->waitForDataAndReplay(); | ||
if (!isset($request['headers'])) { | ||
return []; | ||
} | ||
|
||
ksort($request['headers']); | ||
|
||
$headers = []; | ||
foreach ($request['headers'] as $name => $value) { | ||
$name = strtolower($name); | ||
if ($showOnly && !in_array($name, $showOnly, true)) { | ||
continue; | ||
} | ||
$headers[$name] = $value; | ||
} | ||
return $headers; | ||
} | ||
|
||
public function setResponse($array) { | ||
file_get_contents($this->endpoint . '/next-response', false, stream_context_create([ | ||
"http" => [ | ||
"method" => "POST", | ||
"content" => json_encode($array), | ||
"header" => [ | ||
"Content-Type: application/json", | ||
"X-Datadog-Test-Session-Token: " . ini_get("datadog.trace.agent_test_session_token"), | ||
] | ||
], | ||
])); | ||
} | ||
|
||
public static function launchUnixProxy($socketPath) { | ||
@unlink($socketPath); | ||
$code = str_replace("\n", "", ' | ||
ignore_user_abort(true); /* prevent bailout... */ | ||
$server = stream_socket_server("unix://' . $socketPath . '"); | ||
print "1\n"; /* ready marker */ | ||
if (!$client = stream_socket_accept($server, 5)) { | ||
return; | ||
} | ||
$replayer = stream_socket_client("request-replayer:80"); | ||
$all = $read = [$client, $replayer]; | ||
foreach ($read as $fp) stream_set_blocking($fp, false); | ||
while (stream_select($read, $w, $e, null)) { | ||
$data = fread($fp = reset($read), 4096); | ||
if ($data == "") { | ||
return; | ||
} | ||
fwrite($fp == $replayer ? $client : $replayer, $data); | ||
$read = $all; | ||
} | ||
'); | ||
|
||
static $unix_proxy_process_reference; | ||
$unix_proxy_process_reference = popen(PHP_BINARY . " -r '$code'", 'r'); | ||
fread($unix_proxy_process_reference, 1); // ready | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
appsec/tests/extension/standalone/appsec_upstream_no_attack.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--TEST-- | ||
Appsec upstream and no attack, should leave the priorit as it comes on the upstream | ||
--ENV-- | ||
DD_AGENT_HOST=request-replayer | ||
DD_TRACE_AGENT_PORT=80 | ||
DD_TRACE_AGENT_FLUSH_INTERVAL=333 | ||
DD_TRACE_GENERATE_ROOT_SPAN=0 | ||
DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 | ||
DD_TRACE_SIDECAR_TRACE_SENDER=0 | ||
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 | ||
DD_APPSEC_ENABLED=1 | ||
DD_TRACE_TRACED_INTERNAL_FUNCTIONS=curl_exec | ||
HTTP_X_DATADOG_TRACE_ID=42 | ||
HTTP_X_DATADOG_TAGS=_dd.p.appsec=1 | ||
HTTP_X_DATADOG_SAMPLING_PRIORITY=2 | ||
--INI-- | ||
extension=ddtrace.so | ||
datadog.trace.agent_test_session_token=background-sender/agent_sampling_c | ||
--SKIPIF-- | ||
<?php if (!extension_loaded('curl')) die('skip: curl extension required'); ?> | ||
<?php if (!getenv('HTTPBIN_HOSTNAME')) die('skip: HTTPBIN_HOSTNAME env var required'); ?> | ||
--FILE-- | ||
<?php | ||
include __DIR__ . '/simulate_request.inc'; | ||
include __DIR__ . '/../inc/mock_helper.php'; | ||
|
||
$helper = Helper::createInitedRun([ | ||
...request_without_events() | ||
]); | ||
|
||
$rr = new RequestReplayer(); | ||
$result = simulate_request($rr); | ||
var_dump("Appsec should be present", isset($result['spans'][0]["meta"]["_dd.p.appsec"])); | ||
var_dump("Sampling priority should be 2", $result['spans'][0]["metrics"]["_sampling_priority_v1"]); | ||
var_dump("Apm should be disabled", $result['spans'][0]["metrics"]["_dd.apm.enabled"]); | ||
var_dump("Propagated sampling priority should be 2", $result['curl_headers']['x-datadog-sampling-priority']); | ||
var_dump("Appsec tag should be propagated", strpos($result['curl_headers']['x-datadog-tags'], '_dd.p.appsec=1') !== false); | ||
?> | ||
--EXPECTF-- | ||
string(24) "Appsec should be present" | ||
bool(true) | ||
string(29) "Sampling priority should be 2" | ||
int(2) | ||
string(22) "Apm should be disabled" | ||
int(0) | ||
string(40) "Propagated sampling priority should be 2" | ||
string(1) "2" | ||
string(31) "Appsec tag should be propagated" | ||
bool(true) |
63 changes: 63 additions & 0 deletions
63
appsec/tests/extension/standalone/no_appsec_upstream_no_attack.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--TEST-- | ||
No appsec upstream and no attack, set priority to auto reject | ||
--ENV-- | ||
DD_AGENT_HOST=request-replayer | ||
DD_TRACE_AGENT_PORT=80 | ||
DD_TRACE_AGENT_FLUSH_INTERVAL=333 | ||
DD_TRACE_GENERATE_ROOT_SPAN=0 | ||
DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 | ||
DD_TRACE_SIDECAR_TRACE_SENDER=0 | ||
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 | ||
DD_APPSEC_ENABLED=1 | ||
DD_TRACE_TRACED_INTERNAL_FUNCTIONS=curl_exec | ||
HTTP_X_DATADOG_TRACE_ID=42 | ||
HTTP_X_DATADOG_TAGS=_dd.p.other=1 | ||
--INI-- | ||
extension=ddtrace.so | ||
datadog.trace.agent_test_session_token=background-sender/agent_sampling_a | ||
--SKIPIF-- | ||
<?php if (!extension_loaded('curl')) die('skip: curl extension required'); ?> | ||
<?php if (!getenv('HTTPBIN_HOSTNAME')) die('skip: HTTPBIN_HOSTNAME env var required'); ?> | ||
--FILE-- | ||
<?php | ||
include __DIR__ . '/simulate_request.inc'; | ||
include __DIR__ . '/../inc/mock_helper.php'; | ||
|
||
$helper = Helper::createInitedRun([ | ||
...request_without_events(), | ||
...request_without_events(), | ||
]); | ||
$rr = new RequestReplayer(); | ||
|
||
//We need to make two requests. The first one is allow by the sampler, but not the second | ||
$result = simulate_request($rr); | ||
var_dump("First call: Appsec should not be present", isset($result['spans'][0]["meta"]["_dd.p.appsec"])); | ||
var_dump("First call: Sampling priority should be 1", $result['spans'][0]["metrics"]["_sampling_priority_v1"]); | ||
var_dump("First call: Apm should be disabled", $result['spans'][0]["metrics"]["_dd.apm.enabled"]); | ||
var_dump("First call: There should not be header propagation", $result['curl_headers']); | ||
|
||
$result = simulate_request($rr); | ||
var_dump("Second call: Appsec should not be present", isset($result['spans'][0]["meta"]["_dd.p.appsec"])); | ||
var_dump("Second call: Sampling priority should be 0", $result['spans'][0]["metrics"]["_sampling_priority_v1"]); | ||
var_dump("Second call: Apm should be disabled", $result['spans'][0]["metrics"]["_dd.apm.enabled"]); | ||
var_dump("Second call: There should not be header propagation", $result['curl_headers']); | ||
?> | ||
--EXPECTF-- | ||
string(40) "First call: Appsec should not be present" | ||
bool(false) | ||
string(41) "First call: Sampling priority should be 1" | ||
int(1) | ||
string(34) "First call: Apm should be disabled" | ||
int(0) | ||
string(50) "First call: There should not be header propagation" | ||
array(0) { | ||
} | ||
string(41) "Second call: Appsec should not be present" | ||
bool(false) | ||
string(42) "Second call: Sampling priority should be 0" | ||
int(0) | ||
string(35) "Second call: Apm should be disabled" | ||
int(0) | ||
string(51) "Second call: There should not be header propagation" | ||
array(0) { | ||
} |
45 changes: 45 additions & 0 deletions
45
appsec/tests/extension/standalone/no_appsec_upstream_with_attack.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
--TEST-- | ||
No appsec upstream with attack, set priority to keep | ||
--ENV-- | ||
DD_AGENT_HOST=request-replayer | ||
DD_TRACE_AGENT_PORT=80 | ||
DD_TRACE_AGENT_FLUSH_INTERVAL=333 | ||
DD_TRACE_GENERATE_ROOT_SPAN=1 | ||
DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 | ||
DD_TRACE_SIDECAR_TRACE_SENDER=0 | ||
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 | ||
DD_APPSEC_ENABLED=1 | ||
DD_TRACE_TRACED_INTERNAL_FUNCTIONS=curl_exec | ||
HTTP_X_DATADOG_TRACE_ID=42 | ||
HTTP_X_DATADOG_TAGS=_dd.p.other=1 | ||
--INI-- | ||
extension=ddtrace.so | ||
datadog.trace.agent_test_session_token=background-sender/agent_sampling_b | ||
--FILE-- | ||
<?php | ||
include __DIR__ . '/simulate_request.inc'; | ||
include __DIR__ . '/../inc/mock_helper.php'; | ||
|
||
$helper = Helper::createInitedRun([ | ||
...request_with_events() | ||
]); | ||
|
||
$rr = new RequestReplayer(); | ||
$result = simulate_request($rr); | ||
var_dump("Appsec should be present", isset($result['spans'][0]["meta"]["_dd.p.appsec"])); | ||
var_dump("Sampling priority should be 2", $result['spans'][0]["metrics"]["_sampling_priority_v1"]); | ||
var_dump("Apm should be disabled", $result['spans'][0]["metrics"]["_dd.apm.enabled"]); | ||
var_dump("Propagated sampling priority should be 2", $result['curl_headers']['x-datadog-sampling-priority']); | ||
var_dump("Appsec tag should be propagated", strpos($result['curl_headers']['x-datadog-tags'], '_dd.p.appsec=1') !== false); | ||
?> | ||
--EXPECTF-- | ||
string(24) "Appsec should be present" | ||
bool(true) | ||
string(29) "Sampling priority should be 2" | ||
int(2) | ||
string(22) "Apm should be disabled" | ||
int(0) | ||
string(40) "Propagated sampling priority should be 2" | ||
string(1) "2" | ||
string(31) "Appsec tag should be propagated" | ||
bool(true) |
Oops, something went wrong.