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
16 changes: 8 additions & 8 deletions .github/workflows/e2e-mw-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# required-reviewer Environment — that would either block external PRs even
# after approval, or force an approval click on every maintainer push.)
#
# Required repo configuration (one-time, see tests/e2e-mw-dev/README.md):
# Required repo configuration (one-time, see tests/mw-dev/README.md):
# vars: TS_WIF_CLIENT_ID_MW_DEV, TS_WIF_AUDIENCE_MW_DEV
# secrets: AWS_ECR_PUBLISH_IAM_ROLE (already exists, used by CD),
# MW_DEV_ACCOUNT_ID (mw-dev AWS account id; ARNs built from it)
Expand All @@ -47,7 +47,7 @@ on:
- "go.mod"
- "go.sum"
- "Dockerfile*"
- "tests/e2e-mw-dev/**"
- "tests/mw-dev/**"
- ".github/workflows/e2e-mw-dev.yml"
- ".github/workflows/_image-build.yml"
workflow_dispatch:
Expand Down Expand Up @@ -125,7 +125,7 @@ jobs:
go-version-file: go.mod

- name: Test e2e harness scripts
run: go test -count=1 ./tests/e2e-mw-dev
run: go test -count=1 ./tests/mw-dev

- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
Expand Down Expand Up @@ -160,17 +160,17 @@ jobs:
run: aws eks update-kubeconfig --name "$CLUSTER_NAME" --region us-east-1 --alias "$KUBE_CONTEXT"

- name: Deploy isolated namespace
run: bash tests/e2e-mw-dev/run.sh deploy
run: bash tests/mw-dev/run.sh deploy

- name: Run e2e harness (in-cluster Job)
run: bash tests/e2e-mw-dev/run.sh test
run: bash tests/mw-dev/run.sh test-e2e

# Diagnostics are only worth collecting (and only get read) when the
# harness failed — on green runs this step just added ~15s to the gating
# check. failure() also covers a failed deploy step.
- name: Collect diagnostics
if: failure()
run: bash tests/e2e-mw-dev/run.sh diagnostics
run: bash tests/mw-dev/run.sh diagnostics

# Teardown runs as its OWN job so the gating `e2e` check completes the moment
# the harness verdict is known instead of waiting ~1min for deprovision +
Expand Down Expand Up @@ -214,7 +214,7 @@ jobs:
# Deprovision the ci-pr ducklings (so no S3 / cnpg role+db leaks on
# shared infra) then delete the namespace.
- name: Teardown
run: bash tests/e2e-mw-dev/run.sh teardown
run: bash tests/mw-dev/run.sh teardown

# Backstop sweep of orphaned per-PR namespaces. Scheduled-trigger only (the
# PR/manual triggers run build+e2e instead). Reuses the same Tailscale + e2e
Expand Down Expand Up @@ -248,4 +248,4 @@ jobs:
- name: Update kubeconfig
run: aws eks update-kubeconfig --name "$CLUSTER_NAME" --region us-east-1 --alias "$KUBE_CONTEXT"
- name: Sweep stale per-PR namespaces
run: bash tests/e2e-mw-dev/run.sh e2e-cleanup
run: bash tests/mw-dev/run.sh e2e-cleanup
135 changes: 32 additions & 103 deletions .github/workflows/scenario-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ on:
required: true
default: false
type: boolean
use_shared_dev:
description: Skip isolated deploy and run against the shared dev stack
required: true
default: false
type: boolean
duckgres_image:
description: Existing Duckgres image to deploy instead of building this SHA
required: false
Expand All @@ -31,9 +26,10 @@ concurrency:

jobs:
scenario-runner-image:
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow }}
uses: ./.github/workflows/_image-build.yml
with:
dockerfile: tests/scenario/Dockerfile
dockerfile: tests/mw-dev/scenario/Dockerfile
image-name: duckgres
tag: scenario-runner-${{ github.run_id }}-${{ github.run_attempt }}-arm64
platform: linux/arm64
Expand All @@ -42,7 +38,7 @@ jobs:
ecr-role: ${{ secrets.AWS_ECR_PUBLISH_IAM_ROLE }}

