feat: add connection and ssh zod schemas
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
import * as z from 'zod'
|
||||||
|
|
||||||
|
export const sshConfigSchema = z.object({
|
||||||
|
host: z.string().min(1),
|
||||||
|
port: z.number().int().positive().default(22),
|
||||||
|
user: z.string().min(1),
|
||||||
|
password: z.string().optional(),
|
||||||
|
privateKey: z.string().optional(),
|
||||||
|
privateKeyPath: z.string().optional(),
|
||||||
|
passphrase: z.string().optional(),
|
||||||
|
agent: z.boolean().optional()
|
||||||
|
})
|
||||||
|
|
||||||
|
export const connectionConfigSchema = z.object({
|
||||||
|
name: z.string().regex(/^[a-zA-Z0-9_-]+$/, 'name must match [a-zA-Z0-9_-]+'),
|
||||||
|
type: z.enum(['postgres', 'mysql']),
|
||||||
|
host: z.string().min(1),
|
||||||
|
port: z.number().int().positive().optional(),
|
||||||
|
user: z.string().min(1),
|
||||||
|
password: z.string().optional(),
|
||||||
|
database: z.string().optional(),
|
||||||
|
readonly: z.boolean().default(false),
|
||||||
|
ssh: sshConfigSchema.optional()
|
||||||
|
})
|
||||||
|
|
||||||
|
export type SshConfig = z.infer<typeof sshConfigSchema>
|
||||||
|
export type ConnectionConfig = z.infer<typeof connectionConfigSchema>
|
||||||
|
|
||||||
|
export type ConnectionSource = 'env' | 'config' | 'store'
|
||||||
|
|
||||||
|
export type ResolvedConnection = {
|
||||||
|
config: ConnectionConfig
|
||||||
|
source: ConnectionSource
|
||||||
|
hash: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultPort = (type: ConnectionConfig['type']): number =>
|
||||||
|
type === 'postgres' ? 5432 : 3306
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { connectionConfigSchema, defaultPort } from '../../../src/config/types.js'
|
||||||
|
|
||||||
|
describe('connectionConfigSchema', () => {
|
||||||
|
const minimal = {
|
||||||
|
name: 'lab-pg',
|
||||||
|
type: 'postgres',
|
||||||
|
host: 'localhost',
|
||||||
|
user: 'postgres'
|
||||||
|
}
|
||||||
|
|
||||||
|
it('accepts minimal config and applies defaults', () => {
|
||||||
|
const parsed = connectionConfigSchema.parse(minimal)
|
||||||
|
expect(parsed.readonly).toBe(false)
|
||||||
|
expect(parsed.port).toBeUndefined()
|
||||||
|
expect(parsed.ssh).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accepts full config with ssh and defaults ssh port to 22', () => {
|
||||||
|
const parsed = connectionConfigSchema.parse({
|
||||||
|
...minimal,
|
||||||
|
port: 5433,
|
||||||
|
password: 'secret',
|
||||||
|
database: 'app',
|
||||||
|
readonly: true,
|
||||||
|
ssh: { host: 'bastion', user: 'root', privateKeyPath: '~/.ssh/id_ed25519' }
|
||||||
|
})
|
||||||
|
expect(parsed.ssh?.port).toBe(22)
|
||||||
|
expect(parsed.readonly).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects bad name characters', () => {
|
||||||
|
expect(() => connectionConfigSchema.parse({ ...minimal, name: 'bad name!' })).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects unknown engine type', () => {
|
||||||
|
expect(() => connectionConfigSchema.parse({ ...minimal, type: 'oracle' })).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects empty host', () => {
|
||||||
|
expect(() => connectionConfigSchema.parse({ ...minimal, host: '' })).toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('defaultPort', () => {
|
||||||
|
it('returns 5432 for postgres and 3306 for mysql', () => {
|
||||||
|
expect(defaultPort('postgres')).toBe(5432)
|
||||||
|
expect(defaultPort('mysql')).toBe(3306)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user