Skip to content

fix(flags): load shared definitions without a secret key - #259

Open
dustinbyrne wants to merge 2 commits into
mainfrom
fix/flag-cache-without-secret-key
Open

dustinbyrne wants to merge 2 commits into
mainfrom
fix/flag-cache-without-secret-key

Conversation

@dustinbyrne

@dustinbyrne dustinbyrne commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Like PostHog/posthog-python#1039, a worker consuming shared feature flag definitions should not need a privileged secret key. Existing initialization gates prevent that supported cache-consumer configuration from evaluating flags locally.

Changes

  • Permit the configured definition cache provider to supply definitions without a secret/personal API key.
  • Keep keyless cache misses and read failures out of API recovery, avoiding misleading synthetic HTTP 401 logs while retaining genuine cache-error warnings.
  • Keyless consumers read the shared cache directly, without invoking the fetch-decision callback or publishing definitions. They cannot claim fetch leadership they are unable to use.
  • With privileged credentials, retain the existing decision flow: false reads the cache; true fetches definitions and publishes them. Direct definition requests remain authenticated.
  • Add public-entry regressions, update active credential/provider docs, and include scoped patch release metadata.

Cache-only readers bypass the shared loader specification's decision-first provider step; credentialed consumers retain that step.

Automatic construction loading accepts provider-only consumers. loadFeatureFlags:false remains effective and explicit loadFlags() remains the refresh mechanism; no polling is introduced.

💚 How did you test it?

  • Focused provider suite: 25 tests, 468 assertions, no failures; baseline/candidate comparison: four regressions fail against the prior Client and pass with the fix.
  • PHPUnit excluding only testForkCurlRejectsExpandedShellPayloadWithoutLeakingTempFile: 737 tests, 5,557 assertions, no failures.
  • Unrestricted local PHPUnit still aborts on PHP 8.3.28/macOS at unchanged ForkCurl.php:53 due to the escapeshellarg 1 MiB limit. The exact test fails identically against prior Client code. No transport change is included.
  • Public-entry decision-error reproduction: cached definitions load and evaluate locally, with zero decision calls and empty stderr. Cache misses no longer produce synthetic HTTP 401 warnings; genuine read errors are still logged.
  • API snapshot, PHP syntax and 16 adapter tests: passed. Scoped lint has zero errors and three baseline line-length warnings; repository-wide lint exhausts the default memory limit.
  • PHPUnit reports 5 deprecations and 42 PHPUnit deprecations. Coverage was not collected.

Release scope

Patch release for posthog-php. Existing signatures, capture defaults and wire formats are unchanged.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Implemented with Pi worker agents and reviewed by separate fresh-context Pi reviewers. A simplify pass covered the scoped source/tests/docs before final local validation. Human review remains required.

@dustinbyrne
dustinbyrne requested a review from a team as a code owner October 9, 2026 15:33
@dustinbyrne dustinbyrne self-assigned this Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-lib_curl Compliance Report

Date: 2026-10-10T04:16:34.967310+00:00
Duration: 118876ms

✅ All Tests Passed!

47/47 tests passed


Capture Tests

