or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcompartments.mdenvironment-hardening.mdindex.mdmodules.mdtools.md

assertions.mddocs/

0

# Assertion System

1

2

Enhanced assertion library with detailed error reporting, causal console integration, and rich diagnostic capabilities. The SES assertion system provides more informative error messages while protecting sensitive information from leaking through the exception path.

3

4

## Capabilities

5

6

### Core Assertion Function

7

8

The main assertion function with rich error reporting and type assertion capabilities.

9

10

```javascript { .api }

11

/**

12

* Assert that a condition is truthy with detailed error reporting

13

* @param flag - The condition to test

14

* @param details - Descriptive details about the assertion

15

* @param errConstructor - Optional error constructor to use

16

* @param options - Additional error creation options

17

*/

18

function assert(

19

flag: any,

20

details?: Details,

21

errConstructor?: GenericErrorConstructor,

22

options?: AssertMakeErrorOptions

23

): asserts flag;

24

```

25

26

**Usage Examples:**

27

28

```javascript

29

import 'ses';

30

31

lockdown();

32

33

// Basic assertion

34

assert(x > 0, 'x must be positive');

35

36

// Assertion with template literal details

37

const user = { name: 'Alice', age: 25 };

38

assert(user.age >= 18, assert.details`User ${user.name} must be adult, got age ${user.age}`);

39

40

// Assertion with custom error type

41

assert(user.name, 'User must have name', TypeError);

42

```

43

44

### Type Assertions

45

46

Specialized assertion methods for common type checking scenarios.

47

48

```javascript { .api }

49

/**

50

* Assert expected typeof result with overloaded signatures for different types

51

*/

52

interface AssertTypeof {

53

(specimen: any, typeName: 'bigint', details?: Details): asserts specimen is bigint;

54

(specimen: any, typeName: 'boolean', details?: Details): asserts specimen is boolean;

55

(specimen: any, typeName: 'function', details?: Details): asserts specimen is Function;

56

(specimen: any, typeName: 'number', details?: Details): asserts specimen is number;

57

(specimen: any, typeName: 'object', details?: Details): asserts specimen is Record<any, any> | null;

58

(specimen: any, typeName: 'string', details?: Details): asserts specimen is string;

59

(specimen: any, typeName: 'symbol', details?: Details): asserts specimen is symbol;

60

(specimen: any, typeName: 'undefined', details?: Details): asserts specimen is undefined;

61

}

62

63

/**

64

* Assert that a value is a string (shorthand for typeof)

65

* @param specimen - Value to check

66

* @param details - Optional error details

67

*/

68

function string(specimen: any, details?: Details): asserts specimen is string;

69

70

/**

71

* Assert that two values are Object.is equal

72

* @param actual - The actual value

73

* @param expected - The expected value

74

* @param details - Optional error details

75

* @param errConstructor - Optional error constructor

76

* @param options - Optional error creation options

77

*/

78

function equal<T>(

79

actual: unknown,

80

expected: T,

81

details?: Details,

82

errConstructor?: GenericErrorConstructor,

83

options?: AssertMakeErrorOptions

84

): asserts actual is T;

85

86

/**

87

* Unconditionally fail an assertion

88

* @param details - Error details

89

* @param errConstructor - Optional error constructor

90

* @param options - Optional error creation options

91

*/

92

function fail(

93

details?: Details,

94

errConstructor?: GenericErrorConstructor,

95

options?: AssertMakeErrorOptions

96

): never;

97

```

98

99

**Usage Examples:**

100

101

```javascript

102

import 'ses';

103

104

lockdown();

105

106

// Type checking

107

const value = getUserInput();

108

assert.typeof(value, 'string');

109

// Now TypeScript knows value is a string

110

111

// String assertion shorthand

112

assert.string(value, 'Input must be string');

113

114

// Equality assertion

115

const result = calculate();

116

assert.equal(result, 42, 'Calculation should return 42');

117

118

// Conditional failure

119

if (dangerousCondition) {

120

assert.fail('System is in dangerous state');

121

}

122

```

123

124

### Error Utilities

125

126

Utilities for creating, annotating, and formatting errors with enhanced diagnostic information.

127

128

```javascript { .api }

129

/**

130

* Create error objects with detailed logging

131

* @param details - Error details

132

* @param errConstructor - Optional error constructor

133

* @param options - Optional error creation options

134

* @returns Created error object

135

*/

136

function error(

137

details?: Details,

138

errConstructor?: GenericErrorConstructor,

139

options?: AssertMakeErrorOptions

140

): Error;

141

142

/**

143

* Annotate errors with additional diagnostic details

144

* @param error - Error object to annotate

145

* @param details - Additional details to attach

146

*/

147

function note(error: Error, details: Details): void;

148

```

149

150

**Usage Examples:**

151

152

```javascript

153

import 'ses';

154

155

lockdown();

156

157

// Create detailed errors

158

const createValidationError = (field, value) => {

159

return assert.error(

160

assert.details`Invalid ${field}: expected string, got ${value}`,

161

TypeError,

162

{ errorName: 'ValidationError' }

163

);

164

};

165

166

// Annotate existing errors

167

try {

168

riskyOperation();

169

} catch (originalError) {

170

assert.note(originalError, assert.details`Failed during step ${currentStep}`);

171

throw originalError;

172

}

173

```

174

175

### Template Literal Utilities

176

177

Template literal functions for creating rich, secure error messages.

178

179

```javascript { .api }

180

/**

181

* Create details tokens for error messages with safe substitution

182

* @param template - Template literal strings

183

* @param args - Substitution arguments

184

* @returns Details token for error reporting

185

*/

186

function details(template: TemplateStringsArray | string[], ...args: any): DetailsToken;

187

188

/**

189

* Create and throw errors using template literal syntax

190

* @param template - Template literal strings

191

* @param args - Substitution arguments

192

* @throws Error with formatted message

193

*/

194

function Fail(template: TemplateStringsArray | string[], ...args: any): never;

195

196

/**

197

* Quote values for safe inclusion in error messages

198

* @param payload - Value to quote

199

* @param spaces - JSON.stringify spacing option

200

* @returns Stringable payload that renders quoted

201

*/

202

function quote(payload: any, spaces?: string | number): StringablePayload;

203

204

/**

205

* Embed strings directly without quotes (use with caution)

206

* @param payload - Value to embed

207

* @param spaces - JSON.stringify spacing option

208

* @returns Stringable payload without quotes

209

*/

210

function bare(payload: any, spaces?: string | number): StringablePayload;

211

```

212

213

**Usage Examples:**

214

215

```javascript

216

import 'ses';

217

218

lockdown();

219

220

// Template literal details

221

const { details: X, quote: q } = assert;

222

223

const validateUser = (user) => {

224

user.age >= 18 || assert.fail(X`User ${user.name} must be adult, got age ${user.age}`);

225

226

// Conditional failure with Fail

227

user.email || Fail`User ${user.name} must have email address`;

228

229

// Quote sensitive values

230

const token = getSecretToken();

231

assert(isValidToken(token), X`Invalid token format: ${q(token)}`);

232

};

233

234

// Create reusable details

235

const createUserError = (user, issue) => {

236

return X`User validation failed for ${user.name}: ${issue}`;

237

};

238

```

239

240

## Configuration and Error Handling

241

242

### Error Creation Options

243

244

Options for controlling error creation behavior and metadata.

245

246

```javascript { .api }

247

interface AssertMakeErrorOptions {

248

/** Custom error name for console output identification */

249

errorName?: string;

250

251

/** Causal error that led to this error */

252

cause?: Error;

253

254

/** Array of errors for AggregateError-style reporting */

255

errors?: Error[];

256

257

/** Whether to sanitize error for security (default: true) */

258

sanitize?: boolean;

259

}

260

```

261

262

### Assert Factory Function

263

264

Factory function for creating custom assert functions with different error handling behavior.

265

266

```javascript { .api }

267

/**

268

* Create custom assert function with specific error handling

269

* @param raise - Optional function called before throwing

270

* @param unredacted - Whether to include unredacted details

271

* @returns Configured assert function

272

*/

273

type MakeAssert = (raise?: Raise, unredacted?: boolean) => Assert;

274

275

/**

276

* Function called when assertion fails, for custom termination behavior

277

* @param reason - The error that caused the assertion failure

278

*/

279

type Raise = (reason: Error) => void;

280

```

281

282

**Usage Examples:**

283

284

```javascript

285

import 'ses';

286

287

lockdown();

288

289

// Create custom assert with logging

290

const logAndAssert = assert.makeAssert((error) => {

291

console.error('Assertion failed:', error.message);

292

// Could terminate vat, process, etc.

293

});

294

295

// Use custom assert

296

logAndAssert(condition, 'This will be logged before throwing');

297

298

// Create unredacted assert for debugging

299

const debugAssert = assert.makeAssert(undefined, true);

300

debugAssert(false, debugAssert.details`Debug info: ${sensitiveData}`);

301

```

