Skip to content

Conversation

@leoromanovsky
Copy link
Contributor

Motivation

Enable Feature Flagging and Experimentation (FFE) system tests for PHP, companion to DataDog/dd-trace-php#3630.

Changes

  • utils/build/docker/php/parametric/server.php: Added POST /ffe/start and POST /ffe/evaluate endpoints to the PHP parametric test server
  • utils/build/docker/php/common/ffe.php: Added POST /ffe endpoint for end-to-end tests (Apache weblog)
  • manifests/php.yml: Removed missing_feature for tests/ffe/test_dynamic_evaluation.py, tests/ffe/test_exposures.py, and tests/parametric/test_ffe/test_dynamic_evaluation.py

Decisions

  • PHP endpoints use DDTrace\FeatureFlags\Provider from dd-trace-php for flag evaluation
  • Exposure events are flushed immediately after evaluation in the weblog endpoint for test observability
  • Parametric server uses the same Amphp router pattern as existing endpoints

- Add /ffe/start and /ffe/evaluate to PHP parametric server
- Add /ffe.php for end-to-end tests
- Remove missing_feature for PHP FFE tests in manifest
@leoromanovsky leoromanovsky force-pushed the feature/ff-scan-worktree branch from f75549f to 2db71e0 Compare February 11, 2026 13:48
@github-actions
Copy link
Contributor

CODEOWNERS have been resolved as:

utils/build/docker/php/common/ffe.php                                   @DataDog/apm-php @DataDog/system-tests-core
manifests/php.yml                                                       @DataDog/apm-php @DataDog/asm-php
utils/build/docker/php/parametric/composer.json                         @DataDog/apm-php @DataDog/system-tests-core
utils/build/docker/php/parametric/server.php                            @DataDog/apm-php @DataDog/system-tests-core

@datadog-official
Copy link

datadog-official bot commented Feb 11, 2026

⚠️ Tests

Fix all issues with Cursor

⚠️ Warnings

❄️ 21 New flaky tests detected