duckgres-image:
if: ${{ github.event_name != 'workflow_dispatch' || (!inputs.use_shared_dev && inputs.duckgres_image == '') }}
if: ${{ github.event_name != 'workflow_dispatch' || (!inputs.skip_slow && inputs.duckgres_image == '') }}
uses: ./.github/workflows/_image-build.yml
with:
dockerfile: Dockerfile
Expand All @@ -59,149 +55,82 @@ jobs:
secrets:
ecr-role: ${{ secrets.AWS_ECR_PUBLISH_IAM_ROLE }}

scenarios:
scenario-full:
needs: [scenario-runner-image, duckgres-image]
if: ${{ always() && needs.scenario-runner-image.result == 'success' && (needs.duckgres-image.result == 'success' || (github.event_name == 'workflow_dispatch' && (inputs.use_shared_dev || inputs.duckgres_image != ''))) }}
if: ${{ always() && (github.event_name != 'workflow_dispatch' || !inputs.skip_slow) && needs.scenario-runner-image.result == 'success' && (needs.duckgres-image.result == 'success' || (github.event_name == 'workflow_dispatch' && inputs.duckgres_image != '')) }}
runs-on: ubuntu-24.04
timeout-minutes: 270
strategy:
fail-fast: false
max-parallel: 1
matrix:
include:
- name: provision-smoke
slot: 1
file: tests/scenario/scenarios/provision_smoke.yaml
max_runtime: 30m
go_test_timeout: 45m
slow: false
needs_dbt: false
- name: provision-rejection
slot: 2
file: tests/scenario/scenarios/provision_rejection.yaml
max_runtime: 30m
go_test_timeout: 45m
slow: false
needs_dbt: false
- name: frozen-metadata
slot: 3
file: tests/scenario/scenarios/posthog_frozen_metadata.yaml
max_runtime: 45m
go_test_timeout: 60m
slow: false
needs_dbt: false
- name: frozen-perf
slot: 4
file: tests/scenario/scenarios/posthog_frozen_perf.yaml
max_runtime: 45m
go_test_timeout: 60m
slow: false
needs_dbt: false
- name: frozen-dbt
slot: 5
file: tests/scenario/scenarios/posthog_frozen_dbt.yaml
max_runtime: 4h
go_test_timeout: 4h15m
slow: true
needs_dbt: true
env:
USE_SHARED_DEV: ${{ github.event_name == 'workflow_dispatch' && inputs.use_shared_dev }}
SCENARIO_RUNNER_IMAGE: ${{ needs.scenario-runner-image.outputs.image }}
WORKER_IMAGE: ${{ (github.event_name == 'workflow_dispatch' && inputs.duckgres_image) || needs.duckgres-image.outputs.image }}
CONTROLPLANE_IMAGE: ${{ (github.event_name == 'workflow_dispatch' && inputs.duckgres_image) || needs.duckgres-image.outputs.image }}
KUBE_CONTEXT: ${{ vars.DUCKGRES_SCENARIO_KUBE_CONTEXT }}
CLUSTER_NAME: ${{ vars.DUCKGRES_SCENARIO_EKS_CLUSTER_NAME }}
EKS_CLUSTER_NAME: ${{ vars.DUCKGRES_SCENARIO_EKS_CLUSTER_NAME }}
AWS_REGION: ${{ vars.DUCKGRES_SCENARIO_AWS_REGION || 'us-east-1' }}
CP_POD_IDENTITY_ROLE: ${{ secrets.DUCKGRES_SCENARIO_CP_POD_IDENTITY_ROLE }}
PR_NUMBER: ${{ github.run_id }}${{ matrix.slot }}
NAMESPACE: duckgres-ci-pr-${{ github.run_id }}${{ matrix.slot }}
SCENARIO_NAMESPACE: duckgres-ci-pr-${{ github.run_id }}${{ matrix.slot }}
SCENARIO_NAME: ${{ matrix.name }}
SCENARIO_FILE: ${{ matrix.file }}
SCENARIO_SHARED_NAMESPACE: ${{ vars.DUCKGRES_SCENARIO_SHARED_NAMESPACE }}
SCENARIO_SHARED_API_BASE: ${{ vars.DUCKGRES_SCENARIO_SHARED_API_BASE }}
SCENARIO_SHARED_PG_HOST: ${{ vars.DUCKGRES_SCENARIO_SHARED_PG_HOST }}
SCENARIO_SHARED_FLIGHT_ADDR: ${{ vars.DUCKGRES_SCENARIO_SHARED_FLIGHT_ADDR }}
SCENARIO_CONFIG_SECRET_NAMESPACE: ${{ vars.DUCKGRES_SCENARIO_CONFIG_SECRET_NAMESPACE }}
SCENARIO_CONFIG_SECRET_NAME: ${{ vars.DUCKGRES_SCENARIO_CONFIG_SECRET_NAME }}
SCENARIO_INTERNAL_SECRET_NAME: ${{ vars.DUCKGRES_SCENARIO_INTERNAL_SECRET_NAME }}
SCENARIO_INTERNAL_SECRET_KEY: ${{ vars.DUCKGRES_SCENARIO_INTERNAL_SECRET_KEY }}
SCENARIO_ISOLATED_SNI_SUFFIX: .ci.duckgres.local
SCENARIO_SHARED_SNI_SUFFIX: ${{ vars.DUCKGRES_SCENARIO_SHARED_SNI_SUFFIX || vars.DUCKGRES_SCENARIO_SNI_SUFFIX }}
DUCKGRES_SCENARIO_MAX_RUNTIME: ${{ matrix.max_runtime }}
DUCKGRES_SCENARIO_GO_TEST_TIMEOUT: ${{ matrix.go_test_timeout }}
DUCKGRES_SCENARIO_RUN_ID: scenario-dev-${{ matrix.name }}-${{ github.run_id }}-${{ github.run_attempt }}
KUBE_CONTEXT: posthog-mw-dev
CLUSTER_NAME: posthog-mw-dev
EKS_CLUSTER_NAME: posthog-mw-dev
AWS_REGION: us-east-1
CP_POD_IDENTITY_ROLE: arn:aws:iam::${{ secrets.MW_DEV_ACCOUNT_ID }}:role/duckgres-control-plane-dev
PR_NUMBER: ${{ github.run_id }}
NAMESPACE: duckgres-ci-pr-${{ github.run_id }}
DUCKGRES_SCENARIO_MAX_RUNTIME: 4h
DUCKGRES_SCENARIO_GO_TEST_TIMEOUT: 4h15m
steps:
- name: Skip slow scenario
if: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_slow && matrix.slow }}
run: echo "Skipping slow scenario because skip_slow is true."

- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}

- name: Isolated dev target selected
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.use_shared_dev }}
run: echo "Deploying an isolated Duckgres stack for this scenario."

- name: Shared dev target selected
if: ${{ github.event_name == 'workflow_dispatch' && inputs.use_shared_dev }}
run: echo "Skipping isolated deploy and targeting the shared dev stack."
- name: Scenario dev target selected
run: echo "Deploying an isolated Duckgres stack for scenario.full."

- name: Set up Go
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version-file: go.mod

- name: Test scenario workflow scripts
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
run: go test -count=1 ./tests/scenario ./tests/scenario-dev ./tests/e2e-mw-dev
run: go test -count=1 ./tests/mw-dev/scenario ./tests/mw-dev

- name: Configure AWS credentials (OIDC)
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
role-to-assume: arn:aws:iam::${{ secrets.MW_DEV_ACCOUNT_ID }}:role/github-duckgres-e2e
aws-region: us-east-1

- name: Connect to Tailscale
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
uses: tailscale/github-action@306e68a486fd2350f2bfc3b19fcd143891a4a2d8 # v4.1.2
with:
oauth-client-id: ${{ vars.TS_WIF_CLIENT_ID_MW_DEV }}
audience: ${{ vars.TS_WIF_AUDIENCE_MW_DEV }}
tags: tag:github-runner

- name: Install kubectl
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
uses: azure/setup-kubectl@776406bce94f63e41d621b960d78ee25c8b76ede # v4.0.1

- name: Update kubeconfig
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
run: aws eks update-kubeconfig --name "$CLUSTER_NAME" --region "$AWS_REGION" --alias "$KUBE_CONTEXT"

- name: Deploy isolated Duckgres stack
if: ${{ (github.event_name != 'workflow_dispatch' || !inputs.use_shared_dev) && (github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow) }}
run: tests/scenario-dev/run.sh deploy
run: tests/mw-dev/run.sh deploy

- name: Run scenario
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow }}
run: tests/scenario-dev/run.sh test
- name: Run scenario.full
run: tests/mw-dev/run.sh test-scenario-full

- name: Collect diagnostics
if: ${{ failure() && (github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow) }}
run: tests/scenario-dev/run.sh diagnostics
if: failure()
run: tests/mw-dev/run.sh diagnostics

