Conversation
👀 Auto-assigned reviewersThese soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:
Soft owners come from |
|
Size Change: +391 kB (+0.61%) Total Size: 64.4 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Reviews (1): Last reviewed commit: "feat(flags): authenticate /flags request..." | Re-trigger Greptile |
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 6 · PR risk: 0/10 |
|
Sorry, just noticed this. Will take a look from the feature flags side. |
haacked
left a comment
There was a problem hiding this comment.
Looks good from the feature flags side. Just some non-blocking suggestions.
🔒 Security review notes (via Claude)I reviewed this PR against its core invariant — 1.
|
|
👋 hey folks
Looks like this isn't an immediate blocker to this PR (no capture change yet) but FYI: Just to confirm - at the moment no If we opt to move quota checks entirely downstream, we will ship those events (and future ones...sometimes this can really spike) into the topic just to drop them downstream. Not a hard blocker, but something to consider |
992e917 to
c877c2d
Compare
|
👋 Visual changes detected for this PR. Review and approve in PostHog Visual Review If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix. |
|
Addressed in 49816d9: |
CI statusThe branch is up to date with The only remaining red check is Product tests (data-warehouse, workflows) (and the Django Tests Pass gate that depends on it). This is a pre-existing, master-wide failure unrelated to this PR — this PR touches no Evidence:
This needs the master CI Docker Hub auth issue to be resolved (infra-side). Once master is green again, re-running / re-merging this branch will clear the check. Everything within this PR's control is green. |
059b901 to
543b294
Compare
|
This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the |
05eaa1d to
6c1c095
Compare
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
8fdf216 to
b0a9401
Compare
807c302 to
8e8f044
Compare
8e8f044 to
20565e3
Compare
Rebased onto master. Re-published to re-run the Playwright E2E job.
20565e3 to
d0aaa29
Compare
Rebased onto
|
|
This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the |
|
This PR was closed due to lack of activity. Feel free to reopen if it's still relevant. |
Problem
Server-side SDKs authenticate capture with the public project API key (
phc_), which is world-readable by design — so nothing distinguishes an event genuinely sent by trusted server infrastructure from one forged by anyone holding the public key. For workflows that act automatically on ingested events (e.g. error-tracking automations), we need a way to know an event came from a holder of a server-side secret.An earlier approach signed individual
$exceptionevents with per-team Ed25519 keys (#62750, #62751, posthog-python#657). This PR supersedes that with a much simpler transport-level mechanism: send events with the project's secret API token (phs_, already used for flags local evaluation and the conversations API), and every event ingested that way is marked verified.Changes
TeamManagernow also resolves teams bysecret_api_tokenandsecret_api_token_backup(so token rotation keeps working), and the shared resolve-team step sets a server-controlled$verified: trueproperty on events captured with a secret token. Any client-supplied$verifiedon public-token events is stripped, so the property cannot be forged. Covers the analytics, error-tracking, and heatmap pipelines; a counter metric tracks verified/stripped events.phs_capture would bypass billing limits./flagsrequests now accept aphs_token as theapi_key(reusing the existing cached secret-token validation used by/flag_definitions), so an SDK configured with the secret key keeps evaluating flags. Unknownphs_tokens 401 without polluting the public-token negative cache.$verifiedregistered as a boolean event property.No SDK changes are required — server SDKs send
api_keyverbatim, so settingapi_key="phs_..."works as-is. Capture already acceptsphs_tokens at the edge (format-only validation) and the token is not persisted to ClickHouse.Everything is inert until a team generates a secret token (existing rotate endpoint) and points an SDK at it; teams with
NULLsecret tokens see byte-identical behaviour. No migrations — unique indexes on both secret-token columns already exist.Notes for reviewers:
phc_andphs_as separate keys — accepted.phs_token too to fully block a team.phs_tokens (its team service is public-token-only; server SDKs don't do replay).How did you test this code?
nodejs: new parameterized unit tests forapplyVerifiedPropertyand the resolve-team step (secret/backup/forged/no-properties/null-secret cases), team-manager integration tests for secret-token resolution and cache warming, and two end-to-end ingestion tests (phs_capture lands in ClickHouse with$verified: true; forged$verifiedviaphc_is stripped). Fullevent-preprocessingand error-tracking pipeline suites pass.ee/billing: parameterized pytest coverage over no-secret / primary-only / primary+backup token sets forupdate_org_billing_quotas,update_all_orgs_billing_quotas, and the token helpers; fulltest_quota_limiting.pysuite passes (74 tests).rust/feature-flags: integration tests for/flagsauthenticated with the primary and backup secret token (200 + flags evaluated) and an unknownphs_token (401 with Django-compatible error body).Automatic notifications
Docs update