Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
207 commits
Select commit Hold shift + click to select a range
0698c99
docs: design safe forward engineering workflow
seonghobae Aug 9, 2026
bcce75a
docs: harden forward engineering safety contract
seonghobae Aug 9, 2026
42715ad
feat: establish forward engineering plan authority
seonghobae Aug 9, 2026
61f3152
docs: define forward engineering architecture and contracts
seonghobae Aug 9, 2026
68df39b
fix: make empty schema preservation explicit
seonghobae Aug 9, 2026
853946e
fix: address forward engineering review findings
seonghobae Aug 9, 2026
c1248e4
fix: address forward engineering review findings
seonghobae Aug 9, 2026
ea612ab
fix: address forward engineering review findings
seonghobae Aug 9, 2026
c3600e0
fix: address forward engineering review findings
seonghobae Aug 9, 2026
dcbe80c
fix: address forward engineering review findings
seonghobae Aug 9, 2026
38a91b9
fix: address forward engineering review findings
seonghobae Aug 9, 2026
1fde7fd
fix: address forward engineering review findings
seonghobae Aug 9, 2026
f78fa57
fix: address forward engineering review findings
seonghobae Aug 9, 2026
51e299f
fix: address forward engineering review findings
seonghobae Aug 9, 2026
fc75a76
fix: address forward engineering review findings
seonghobae Aug 9, 2026
4a75726
fix: address forward engineering review findings
seonghobae Aug 9, 2026
731821a
fix: address forward engineering review findings
seonghobae Aug 9, 2026
97a9ff5
fix: address forward engineering review findings
seonghobae Aug 9, 2026
712e9af
fix: address forward engineering review findings
seonghobae Aug 9, 2026
a667113
fix: address forward engineering review findings
seonghobae Aug 9, 2026
e2abfea
fix: address forward engineering review findings
seonghobae Aug 9, 2026
e4a2e8f
test: close forward engineering review gaps
seonghobae Aug 9, 2026
195a511
test: close forward engineering review gaps
seonghobae Aug 9, 2026
6667e90
test: close forward engineering review gaps
seonghobae Aug 9, 2026
b9083e2
refactor: type migration plan API contract
seonghobae Aug 9, 2026
59d4d3e
refactor: type migration plan API contract
seonghobae Aug 9, 2026
265165e
refactor: type migration plan API contract
seonghobae Aug 9, 2026
c17c692
test(api): require immutable migration plan retrieval
seonghobae Aug 9, 2026
35e076b
feat(api): expose immutable migration plan preview
seonghobae Aug 9, 2026
c12f597
test(docs): track implemented plan retrieval
seonghobae Aug 9, 2026
351bbcd
docs(trd): mark immutable plan retrieval implemented
seonghobae Aug 9, 2026
fae3d39
docs(contract): publish plan preview maturity
seonghobae Aug 9, 2026
bfd54ea
docs(changelog): record plan preview retrieval
seonghobae Aug 9, 2026
aee3bb3
test(docs): catch stale plan retrieval maturity
seonghobae Aug 9, 2026
0ac9b61
docs: align retrieval contract with implementation
seonghobae Aug 9, 2026
885247b
test(api): require immutable plan binding evidence
seonghobae Aug 9, 2026
2e295d8
feat(api): expose immutable plan binding fields
seonghobae Aug 9, 2026
d80a18a
feat(api): return bound plan execution identity
seonghobae Aug 9, 2026
53a6b05
test(docs): pin immutable plan binding contract
seonghobae Aug 9, 2026
b3cc4f6
docs: define immutable plan preview bindings
seonghobae Aug 9, 2026
8c0c77d
docs: surface plan binding evidence in TRD
seonghobae Aug 9, 2026
b4b78d1
docs: record plan identity review evidence
seonghobae Aug 9, 2026
4b568f4
test(api): reject tampered persisted plans
seonghobae Aug 9, 2026
86945be
feat(plan): verify persisted plan digest
seonghobae Aug 9, 2026
1bb87ed
feat(api): fail closed on plan integrity drift
seonghobae Aug 9, 2026
0ced02c
test(docs): retain plan integrity verification
seonghobae Aug 9, 2026
8a93011
docs: specify plan integrity verification
seonghobae Aug 9, 2026
4930833
docs: record plan tamper detection
seonghobae Aug 9, 2026
2d37d6c
test(api): reject mismatched persisted plan bindings
seonghobae Aug 9, 2026
6b8a9aa
feat(api): verify denormalized plan bindings
seonghobae Aug 9, 2026
7c72ea0
docs: bind persisted plan fields to integrity check
seonghobae Aug 9, 2026
3282c3b
docs: record persisted binding verification
seonghobae Aug 9, 2026
5d4ed6e
test(run): define durable migration run contract
seonghobae Aug 9, 2026
e03c1b2
feat(run): enforce state and evidence contracts
seonghobae Aug 9, 2026
d27da1e
feat(run): persist durable run and event evidence
seonghobae Aug 9, 2026
596e696
feat(db): add durable migration run tables
seonghobae Aug 9, 2026
4d55e11
test(docs): track durable run maturity
seonghobae Aug 9, 2026
e819e84
docs: mark durable run foundation partial
seonghobae Aug 9, 2026
75540a5
docs: align TRD with run persistence
seonghobae Aug 9, 2026
b04ff1f
docs: record ADR-0004 implementation evidence
seonghobae Aug 9, 2026
4cf87eb
docs: add physical migration run ERD
seonghobae Aug 9, 2026
4003980
docs: record durable run foundation
seonghobae Aug 9, 2026
4ea7047
test(run): reject camelCase secret evidence keys
seonghobae Aug 9, 2026
0783001
fix(run): tokenize camelCase evidence keys
seonghobae Aug 9, 2026
f2ffcfc
test(run): scope idempotency across plan changes
seonghobae Aug 9, 2026
195ca39
fix(run): bind idempotency to effective request
seonghobae Aug 9, 2026
008fcb8
fix(db): enforce cross-plan idempotency conflicts
seonghobae Aug 9, 2026
178203a
docs: define run request conflict identity
seonghobae Aug 9, 2026
bc22004
docs: align run idempotency data model
seonghobae Aug 9, 2026
c79ad05
docs: record cross-plan idempotency rule
seonghobae Aug 9, 2026
0344b82
test(forward): reject DSNs from durable run evidence
seonghobae Aug 9, 2026
d468c33
fix(forward): keep PostgreSQL DSNs out of run evidence
seonghobae Aug 9, 2026
b245637
test(forward): bind migration run request identity
seonghobae Aug 9, 2026
5aeb47b
feat(forward): bind migration run request digests
seonghobae Aug 9, 2026
1b0d9a6
docs(forward): specify durable run request binding
seonghobae Aug 9, 2026
fa408ee
docs(adr): record run intent digest authority
seonghobae Aug 9, 2026
06d8ee7
docs(changelog): record run intent binding
seonghobae Aug 9, 2026
c3bbb81
test(forward): require run-kind state isolation
seonghobae Aug 9, 2026
77054f2
fix(forward): isolate run states by execution kind
seonghobae Aug 9, 2026
55482f5
fix(db): enforce run kind state compatibility
seonghobae Aug 9, 2026
7a9c2df
docs(forward): record run state isolation
seonghobae Aug 9, 2026
ef9cdb9
docs(adr): record database state isolation
seonghobae Aug 9, 2026
49208e5
test(forward): require atomic run state transitions
seonghobae Aug 9, 2026
73a6776
feat(forward): persist atomic run transitions
seonghobae Aug 9, 2026
87ee264
refactor(forward): preserve proven evidence object type
seonghobae Aug 9, 2026
48ffe23
test(forward): close run transition boundary coverage
seonghobae Aug 9, 2026
205109d
docs(forward): document atomic run transition authority
seonghobae Aug 9, 2026
2487e7a
docs(forward): align durable run CAS contract
seonghobae Aug 9, 2026
e664233
docs(forward): align durable run CAS status
seonghobae Aug 9, 2026
8b39d9a
docs(forward): align durable run CAS status
seonghobae Aug 9, 2026
c19eece
docs(forward): align durable run CAS status
seonghobae Aug 9, 2026
f5a174b
docs(forward): align durable run CAS status
seonghobae Aug 9, 2026
3a366d5
test(forward): require idempotent durable run creation
seonghobae Aug 9, 2026
3ec0292
feat(forward): create idempotent durable dry runs
seonghobae Aug 9, 2026
4e40448
test(forward): cover run creation conflict boundaries
seonghobae Aug 9, 2026
b2bb5dd
docs(forward): document idempotent dry-run creation
seonghobae Aug 9, 2026
d60030c
docs(forward): align internal run creation status
seonghobae Aug 9, 2026
57cbb74
docs(forward): align internal run creation status
seonghobae Aug 9, 2026
8244d59
docs(forward): align internal run creation status
seonghobae Aug 9, 2026
3727227
docs(forward): align internal run creation status
seonghobae Aug 9, 2026
fe7c5dc
docs(forward): align internal run creation status
seonghobae Aug 9, 2026
1f18d9e
test(forward): require durable cancellation intent
seonghobae Aug 9, 2026
4684bc3
feat(forward): persist cancellation intent with CAS
seonghobae Aug 9, 2026
99a7811
test(forward): cover cancellation race boundaries
seonghobae Aug 9, 2026
26d0aab
docs(forward): document cancellation CAS authority
seonghobae Aug 9, 2026
bfa3f46
docs(forward): align cancellation recovery status
seonghobae Aug 9, 2026
2e7969a
docs(forward): align cancellation recovery status
seonghobae Aug 9, 2026
48cdf43
docs(forward): align cancellation recovery status
seonghobae Aug 9, 2026
93becfd
docs(forward): align cancellation recovery status
seonghobae Aug 9, 2026
63a5852
test(forward): require authorized run history polling
seonghobae Aug 9, 2026
9b1a90c
feat(forward): type durable run history responses
seonghobae Aug 9, 2026
7eb7868
feat(forward): expose verified run history
seonghobae Aug 9, 2026
e502349
feat(forward): register run history route
seonghobae Aug 9, 2026
1d135a8
test(forward): close run history integrity coverage
seonghobae Aug 9, 2026
0a36e60
docs(forward): document verified run polling
seonghobae Aug 9, 2026
8312903
docs(forward): align run polling implementation status
seonghobae Aug 9, 2026
422d749
docs(forward): align run polling implementation status
seonghobae Aug 9, 2026
3b1f019
docs(forward): align run polling implementation status
seonghobae Aug 9, 2026
77728f7
docs(forward): align run polling implementation status
seonghobae Aug 9, 2026
b1b18a3
docs(forward): align run polling implementation status
seonghobae Aug 9, 2026
82e101f
docs(forward): align run polling implementation status
seonghobae Aug 9, 2026
880db77
fix(ci): restore complete response schema module
seonghobae Aug 9, 2026
ccc9311
feat: make migration run evidence tamper-evident
seonghobae Aug 9, 2026
b0c0f48
fix: constrain durable event digest shapes
seonghobae Aug 9, 2026
1caa74d
fix: verify durable event transition history
seonghobae Aug 9, 2026
0e4bbd4
fix: bind cancellation intent to audit evidence
seonghobae Aug 9, 2026
0bfb343
fix: constrain durable run evidence tokens
seonghobae Aug 9, 2026
89fdf04
fix: keep raw job errors out of durable evidence
seonghobae Aug 9, 2026
5739fd3
fix: close forward control-plane review gaps
seonghobae Aug 11, 2026
2c3f3c3
docs: reconcile durable run audit status
seonghobae Aug 11, 2026
fab047a
feat: expose durable run cancellation intent
seonghobae Aug 11, 2026
a4717ba
feat: expose idempotent dry-run intents
seonghobae Aug 11, 2026
69b6386
feat: persist dry-run dispatch outbox
seonghobae Aug 11, 2026
90e3504
test: verify outbox on PostgreSQL matrix
seonghobae Aug 11, 2026
7bb7cb2
test: order PostgreSQL integration fixtures
seonghobae Aug 11, 2026
7c70695
feat: claim dry-run dispatch outbox
seonghobae Aug 11, 2026
de5554d
docs: remove design spec trailing whitespace
seonghobae Aug 11, 2026
519c2b3
feat: publish identifier-only migration signals
seonghobae Aug 11, 2026
160f9eb
test: verify signals against real Valkey
seonghobae Aug 11, 2026
5deedf5
fix: preserve cancellation and harden integration CI
seonghobae Aug 11, 2026
3c019a8
feat: schedule identifier-only migration dispatch relay
seonghobae Aug 11, 2026
c6e89ef
test: harden dispatch relay acceptance
seonghobae Aug 11, 2026
be1bd78
feat: add migration signal lease safety
seonghobae Aug 11, 2026
d439340
fix: quarantine invalid queue bytes
seonghobae Aug 11, 2026
4a86466
feat: add migration signal consumer contract
seonghobae Aug 11, 2026
fab2bbb
test: remove unused consumer test import
seonghobae Aug 11, 2026
fb6d839
feat(forward): add bounded live preflight reads
seonghobae Aug 11, 2026
d0db7bf
feat(forward): bind preflight snapshot digest
seonghobae Aug 11, 2026
82f3d8b
fix(forward): bind and prepare preflight evidence
seonghobae Aug 11, 2026
63d0e5b
fix(forward): reserve observed digest evidence
seonghobae Aug 11, 2026
525d67d
fix(forward): bind preflight timeout value
seonghobae Aug 11, 2026
8fc12db
fix: sanitize preflight transaction startup
seonghobae Aug 11, 2026
a2df199
fix: sanitize preflight finalization failures
seonghobae Aug 11, 2026
9d0faad
fix: bind preflight timeout as decimal
seonghobae Aug 11, 2026
38680be
feat: execute signed plans in isolated sandbox
seonghobae Aug 11, 2026
f2d5362
fix: reject noncanonical sandbox plans
seonghobae Aug 11, 2026
60c08b2
fix: bound sandbox driver operations
seonghobae Aug 11, 2026
34b2a72
test: isolate PostgreSQL sandbox database
seonghobae Aug 11, 2026
e10fd05
fix: preserve cancellation without broad catches
seonghobae Aug 11, 2026
37b1485
fix: bound live preflight lifecycle
seonghobae Aug 11, 2026
a91c4ce
test: separate live preflight target
seonghobae Aug 11, 2026
42fd749
test: prove preflight least privilege
seonghobae Aug 11, 2026
e990319
fix: avoid reserved PostgreSQL role prefix
seonghobae Aug 11, 2026
6caee00
Bind live preflight capture to one snapshot
seonghobae Aug 11, 2026
8779aab
Bind live preflight outcomes to durable CAS
seonghobae Aug 11, 2026
850da88
Bind isolated dry run success to durable CAS
seonghobae Aug 11, 2026
86154ac
Bind PostgreSQL matrix plan to server major
seonghobae Aug 11, 2026
ac223d8
Bind preflight evidence to persisted plan
seonghobae Aug 11, 2026
d2f578c
Prove live preflight lock timeout cleanup
seonghobae Aug 11, 2026
3b36145
Document preflight timeout acceptance
seonghobae Aug 11, 2026
b5049d3
Prove preflight privilege and network failures
seonghobae Aug 12, 2026
61c9ffb
test: make backend termination evidence deterministic
seonghobae Aug 12, 2026
6f57e59
test: consume unexpected preflight task results
seonghobae Aug 12, 2026
6bd02ea
docs: align preflight capability maturity
seonghobae Aug 12, 2026
480f2e1
docs: align engineering baseline maturity
seonghobae Aug 12, 2026
44f6235
fix: bind migration handler to signal lease
seonghobae Aug 12, 2026
69c1454
feat: renew exact migration signal lease
seonghobae Aug 12, 2026
e552563
feat: heartbeat migration signal lease
seonghobae Aug 12, 2026
5f3147e
docs: align signal lease maturity table
seonghobae Aug 12, 2026
0ab122f
fix: use one asyncio import style
seonghobae Aug 12, 2026
5593e68
feat: persist lease-bound migration attempts
seonghobae Aug 12, 2026
f91027d
docs: align durable attempt maturity
seonghobae Aug 12, 2026
f5b96df
test: close migration attempt input branches
seonghobae Aug 12, 2026
41f35a6
feat: bind migration consumer attempts
seonghobae Aug 12, 2026
841c120
test: make cancellation assertions explicit
seonghobae Aug 12, 2026
e91c3c4
test: compose PostgreSQL and Valkey leases
seonghobae Aug 12, 2026
059f5bf
test: recover expired dual leases
seonghobae Aug 12, 2026
6a683d1
fix: reject expired signal lease renewal
seonghobae Aug 12, 2026
09e976f
feat: persist non-dispatched apply intents
seonghobae Aug 12, 2026
aebac6a
test: normalize apply intent imports
seonghobae Aug 12, 2026
1639478
test: close apply intent fail-closed branches
seonghobae Aug 12, 2026
3c10a44
fix: reject stale apply intent revisions
seonghobae Aug 12, 2026
19e38ff
test: classify apply intent route as current
seonghobae Aug 12, 2026
4c648f8
feat: add forward workflow browser transport
seonghobae Aug 12, 2026
232ea5d
test(frontend): encode forward resource paths
seonghobae Aug 12, 2026
e8c4ddc
test(frontend): cover forward write failures
seonghobae Aug 12, 2026
7f00daa
docs: align TRD with apply intent boundary
seonghobae Aug 12, 2026
f860fb2
feat(frontend): type migration plan statements
seonghobae Aug 12, 2026
52b96c4
fix(frontend): allowlist apply intent fields
seonghobae Aug 12, 2026
14660e1
feat(frontend): add immutable plan review panel
seonghobae Aug 12, 2026
8cc123a
feat(frontend): load exact plan review safely
seonghobae Aug 12, 2026
e1d9c5e
feat(frontend): add actionless forward modal
seonghobae Aug 12, 2026
f5ec776
feat(ui): add safe migration run audit surface
seonghobae Aug 12, 2026
e360ec4
feat(ui): poll migration runs until terminal
seonghobae Aug 12, 2026
56605f9
feat(ui): request exact dry-run intents
seonghobae Aug 12, 2026
9fdb393
feat(ui): request exact run cancellation
seonghobae Aug 12, 2026
d2bd3a1
fix(ui): retain cancellation single-flight guard
seonghobae Aug 12, 2026
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
15 changes: 15 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ SHARE_LINK_RATE_LIMIT_REQUESTS=30
SHARE_LINK_RATE_LIMIT_WINDOW_SECONDS=60
SHARE_LINK_RATE_LIMIT_MAX_KEYS=10000