- name: Teardown
if: ${{ always() && (github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow) }}
run: tests/scenario-dev/run.sh teardown
if: always()
run: tests/mw-dev/run.sh teardown

- name: Upload scenario artifacts
if: ${{ always() && (github.event_name != 'workflow_dispatch' || !inputs.skip_slow || !matrix.slow) }}
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: scenario-dev-${{ matrix.name }}-${{ github.run_id }}-${{ github.run_attempt }}
name: scenario-dev-full-${{ github.run_id }}-${{ github.run_attempt }}
path: artifacts/scenario-dev/
if-no-files-found: warn
retention-days: 14

scenario-skipped:
if: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_slow }}
runs-on: ubuntu-24.04
steps:
- run: echo "Skipping scenario.full because skip_slow is true."
2 changes: 1 addition & 1 deletion docs/design/admin-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,6 @@ and the admin Google-group name via values. Ship to `mw-dev` first, then `mw-pro
Unit (`-tags kubernetes`): RBAC gate (viewer blocked from writes/impersonation; TokenSet
bypass), Prometheus proxy allow-list, impersonation round-trip with a fake stack +
session-destroy-on-defer, audit row written per mutation, new configstore writes.
e2e (`tests/e2e-mw-dev/harness.sh`): admin UI reachable in-cluster, RBAC enforced,
e2e (`tests/mw-dev/e2e/harness.sh`): admin UI reachable in-cluster, RBAC enforced,
impersonation SQL round-trip against a real org worker is audited, a config-store edit via
the API is observed by a subsequent connection. Update CLAUDE.md + admin/README.md.
2 changes: 1 addition & 1 deletion docs/design/billing-compute-seconds-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ plumbing exists and can be wired later. Out of scope now.)
Flush UPSERT-increment of both columns + drain ship-then-delete + high-water +
idempotent uuid.

### duckgres (e2e — `tests/e2e-mw-dev/harness.sh`, required per CLAUDE.md)
### duckgres (e2e — `tests/mw-dev/e2e/harness.sh`, required per CLAUDE.md)
Provision an org with a known worker profile, then assert the emitted event's
`cpu_seconds` ≈ cores × ceil(conn) and `memory_seconds` ≈ gib × ceil(conn):
- run a query, disconnect → both metrics ≈ size × ceil(connection wall-clock).
Expand Down
2 changes: 1 addition & 1 deletion docs/design/resharding.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Unit: `configstore` (tests/configstore/reshard_postgres_test.go — claim CAS,
takeover fencing, cancel, log pagination, the grant-path gate),
`provisioner/reshard_runner_test.go` (all three directions, rollbacks, cancel,
ephemeral-password loss), `admin/reshard_test.go` (validation, secrets never
persisted). e2e (`tests/e2e-mw-dev/harness.sh`): validation 400s,
persisted). e2e (`tests/mw-dev/e2e/harness.sh`): validation 400s,
cancel-during-drain (drain-not-kill + 57P03 visible), bogus-shard rollback
(real flip → Synced=False → rollback, data intact), and the **ext→cnpg
positive path** (real catalog move off the harness RDS onto shard-001).
Expand Down
2 changes: 1 addition & 1 deletion docs/design/worker-ttl-pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,4 @@ workers cannot overcommit a node).
## Rollout

Build arm64 control-plane + worker images, push to ECR, deploy to **mw-dev only**
(`tests/e2e-mw-dev/run.sh`), run harness, iterate. Never prod.
(`tests/mw-dev/run.sh`), run harness, iterate. Never prod.
2 changes: 1 addition & 1 deletion docs/perf-harness-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Golden-query performance signal collection for `pgwire` and `flight` protocols.
This is observability-only; there is no pass/fail performance gate.

Status: the old prod-us deployed perf runner path is legacy while the dev Duckgres Scenario Runner replacement is being built. Prefer `tests/scenario/scenarios/posthog_frozen_metadata.yaml` for current frozen dataset end-to-end validation; keep this perf harness for local/library use and historical artifact compatibility until the scenario perf adapter is available.
Status: the old prod-us deployed perf runner path is legacy while the dev Duckgres Scenario Runner replacement is being built. Prefer `tests/mw-dev/scenario/scenarios/posthog_frozen_metadata.yaml` for current frozen dataset end-to-end validation; keep this perf harness for local/library use and historical artifact compatibility until the scenario perf adapter is available.

## Local Prerequisites

Expand Down
Loading
Loading