Compare commits

..

3 Commits

Author SHA1 Message Date
Zimeng Xiong 6fe136ae5a validate SQlite magic header 2025-11-22 21:27:34 -08:00
Zimeng Xiong 888834c8f0 Merge pull request #2 from ZimengXiong/fix-bind-mount-prisma
fix bind mount prisma, auto hydrate empty folder
2025-11-22 20:25:44 -08:00
Zimeng Xiong ae8f6d696e fix bind mount prisma, auto hydrate empty folder 2025-11-22 20:25:07 -08:00
3 changed files with 48 additions and 1 deletions
+2 -1
View File
@@ -36,8 +36,9 @@ COPY package*.json ./
# Install production dependencies only # Install production dependencies only
RUN npm ci --only=production RUN npm ci --only=production
# Copy prisma schema and migrations # Copy prisma schema and migrations for runtime and hydration template
COPY prisma ./prisma/ COPY prisma ./prisma/
COPY prisma ./prisma_template/
# Copy built application from builder # Copy built application from builder
COPY --from=builder /app/dist ./dist COPY --from=builder /app/dist ./dist
+6
View File
@@ -1,6 +1,12 @@
#!/bin/sh #!/bin/sh
set -e set -e
# Auto-hydrate prisma directory when bind-mounted volume is empty
if [ ! -f "/app/prisma/schema.prisma" ]; then
echo "Mount is empty. Hydrating /app/prisma from /app/prisma_template..."
cp -R /app/prisma_template/. /app/prisma/
fi
# Run migrations # Run migrations
npx prisma migrate deploy npx prisma migrate deploy
+40
View File
@@ -125,7 +125,47 @@ const respondWithValidationErrors = (
}); });
}; };
const validateSqliteHeader = (filePath: string): boolean => {
try {
const buffer = Buffer.alloc(16);
const fd = fs.openSync(filePath, "r");
const bytesRead = fs.readSync(fd, buffer, 0, 16, 0);
fs.closeSync(fd);
if (bytesRead < 16) {
console.warn("File too small to be a valid SQLite database");
return false;
}
// SQLite format 3 header: "SQLite format 3\0" (16 bytes)
// Hex: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00
const expectedHeader = Buffer.from([
0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61,
0x74, 0x20, 0x33, 0x00,
]);
const isValid = buffer.equals(expectedHeader);
if (!isValid) {
console.warn("Invalid SQLite file header detected", {
filePath,
header: buffer.toString("hex"),
expected: expectedHeader.toString("hex"),
});
}
return isValid;
} catch (error) {
console.error("Failed to validate SQLite header:", error);
return false;
}
};
const runIntegrityCheck = (filePath: string): boolean => { const runIntegrityCheck = (filePath: string): boolean => {
// First validate the file header to prevent RCE attacks
if (!validateSqliteHeader(filePath)) {
return false;
}
let dbInstance: Database.Database | undefined; let dbInstance: Database.Database | undefined;
try { try {
dbInstance = new Database(filePath, { dbInstance = new Database(filePath, {