Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
54e0225
chore(dashboard): switch linting and formatting to ultracite (biome)
Mujhtech Jul 31, 2026
4dd0923
refactor(dashboard): give JSX handlers stable identities via a codemod
Mujhtech Jul 31, 2026
7735151
fix(dashboard): associate labels and use semantic elements
Mujhtech Jul 31, 2026
f7f4a2a
fix(dashboard): finish the a11y rules
Mujhtech Jul 31, 2026
7917f91
refactor(dashboard): memoize functions that hooks already depend on
Mujhtech Jul 31, 2026
1809655
fix(dashboard): clear the remaining bug-surfacing lint rules
Mujhtech Jul 31, 2026
ffbbbc2
fix(dashboard): hoist two useId calls out of map callbacks
Mujhtech Jul 31, 2026
7e31032
refactor(dashboard): clear empty blocks, return assigns and forEach
Mujhtech Jul 31, 2026
7f25f83
refactor(dashboard): give every switch a default clause
Mujhtech Jul 31, 2026
e85e23a
refactor(dashboard): clear shadowed bindings and pointless async
Mujhtech Jul 31, 2026
c65faa1
fix(dashboard): replace window.confirm and clear the remaining stragg…
Mujhtech Aug 1, 2026
bdcf254
refactor(dashboard): destructure indexed access and record the assert…
Mujhtech Aug 1, 2026
d5ec986
chore(dashboard): disable noUnnecessaryConditions and noJsxPropsBind
Mujhtech Aug 1, 2026
8ee2428
refactor(dashboard): flatten nested ternaries into early returns
Mujhtech Aug 1, 2026
306fb0c
refactor(dashboard): replace non-null assertions with real checks
Mujhtech Aug 1, 2026
d909cbf
refactor(dashboard): finish the non-null assertions
Mujhtech Aug 1, 2026
dfcc16e
refactor(dashboard): split PreviewNode into per-node-type renderers
Mujhtech Aug 1, 2026
1f1b255
refactor(dashboard): split the editor document validator by concern
Mujhtech Aug 1, 2026
7e3f58a
refactor(dashboard): split the editor keydown handler by shortcut family
Mujhtech Aug 1, 2026
9500de8
refactor(dashboard): split the preview socket message handler
Mujhtech Aug 1, 2026
8007bb7
refactor(dashboard): split the relay frame handler
Mujhtech Aug 1, 2026
1905de3
chore(dashboard): raise the complexity limit above what is left
Mujhtech Aug 1, 2026
5804fba
fix(ci): repair the writer/schema drift sweep
Mujhtech Aug 1, 2026
502f5f5
fix(ci): pin flutter, repair the minio bootstrap, scope the secret scan
Mujhtech Aug 1, 2026
e38ebae
fix(ci): resolve flutter packages before checking format
Mujhtech Aug 1, 2026
6bcd356
fix(api): write due_at and max_attempts when queueing migration jobs
Mujhtech Aug 1, 2026
8239553
fix(ci): resolve every flutter package, not only the root
Mujhtech Aug 1, 2026
74ef411
fix(api): repair the stabilization observation write path
Mujhtech Aug 1, 2026
34e882a
test(api): exercise the migration rollback guards against reachable v…
Mujhtech Aug 1, 2026
dff41c0
test(flutter): keep the golden baseline off the CI matrix
Mujhtech Aug 1, 2026
8f27954
test(android): let the gate hold the collapsed refresh open
Mujhtech Aug 1, 2026
86c51bf
Merge branch 'chore/dashboard-ultracite-biome' into fix/ci-failures
Mujhtech Aug 1, 2026
7d529aa
fix(dashboard): upgrade Biome past the module-graph panic
Mujhtech Aug 1, 2026
2bfc013
ci(dashboard): install the protocol runtime dependencies
Mujhtech Aug 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
48 changes: 44 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,21 @@ jobs:
-e MINIO_ROOT_USER=mosaic_ci -e MINIO_ROOT_PASSWORD=mosaic_ci_secret \
minio/minio:RELEASE.2025-07-23T15-54-02Z server /data
for i in $(seq 1 30); do
curl -fsS http://localhost:9000/minio/health/live && break; sleep 2
curl -fsS http://localhost:9000/minio/health/live && break
sleep 2
done
docker run --rm --network host \
# The loop above exits on its last iteration whether or not MinIO ever
# answered, so failure has to be its own statement: otherwise the
# bucket step is the first thing to notice, and it reports a client
# error rather than an unreachable server.
curl -fsS http://localhost:9000/minio/health/live >/dev/null || {
echo "MinIO did not become ready"; docker logs mosaic-ci-minio | tail -50; exit 1;
}
# `mc` is the image's entrypoint, so an `sh -c` argument is read as an
# mc subcommand and fails with "`sh` is not a recognized command".
docker run --rm --network host --entrypoint sh \
minio/mc:RELEASE.2025-07-21T05-28-08Z \
sh -c "mc alias set ci http://localhost:9000 mosaic_ci mosaic_ci_secret && mc mb --ignore-existing ci/mosaic-ci-assets"
-c "mc alias set ci http://localhost:9000 mosaic_ci mosaic_ci_secret && mc mb --ignore-existing ci/mosaic-ci-assets"
- uses: actions/setup-go@v5
with:
go-version-file: apps/api/go.mod
Expand Down Expand Up @@ -112,6 +122,15 @@ jobs:
- name: Install
working-directory: apps/dashboard
run: npm ci
# apps/dashboard/scripts/*.mjs reach protocol/browser/index.js by relative
# path rather than as a declared dependency, so its runtime deps resolve
# from protocol/node_modules — which installing the dashboard alone never
# creates. The relay test is the step that notices, and only in a clean
# checkout: any working copy that has built the protocol package has the
# directory already and passes.
- name: Install protocol runtime dependencies
working-directory: protocol
run: npm ci --omit=dev
- name: Check (format, lint, typecheck, tests, relay, build)
working-directory: apps/dashboard
run: npm run check
Expand All @@ -133,15 +152,36 @@ jobs:
- uses: subosito/flutter-action@v2
with:
channel: stable
# `dart format` picks its style from the package's language version, which
# it reads from .dart_tool/package_config.json. On a fresh checkout that
# file does not exist yet, so it falls back to the newest language version
# and applies the tall style introduced in Dart 3.7 — rewriting 86 of 90
# files against a package that declares `sdk: ">=3.4.0"`. Resolving first
# pins the language version to 3.4 and the formatter to the style the
# sources are actually written in. One `pub get` here also resolves the
# example package, which the format step covers.
- name: Resolve packages
working-directory: sdk/flutter
run: |
# Every package with a pubspec, not just the root: `flutter pub get`
# here resolves the root and the example, but packages/* are separate
# and analyze covers them, so unresolved they report as missing URIs.
for pubspec in $(find . -name pubspec.yaml -not -path "*/build/*" | sort); do
(cd "$(dirname "$pubspec")" && flutter pub get)
done
- name: Format
working-directory: sdk/flutter
run: dart format --output=none --set-exit-if-changed lib test example/lib
- name: Analyze
working-directory: sdk/flutter
run: flutter analyze
# Goldens are rasterised output, so they encode the host's font rendering
# and the Flutter version that produced them. The baselines are macOS and
# this runner is Linux on a channel that moves, so comparing here fails on
# the environment rather than on the renderer. See sdk/flutter/dart_test.yaml.
- name: Tests
working-directory: sdk/flutter
run: flutter test
run: flutter test --exclude-tags golden

