ci: fix port 5432 collision and include read-only-prisma helper
CI / Architecture Guardrails (push) Successful in 1m37s
CI / Assistant Split Regression (push) Failing after 4m58s
CI / Typecheck (push) Failing after 5m18s
CI / Build (push) Has been skipped
CI / E2E Tests (push) Has been skipped
CI / Fresh-Linux Docker Deploy (push) Has been skipped
CI / Lint (push) Successful in 6m18s
CI / Unit Tests (push) Failing after 5m16s
CI / Release Images (push) Has been skipped
CI / Architecture Guardrails (push) Successful in 1m37s
CI / Assistant Split Regression (push) Failing after 4m58s
CI / Typecheck (push) Failing after 5m18s
CI / Build (push) Has been skipped
CI / E2E Tests (push) Has been skipped
CI / Fresh-Linux Docker Deploy (push) Has been skipped
CI / Lint (push) Successful in 6m18s
CI / Unit Tests (push) Failing after 5m16s
CI / Release Images (push) Has been skipped
- Remove host port mappings from postgres/redis services in ci.yml; QNAP runner already occupies 5432. Use service DNS names (postgres/redis) instead of localhost for DB/Redis URLs. - Track packages/api/src/lib/read-only-prisma.ts which was imported by assistant-tools.ts but never committed, breaking check:imports.
This commit is contained in:
@@ -161,8 +161,6 @@ jobs:
|
|||||||
POSTGRES_DB: capakraken_test
|
POSTGRES_DB: capakraken_test
|
||||||
POSTGRES_USER: capakraken
|
POSTGRES_USER: capakraken
|
||||||
POSTGRES_PASSWORD: capakraken_test
|
POSTGRES_PASSWORD: capakraken_test
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd="pg_isready -U capakraken -d capakraken_test"
|
--health-cmd="pg_isready -U capakraken -d capakraken_test"
|
||||||
--health-interval=10s
|
--health-interval=10s
|
||||||
@@ -170,16 +168,14 @@ jobs:
|
|||||||
--health-retries=5
|
--health-retries=5
|
||||||
redis:
|
redis:
|
||||||
image: redis:7
|
image: redis:7
|
||||||
ports:
|
|
||||||
- 6379:6379
|
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd="redis-cli ping"
|
--health-cmd="redis-cli ping"
|
||||||
--health-interval=10s
|
--health-interval=10s
|
||||||
--health-timeout=5s
|
--health-timeout=5s
|
||||||
--health-retries=5
|
--health-retries=5
|
||||||
env:
|
env:
|
||||||
DATABASE_URL: postgresql://capakraken:capakraken_test@localhost:5432/capakraken_test
|
DATABASE_URL: postgresql://capakraken:capakraken_test@postgres:5432/capakraken_test
|
||||||
REDIS_URL: redis://localhost:6379
|
REDIS_URL: redis://redis:6379
|
||||||
NEXTAUTH_URL: ${{ env.CI_AUTH_URL }}
|
NEXTAUTH_URL: ${{ env.CI_AUTH_URL }}
|
||||||
AUTH_URL: ${{ env.CI_AUTH_URL }}
|
AUTH_URL: ${{ env.CI_AUTH_URL }}
|
||||||
NEXTAUTH_SECRET: ${{ env.CI_AUTH_SECRET }}
|
NEXTAUTH_SECRET: ${{ env.CI_AUTH_SECRET }}
|
||||||
@@ -286,8 +282,6 @@ jobs:
|
|||||||
POSTGRES_DB: capakraken_test
|
POSTGRES_DB: capakraken_test
|
||||||
POSTGRES_USER: capakraken
|
POSTGRES_USER: capakraken
|
||||||
POSTGRES_PASSWORD: capakraken_test
|
POSTGRES_PASSWORD: capakraken_test
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd="pg_isready -U capakraken -d capakraken_test"
|
--health-cmd="pg_isready -U capakraken -d capakraken_test"
|
||||||
--health-interval=10s
|
--health-interval=10s
|
||||||
@@ -295,18 +289,16 @@ jobs:
|
|||||||
--health-retries=5
|
--health-retries=5
|
||||||
redis:
|
redis:
|
||||||
image: redis:7
|
image: redis:7
|
||||||
ports:
|
|
||||||
- 6379:6379
|
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd="redis-cli ping"
|
--health-cmd="redis-cli ping"
|
||||||
--health-interval=10s
|
--health-interval=10s
|
||||||
--health-timeout=5s
|
--health-timeout=5s
|
||||||
--health-retries=5
|
--health-retries=5
|
||||||
env:
|
env:
|
||||||
DATABASE_URL: postgresql://capakraken:capakraken_test@localhost:5432/capakraken_test
|
DATABASE_URL: postgresql://capakraken:capakraken_test@postgres:5432/capakraken_test
|
||||||
ALLOW_DESTRUCTIVE_DB_TOOLS: "true"
|
ALLOW_DESTRUCTIVE_DB_TOOLS: "true"
|
||||||
CONFIRM_DESTRUCTIVE_DB_NAME: capakraken_test
|
CONFIRM_DESTRUCTIVE_DB_NAME: capakraken_test
|
||||||
REDIS_URL: redis://localhost:6379
|
REDIS_URL: redis://redis:6379
|
||||||
PORT: 3100
|
PORT: 3100
|
||||||
NEXTAUTH_URL: ${{ env.CI_AUTH_URL }}
|
NEXTAUTH_URL: ${{ env.CI_AUTH_URL }}
|
||||||
AUTH_URL: ${{ env.CI_AUTH_URL }}
|
AUTH_URL: ${{ env.CI_AUTH_URL }}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Read-only Prisma proxy.
|
||||||
|
*
|
||||||
|
* Wraps a PrismaClient and blocks write operations at the application level.
|
||||||
|
* Used to enforce read-only access for AI read-tools (EGAI 4.1.1.2 / IAAI 3.6.22).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { prisma } from "@capakraken/db";
|
||||||
|
|
||||||
|
type PrismaClient = typeof prisma;
|
||||||
|
|
||||||
|
const WRITE_METHODS = new Set([
|
||||||
|
"create",
|
||||||
|
"createMany",
|
||||||
|
"createManyAndReturn",
|
||||||
|
"update",
|
||||||
|
"updateMany",
|
||||||
|
"upsert",
|
||||||
|
"delete",
|
||||||
|
"deleteMany",
|
||||||
|
]);
|
||||||
|
|
||||||
|
function readOnlyModelProxy(model: Record<string, unknown>, modelName: string): unknown {
|
||||||
|
return new Proxy(model, {
|
||||||
|
get(target, prop) {
|
||||||
|
if (typeof prop === "string" && WRITE_METHODS.has(prop)) {
|
||||||
|
return () => {
|
||||||
|
throw new Error(
|
||||||
|
`Write operation "${prop}" on "${modelName}" not permitted on read-only context`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Reflect.get(target, prop);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createReadOnlyProxy(client: PrismaClient): PrismaClient {
|
||||||
|
return new Proxy(client, {
|
||||||
|
get(target, prop) {
|
||||||
|
const value = Reflect.get(target, prop);
|
||||||
|
// If accessing a model delegate (object with findMany, etc.), wrap it
|
||||||
|
if (value && typeof value === "object" && "findMany" in (value as Record<string, unknown>)) {
|
||||||
|
return readOnlyModelProxy(value as Record<string, unknown>, String(prop));
|
||||||
|
}
|
||||||
|
// Block $executeRaw and $executeRawUnsafe at the client level
|
||||||
|
if (prop === "$executeRaw" || prop === "$executeRawUnsafe") {
|
||||||
|
return () => {
|
||||||
|
throw new Error(
|
||||||
|
`Raw write operation "${String(prop)}" not permitted on read-only context`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
}) as PrismaClient;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user