# Optional durable job signal backend. Database rows remain authoritative.
# Migration dispatch uses a separate key and publishes only migration-run UUIDs;
# no SQL, plan payload, connection string, or credential crosses this queue.
# JOB_QUEUE_BACKEND=valkey
# VALKEY_URL=redis://valkey:6379/0
# VALKEY_QUEUE_KEY=pg-erd-cloud:job-queue
# VALKEY_MIGRATION_RUN_QUEUE_KEY=pg-erd-cloud:migration-run-queue
# VALKEY_MIGRATION_RUN_PROCESSING_KEY=pg-erd-cloud:migration-run-processing
# VALKEY_MIGRATION_RUN_LEASE_TOKEN_KEY=pg-erd-cloud:migration-run-lease-token
# MIGRATION_RUN_SIGNAL_LEASE_SECONDS=60
# The identifier-only migration outbox relay is opt-in and requires the Valkey
# backend above. It publishes run UUIDs only; it starts no consumer or executor.
MIGRATION_DISPATCH_RELAY_ENABLED=false
MIGRATION_DISPATCH_RELAY_POLL_INTERVAL_SECONDS=1.0

# Optional: OIDC (Casdoor) issuer; if set backend verifies JWTs
# OIDC_ISSUER=http://localhost:8002
# OIDC_AUDIENCE=erd-local
Expand Down
184 changes: 184 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:

- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
Expand All @@ -43,6 +45,186 @@ jobs:
PYTHONPATH: .
run: pytest -q

postgres-integration:
name: PostgreSQL ${{ matrix.major }} + Valkey dual-lease acceptance
runs-on: ubuntu-latest
services:
valkey:
image: valkey/valkey@sha256:a038175878d66b9d274fbf8be73c0305e93798b83917647f167e18cef3c71eec
ports:
- 6379:6379
options: >-
--health-cmd "valkey-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
strategy:
fail-fast: false
matrix:
include:
- major: "14"
image: postgres@sha256:f1341c01408dc7278e9d365ed4f860cd3f87dd16b4464ac326fc0f422083a579
- major: "15"
image: postgres@sha256:3d0f7584ed7d04e27fa050d6683a74746608faf21f202be78460d679cc56461f
- major: "16"
image: postgres@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777
- major: "17"
image: postgres@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193
- major: "18"
image: postgres@sha256:9a8afca54e7861fd90fab5fdf4c42477a6b1cb7d293595148e674e0a3181de15
steps:
- name: Harden runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
with:
persist-credentials: false

- name: Start PostgreSQL with ephemeral credentials
shell: bash
run: |
set -euo pipefail
password="$(openssl rand -hex 24)"
preflight_password="$(openssl rand -hex 24)"
app_secret="$(openssl rand -hex 32)"
echo "::add-mask::$password"
echo "::add-mask::$preflight_password"
echo "::add-mask::$app_secret"