✅ 30/30 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 27ms
Format Validation.Event Has Uuid ✅ 523ms
Format Validation.Event Has Lib Properties ✅ 524ms
Format Validation.Distinct Id Is String ✅ 525ms
Format Validation.Token Is Present ✅ 524ms
Format Validation.Custom Properties Preserved ✅ 523ms
Format Validation.Event Has Timestamp ✅ 526ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 524ms
Retry Behavior.Retries On 503 ✅ 5834ms
Retry Behavior.Does Not Retry On 400 ✅ 2526ms
Retry Behavior.Does Not Retry On 401 ✅ 2526ms
Retry Behavior.Respects Retry After Header ✅ 8532ms
Retry Behavior.Implements Backoff ✅ 16250ms
Retry Behavior.Retries On 500 ✅ 5634ms
Retry Behavior.Retries On 502 ✅ 5633ms
Retry Behavior.Retries On 504 ✅ 5633ms
Retry Behavior.Max Retries Respected ✅ 17049ms
Deduplication.Generates Unique Uuids ✅ 232ms
Deduplication.Preserves Uuid On Retry ✅ 5634ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10840ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5635ms
Deduplication.No Duplicate Events In Batch ✅ 531ms
Deduplication.Different Events Have Different Uuids ✅ 525ms
Compression.Sends Gzip When Enabled ✅ 524ms
Batch Format.Uses Proper Batch Structure ✅ 527ms
Batch Format.Flush With No Events Sends Nothing ✅ 520ms
Batch Format.Multiple Events Batched Together ✅ 513ms
Error Handling.Does Not Retry On 403 ✅ 2526ms
Error Handling.Does Not Retry On 413 ✅ 2526ms
Error Handling.Retries On 408 ✅ 5634ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 525ms
Request Payload.Flags Request Uses V2 Query Param ✅ 521ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 522ms
Request Payload.Flags Request Omits Authorization Header ✅ 524ms
Request Payload.Token In Flags Body Matches Init ✅ 522ms
Request Payload.Groups Round Trip ✅ 522ms
Request Payload.Groups Default To Empty Object ✅ 523ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 522ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 522ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 521ms
Request Lifecycle.No Flags Request On Init Alone ✅ 516ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 510ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 527ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 524ms
Retry Behavior.Retries Flags On 502 ✅ 626ms
Retry Behavior.Retries Flags On 504 ✅ 624ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 525ms

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-fork_curl Compliance Report

Date: 2026-10-10T04:16:31.274216+00:00
Duration: 112964ms

⚠️ Some Tests Failed

36/47 tests passed, 11 failed


Capture Tests

⚠️ 19/30 tests passed, 11 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 38ms
Format Validation.Event Has Uuid ✅ 529ms
Format Validation.Event Has Lib Properties ✅ 531ms
Format Validation.Distinct Id Is String ✅ 531ms
Format Validation.Token Is Present ✅ 533ms
Format Validation.Custom Properties Preserved ✅ 532ms
Format Validation.Event Has Timestamp ✅ 533ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 531ms
Retry Behavior.Retries On 503 ❌ 5536ms
Retry Behavior.Does Not Retry On 400 ✅ 2533ms
Retry Behavior.Does Not Retry On 401 ✅ 2535ms
Retry Behavior.Respects Retry After Header ❌ 5539ms
Retry Behavior.Implements Backoff ❌ 15548ms
Retry Behavior.Retries On 500 ❌ 5540ms
Retry Behavior.Retries On 502 ❌ 5536ms
Retry Behavior.Retries On 504 ❌ 5537ms
Retry Behavior.Max Retries Respected ❌ 15545ms
Deduplication.Generates Unique Uuids ✅ 541ms
Deduplication.Preserves Uuid On Retry ❌ 5536ms
Deduplication.Preserves Uuid And Timestamp On Retry ❌ 10542ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ❌ 5541ms
Deduplication.No Duplicate Events In Batch ✅ 538ms
Deduplication.Different Events Have Different Uuids ✅ 534ms
Compression.Sends Gzip When Enabled ✅ 534ms
Batch Format.Uses Proper Batch Structure ✅ 532ms
Batch Format.Flush With No Events Sends Nothing ✅ 518ms
Batch Format.Multiple Events Batched Together ✅ 525ms
Error Handling.Does Not Retry On 403 ✅ 2533ms
Error Handling.Does Not Retry On 413 ✅ 2535ms
Error Handling.Retries On 408 ❌ 5536ms

Failures

retry_behavior.retries_on_503

Expected at least 3 requests, got 1

retry_behavior.respects_retry_after_header

Expected at least 2 requests, got 1

retry_behavior.implements_backoff

Expected at least 3 requests, got 1

retry_behavior.retries_on_500

Expected at least 2 requests, got 1

retry_behavior.retries_on_502

Expected at least 2 requests, got 1

retry_behavior.retries_on_504

Expected at least 2 requests, got 1

retry_behavior.max_retries_respected

Expected 4 requests, got 1

deduplication.preserves_uuid_on_retry

Need at least 2 requests to check retry

deduplication.preserves_uuid_and_timestamp_on_retry

Expected at least 3 requests, got 1

deduplication.preserves_uuid_and_timestamp_on_batch_retry

Expected at least 2 requests, got 1

error_handling.retries_on_408

