@ontrails/permits 1.0.0-beta.15 → 1.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/README.md +30 -22
- package/package.json +12 -3
- package/src/adapters/adapter.ts +41 -0
- package/src/{connectors → adapters}/jwt.ts +148 -21
- package/src/auth-resource.ts +81 -18
- package/src/boundary.ts +200 -0
- package/src/errors.ts +1 -18
- package/src/extraction.ts +22 -16
- package/src/index.ts +22 -10
- package/src/trails/auth-verify.ts +11 -13
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/dist/auth-layer.d.ts +0 -18
- package/dist/auth-layer.d.ts.map +0 -1
- package/dist/auth-layer.js +0 -56
- package/dist/auth-layer.js.map +0 -1
- package/dist/auth-resource.d.ts +0 -11
- package/dist/auth-resource.d.ts.map +0 -1
- package/dist/auth-resource.js +0 -22
- package/dist/auth-resource.js.map +0 -1
- package/dist/connectors/connector.d.ts +0 -26
- package/dist/connectors/connector.d.ts.map +0 -1
- package/dist/connectors/connector.js +0 -2
- package/dist/connectors/connector.js.map +0 -1
- package/dist/connectors/jwt.d.ts +0 -25
- package/dist/connectors/jwt.d.ts.map +0 -1
- package/dist/connectors/jwt.js +0 -148
- package/dist/connectors/jwt.js.map +0 -1
- package/dist/errors.d.ts +0 -15
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -15
- package/dist/errors.js.map +0 -1
- package/dist/extraction.d.ts +0 -20
- package/dist/extraction.d.ts.map +0 -1
- package/dist/extraction.js +0 -2
- package/dist/extraction.js.map +0 -1
- package/dist/index.d.ts +0 -11
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -11
- package/dist/index.js.map +0 -1
- package/dist/permit.d.ts +0 -26
- package/dist/permit.d.ts.map +0 -1
- package/dist/permit.js +0 -17
- package/dist/permit.js.map +0 -1
- package/dist/rules.d.ts +0 -47
- package/dist/rules.d.ts.map +0 -1
- package/dist/rules.js +0 -127
- package/dist/rules.js.map +0 -1
- package/dist/testing.d.ts +0 -20
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -22
- package/dist/testing.js.map +0 -1
- package/dist/trails/auth-verify.d.ts +0 -22
- package/dist/trails/auth-verify.d.ts.map +0 -1
- package/dist/trails/auth-verify.js +0 -85
- package/dist/trails/auth-verify.js.map +0 -1
- package/src/__tests__/auth-layer.test.ts +0 -130
- package/src/__tests__/auth-resource.test.ts +0 -62
- package/src/__tests__/auth-verify.test.ts +0 -278
- package/src/__tests__/connector.test.ts +0 -338
- package/src/__tests__/permit.test.ts +0 -122
- package/src/__tests__/rules.test.ts +0 -239
- package/src/__tests__/testing.test.ts +0 -57
- package/src/auth-layer.ts +0 -80
- package/src/connectors/connector.ts +0 -35
- package/tsconfig.json +0 -9
- package/tsconfig.tests.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
package/dist/connectors/jwt.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { Result } from '@ontrails/core';
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Helpers (defined before callers)
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
const authErr = (code, message) => Result.err({ code, message });
|
|
6
|
-
/** Base64url-decode a string to bytes. */
|
|
7
|
-
const base64urlDecode = (input) => {
|
|
8
|
-
const padded = input
|
|
9
|
-
.replaceAll('-', '+')
|
|
10
|
-
.replaceAll('_', '/')
|
|
11
|
-
.padEnd(input.length + ((4 - (input.length % 4)) % 4), '=');
|
|
12
|
-
const binary = atob(padded);
|
|
13
|
-
const bytes = new Uint8Array(binary.length);
|
|
14
|
-
for (let i = 0; i < binary.length; i += 1) {
|
|
15
|
-
bytes[i] = binary.codePointAt(i) ?? 0;
|
|
16
|
-
}
|
|
17
|
-
return bytes;
|
|
18
|
-
};
|
|
19
|
-
/** Decode a JWT payload without verifying the signature. */
|
|
20
|
-
const decodePayload = (token) => {
|
|
21
|
-
const parts = token.split('.');
|
|
22
|
-
if (parts.length !== 3) {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
const json = new TextDecoder().decode(base64urlDecode(parts[1] ?? ''));
|
|
27
|
-
return JSON.parse(json);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
/** Import a secret as an HMAC CryptoKey. */
|
|
34
|
-
const importHmacKey = (secret) => {
|
|
35
|
-
const encoder = new TextEncoder();
|
|
36
|
-
return crypto.subtle.importKey('raw', encoder.encode(secret), { hash: 'SHA-256', name: 'HMAC' }, false, ['verify']);
|
|
37
|
-
};
|
|
38
|
-
/** Verify the HMAC-SHA256 signature of a JWT. */
|
|
39
|
-
const verifyHmacSignature = (token, key) => {
|
|
40
|
-
const lastDot = token.lastIndexOf('.');
|
|
41
|
-
if (lastDot === -1) {
|
|
42
|
-
return Promise.resolve(false);
|
|
43
|
-
}
|
|
44
|
-
const data = token.slice(0, lastDot);
|
|
45
|
-
const signature = base64urlDecode(token.slice(lastDot + 1));
|
|
46
|
-
const encoder = new TextEncoder();
|
|
47
|
-
return crypto.subtle.verify('HMAC', key, signature.buffer, encoder.encode(data));
|
|
48
|
-
};
|
|
49
|
-
/** Validate standard claims (exp, iss, aud). */
|
|
50
|
-
const validateClaims = (payload, options) => {
|
|
51
|
-
if (payload.exp !== undefined &&
|
|
52
|
-
payload.exp < Math.floor(Date.now() / 1000)) {
|
|
53
|
-
return { code: 'expired_token', message: 'Token has expired' };
|
|
54
|
-
}
|
|
55
|
-
if (options.issuer && payload.iss !== options.issuer) {
|
|
56
|
-
return { code: 'invalid_token', message: 'Issuer mismatch' };
|
|
57
|
-
}
|
|
58
|
-
if (options.audience) {
|
|
59
|
-
const { aud } = payload;
|
|
60
|
-
const matches = Array.isArray(aud)
|
|
61
|
-
? aud.includes(options.audience)
|
|
62
|
-
: aud === options.audience;
|
|
63
|
-
if (!matches) {
|
|
64
|
-
return { code: 'invalid_token', message: 'Audience mismatch' };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return undefined;
|
|
68
|
-
};
|
|
69
|
-
/** Extract scopes from a payload claim (space-separated string or array). */
|
|
70
|
-
const extractScopes = (payload, claim) => {
|
|
71
|
-
const raw = payload[claim];
|
|
72
|
-
if (typeof raw === 'string') {
|
|
73
|
-
return raw.split(' ').filter(Boolean);
|
|
74
|
-
}
|
|
75
|
-
if (Array.isArray(raw)) {
|
|
76
|
-
return raw.filter((s) => typeof s === 'string' && s.length > 0);
|
|
77
|
-
}
|
|
78
|
-
return [];
|
|
79
|
-
};
|
|
80
|
-
/** Extract roles from a payload claim (string array). */
|
|
81
|
-
const extractRoles = (payload, claim) => {
|
|
82
|
-
const raw = payload[claim];
|
|
83
|
-
if (!Array.isArray(raw)) {
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
return raw.filter((r) => typeof r === 'string');
|
|
87
|
-
};
|
|
88
|
-
/** Build a Permit from a validated JWT payload. */
|
|
89
|
-
const buildPermit = (payload, options) => {
|
|
90
|
-
if (!payload.sub) {
|
|
91
|
-
return authErr('invalid_token', 'Missing subject claim (sub)');
|
|
92
|
-
}
|
|
93
|
-
const roles = extractRoles(payload, options.rolesClaim ?? 'roles');
|
|
94
|
-
return Result.ok({
|
|
95
|
-
id: payload.sub,
|
|
96
|
-
scopes: extractScopes(payload, options.scopesClaim ?? 'scope'),
|
|
97
|
-
...(roles ? { roles } : {}),
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
/** Verify the signature and return the decoded payload, or an error. */
|
|
101
|
-
const decodeAndVerify = async (token, secret) => {
|
|
102
|
-
const payload = decodePayload(token);
|
|
103
|
-
if (!payload) {
|
|
104
|
-
return authErr('invalid_token', 'Malformed JWT');
|
|
105
|
-
}
|
|
106
|
-
try {
|
|
107
|
-
const key = await importHmacKey(secret);
|
|
108
|
-
const valid = await verifyHmacSignature(token, key);
|
|
109
|
-
return valid
|
|
110
|
-
? Result.ok(payload)
|
|
111
|
-
: authErr('invalid_token', 'Invalid signature');
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
return authErr('invalid_token', 'Malformed token signature');
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
/** Validate claims and build a permit from a verified payload. */
|
|
118
|
-
const payloadToPermit = (payload, options) => {
|
|
119
|
-
const claimError = validateClaims(payload, options);
|
|
120
|
-
if (claimError) {
|
|
121
|
-
return Result.err(claimError);
|
|
122
|
-
}
|
|
123
|
-
return buildPermit(payload, options);
|
|
124
|
-
};
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
// Factory
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
/**
|
|
129
|
-
* Create a JWT auth connector using Bun's native crypto.
|
|
130
|
-
*
|
|
131
|
-
* Verifies HS256-signed JWTs, extracts claims into a Permit, and checks
|
|
132
|
-
* issuer/audience when configured. Returns `Result.ok(null)` when no
|
|
133
|
-
* credentials are provided.
|
|
134
|
-
*/
|
|
135
|
-
export const createJwtConnector = (options) => {
|
|
136
|
-
const authenticate = async (input) => {
|
|
137
|
-
if (!input.bearerToken) {
|
|
138
|
-
return Result.ok(null);
|
|
139
|
-
}
|
|
140
|
-
if (!options.secret) {
|
|
141
|
-
return authErr('invalid_token', 'No secret configured');
|
|
142
|
-
}
|
|
143
|
-
const decoded = await decodeAndVerify(input.bearerToken, options.secret);
|
|
144
|
-
return decoded.isErr() ? decoded : payloadToPermit(decoded.value, options);
|
|
145
|
-
};
|
|
146
|
-
return { authenticate };
|
|
147
|
-
};
|
|
148
|
-
//# sourceMappingURL=jwt.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/connectors/jwt.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { PermissionError } from '@ontrails/core';
|
|
2
|
-
/**
|
|
3
|
-
* Error returned when permit scope enforcement fails.
|
|
4
|
-
*
|
|
5
|
-
* Extends `PermissionError` (category `'permission'`, HTTP 403) because
|
|
6
|
-
* it represents an *authorization* failure — the caller's identity is known
|
|
7
|
-
* but lacks the required scopes.
|
|
8
|
-
*/
|
|
9
|
-
export declare class PermitError extends PermissionError {
|
|
10
|
-
constructor(message: string, options?: {
|
|
11
|
-
cause?: Error;
|
|
12
|
-
context?: Record<string, unknown>;
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;GAMG;AACH,qBAAa,WAAY,SAAQ,eAAe;gBAE5C,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE;CAKjE"}
|
package/dist/errors.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { PermissionError } from '@ontrails/core';
|
|
2
|
-
/**
|
|
3
|
-
* Error returned when permit scope enforcement fails.
|
|
4
|
-
*
|
|
5
|
-
* Extends `PermissionError` (category `'permission'`, HTTP 403) because
|
|
6
|
-
* it represents an *authorization* failure — the caller's identity is known
|
|
7
|
-
* but lacks the required scopes.
|
|
8
|
-
*/
|
|
9
|
-
export class PermitError extends PermissionError {
|
|
10
|
-
constructor(message, options) {
|
|
11
|
-
super(message, options);
|
|
12
|
-
this.name = 'PermitError';
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,OAAO,WAAY,SAAQ,eAAe;IAC9C,YACE,OAAe,EACf,OAA8D;QAE9D,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
|
package/dist/extraction.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Normalized input for auth connectors.
|
|
3
|
-
*
|
|
4
|
-
* Each trailhead extracts raw credentials from its transport and normalizes
|
|
5
|
-
* them into this shape. No trailhead types (Request, McpSession, etc.) cross
|
|
6
|
-
* into core — only this interface.
|
|
7
|
-
*/
|
|
8
|
-
export interface PermitExtractionInput {
|
|
9
|
-
/** Which trailhead produced this extraction */
|
|
10
|
-
readonly trailhead: 'http' | 'mcp' | 'cli';
|
|
11
|
-
/** Bearer token from Authorization header or equivalent */
|
|
12
|
-
readonly bearerToken?: string;
|
|
13
|
-
/** Session identifier from transport handshake */
|
|
14
|
-
readonly sessionId?: string;
|
|
15
|
-
/** Raw headers (HTTP trailhead only, typically) */
|
|
16
|
-
readonly headers?: Headers;
|
|
17
|
-
/** Correlation ID for tracing */
|
|
18
|
-
readonly requestId: string;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=extraction.d.ts.map
|
package/dist/extraction.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAC3C,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B"}
|
package/dist/extraction.js
DELETED
package/dist/extraction.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.js","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { type AuthConnector, type AuthCredentials, type AuthError, } from './connectors/connector.js';
|
|
2
|
-
export { createJwtConnector, type JwtConnectorOptions, } from './connectors/jwt.js';
|
|
3
|
-
export { authLayer } from './auth-layer.js';
|
|
4
|
-
export { authResource } from './auth-resource.js';
|
|
5
|
-
export { authVerify } from './trails/auth-verify.js';
|
|
6
|
-
export { PermitError } from './errors.js';
|
|
7
|
-
export { type PermitExtractionInput } from './extraction.js';
|
|
8
|
-
export { type Permit, getPermit } from './permit.js';
|
|
9
|
-
export { validatePermits, type PermitDiagnostic } from './rules.js';
|
|
10
|
-
export { createTestPermit, createPermitForTrail } from './testing.js';
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,kBAAkB,EAClB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export {} from './connectors/connector.js';
|
|
2
|
-
export { createJwtConnector, } from './connectors/jwt.js';
|
|
3
|
-
export { authLayer } from './auth-layer.js';
|
|
4
|
-
export { authResource } from './auth-resource.js';
|
|
5
|
-
export { authVerify } from './trails/auth-verify.js';
|
|
6
|
-
export { PermitError } from './errors.js';
|
|
7
|
-
export {} from './extraction.js';
|
|
8
|
-
export { getPermit } from './permit.js';
|
|
9
|
-
export { validatePermits } from './rules.js';
|
|
10
|
-
export { createTestPermit, createPermitForTrail } from './testing.js';
|
|
11
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAA8B,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAe,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,eAAe,EAAyB,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/permit.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { BasePermit } from '@ontrails/core';
|
|
2
|
-
/** The resolved identity and scopes from a successful authentication. */
|
|
3
|
-
export interface Permit extends BasePermit {
|
|
4
|
-
readonly roles?: readonly string[];
|
|
5
|
-
readonly tenantId?: string;
|
|
6
|
-
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Type-safe accessor for `ctx.permit` with a downcast to `Permit`.
|
|
10
|
-
*
|
|
11
|
-
* `TrailContext.permit` is typed as `BasePermit` (id + scopes). This accessor
|
|
12
|
-
* returns the full `Permit` when the auth layer has set one. Safe because
|
|
13
|
-
* the auth layer is the only writer and always sets a full `Permit`.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* const permit = getPermit(ctx);
|
|
18
|
-
* if (permit) {
|
|
19
|
-
* console.log(permit.roles, permit.tenantId);
|
|
20
|
-
* }
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export declare const getPermit: (ctx: {
|
|
24
|
-
permit?: BasePermit;
|
|
25
|
-
}) => Permit | undefined;
|
|
26
|
-
//# sourceMappingURL=permit.d.ts.map
|
package/dist/permit.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"permit.d.ts","sourceRoot":"","sources":["../src/permit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,yEAAyE;AACzE,MAAM,WAAW,MAAO,SAAQ,UAAU;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,SAAS,GAAI,KAAK;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,KAAG,MAAM,GAAG,SACH,CAAC"}
|
package/dist/permit.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-safe accessor for `ctx.permit` with a downcast to `Permit`.
|
|
3
|
-
*
|
|
4
|
-
* `TrailContext.permit` is typed as `BasePermit` (id + scopes). This accessor
|
|
5
|
-
* returns the full `Permit` when the auth layer has set one. Safe because
|
|
6
|
-
* the auth layer is the only writer and always sets a full `Permit`.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* const permit = getPermit(ctx);
|
|
11
|
-
* if (permit) {
|
|
12
|
-
* console.log(permit.roles, permit.tenantId);
|
|
13
|
-
* }
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
export const getPermit = (ctx) => ctx.permit === undefined ? undefined : ctx.permit;
|
|
17
|
-
//# sourceMappingURL=permit.js.map
|
package/dist/permit.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"permit.js","sourceRoot":"","sources":["../src/permit.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAA4B,EAAsB,EAAE,CAC5E,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,MAAiB,CAAC"}
|
package/dist/rules.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { Trail } from '@ontrails/core';
|
|
2
|
-
/** A single governance finding from a permit rule. */
|
|
3
|
-
export interface PermitDiagnostic {
|
|
4
|
-
readonly trailId: string;
|
|
5
|
-
readonly rule: string;
|
|
6
|
-
readonly severity: 'error' | 'warning';
|
|
7
|
-
readonly message: string;
|
|
8
|
-
}
|
|
9
|
-
type AnyTrail = Trail<unknown, unknown, unknown>;
|
|
10
|
-
type Rule = (trails: readonly AnyTrail[]) => readonly PermitDiagnostic[];
|
|
11
|
-
/**
|
|
12
|
-
* Destructive trails without a real permit declaration are a governance failure.
|
|
13
|
-
*
|
|
14
|
-
* Reports an error for every trail with `intent: 'destroy'` that has no
|
|
15
|
-
* `permit` field or explicitly opts out with `permit: 'public'`.
|
|
16
|
-
*/
|
|
17
|
-
export declare const destroyWithoutPermit: Rule;
|
|
18
|
-
/**
|
|
19
|
-
* Write trails without a permit declaration get a warning.
|
|
20
|
-
*
|
|
21
|
-
* Trails with `intent: 'write'` (or no intent, which defaults to write) that
|
|
22
|
-
* lack a permit are flagged unless `permit: 'public'` is explicitly set.
|
|
23
|
-
*/
|
|
24
|
-
export declare const writeWithoutPermit: Rule;
|
|
25
|
-
/**
|
|
26
|
-
* Warns for scopes that don't follow the `entity:action` convention.
|
|
27
|
-
*
|
|
28
|
-
* A valid scope contains exactly one colon separating a non-empty entity
|
|
29
|
-
* and a non-empty action.
|
|
30
|
-
*/
|
|
31
|
-
export declare const scopeNamingConsistency: Rule;
|
|
32
|
-
/**
|
|
33
|
-
* Warns for scopes that appear in only one trail's permit.
|
|
34
|
-
*
|
|
35
|
-
* Catches typos like `user:wirte` by surfacing scopes not shared with any
|
|
36
|
-
* other trail. Only runs when at least 2 trails have permit declarations.
|
|
37
|
-
*/
|
|
38
|
-
export declare const orphanScopeDetection: Rule;
|
|
39
|
-
/**
|
|
40
|
-
* Run all permit governance rules against a set of trails.
|
|
41
|
-
*
|
|
42
|
-
* Returns a flat array of diagnostics from every rule. An empty array
|
|
43
|
-
* means the topo passes all permit governance checks.
|
|
44
|
-
*/
|
|
45
|
-
export declare const validatePermits: (trails: readonly Trail<unknown, unknown, unknown>[]) => readonly PermitDiagnostic[];
|
|
46
|
-
export {};
|
|
47
|
-
//# sourceMappingURL=rules.d.ts.map
|
package/dist/rules.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAM5C,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAMD,KAAK,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACjD,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,KAAK,SAAS,gBAAgB,EAAE,CAAC;AAiBzE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,IAU5B,CAAC;AAMR;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,IAU1B,CAAC;AAgBR;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,IAUlC,CAAC;AA2CJ;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,IAMlC,CAAC;AAaF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,SAAS,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,KAClD,SAAS,gBAAgB,EAA8C,CAAC"}
|
package/dist/rules.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/** Check whether a trail has any permit declaration (scopes object or 'public'). */
|
|
2
|
-
const hasPermit = (t) => t.permit !== undefined;
|
|
3
|
-
/** Extract scopes from a trail's permit declaration, or empty array. */
|
|
4
|
-
const getScopes = (t) => {
|
|
5
|
-
if (t.permit !== undefined && t.permit !== 'public') {
|
|
6
|
-
return t.permit.scopes;
|
|
7
|
-
}
|
|
8
|
-
return [];
|
|
9
|
-
};
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// Rule: destroyWithoutPermit
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
/**
|
|
14
|
-
* Destructive trails without a real permit declaration are a governance failure.
|
|
15
|
-
*
|
|
16
|
-
* Reports an error for every trail with `intent: 'destroy'` that has no
|
|
17
|
-
* `permit` field or explicitly opts out with `permit: 'public'`.
|
|
18
|
-
*/
|
|
19
|
-
export const destroyWithoutPermit = (trails) => trails
|
|
20
|
-
.filter((t) => t.intent === 'destroy' && (!hasPermit(t) || t.permit === 'public'))
|
|
21
|
-
.map((t) => ({
|
|
22
|
-
message: `Trail "${t.id}" has intent 'destroy' but no permit declaration`,
|
|
23
|
-
rule: 'destroyWithoutPermit',
|
|
24
|
-
severity: 'error',
|
|
25
|
-
trailId: t.id,
|
|
26
|
-
}));
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// Rule: writeWithoutPermit
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
/**
|
|
31
|
-
* Write trails without a permit declaration get a warning.
|
|
32
|
-
*
|
|
33
|
-
* Trails with `intent: 'write'` (or no intent, which defaults to write) that
|
|
34
|
-
* lack a permit are flagged unless `permit: 'public'` is explicitly set.
|
|
35
|
-
*/
|
|
36
|
-
export const writeWithoutPermit = (trails) => trails
|
|
37
|
-
.filter((t) => (t.intent === 'write' || t.intent === undefined) && !hasPermit(t))
|
|
38
|
-
.map((t) => ({
|
|
39
|
-
message: `Trail "${t.id}" has write intent but no permit declaration`,
|
|
40
|
-
rule: 'writeWithoutPermit',
|
|
41
|
-
severity: 'warning',
|
|
42
|
-
trailId: t.id,
|
|
43
|
-
}));
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Rule: scopeNamingConsistency
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
/** Returns true when a scope follows the `entity:action` convention. */
|
|
48
|
-
const isValidScopeFormat = (scope) => {
|
|
49
|
-
const parts = scope.split(':');
|
|
50
|
-
return (parts.length === 2 &&
|
|
51
|
-
(parts[0]?.length ?? 0) > 0 &&
|
|
52
|
-
(parts[1]?.length ?? 0) > 0);
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Warns for scopes that don't follow the `entity:action` convention.
|
|
56
|
-
*
|
|
57
|
-
* A valid scope contains exactly one colon separating a non-empty entity
|
|
58
|
-
* and a non-empty action.
|
|
59
|
-
*/
|
|
60
|
-
export const scopeNamingConsistency = (trails) => trails.flatMap((t) => getScopes(t)
|
|
61
|
-
.filter((scope) => !isValidScopeFormat(scope))
|
|
62
|
-
.map((scope) => ({
|
|
63
|
-
message: `Scope "${scope}" on trail "${t.id}" does not follow entity:action convention`,
|
|
64
|
-
rule: 'scopeNamingConsistency',
|
|
65
|
-
severity: 'warning',
|
|
66
|
-
trailId: t.id,
|
|
67
|
-
})));
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
// Rule: orphanScopeDetection
|
|
70
|
-
// ---------------------------------------------------------------------------
|
|
71
|
-
/** Build a map of scope -> set of trail IDs that declare it. */
|
|
72
|
-
const buildScopeMap = (trails) => {
|
|
73
|
-
const map = new Map();
|
|
74
|
-
for (const t of trails) {
|
|
75
|
-
for (const scope of getScopes(t)) {
|
|
76
|
-
const existing = map.get(scope);
|
|
77
|
-
if (existing) {
|
|
78
|
-
existing.add(t.id);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
map.set(scope, new Set([t.id]));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return map;
|
|
86
|
-
};
|
|
87
|
-
/** Filter trails that have a scoped (non-public) permit declaration. */
|
|
88
|
-
const trailsWithScopedPermit = (trails) => trails.filter((t) => t.permit !== undefined && t.permit !== 'public');
|
|
89
|
-
/** Convert orphan scope map entries into diagnostics. */
|
|
90
|
-
const orphanDiagnostics = (scopeMap) => [...scopeMap.entries()]
|
|
91
|
-
.filter(([, ids]) => ids.size === 1)
|
|
92
|
-
.map(([scope, ids]) => ({
|
|
93
|
-
message: `Scope "${scope}" appears only on trail "${[...ids][0]}" — possible typo`,
|
|
94
|
-
rule: 'orphanScopeDetection',
|
|
95
|
-
severity: 'warning',
|
|
96
|
-
trailId: [...ids][0] ?? '',
|
|
97
|
-
}));
|
|
98
|
-
/**
|
|
99
|
-
* Warns for scopes that appear in only one trail's permit.
|
|
100
|
-
*
|
|
101
|
-
* Catches typos like `user:wirte` by surfacing scopes not shared with any
|
|
102
|
-
* other trail. Only runs when at least 2 trails have permit declarations.
|
|
103
|
-
*/
|
|
104
|
-
export const orphanScopeDetection = (trails) => {
|
|
105
|
-
const scoped = trailsWithScopedPermit(trails);
|
|
106
|
-
if (scoped.length < 2) {
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
return orphanDiagnostics(buildScopeMap(scoped));
|
|
110
|
-
};
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
// Top-level validator
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
|
-
const allRules = [
|
|
115
|
-
destroyWithoutPermit,
|
|
116
|
-
writeWithoutPermit,
|
|
117
|
-
scopeNamingConsistency,
|
|
118
|
-
orphanScopeDetection,
|
|
119
|
-
];
|
|
120
|
-
/**
|
|
121
|
-
* Run all permit governance rules against a set of trails.
|
|
122
|
-
*
|
|
123
|
-
* Returns a flat array of diagnostics from every rule. An empty array
|
|
124
|
-
* means the topo passes all permit governance checks.
|
|
125
|
-
*/
|
|
126
|
-
export const validatePermits = (trails) => allRules.flatMap((rule) => rule(trails));
|
|
127
|
-
//# sourceMappingURL=rules.js.map
|
package/dist/rules.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
|
package/dist/testing.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { PermitRequirement } from '@ontrails/core';
|
|
2
|
-
import type { Permit } from './permit.js';
|
|
3
|
-
/**
|
|
4
|
-
* Create a synthetic test permit with exactly the declared scopes.
|
|
5
|
-
* No admin permit, no wildcard — tests get only what the trail declares.
|
|
6
|
-
*/
|
|
7
|
-
export declare const createTestPermit: (options?: {
|
|
8
|
-
readonly id?: string;
|
|
9
|
-
readonly scopes?: readonly string[];
|
|
10
|
-
readonly roles?: readonly string[];
|
|
11
|
-
readonly tenantId?: string;
|
|
12
|
-
}) => Permit;
|
|
13
|
-
/**
|
|
14
|
-
* Create a test permit matching a trail's permit requirement.
|
|
15
|
-
* Extracts scopes from the requirement and creates a permit with exactly those scopes.
|
|
16
|
-
*/
|
|
17
|
-
export declare const createPermitForTrail: (trail: {
|
|
18
|
-
readonly permit?: PermitRequirement | undefined;
|
|
19
|
-
}) => Permit | undefined;
|
|
20
|
-
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU;IACzC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,KAAG,MAOF,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACjD,KAAG,MAAM,GAAG,SAKZ,CAAC"}
|
package/dist/testing.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Create a synthetic test permit with exactly the declared scopes.
|
|
3
|
-
* No admin permit, no wildcard — tests get only what the trail declares.
|
|
4
|
-
*/
|
|
5
|
-
export const createTestPermit = (options) => ({
|
|
6
|
-
id: options?.id ??
|
|
7
|
-
`test-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
8
|
-
scopes: [...(options?.scopes ?? [])],
|
|
9
|
-
...(options?.roles === undefined ? {} : { roles: [...options.roles] }),
|
|
10
|
-
...(options?.tenantId === undefined ? {} : { tenantId: options.tenantId }),
|
|
11
|
-
});
|
|
12
|
-
/**
|
|
13
|
-
* Create a test permit matching a trail's permit requirement.
|
|
14
|
-
* Extracts scopes from the requirement and creates a permit with exactly those scopes.
|
|
15
|
-
*/
|
|
16
|
-
export const createPermitForTrail = (trail) => {
|
|
17
|
-
if (!trail.permit || trail.permit === 'public') {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
return createTestPermit({ scopes: trail.permit.scopes });
|
|
21
|
-
};
|
|
22
|
-
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAKhC,EAAU,EAAE,CAAC,CAAC;IACb,EAAE,EACA,OAAO,EAAE,EAAE;QACX,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;IAChE,MAAM,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;IACpC,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACtE,GAAG,CAAC,OAAO,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;CAC3E,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAEpC,EAAsB,EAAE;IACvB,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/C,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,gBAAgB,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Infrastructure trail that verifies a bearer token and returns the resolved permit.
|
|
3
|
-
*
|
|
4
|
-
* Reads the auth connector from `authResource` — the connector is configured
|
|
5
|
-
* at bootstrap (e.g. JWT with HMAC secret). The mock connector always
|
|
6
|
-
* succeeds with a null permit, so `testAll(app)` works without configuration.
|
|
7
|
-
*/
|
|
8
|
-
export declare const authVerify: import("@ontrails/core").Trail<{
|
|
9
|
-
token: string;
|
|
10
|
-
}, {
|
|
11
|
-
valid: boolean;
|
|
12
|
-
error?: string | undefined;
|
|
13
|
-
errorCode?: "expired_token" | "insufficient_scope" | "invalid_token" | "missing_credentials" | undefined;
|
|
14
|
-
permit?: {
|
|
15
|
-
id: string;
|
|
16
|
-
scopes: string[];
|
|
17
|
-
metadata?: Record<string, unknown> | undefined;
|
|
18
|
-
roles?: string[] | undefined;
|
|
19
|
-
tenantId?: string | undefined;
|
|
20
|
-
} | undefined;
|
|
21
|
-
}, never>;
|
|
22
|
-
//# sourceMappingURL=auth-verify.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth-verify.d.ts","sourceRoot":"","sources":["../../src/trails/auth-verify.ts"],"names":[],"mappings":"AA4CA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;SAiDrB,CAAC"}
|