credentials_file="$RUNNER_TEMP/postgres.env"
umask 077
{
echo "POSTGRES_DB=pg_erd_cloud_test"
echo "POSTGRES_PASSWORD=$password"
echo "POSTGRES_USER=postgres"
} > "$credentials_file"
docker run --detach --name pg-erd-cloud-postgres \
--env-file "$credentials_file" \
--publish 5432:5432 \
"${{ matrix.image }}"
rm -f "$credentials_file"

encoded_password="$(PASSWORD="$password" python3 - <<'PY'
import os
from urllib.parse import quote

print(quote(os.environ["PASSWORD"], safe=""))
PY
)"
database_url="postgresql+asyncpg://postgres:${encoded_password}@127.0.0.1:5432/pg_erd_cloud_test"
echo "::add-mask::$database_url"
{
echo "APP_SECRET=$app_secret"
echo "DATABASE_URL=$database_url"
echo "POSTGRES_INTEGRATION_URL=$database_url"
} >> "$GITHUB_ENV"

for attempt in {1..20}; do
if docker exec pg-erd-cloud-postgres \
pg_isready -U postgres -d pg_erd_cloud_test; then
break
fi
if [ "$attempt" -eq 20 ]; then
docker logs pg-erd-cloud-postgres
exit 1
fi
sleep 2
done