android:
runs-on: ubuntu-latest
Expand Down
28 changes: 28 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Gitleaks configuration.
#
# The default rules are kept in full. This narrows exactly one of them.
#
# `generic-api-key` fires on any assignment whose value clears a Shannon
# entropy of 3.5, which readable Go test fixtures do as soon as they get
# descriptive: `redelivery-v1-destination` scores 3.65, while its siblings
# `redelivery-stale-digest` (3.41) and `redelivery-1` (3.02) pass. Renaming is
# not a fix — a longer, clearer name scores *higher* — so without this the
# repository would have to name its test fixtures against an entropy budget.
#
# Scope is by value, not by path. An earlier attempt allowlisted `_test.go`
# paths as well, which turned out to widen rather than narrow: allowlist
# conditions are OR'd, so the path alone exempted the file and real secrets
# planted in a test went unreported. Matching only the secret, anchored, means
# a value has to *be* a fixture identifier end to end to be exempt; a random
# credential in the same file still fails the scan.
#
# Verified both directions — see the commit that introduced this file.
[extend]
useDefault = true

[[allowlists]]
description = "Readable fixture identifiers, matched only by the generic entropy rule"
targetRules = ["generic-api-key"]
regexes = [
'''(?i)^(idempotency|correlation|redelivery|fixture|expected|request)[-_][a-z0-9-]+$''',
]
Original file line number Diff line number Diff line change
Expand Up @@ -339,12 +339,61 @@ func TestCutoverPreparationRequiresAuthoritativeEvidenceAndDistinctProductionApp
if _, err := service.PromoteReady(ctx, billingmigration.Actor{ID: "owner_one"}, billingmigration.PromoteReadyInput{ProjectID: "project_one", ProgramID: "program_ready", ExpectedStateVersion: 6}); !errors.Is(err, billingmigration.ErrConflict) {
t.Fatalf("unsupported in-window version bypassed by outside-window flag: %v", err)
}
if err := goose.DownContext(ctx, db, "."); err == nil || !strings.Contains(err.Error(), "immutable cohort or rollback proposal evidence exists") {
}