Expected at least 2 requests, got 1

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 525ms
Request Payload.Flags Request Uses V2 Query Param ✅ 522ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 521ms
Request Payload.Flags Request Omits Authorization Header ✅ 524ms
Request Payload.Token In Flags Body Matches Init ✅ 521ms
Request Payload.Groups Round Trip ✅ 522ms
Request Payload.Groups Default To Empty Object ✅ 522ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 522ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 523ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 522ms
Request Lifecycle.No Flags Request On Init Alone ✅ 517ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 519ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 524ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 526ms
Retry Behavior.Retries Flags On 502 ✅ 626ms
Retry Behavior.Retries Flags On 504 ✅ 625ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 535ms

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-socket Compliance Report

Date: 2026-10-10T04:17:12.957978+00:00
Duration: 149277ms

⚠️ Some Tests Failed

36/47 tests passed, 11 failed


Capture Tests

⚠️ 19/30 tests passed, 11 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 31ms
Format Validation.Event Has Uuid ✅ 522ms
Format Validation.Event Has Lib Properties ✅ 524ms
Format Validation.Distinct Id Is String ✅ 524ms
Format Validation.Token Is Present ✅ 524ms
Format Validation.Custom Properties Preserved ✅ 525ms
Format Validation.Event Has Timestamp ✅ 524ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 524ms
Retry Behavior.Retries On 503 ❌ 9234ms
Retry Behavior.Does Not Retry On 400 ✅ 2528ms
Retry Behavior.Does Not Retry On 401 ✅ 2526ms
Retry Behavior.Respects Retry After Header ❌ 9234ms
Retry Behavior.Implements Backoff ❌ 19245ms
Retry Behavior.Retries On 500 ❌ 9238ms
Retry Behavior.Retries On 502 ❌ 9235ms
Retry Behavior.Retries On 504 ❌ 9236ms
Retry Behavior.Max Retries Respected ❌ 19231ms
Deduplication.Generates Unique Uuids ✅ 46ms
Deduplication.Preserves Uuid On Retry ❌ 9233ms
Deduplication.Preserves Uuid And Timestamp On Retry ❌ 14241ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ❌ 9241ms
Deduplication.No Duplicate Events In Batch ✅ 532ms
Deduplication.Different Events Have Different Uuids ✅ 525ms
Compression.Sends Gzip When Enabled ✅ 524ms
Batch Format.Uses Proper Batch Structure ✅ 524ms
Batch Format.Flush With No Events Sends Nothing ✅ 519ms
Batch Format.Multiple Events Batched Together ✅ 513ms
Error Handling.Does Not Retry On 403 ✅ 2524ms
Error Handling.Does Not Retry On 413 ✅ 2526ms
Error Handling.Retries On 408 ❌ 5531ms

Failures

retry_behavior.retries_on_503

Expected at least 3 requests, got 1

retry_behavior.respects_retry_after_header

Expected at least 2 requests, got 1

retry_behavior.implements_backoff

Expected at least 3 requests, got 1

retry_behavior.retries_on_500

Expected at least 2 requests, got 1

retry_behavior.retries_on_502

Expected at least 2 requests, got 1

retry_behavior.retries_on_504

Expected at least 2 requests, got 1

retry_behavior.max_retries_respected

Expected 4 requests, got 1

deduplication.preserves_uuid_on_retry

Need at least 2 requests to check retry

deduplication.preserves_uuid_and_timestamp_on_retry

Expected at least 3 requests, got 1

deduplication.preserves_uuid_and_timestamp_on_batch_retry

Expected at least 2 requests, got 1

error_handling.retries_on_408

Expected at least 2 requests, got 1

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 524ms
Request Payload.Flags Request Uses V2 Query Param ✅ 521ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 523ms
Request Payload.Flags Request Omits Authorization Header ✅ 522ms
Request Payload.Token In Flags Body Matches Init ✅ 521ms
Request Payload.Groups Round Trip ✅ 523ms
Request Payload.Groups Default To Empty Object ✅ 523ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 521ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 522ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 523ms
Request Lifecycle.No Flags Request On Init Alone ✅ 516ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 509ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 526ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 522ms
Retry Behavior.Retries Flags On 502 ✅ 626ms
Retry Behavior.Retries Flags On 504 ✅ 624ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 524ms

Comment thread lib/Client.php
Comment thread lib/Client.php Outdated
@turnipdabeets
turnipdabeets requested a review from a team October 9, 2026 20:04

This branch has not been deployed

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants