or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

expressions.mdindex.mdsecurity.mdsql-parsing.mdutilities.md

security.mddocs/

0

# Authority and Security

1

2

Table and column access analysis with whitelist validation for security and authorization checking. This functionality helps enforce access controls and analyze SQL queries for security compliance.

3

4

## Capabilities

5

6

### Table List Extraction

7

8

Extract all tables accessed by a SQL query with operation type information.

9

10

```javascript { .api }

11

/**

12

* Extract list of tables from SQL query

13

* @param sql - SQL string to analyze

14

* @param opt - Optional configuration object

15

* @returns Array of table names with authority format

16

*/

17

tableList(sql: string, opt?: Option): string[];

18

```

19

20

**Authority Format**: `{type}::{dbName}::{tableName}`

21

22

Where:

23

- `type` is the operation type: `select`, `update`, `delete`, `insert`

24

- `dbName` is the database name (or `null` if not specified)

25

- `tableName` is the table name

26

27

**Usage Examples:**

28

29

```javascript

30

const { Parser } = require('node-sql-parser');

31

const parser = new Parser();

32

33

// Simple table access

34

const tables1 = parser.tableList('SELECT * FROM users');

35

console.log(tables1); // ["select::null::users"]

36

37

// Multiple tables with joins

38

const tables2 = parser.tableList(`

39

SELECT u.name, p.title

40

FROM users u

41

JOIN posts p ON u.id = p.user_id

42

`);

43

console.log(tables2); // ["select::null::users", "select::null::posts"]

44

45

// Database-qualified table names

46

const tables3 = parser.tableList('SELECT * FROM mydb.users');

47

console.log(tables3); // ["select::mydb::users"]

48

49

// Mixed operations

50

const tables4 = parser.tableList(`

51

UPDATE orders SET status = 'shipped'

52

WHERE user_id IN (SELECT id FROM users WHERE active = 1)

53

`);

54

console.log(tables4); // ["update::null::orders", "select::null::users"]

55

56

// Schema-qualified names (e.g., PostgreSQL)

57

const tables5 = parser.tableList('SELECT * FROM public.users', { database: 'PostgreSQL' });

58

console.log(tables5); // ["select::public::users"]

59

60

// Server.database.schema.table (TransactSQL)

61

const tables6 = parser.tableList(

62

'SELECT * FROM server1.mydb.dbo.users',

63

{ database: 'TransactSQL' }

64

);

65

console.log(tables6); // ["select::server1.mydb.dbo::users"]

66

```

67

68

### Column List Extraction

69

70

Extract all columns accessed by a SQL query with operation and table context.

71

72

```javascript { .api }

73

/**

74

* Extract list of columns from SQL query

75

* @param sql - SQL string to analyze

76

* @param opt - Optional configuration object

77

* @returns Array of column names with authority format

78

*/

79

columnList(sql: string, opt?: Option): string[];

80

```

81

82

**Authority Format**: `{type}::{tableName}::{columnName}`

83

84

Where:

85

- `type` is the operation type: `select`, `update`, `delete`, `insert`

86

- `tableName` is the table name (or `null` if not determinable)

87

- `columnName` is the column name

88

89

**Special Cases:**

90

- For `SELECT *`, `DELETE`, and `INSERT INTO table VALUES()` without specified columns, the `.*` regex pattern is used

91

92

**Usage Examples:**

93

94

```javascript

95

// Specific column access

96

const columns1 = parser.columnList('SELECT name, email FROM users');

97

console.log(columns1); // ["select::users::name", "select::users::email"]

98

99

// Qualified column names

100

const columns2 = parser.columnList('SELECT u.name, p.title FROM users u JOIN posts p ON u.id = p.user_id');

101

console.log(columns2);

102

// ["select::u::name", "select::p::title", "select::u::id", "select::p::user_id"]

103

104

// WHERE clause columns

105

const columns3 = parser.columnList('SELECT name FROM users WHERE age > 18 AND status = "active"');

106

console.log(columns3);

107

// ["select::users::name", "select::users::age", "select::users::status"]

108

109

// UPDATE operations

110

const columns4 = parser.columnList('UPDATE users SET email = "new@email.com" WHERE id = 1');

111

console.log(columns4); // ["update::users::email", "update::users::id"]

112

113

// Wildcard selections (require .* authority)

114

const columns5 = parser.columnList('SELECT * FROM users');

115

console.log(columns5); // ["select::users::.*"]

116

117

// Complex expressions

118

const columns6 = parser.columnList('SELECT COUNT(id), MAX(created_at) FROM orders GROUP BY user_id');

119

console.log(columns6);

120

// ["select::orders::id", "select::orders::created_at", "select::orders::user_id"]

121

```