docker exec pg-erd-cloud-postgres \
psql -v ON_ERROR_STOP=1 -U postgres -d postgres \
-c "CREATE DATABASE pg_erd_cloud_sandbox"
docker exec pg-erd-cloud-postgres \
psql -v ON_ERROR_STOP=1 -U postgres -d postgres \
-c "CREATE DATABASE pg_erd_cloud_target"
docker exec pg-erd-cloud-postgres \
psql -v ON_ERROR_STOP=1 -U postgres -d postgres \
-c "CREATE ROLE cwl_erd_preflight LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS PASSWORD '$preflight_password'; ALTER ROLE cwl_erd_preflight SET default_transaction_read_only = on; ALTER ROLE cwl_erd_preflight SET statement_timeout = '5s'; REVOKE ALL ON DATABASE pg_erd_cloud_target FROM PUBLIC; GRANT CONNECT ON DATABASE pg_erd_cloud_target TO cwl_erd_preflight; REVOKE CREATE, TEMPORARY ON DATABASE pg_erd_cloud_target FROM cwl_erd_preflight"
encoded_preflight_password="$(PASSWORD="$preflight_password" python3 - <<'PY'
import os
from urllib.parse import quote

print(quote(os.environ["PASSWORD"], safe=""))
PY
)"
sandbox_database_url="postgresql+asyncpg://postgres:${encoded_password}@127.0.0.1:5432/pg_erd_cloud_sandbox"
target_database_url="postgresql+asyncpg://postgres:${encoded_password}@127.0.0.1:5432/pg_erd_cloud_target"
preflight_database_url="postgresql+asyncpg://cwl_erd_preflight:${encoded_preflight_password}@127.0.0.1:5432/pg_erd_cloud_target"
echo "::add-mask::$sandbox_database_url"
echo "::add-mask::$target_database_url"
echo "::add-mask::$preflight_database_url"
{
echo "POSTGRES_SANDBOX_INTEGRATION_URL=$sandbox_database_url"
echo "POSTGRES_TARGET_INTEGRATION_URL=$target_database_url"
echo "POSTGRES_PREFLIGHT_INTEGRATION_URL=$preflight_database_url"
} >> "$GITHUB_ENV"

- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.10"

- name: Install backend deps
working-directory: backend
run: python -m pip install --require-hashes -r requirements-dev.lock

- name: Apply metadata migrations
working-directory: backend
env:
PYTHONPATH: .
run: alembic upgrade head

- name: Verify PostgreSQL and Valkey dual-lease recovery
working-directory: backend
env:
EXPECTED_POSTGRES_MAJOR: ${{ matrix.major }}
PYTHONPATH: .
VALKEY_INTEGRATION_URL: redis://127.0.0.1:6379/0
run: pytest -q tests/test_postgres_migration_run_integration.py

valkey-integration:
name: Valkey 8 queue signal boundary
runs-on: ubuntu-latest
services:
valkey:
image: valkey/valkey@sha256:a038175878d66b9d274fbf8be73c0305e93798b83917647f167e18cef3c71eec
ports:
- 6379:6379
options: >-
--health-cmd "valkey-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- name: Harden runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.10"

- name: Install backend deps
working-directory: backend
run: python -m pip install --require-hashes -r requirements-dev.lock

- name: Verify real Valkey signal isolation
working-directory: backend
env:
PYTHONPATH: .
VALKEY_INTEGRATION_URL: redis://127.0.0.1:6379/0
run: pytest -q tests/test_valkey_queue_integration.py

frontend:
runs-on: ubuntu-latest
steps:
Expand All @@ -53,6 +235,8 @@ jobs:

- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
Expand Down
Loading
Loading