func TestExecutionPrerequisiteRollbackGuardRetainsCohortEvidence(t *testing.T) {
databaseURL := os.Getenv("DATABASE_TEST_URL")
if databaseURL == "" {
t.Skip("DATABASE_TEST_URL is required for PostgreSQL integration tests")
}
configuration, err := pgx.ParseConfig(databaseURL)
if err != nil {
t.Fatal(err)
}
db := stdlib.OpenDB(*configuration)
t.Cleanup(func() { _ = db.Close() })
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
t.Cleanup(cancel)
if _, err = db.ExecContext(ctx, `DROP SCHEMA public CASCADE; CREATE SCHEMA public`); err != nil {
t.Fatal(err)
}
goose.SetBaseFS(migrations.Files)
if err = goose.SetDialect("postgres"); err != nil {
t.Fatal(err)
}
if err = goose.UpContext(ctx, db, "."); err != nil {
t.Fatal(err)
}
seedMigrationTenant(t, ctx, db)
now := time.Date(2026, 7, 29, 12, 0, 0, 0, time.UTC)
// A frozen cohort set is 00054 evidence and nothing later, so the program
// is seeded by hand rather than via seedReadyProgram: that helper also
// writes final-delta jobs and prepared pointers, and 00055 refuses to roll
// back over those — 54 would never be reached and its guard never
// exercised.
for _, statement := range []string{
`INSERT INTO billing_migration_credentials(id,project_id,provider,external_project_id,status,envelope_version,algorithm,key_id,nonce,ciphertext,fingerprint,created_by_actor_id,created_at) VALUES('credential_ready','project_one','revenuecat','rc','active',1,'AES-256-GCM','key',decode(repeat('01',12),'hex'),decode(repeat('02',16),'hex'),decode(repeat('03',32),'hex'),'owner_one',$1)`,
`INSERT INTO billing_migration_programs(id,project_id,environment_id,source_adapter,source_adapter_version,credential_id,state,state_version,authority_epoch_before,stabilization_days,rollback_window_days,scope_digest,policy_digest,idempotency_key,request_digest,created_by_actor_id,created_at,updated_at) VALUES('program_ready','project_one','environment_one','revenuecat','v2','credential_ready','shadowing',4,0,7,7,decode(repeat('61',32),'hex'),decode(repeat('62',32),'hex'),'ready-program',decode(repeat('63',32),'hex'),'owner_one',$1,$1)`,
`INSERT INTO billing_migration_final_deltas(id,program_id,project_id,state_version,manifest_digest,mapping_digest,evidence_digest,final_watermark_digest,source_watermark,provider_watermark,shadow_watermark,delta_digest,completed_at) VALUES('delta_guard','program_ready','project_one',4,decode(repeat('65',32),'hex'),decode(repeat('66',32),'hex'),decode(repeat('67',32),'hex'),decode(repeat('96',32),'hex'),$1,$1,$1,decode(repeat('97',32),'hex'),$1)`,
`INSERT INTO billing_migration_final_delta_cohort_sets(id,final_delta_id,program_id,project_id,customer_count,cohort_digest,frozen_at) VALUES('cohort_guard','delta_guard','program_ready','project_one',1,decode(repeat('99',32),'hex'),$1)`,
} {
if _, err = db.ExecContext(ctx, statement, now); err != nil {
t.Fatal(err)
}
}
if err = goose.DownToContext(ctx, db, ".", 54); err != nil {
t.Fatalf("down to 54: %v", err)
}
if err = goose.DownToContext(ctx, db, ".", 53); err == nil || !strings.Contains(err.Error(), "immutable cohort or rollback proposal evidence exists") {
t.Fatalf("migration 54 evidence guard error=%v", err)
}
version, err := goose.GetDBVersionContext(ctx, db)
if err != nil || version != 54 {
t.Fatalf("guarded rollback version=%d err=%v", version, err)
version, versionErr := goose.GetDBVersionContext(ctx, db)
if versionErr != nil || version != 54 {
t.Fatalf("guarded rollback version=%d err=%v", version, versionErr)
}
var cohorts int
if err = db.QueryRowContext(ctx, `SELECT count(*) FROM billing_migration_final_delta_cohort_sets`).Scan(&cohorts); err != nil || cohorts != 1 {
t.Fatalf("guard lost cohorts count=%d err=%v", cohorts, err)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ func (r *Repository) CreateImportBatch(ctx context.Context, expectedStateVersion
command, err := tx.Exec(ctx, `INSERT INTO billing_migration_import_batches(
id,program_id,project_id,manifest_id,mapping_set_id,idempotency_key,request_digest,
expected_program_state_version,status,record_count,validated_count,quarantined_count,
cursor_before,cursor_after,attempt_count,created_at,updated_at)
VALUES($1,$2,$3,$4,$5,$6,$7,$8,'pending',$9,0,0,$10,'',0,$11,$11)
cursor_before,cursor_after,attempt_count,created_at,updated_at,due_at,max_attempts)
VALUES($1,$2,$3,$4,$5,$6,$7,$8,'pending',$9,0,0,$10,'',0,$11,$11,$11,8)
ON CONFLICT (program_id,idempotency_key) DO NOTHING`,
batch.BatchID, batch.ProgramID, write.ProjectID, write.ManifestID, write.MappingSetID,
batch.IdempotencyKey, write.RequestDigest, expectedStateVersion, batch.RecordCount,
Expand Down Expand Up @@ -328,8 +328,8 @@ func (r *Repository) QueueRun(ctx context.Context, expectedStateVersion int64, w
return false, err
}
command, err := tx.Exec(ctx, `INSERT INTO billing_migration_run_jobs(id,program_id,project_id,run_kind,idempotency_key,
request_digest,expected_program_state_version,manifest_digest,mapping_digest,policy_digest,status,created_at,updated_at)
SELECT $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,'pending',$11,$11
request_digest,expected_program_state_version,manifest_digest,mapping_digest,policy_digest,status,created_at,updated_at,due_at,max_attempts)
SELECT $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,'pending',$11,$11,$11,8
WHERE EXISTS(SELECT 1 FROM billing_migration_source_manifests WHERE program_id=$2 AND project_id=$3 AND manifest_digest=$8)
AND EXISTS(SELECT 1 FROM billing_migration_mapping_sets WHERE program_id=$2 AND project_id=$3 AND mapping_digest=$9 AND status='frozen')
AND EXISTS(SELECT 1 FROM billing_migration_programs WHERE id=$2 AND project_id=$3 AND policy_digest=$10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,16 +358,16 @@ func TestProgramTransactionEnforcesTenantScopeAndEncryptedCredential(t *testing.
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_source_access_exceptions(id,case_id,program_id,project_id,application_id,platform,reason,affected_customer_count,rollback_treatment,identity_ambiguity_count,proposer_actor_id,approver_actor_id,approved_at,expires_at,exception_digest) VALUES('exception_same_actor','case_distinct_exception',$1,'project_one','app_one','ios','reviewed',1,'restore source',0,'owner_one','owner_one',now(),now()+interval '1 hour',decode(repeat('93',32),'hex'))`, created.Program.ProgramID); err == nil {
t.Fatal("nonproduction source-access exception accepted identical proposer and approver")
}
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest) VALUES('completion_bad',$1,'project_one',4,now(),now(),now()+interval '1 day',true,now(),false,now()+interval '30 days',decode(repeat('94',32),'hex'))`, created.Program.ProgramID); err == nil {
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest,authority_digest,stability_evidence_digest,completion_policy_digest) VALUES('completion_bad',$1,'project_one',4,now(),now(),now()+interval '1 day',true,now(),false,now()+interval '30 days',decode(repeat('94',32),'hex'),decode(repeat('a7',32),'hex'),decode(repeat('b7',32),'hex'),decode(repeat('c7',32),'hex'))`, created.Program.ProgramID); err == nil {
t.Fatal("completion accepted completion/credential removal before rollback window ended")
}
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest) VALUES('completion_bad_stabilization',$1,'project_one',4,now(),now()+interval '1 second',now(),true,now(),false,now()+interval '30 days',decode(repeat('99',32),'hex'))`, created.Program.ProgramID); err == nil {
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest,authority_digest,stability_evidence_digest,completion_policy_digest) VALUES('completion_bad_stabilization',$1,'project_one',4,now(),now()+interval '1 second',now(),true,now(),false,now()+interval '30 days',decode(repeat('99',32),'hex'),decode(repeat('a7',32),'hex'),decode(repeat('b7',32),'hex'),decode(repeat('c7',32),'hex'))`, created.Program.ProgramID); err == nil {
t.Fatal("completion accepted completed_at before stabilization ended")
}
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest) VALUES('completion_bad_delete',$1,'project_one',4,now(),now(),now(),true,now(),false,now()+interval '31 days',decode(repeat('95',32),'hex'))`, created.Program.ProgramID); err == nil {
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest,authority_digest,stability_evidence_digest,completion_policy_digest) VALUES('completion_bad_delete',$1,'project_one',4,now(),now(),now(),true,now(),false,now()+interval '31 days',decode(repeat('95',32),'hex'),decode(repeat('a7',32),'hex'),decode(repeat('b7',32),'hex'),decode(repeat('c7',32),'hex'))`, created.Program.ProgramID); err == nil {
t.Fatal("completion accepted a non-deterministic source-object deletion time")
}
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest) VALUES('completion_valid',$1,'project_one',4,now(),now()-interval '1 day',now(),true,now(),false,now()+interval '30 days',decode(repeat('96',32),'hex'))`, created.Program.ProgramID); err != nil {
if _, err := pool.Exec(ctx, `INSERT INTO billing_migration_completion_reports(id,program_id,project_id,state_version,completed_at,stabilization_ended_at,rollback_window_ended_at,credential_removed,credential_removed_at,legal_hold,source_objects_delete_at,completion_digest,authority_digest,stability_evidence_digest,completion_policy_digest) VALUES('completion_valid',$1,'project_one',4,now(),now()-interval '1 day',now(),true,now(),false,now()+interval '30 days',decode(repeat('96',32),'hex'),decode(repeat('a7',32),'hex'),decode(repeat('b7',32),'hex'),decode(repeat('c7',32),'hex'))`, created.Program.ProgramID); err != nil {
t.Fatalf("valid completion timing rejected: %v", err)
}
}
Expand Down
Loading
Loading