122

123

### Whitelist Authorization

124

125

Check SQL queries against whitelist patterns to enforce access control policies.

126

127

```javascript { .api }

128

/**

129

* Check SQL against whitelist authority patterns

130

* @param sql - SQL string to check

131

* @param whiteList - Array of allowed patterns (regex strings)

132

* @param opt - Optional configuration object

133

* @returns Error if check fails, undefined if passes

134

* @throws Error with detailed message if unauthorized access detected

135

*/

136

whiteListCheck(sql: string, whiteList: string[], opt?: Option): Error | undefined;

137

138

type WhilteListCheckMode = "table" | "column";

139

140

interface Option {

141

database?: string;

142

type?: WhilteListCheckMode; // Default: "table"

143

}

144

```

145

146

**Usage Examples:**

147

148

```javascript

149

// Table whitelist checking (default mode)

150

const tableWhitelist = [

151

'select::(.*)::(users|posts)', // Allow SELECT on users and posts tables

152

'update::(.*)::users', // Allow UPDATE on users table

153

'insert::(.*)::posts' // Allow INSERT on posts table

154

];

155

156

try {

157

// This passes - SELECT on users is allowed

158

parser.whiteListCheck(

159

'SELECT * FROM users',

160

tableWhitelist

161

);

162

163

// This fails - DELETE is not in whitelist

164

parser.whiteListCheck(

165

'DELETE FROM users WHERE id = 1',

166

tableWhitelist

167

);

168

} catch (error) {

169

console.error('Access denied:', error.message);

170

// "authority = 'delete::null::users' is required in table whiteList to execute SQL = 'DELETE FROM users WHERE id = 1'"

171

}

172

173

// Column whitelist checking

174

const columnWhitelist = [

175

'select::users::(name|email)', // Allow SELECT on name and email columns

176

'select::users::.*', // Allow wildcard SELECT on users

177

'update::users::email' // Allow UPDATE on email column only

178

];

179

180

try {

181

// This passes - accessing allowed columns

182

parser.whiteListCheck(

183

'SELECT name, email FROM users',

184

columnWhitelist,

185

{ type: 'column' }

186

);

187

188

// This fails - password column not allowed

189

parser.whiteListCheck(

190

'SELECT name, password FROM users',

191

columnWhitelist,

192

{ type: 'column' }

193

);

194

} catch (error) {

195

console.error('Column access denied:', error.message);

196

}

197

198

// Database-specific whitelist

199

const pgWhitelist = ['select::public::(users|posts)'];

200

201

parser.whiteListCheck(

202

'SELECT * FROM public.users',

203

pgWhitelist,

204

{ database: 'PostgreSQL', type: 'table' }

205

);

206

207

// Complex whitelist patterns

208

const complexWhitelist = [

209

'^(select|insert)::(.*)::(user_.*|post_.*)$', // Allow select/insert on tables starting with user_ or post_

210

'^update::(.*)::(user_profile|user_settings)$' // Allow update only on specific user tables

211

];

212

```

213

214

### Authority Pattern Matching

215

216

Whitelist patterns use regular expressions for flexible access control:

217

218