tests.appsec.iast.sink.test_unvalidated_redirect.TestUnvalidatedHeader_ExtendedLocation.test_extended_location_data[flask-poc] from system_tests_suite (Datadog) (Fix with Cursor)
AssertionError: Expected a single vulnerability with the matching criteria
assert 2 == 1
 +  where 2 = len([{'evidence': {'valueParts': [{'source': 0, 'value': 'http://dummy.location.com'}]}, 'hash': 1185812129, 'location': {...ated_redirect_insecure_header', 'path': 'app.py', 'spanId': 7805935051089620766, ...}, 'type': 'UNVALIDATED_REDIRECT'}])

self = <tests.appsec.iast.sink.test_unvalidated_redirect.TestUnvalidatedHeader_ExtendedLocation object at 0x7f8885fcd8e0>

    def test_extended_location_data(self):
>       validate_extended_location_data(self.r, self.vulnerability_type)

tests/appsec/iast/sink/test_unvalidated_redirect.py:129: 
...
tests.appsec.test_blocking_addresses.Test_Blocking_client_ip.test_blocking_before[envoy] from system_tests_suite (Datadog) (Fix with Cursor)
ValueError: No appsec event validate this condition

self = <tests.appsec.test_blocking_addresses.Test_Blocking_client_ip object at 0x7f9e542db8f0>

    def test_blocking_before(self):
        """Test that blocked requests are blocked before being processed"""
        # second request should block and must not set the tag in span
        assert self.block_req2.status_code == 403
>       interfaces.library.assert_waf_attack(self.block_req2, rule="blk-001-001")

...
tests.appsec.test_blocking_addresses.Test_Blocking_client_ip.test_blocking[envoy] from system_tests_suite (Datadog) (Fix with Cursor)
ValueError: No appsec event validate this condition

self = <tests.appsec.test_blocking_addresses.Test_Blocking_client_ip object at 0x7f9e542db830>

    def test_blocking(self):
        """Can block the request forwarded for the ip"""
    
        assert self.rm_req_block.status_code == 403
>       interfaces.library.assert_waf_attack(self.rm_req_block, rule="blk-001-001")

...
View all

🧪 312 Tests failed

tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start.test_ffe_rc_down_from_start[apache-mod-7.0] from system_tests_suite (Datadog) (Fix with Cursor)
AssertionError: Flag evaluation failed: 
assert 404 == 200
 +  where 404 = HttpResponse(status_code:404, headers:{'Date': 'Wed, 11 Feb 2026 14:19:29 GMT', 'Server': 'Apache/2.4.66 (Debian)', 'X-Powered-By': 'PHP/7.0.33', 'Content-Length': '0', 'Content-Type': 'text/html; charset=UTF-8'}, text:).status_code
 +    where HttpResponse(status_code:404, headers:{'Date': 'Wed, 11 Feb 2026 14:19:29 GMT', 'Server': 'Apache/2.4.66 (Debian)', 'X-Powered-By': 'PHP/7.0.33', 'Content-Length': '0', 'Content-Type': 'text/html; charset=UTF-8'}, text:) = <tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start object at 0x7f15f6be3680>.r

self = <tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start object at 0x7f15f6be3680>

    def test_ffe_rc_down_from_start(self):
        """Test that default value is returned when RC is down from start."""
        # Verify tracer received 503 from RC
...
tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start.test_ffe_rc_down_from_start[apache-mod-7.0-zts] from system_tests_suite (Datadog) (Fix with Cursor)
AssertionError: Flag evaluation failed: 
assert 404 == 200
 +  where 404 = HttpResponse(status_code:404, headers:{'Date': 'Wed, 11 Feb 2026 14:20:37 GMT', 'Server': 'Apache/2.4.66 (Debian)', 'X-Powered-By': 'PHP/7.0.33', 'Content-Length': '0', 'Content-Type': 'text/html; charset=UTF-8'}, text:).status_code
 +    where HttpResponse(status_code:404, headers:{'Date': 'Wed, 11 Feb 2026 14:20:37 GMT', 'Server': 'Apache/2.4.66 (Debian)', 'X-Powered-By': 'PHP/7.0.33', 'Content-Length': '0', 'Content-Type': 'text/html; charset=UTF-8'}, text:) = <tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start object at 0x7ff73102bd40>.r

self = <tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start object at 0x7ff73102bd40>

    def test_ffe_rc_down_from_start(self):
        """Test that default value is returned when RC is down from start."""
        # Verify tracer received 503 from RC
...
tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start.test_ffe_rc_down_from_start[apache-mod-7.1] from system_tests_suite (Datadog) (Fix with Cursor)
AssertionError: Flag evaluation failed: 
assert 404 == 200
 +  where 404 = HttpResponse(status_code:404, headers:{'Date': 'Wed, 11 Feb 2026 14:20:07 GMT', 'Server': 'Apache/2.4.66 (Debian)', 'X-Powered-By': 'PHP/7.1.33', 'Content-Length': '0', 'Content-Type': 'text/html; charset=UTF-8'}, text:).status_code
 +    where HttpResponse(status_code:404, headers:{'Date': 'Wed, 11 Feb 2026 14:20:07 GMT', 'Server': 'Apache/2.4.66 (Debian)', 'X-Powered-By': 'PHP/7.1.33', 'Content-Length': '0', 'Content-Type': 'text/html; charset=UTF-8'}, text:) = <tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start object at 0x7fa802df82c0>.r

self = <tests.ffe.test_dynamic_evaluation.Test_FFE_RC_Down_From_Start object at 0x7fa802df82c0>

    def test_ffe_rc_down_from_start(self):
        """Test that default value is returned when RC is down from start."""
        # Verify tracer received 503 from RC
...
View all
This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 2db71e0 | Docs | Datadog PR Page | Was this helpful? Give us feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant