426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
142 lines
5.4 KiB
TypeScript
142 lines
5.4 KiB
TypeScript
/**
|
|
* Guards the Worker plugin-sql stub against schema drift (#13406). The
|
|
* wrangler alias swaps @elizaos/plugin-sql for src/stubs/elizaos-plugin-sql.ts
|
|
* at bundle time, so cloud-shared repositories typecheck against the REAL
|
|
* schema but execute against the STUB — a drifted stub column (42703), a
|
|
* wrong/phantom table name (42P01), or a column the stub simply lacks
|
|
* (undefined drizzle ref) all surface only in the deployed Worker as 500s on
|
|
* console page loads. Three mechanical invariants close that gap:
|
|
* 1. every stub table exists upstream under the same export name,
|
|
* 2. same SQL table name, stub columns ⊆ upstream columns (renames fail),
|
|
* 3. every `<x>Table.<column>` property that cloud Worker source actually
|
|
* dereferences exists on the stub table (partial-stub gaps fail).
|
|
*/
|
|
|
|
import { describe, expect, test } from "bun:test";
|
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { join, resolve } from "node:path";
|
|
import { getTableColumns, getTableName, is } from "drizzle-orm";
|
|
import { PgTable } from "drizzle-orm/pg-core";
|
|
import * as realSchema from "../../../../plugins/plugin-sql/src/schema/index";
|
|
import * as stubSchema from "../src/stubs/elizaos-plugin-sql";
|
|
|
|
function isPgTable(value: unknown): value is PgTable {
|
|
return is(value, PgTable);
|
|
}
|
|
|
|
function tableExports(mod: Record<string, unknown>): Map<string, PgTable> {
|
|
const tables = new Map<string, PgTable>();
|
|
for (const [name, value] of Object.entries(mod)) {
|
|
if (name.endsWith("Table") && isPgTable(value)) {
|
|
tables.set(name, value);
|
|
}
|
|
}
|
|
return tables;
|
|
}
|
|
|
|
const stubTables = tableExports(stubSchema as Record<string, unknown>);
|
|
const realTables = tableExports(realSchema as Record<string, unknown>);
|
|
|
|
describe("plugin-sql Worker stub mirrors the real schema", () => {
|
|
test("stub exports at least the tables cloud-shared destructures", () => {
|
|
expect(stubTables.size).toBeGreaterThan(0);
|
|
});
|
|
|
|
for (const [exportName, stubTable] of stubTables) {
|
|
test(`${exportName}: same table name and no drifted columns`, () => {
|
|
const realTable = realTables.get(exportName);
|
|
expect(
|
|
realTable,
|
|
`stub exports ${exportName} but plugins/plugin-sql/src/schema does not — phantom table`,
|
|
).toBeDefined();
|
|
if (!realTable) return;
|
|
|
|
expect(getTableName(stubTable)).toBe(getTableName(realTable));
|
|
|
|
// Compare property-key → SQL-name pairs: a stale SQL name is the #13495
|
|
// 42703 class, and a mismatched property key means real-schema-typechecked
|
|
// repo code dereferences `undefined` in the Worker bundle.
|
|
const realColumns = getTableColumns(realTable);
|
|
for (const [key, column] of Object.entries(getTableColumns(stubTable))) {
|
|
const realColumn = realColumns[key];
|
|
expect(
|
|
realColumn,
|
|
`${exportName}.${key} is not a column of the real ${getTableName(realTable)} table — renamed or removed upstream (the #13495 drift class)`,
|
|
).toBeDefined();
|
|
expect(
|
|
realColumn?.name,
|
|
`${exportName}.${key} maps to "${column.name}" in the stub but "${realColumn?.name}" upstream`,
|
|
).toBe(column.name);
|
|
}
|
|
});
|
|
}
|
|
|
|
test("every eliza-table column referenced by Worker source exists on the stub", () => {
|
|
// Walk the source that ends up in the Worker bundle: cloud-shared src and
|
|
// this package's route tree + src (minus the stubs themselves and tests).
|
|
const apiRoot = resolve(import.meta.dir, "..");
|
|
const roots = [resolve(apiRoot, "../shared/src"), apiRoot];
|
|
const skipDirs = new Set([
|
|
"node_modules",
|
|
"__tests__",
|
|
"test",
|
|
"stubs",
|
|
"migrations",
|
|
"dist",
|
|
".turbo",
|
|
".wrangler",
|
|
]);
|
|
|
|
const files: string[] = [];
|
|
const walk = (dir: string): void => {
|
|
for (const entry of readdirSync(dir)) {
|
|
if (skipDirs.has(entry)) continue;
|
|
const full = join(dir, entry);
|
|
if (statSync(full).isDirectory()) {
|
|
walk(full);
|
|
} else if (
|
|
entry.endsWith(".ts") &&
|
|
!entry.endsWith(".test.ts") &&
|
|
!entry.endsWith(".d.ts")
|
|
) {
|
|
files.push(full);
|
|
}
|
|
}
|
|
};
|
|
for (const root of roots) walk(root);
|
|
expect(files.length).toBeGreaterThan(0);
|
|
|
|
const columnKeysByTable = new Map<string, Set<string>>();
|
|
for (const [exportName, table] of stubTables) {
|
|
columnKeysByTable.set(
|
|
exportName,
|
|
new Set(Object.keys(getTableColumns(table))),
|
|
);
|
|
}
|
|
|
|
const missing: string[] = [];
|
|
const reference = /\b(\w+Table)\.(\w+)\b/g;
|
|
for (const file of files) {
|
|
const source = readFileSync(file, "utf8");
|
|
for (const match of source.matchAll(reference)) {
|
|
const [, tableName, property] = match;
|
|
const columns = columnKeysByTable.get(tableName);
|
|
// Only tables the stub stands in for; other *Table identifiers are
|
|
// unrelated (cloud-only tables, local variables).
|
|
if (!columns) continue;
|
|
// Non-column drizzle surface (e.g. `_`, `enableRLS`) never appears in
|
|
// repo query code for these tables; a miss here means the stub lacks
|
|
// a column the bundled Worker will dereference as `undefined`.
|
|
if (!columns.has(property)) {
|
|
missing.push(`${tableName}.${property} (${file})`);
|
|
}
|
|
}
|
|
}
|
|
|
|
expect(
|
|
missing,
|
|
`Worker source dereferences eliza-table columns the stub does not declare:\n${missing.join("\n")}`,
|
|
).toEqual([]);
|
|
});
|
|
});
|