```javascript

219

// Exact match

220

'select::null::users' // Exact table match

221

222

// Wildcard database

223

'select::(.*)::users' // Any database, users table

224

225

// Multiple tables

226

'select::(.*)::(users|posts|comments)' // Multiple specific tables

227

228

// Table pattern matching

229

'^(select|insert)::(.*)::(user_.*)$' // Tables starting with user_

230

231

// Column patterns

232

'select::users::(name|email|created_at)' // Specific columns only

233

'select::users::.*' // All columns (wildcard)

234

'^select::(.*)::(?!password).*$' // All columns except password

235

236

// Mixed patterns

237

'(select|update)::(.*)::(users|profiles)' // Multiple operations and tables

238

```

239

240

**Common Whitelist Scenarios:**

241

242

```javascript

243

// Read-only access to specific tables

244

const readOnlyWhitelist = [

245

'select::(.*)::(users|posts|comments)',

246

'select::(.*)::.*' // Allow column wildcards

247

];

248

249

// Limited user management

250

const userMgmtWhitelist = [

251

'select::(.*)::(users|user_profiles)',

252

'update::(.*)::user_profiles',

253

'insert::(.*)::user_profiles'

254

];

255

256

// Reporting access (read-only, specific columns)

257

const reportingWhitelist = [

258

'select::users::(id|name|email|created_at)',

259

'select::orders::(id|user_id|total|status|created_at)',

260

'select::products::(id|name|price|category)'

261

];

262

263

// Admin access (most operations allowed)

264

const adminWhitelist = [

265

'(select|insert|update)::(.*)::((?!sensitive_data).)*', // All except sensitive_data table

266

'select::(.*)::((?!password|ssn|credit_card).)*' // All columns except sensitive ones

267

];

268

```

269

270

## Security Best Practices

271

272

### Input Validation

273

274

Always validate SQL queries before processing:

275

276

```javascript

277

function validateAndExecute(sql, whitelist) {

278

try {

279

// First check syntax by parsing

280

const ast = parser.astify(sql);

281

282

// Then check authorization

283

parser.whiteListCheck(sql, whitelist);

284

285

// Safe to execute

286

return executeQuery(sql);

287

} catch (error) {

288

if (error.message.includes('authority')) {

289

throw new Error('Access denied: ' + error.message);

290

} else {

291

throw new Error('Invalid SQL: ' + error.message);

292

}

293

}

294

}

295

```

296

297

### Comprehensive Authority Analysis

298

299

Analyze all aspects of a query:

300

301

```javascript

302

function analyzeQuery(sql) {

303

const tables = parser.tableList(sql);

304

const columns = parser.columnList(sql);

305

const ast = parser.astify(sql);

306

307

return {

308

tables,

309

columns,

310

operations: [...new Set(tables.map(t => t.split('::')[0]))],

311

databases: [...new Set(tables.map(t => t.split('::')[1]).filter(d => d !== 'null'))],

312

ast

313

};

314

}

315

316

const analysis = analyzeQuery('UPDATE users SET email = "new@email.com" WHERE id = 1');

317

console.log(analysis);

318

// {

319

// tables: ["update::null::users"],

320

// columns: ["update::users::email", "update::users::id"],

321

// operations: ["update"],

322

// databases: [],

323

// ast: { ... }

324

// }

325

```

326

327

### Multi-Level Authorization

328

329

Implement layered security checks:

330

331

```javascript

332

function checkMultiLevelAuth(sql, userRole) {

333

const baseWhitelist = ['select::(.*)::(users|posts)']; // Basic read access

334

const adminWhitelist = [...baseWhitelist, 'update::(.*)::(.*)', 'delete::(.*)::(.*)']; // Admin access

335

336

const whitelist = userRole === 'admin' ? adminWhitelist : baseWhitelist;

337

338

// Check table access

339

parser.whiteListCheck(sql, whitelist, { type: 'table' });

340

341

// Additional column-level check for sensitive operations

342

if (sql.toLowerCase().includes('update') || sql.toLowerCase().includes('insert')) {

343

const columnWhitelist = userRole === 'admin'

344

? ['(update|insert)::(.*)::((?!password|ssn).)*']

345

: ['insert::(.*)::(name|email)'];

346

347

parser.whiteListCheck(sql, columnWhitelist, { type: 'column' });

348

}

349

}