302

303

## Advanced Usage Patterns

304

305

### Secure Error Reporting

306

307

The SES assertion system provides two levels of detail for errors:

308

309

1. **Console Output**: Full, unredacted details visible to console (assumed privileged)

310

2. **Exception Path**: Redacted details that hide sensitive substitution values

311

312

```javascript

313

import 'ses';

314

315

lockdown();

316

317

const sensitiveData = { token: 'secret-abc-123', userId: 'user-456' };

318

319

try {

320

assert(false, assert.details`Authentication failed for user ${sensitiveData.userId} with token ${sensitiveData.token}`);

321

} catch (error) {

322

// Exception message is redacted: "Authentication failed for user (a string) with token (a string)"

323

console.log('Exception:', error.message);

324

325

// Console sees full details when the error is logged

326

console.error(error); // Shows actual values

327

}

328

```

329

330

### Validation Pipelines

331

332

Using assertions for data validation with detailed error reporting:

333

334

```javascript

335

import 'ses';

336

337

lockdown();

338

339

const validateUserData = (userData) => {

340

const { details: X, quote: q } = assert;

341

342

// Chain validations with descriptive errors

343

assert.typeof(userData, 'object', X`User data must be object, got ${q(userData)}`);

344

assert(userData !== null, 'User data cannot be null');

345

346

assert.string(userData.name, X`User name must be string, got ${q(userData.name)}`);

347

assert(userData.name.length > 0, X`User name cannot be empty`);

348

349

assert.typeof(userData.age, 'number', X`User age must be number, got ${q(userData.age)}`);

350

assert(userData.age >= 0, X`User age must be non-negative, got ${userData.age}`);

351

assert(userData.age < 150, X`User age must be realistic, got ${userData.age}`);

352

353

if (userData.email !== undefined) {

354

assert.string(userData.email, X`User email must be string, got ${q(userData.email)}`);

355

assert(/\S+@\S+\.\S+/.test(userData.email), X`User email must be valid format, got ${q(userData.email)}`);

356

}

357

358

return userData; // TypeScript now knows userData is properly shaped

359

};

360

361

// Usage

362

try {

363

const validUser = validateUserData({

364

name: 'Alice',

365

age: 30,

366

email: 'alice@example.com'

367

});

368

console.log('Valid user:', validUser);

369

} catch (error) {

370

console.error('Validation failed:', error.message);

371

}

372

```

373

374

### Contract-Based Programming

375

376

Using assertions for pre-conditions, post-conditions, and invariants:

377

378

```javascript

379

import 'ses';

380

381

lockdown();

382

383

class BankAccount {

384

#balance = 0;

385

386

constructor(initialBalance) {

387

assert.typeof(initialBalance, 'number', 'Initial balance must be number');

388

assert(initialBalance >= 0, assert.details`Initial balance must be non-negative, got ${initialBalance}`);

389

this.#balance = initialBalance;

390

}

391

392

deposit(amount) {

393

// Pre-condition

394

assert.typeof(amount, 'number', 'Deposit amount must be number');

395

assert(amount > 0, assert.details`Deposit amount must be positive, got ${amount}`);

396

397

const oldBalance = this.#balance;

398

this.#balance += amount;

399

400

// Post-condition

401

assert(this.#balance === oldBalance + amount, 'Balance should increase by deposit amount');

402

assert(this.#balance >= 0, 'Balance should never be negative');

403

404

return this.#balance;

405

}

406

407

withdraw(amount) {

408

// Pre-conditions

409

assert.typeof(amount, 'number', 'Withdrawal amount must be number');

410

assert(amount > 0, assert.details`Withdrawal amount must be positive, got ${amount}`);

411

assert(amount <= this.#balance, assert.details`Insufficient funds: requested ${amount}, available ${this.#balance}`);

412

413

const oldBalance = this.#balance;

414

this.#balance -= amount;

415

416

// Post-conditions

417

assert(this.#balance === oldBalance - amount, 'Balance should decrease by withdrawal amount');

418

assert(this.#balance >= 0, 'Balance should never be negative');

419

420

return this.#balance;

421

}

422

423

getBalance() {

424

// Invariant check

425

assert(this.#balance >= 0, 'Balance invariant violated');

426

return this.#balance;

427

}

428

}

429

```