@naylence/runtime 0.3.21 → 0.4.0

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.
Files changed (85) hide show
  1. package/dist/browser/index.cjs +3144 -1307
  2. package/dist/browser/index.mjs +3116 -1301
  3. package/dist/cjs/naylence/fame/factory-manifest.js +6 -0
  4. package/dist/cjs/naylence/fame/node/node-event-listener.js +4 -0
  5. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer-factory.js +147 -0
  6. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer.js +291 -0
  7. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  8. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  9. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-definition.js +60 -0
  10. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-factory.js +35 -0
  11. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +35 -0
  12. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source.js +2 -0
  13. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy.js +2 -0
  14. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +99 -0
  15. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy.js +449 -0
  16. package/dist/cjs/naylence/fame/security/auth/policy/index.js +40 -0
  17. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +101 -0
  18. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +164 -0
  19. package/dist/cjs/naylence/fame/security/auth/policy/pattern-matcher.js +195 -0
  20. package/dist/cjs/naylence/fame/security/auth/policy/scope-matcher.js +169 -0
  21. package/dist/cjs/naylence/fame/security/auth/policy-authorizer.js +2 -0
  22. package/dist/cjs/naylence/fame/security/default-security-manager.js +94 -0
  23. package/dist/cjs/naylence/fame/security/index.js +3 -0
  24. package/dist/cjs/naylence/fame/security/node-security-profile-factory.js +3 -1
  25. package/dist/cjs/naylence/fame/sentinel/router.js +67 -1
  26. package/dist/cjs/naylence/fame/sentinel/sentinel.js +46 -2
  27. package/dist/cjs/naylence/fame/util/register-runtime-factories.js +2 -0
  28. package/dist/cjs/version.js +2 -2
  29. package/dist/esm/naylence/fame/factory-manifest.js +6 -0
  30. package/dist/esm/naylence/fame/node/node-event-listener.js +4 -0
  31. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer-factory.js +110 -0
  32. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer.js +287 -0
  33. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  34. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  35. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-definition.js +57 -0
  36. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-factory.js +31 -0
  37. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +31 -0
  38. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source.js +1 -0
  39. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy.js +1 -0
  40. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +62 -0
  41. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy.js +445 -0
  42. package/dist/esm/naylence/fame/security/auth/policy/index.js +20 -0
  43. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +64 -0
  44. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +127 -0
  45. package/dist/esm/naylence/fame/security/auth/policy/pattern-matcher.js +185 -0
  46. package/dist/esm/naylence/fame/security/auth/policy/scope-matcher.js +162 -0
  47. package/dist/esm/naylence/fame/security/auth/policy-authorizer.js +1 -0
  48. package/dist/esm/naylence/fame/security/default-security-manager.js +94 -0
  49. package/dist/esm/naylence/fame/security/index.js +3 -0
  50. package/dist/esm/naylence/fame/security/node-security-profile-factory.js +2 -0
  51. package/dist/esm/naylence/fame/sentinel/router.js +64 -0
  52. package/dist/esm/naylence/fame/sentinel/sentinel.js +47 -3
  53. package/dist/esm/naylence/fame/util/register-runtime-factories.js +2 -0
  54. package/dist/esm/version.js +2 -2
  55. package/dist/node/index.cjs +3140 -1303
  56. package/dist/node/index.mjs +3116 -1301
  57. package/dist/node/node.cjs +3191 -1338
  58. package/dist/node/node.mjs +3167 -1336
  59. package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
  60. package/dist/types/naylence/fame/node/node-event-listener.d.ts +31 -0
  61. package/dist/types/naylence/fame/security/auth/authorizer.d.ts +37 -0
  62. package/dist/types/naylence/fame/security/auth/default-policy-authorizer-factory.d.ts +55 -0
  63. package/dist/types/naylence/fame/security/auth/default-policy-authorizer.d.ts +99 -0
  64. package/dist/types/naylence/fame/security/auth/oauth2-authorizer-factory.d.ts +2 -0
  65. package/dist/types/naylence/fame/security/auth/oauth2-authorizer.d.ts +2 -0
  66. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-definition.d.ts +166 -0
  67. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-factory.d.ts +38 -0
  68. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source-factory.d.ts +38 -0
  69. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source.d.ts +20 -0
  70. package/dist/types/naylence/fame/security/auth/policy/authorization-policy.d.ts +55 -0
  71. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy-factory.d.ts +42 -0
  72. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy.d.ts +78 -0
  73. package/dist/types/naylence/fame/security/auth/policy/index.d.ts +19 -0
  74. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.d.ts +51 -0
  75. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source.d.ts +67 -0
  76. package/dist/types/naylence/fame/security/auth/policy/pattern-matcher.d.ts +84 -0
  77. package/dist/types/naylence/fame/security/auth/policy/scope-matcher.d.ts +61 -0
  78. package/dist/types/naylence/fame/security/auth/policy-authorizer.d.ts +12 -0
  79. package/dist/types/naylence/fame/security/default-security-manager.d.ts +22 -0
  80. package/dist/types/naylence/fame/security/index.d.ts +2 -0
  81. package/dist/types/naylence/fame/security/node-security-profile-factory.d.ts +1 -0
  82. package/dist/types/naylence/fame/sentinel/router.d.ts +68 -0
  83. package/dist/types/naylence/fame/sentinel/sentinel.d.ts +16 -0
  84. package/dist/types/version.d.ts +1 -1
  85. package/package.json +1 -1
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthorizationPolicySourceFactory = exports.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE = void 0;
4
+ const factory_1 = require("@naylence/factory");
5
+ /**
6
+ * Base type identifier for authorization policy source factories.
7
+ */
8
+ exports.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE = 'AuthorizationPolicySourceFactory';
9
+ /**
10
+ * Abstract factory base class for creating authorization policy sources.
11
+ *
12
+ * Implementations of this factory create specific types of policy sources
13
+ * (e.g., local file, remote store, in-memory, etc.).
14
+ */
15
+ class AuthorizationPolicySourceFactory extends factory_1.AbstractResourceFactory {
16
+ /**
17
+ * Static helper to create an authorization policy source using the factory registry.
18
+ *
19
+ * @param config - Configuration for the policy source
20
+ * @param options - Resource creation options
21
+ * @returns The created policy source, or undefined if no factory matched
22
+ */
23
+ static async createAuthorizationPolicySource(config, options = {}) {
24
+ if (config) {
25
+ const source = await (0, factory_1.createResource)(exports.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE, config, options);
26
+ if (!source) {
27
+ throw new Error('Failed to create authorization policy source from configuration');
28
+ }
29
+ return source;
30
+ }
31
+ const source = await (0, factory_1.createDefaultResource)(exports.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE, null, options);
32
+ return source ?? undefined;
33
+ }
34
+ }
35
+ exports.AuthorizationPolicySourceFactory = AuthorizationPolicySourceFactory;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ /**
3
+ * Factory for creating BasicAuthorizationPolicy instances.
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.BasicAuthorizationPolicyFactory = exports.FACTORY_META = void 0;
40
+ const authorization_policy_factory_js_1 = require("./authorization-policy-factory.js");
41
+ /**
42
+ * Lazy import for tree-shaking.
43
+ */
44
+ async function safeImportModule() {
45
+ return await Promise.resolve().then(() => __importStar(require('./basic-authorization-policy.js')));
46
+ }
47
+ function normalizeConfig(config) {
48
+ if (!config) {
49
+ throw new Error('BasicAuthorizationPolicyFactory requires a configuration with a policyDefinition');
50
+ }
51
+ const candidate = config;
52
+ // Support both camelCase and snake_case for policyDefinition
53
+ const policyDefinition = (candidate.policyDefinition ??
54
+ candidate.policy_definition);
55
+ if (!policyDefinition || typeof policyDefinition !== 'object') {
56
+ throw new Error('BasicAuthorizationPolicyConfig requires a policyDefinition object');
57
+ }
58
+ // Support both camelCase and snake_case for warnOnUnknownFields
59
+ const warnOnUnknownFields = candidate.warnOnUnknownFields ?? candidate.warn_on_unknown_fields;
60
+ if (warnOnUnknownFields !== undefined && typeof warnOnUnknownFields !== 'boolean') {
61
+ throw new Error('warnOnUnknownFields must be a boolean');
62
+ }
63
+ return {
64
+ policyDefinition,
65
+ warnOnUnknownFields: warnOnUnknownFields ?? true,
66
+ };
67
+ }
68
+ /**
69
+ * Factory metadata for registration.
70
+ */
71
+ exports.FACTORY_META = {
72
+ base: authorization_policy_factory_js_1.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE,
73
+ key: 'BasicAuthorizationPolicy',
74
+ };
75
+ /**
76
+ * Factory for creating BasicAuthorizationPolicy instances.
77
+ */
78
+ class BasicAuthorizationPolicyFactory extends authorization_policy_factory_js_1.AuthorizationPolicyFactory {
79
+ constructor() {
80
+ super(...arguments);
81
+ this.type = 'BasicAuthorizationPolicy';
82
+ }
83
+ /**
84
+ * Creates a BasicAuthorizationPolicy from the given configuration.
85
+ *
86
+ * @param config - Configuration with policyDefinition
87
+ * @returns The created authorization policy
88
+ */
89
+ async create(config) {
90
+ const normalized = normalizeConfig(config);
91
+ const { BasicAuthorizationPolicy } = await safeImportModule();
92
+ return new BasicAuthorizationPolicy({
93
+ policyDefinition: normalized.policyDefinition,
94
+ warnOnUnknownFields: normalized.warnOnUnknownFields,
95
+ });
96
+ }
97
+ }
98
+ exports.BasicAuthorizationPolicyFactory = BasicAuthorizationPolicyFactory;
99
+ exports.default = BasicAuthorizationPolicyFactory;
@@ -0,0 +1,449 @@
1
+ "use strict";
2
+ /**
3
+ * Basic authorization policy implementation.
4
+ *
5
+ * Evaluates authorization rules defined in YAML/JSON policy files.
6
+ * Uses first-match-wins semantics with glob/regex pattern matching.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.BasicAuthorizationPolicy = void 0;
10
+ const logging_js_1 = require("../../../util/logging.js");
11
+ const authorization_policy_definition_js_1 = require("./authorization-policy-definition.js");
12
+ const pattern_matcher_js_1 = require("./pattern-matcher.js");
13
+ const scope_matcher_js_1 = require("./scope-matcher.js");
14
+ const logger = (0, logging_js_1.getLogger)('naylence.fame.security.auth.policy.basic_authorization_policy');
15
+ /**
16
+ * Extracts the target address string from the envelope.
17
+ */
18
+ function extractAddress(envelope) {
19
+ const to = envelope.to;
20
+ if (!to) {
21
+ return undefined;
22
+ }
23
+ // FameAddress can be a string or object with toString()
24
+ if (typeof to === 'string') {
25
+ return to;
26
+ }
27
+ if (typeof to === 'object' && 'toString' in to) {
28
+ return to.toString();
29
+ }
30
+ return undefined;
31
+ }
32
+ /**
33
+ * Extracts granted scopes from the authorization context.
34
+ */
35
+ function extractGrantedScopes(context) {
36
+ const authContext = context?.security?.authorization;
37
+ if (!authContext) {
38
+ return [];
39
+ }
40
+ // Check grantedScopes first
41
+ if (Array.isArray(authContext.grantedScopes)) {
42
+ return authContext.grantedScopes;
43
+ }
44
+ // Fall back to claims.scope if available
45
+ const claims = authContext.claims;
46
+ if (claims) {
47
+ const scopeClaim = claims.scope ?? claims.scopes ?? claims.scp;
48
+ if (typeof scopeClaim === 'string') {
49
+ // Space-separated scopes (OAuth2 convention)
50
+ return scopeClaim.split(/\s+/).filter((s) => s.length > 0);
51
+ }
52
+ if (Array.isArray(scopeClaim)) {
53
+ return scopeClaim.filter((s) => typeof s === 'string');
54
+ }
55
+ }
56
+ return [];
57
+ }
58
+ /**
59
+ * Basic authorization policy that evaluates rules from a policy definition.
60
+ *
61
+ * Features:
62
+ * - First-match-wins rule evaluation
63
+ * - Glob and regex pattern matching for addresses
64
+ * - Scope matching with any_of/all_of/none_of operators
65
+ * - Action-based filtering (connect, send, receive)
66
+ */
67
+ class BasicAuthorizationPolicy {
68
+ constructor(options) {
69
+ const { policyDefinition, warnOnUnknownFields = true } = options;
70
+ // Validate and extract default effect
71
+ this.defaultEffect = this.validateDefaultEffect(policyDefinition.default_effect);
72
+ // Warn about unknown policy fields
73
+ if (warnOnUnknownFields) {
74
+ this.warnUnknownPolicyFields(policyDefinition);
75
+ }
76
+ // Compile rules for efficient evaluation
77
+ this.compiledRules = this.compileRules(policyDefinition.rules, warnOnUnknownFields);
78
+ logger.debug('policy_compiled', {
79
+ defaultEffect: this.defaultEffect,
80
+ ruleCount: this.compiledRules.length,
81
+ });
82
+ }
83
+ /**
84
+ * Evaluates the policy against a request with an explicitly provided action.
85
+ *
86
+ * @param _node - The node handling the request (unused in basic policy)
87
+ * @param envelope - The FAME envelope being authorized
88
+ * @param context - Optional delivery context with authorization info
89
+ * @param action - The authorization action token (required, no inference)
90
+ * @returns Authorization decision indicating allow/deny
91
+ */
92
+ async evaluateRequest(_node, envelope, context, action) {
93
+ // Action must be explicitly provided; default to wildcard if omitted
94
+ // for backward compatibility during transition
95
+ const resolvedAction = action ?? '*';
96
+ const address = extractAddress(envelope);
97
+ const grantedScopes = extractGrantedScopes(context);
98
+ const rawFrameType = envelope.frame
99
+ ?.type;
100
+ const frameTypeNormalized = typeof rawFrameType === 'string' && rawFrameType.trim().length > 0
101
+ ? rawFrameType.trim().toLowerCase()
102
+ : '';
103
+ // Extract and normalize origin type for rule matching
104
+ const rawOriginType = context?.originType;
105
+ const originTypeNormalized = typeof rawOriginType === 'string' && rawOriginType.trim().length > 0
106
+ ? rawOriginType.trim().toLowerCase()
107
+ : undefined;
108
+ const evaluationTrace = [];
109
+ // Evaluate rules in order (first match wins)
110
+ for (const rule of this.compiledRules) {
111
+ const step = {
112
+ ruleId: rule.id,
113
+ result: false,
114
+ };
115
+ // Skip rules with 'when' clause (handled by advanced policy)
116
+ if (rule.hasWhenClause) {
117
+ step.expression = 'when clause (skipped by basic policy)';
118
+ step.result = false;
119
+ evaluationTrace.push(step);
120
+ continue;
121
+ }
122
+ // Check frame type match
123
+ if (rule.frameTypes) {
124
+ if (!frameTypeNormalized) {
125
+ step.expression = 'frame_type: missing';
126
+ step.result = false;
127
+ evaluationTrace.push(step);
128
+ continue;
129
+ }
130
+ if (!rule.frameTypes.has(frameTypeNormalized)) {
131
+ step.expression = `frame_type: ${rawFrameType ?? 'unknown'} not in rule set`;
132
+ step.result = false;
133
+ evaluationTrace.push(step);
134
+ continue;
135
+ }
136
+ }
137
+ // Check origin type match (early gate for efficiency)
138
+ if (rule.originTypes) {
139
+ if (originTypeNormalized === undefined) {
140
+ step.expression = 'origin_type: missing (rule requires origin)';
141
+ step.result = false;
142
+ evaluationTrace.push(step);
143
+ continue;
144
+ }
145
+ if (!rule.originTypes.has(originTypeNormalized)) {
146
+ step.expression = `origin_type: ${rawOriginType ?? 'unknown'} not in [${Array.from(rule.originTypes).join(', ')}]`;
147
+ step.result = false;
148
+ evaluationTrace.push(step);
149
+ continue;
150
+ }
151
+ }
152
+ // Check action match
153
+ if (!rule.actions.has('*') && !rule.actions.has(resolvedAction)) {
154
+ step.expression = `action: ${resolvedAction} not in [${Array.from(rule.actions).join(', ')}]`;
155
+ step.result = false;
156
+ evaluationTrace.push(step);
157
+ continue;
158
+ }
159
+ // Check address match (any pattern in the list matches)
160
+ if (rule.addressPatterns) {
161
+ if (!address) {
162
+ step.expression = `address: pattern requires address, but none provided`;
163
+ step.result = false;
164
+ evaluationTrace.push(step);
165
+ continue;
166
+ }
167
+ const matched = rule.addressPatterns.some((p) => p.match(address));
168
+ if (!matched) {
169
+ const patterns = rule.addressPatterns.map((p) => p.source).join(', ');
170
+ step.expression = `address: none of [${patterns}] matched ${address}`;
171
+ step.result = false;
172
+ evaluationTrace.push(step);
173
+ continue;
174
+ }
175
+ }
176
+ // Check scope match
177
+ if (rule.scopeMatcher) {
178
+ if (!rule.scopeMatcher(grantedScopes)) {
179
+ step.expression = `scope: requirement not satisfied`;
180
+ step.boundValues = { grantedScopes: [...grantedScopes] };
181
+ step.result = false;
182
+ evaluationTrace.push(step);
183
+ continue;
184
+ }
185
+ }
186
+ // Rule matched
187
+ step.result = true;
188
+ step.expression = 'all conditions matched';
189
+ step.boundValues = {
190
+ action: resolvedAction,
191
+ address,
192
+ grantedScopes: [...grantedScopes],
193
+ };
194
+ evaluationTrace.push(step);
195
+ logger.debug('rule_matched', {
196
+ ruleId: rule.id,
197
+ effect: rule.effect,
198
+ action: resolvedAction,
199
+ address,
200
+ });
201
+ return {
202
+ effect: rule.effect,
203
+ reason: rule.description ?? `Matched rule: ${rule.id}`,
204
+ matchedRule: rule.id,
205
+ evaluationTrace,
206
+ };
207
+ }
208
+ // No rule matched, apply default effect
209
+ logger.debug('no_rule_matched', {
210
+ defaultEffect: this.defaultEffect,
211
+ action: resolvedAction,
212
+ address,
213
+ });
214
+ return {
215
+ effect: this.defaultEffect,
216
+ reason: `No rule matched, applying default effect: ${this.defaultEffect}`,
217
+ evaluationTrace,
218
+ };
219
+ }
220
+ validateDefaultEffect(effect) {
221
+ if (effect !== 'allow' && effect !== 'deny') {
222
+ throw new Error(`Invalid default_effect: "${String(effect)}". Must be "allow" or "deny"`);
223
+ }
224
+ return effect;
225
+ }
226
+ warnUnknownPolicyFields(definition) {
227
+ for (const key of Object.keys(definition)) {
228
+ if (!authorization_policy_definition_js_1.KNOWN_POLICY_FIELDS.has(key)) {
229
+ logger.warning('unknown_policy_field', { field: key });
230
+ }
231
+ }
232
+ }
233
+ compileRules(rules, warnOnUnknown) {
234
+ return rules.map((rule, index) => this.compileRule(rule, index, warnOnUnknown));
235
+ }
236
+ compileRule(rule, index, warnOnUnknown) {
237
+ // Generate ID if not provided
238
+ const id = rule.id ?? `rule_${index}`;
239
+ // Validate effect
240
+ if (!authorization_policy_definition_js_1.VALID_EFFECTS.includes(rule.effect)) {
241
+ throw new Error(`Invalid effect in rule "${id}": "${String(rule.effect)}". Must be "allow" or "deny"`);
242
+ }
243
+ // Validate and compile action(s)
244
+ const actions = this.compileActions(rule.action, id);
245
+ // Compile address patterns (glob-only, no regex)
246
+ const addressPatterns = this.compileAddress(rule.address, id);
247
+ // Compile frame type gating
248
+ const frameTypes = this.compileFrameTypes(rule.frame_type, id);
249
+ // Compile origin type gating
250
+ const originTypes = this.compileOriginTypes(rule.origin_type, id);
251
+ // Compile scope matcher (glob-only, no regex)
252
+ let scopeMatcher;
253
+ if (rule.scope !== undefined) {
254
+ try {
255
+ const compiled = (0, scope_matcher_js_1.compileGlobOnlyScopeRequirement)(rule.scope, id);
256
+ scopeMatcher = (scopes) => compiled.evaluate(scopes);
257
+ }
258
+ catch (error) {
259
+ throw new Error(`Invalid scope requirement in rule "${id}": ${error instanceof Error ? error.message : String(error)}`);
260
+ }
261
+ }
262
+ // Warn about unknown fields
263
+ if (warnOnUnknown) {
264
+ for (const key of Object.keys(rule)) {
265
+ if (!authorization_policy_definition_js_1.KNOWN_RULE_FIELDS.has(key)) {
266
+ logger.warning('unknown_rule_field', { ruleId: id, field: key });
267
+ }
268
+ }
269
+ }
270
+ return {
271
+ id,
272
+ description: rule.description,
273
+ effect: rule.effect,
274
+ actions,
275
+ frameTypes,
276
+ originTypes,
277
+ addressPatterns,
278
+ scopeMatcher,
279
+ hasWhenClause: typeof rule.when === 'string' && rule.when.length > 0,
280
+ };
281
+ }
282
+ /**
283
+ * Compiles action field into a Set of valid actions.
284
+ * Supports single RuleAction or array of RuleAction (implicit any-of).
285
+ */
286
+ compileActions(action, ruleId) {
287
+ // Default to wildcard if not specified
288
+ if (action === undefined) {
289
+ return new Set(['*']);
290
+ }
291
+ // Handle single action
292
+ if (typeof action === 'string') {
293
+ if (!authorization_policy_definition_js_1.VALID_ACTIONS.includes(action)) {
294
+ throw new Error(`Invalid action in rule "${ruleId}": "${action}". Must be one of: ${authorization_policy_definition_js_1.VALID_ACTIONS.join(', ')}`);
295
+ }
296
+ return new Set([action]);
297
+ }
298
+ // Handle array of actions
299
+ if (!Array.isArray(action)) {
300
+ throw new Error(`Invalid action in rule "${ruleId}": must be a string or array of strings`);
301
+ }
302
+ if (action.length === 0) {
303
+ throw new Error(`Invalid action in rule "${ruleId}": array must not be empty`);
304
+ }
305
+ const actions = new Set();
306
+ for (const a of action) {
307
+ if (typeof a !== 'string') {
308
+ throw new Error(`Invalid action in rule "${ruleId}": all values must be strings`);
309
+ }
310
+ if (!authorization_policy_definition_js_1.VALID_ACTIONS.includes(a)) {
311
+ throw new Error(`Invalid action in rule "${ruleId}": "${a}". Must be one of: ${authorization_policy_definition_js_1.VALID_ACTIONS.join(', ')}`);
312
+ }
313
+ actions.add(a);
314
+ }
315
+ return actions;
316
+ }
317
+ /**
318
+ * Compiles address field into an array of glob matchers.
319
+ * Supports single string or array of strings (implicit any-of).
320
+ * Returns undefined if not specified (no address gating).
321
+ *
322
+ * All patterns are treated as globs - `^` prefix is rejected as an error.
323
+ */
324
+ compileAddress(address, ruleId) {
325
+ if (address === undefined) {
326
+ return undefined;
327
+ }
328
+ const context = `address in rule "${ruleId}"`;
329
+ // Handle single address pattern
330
+ if (typeof address === 'string') {
331
+ const trimmed = address.trim();
332
+ if (!trimmed) {
333
+ throw new Error(`Invalid address in rule "${ruleId}": value must not be empty`);
334
+ }
335
+ try {
336
+ return [(0, pattern_matcher_js_1.compileGlobPattern)(trimmed, context)];
337
+ }
338
+ catch (error) {
339
+ throw new Error(`Invalid address in rule "${ruleId}": ${error instanceof Error ? error.message : String(error)}`);
340
+ }
341
+ }
342
+ // Handle array of address patterns
343
+ if (!Array.isArray(address)) {
344
+ throw new Error(`Invalid address in rule "${ruleId}": must be a string or array of strings`);
345
+ }
346
+ if (address.length === 0) {
347
+ throw new Error(`Invalid address in rule "${ruleId}": array must not be empty`);
348
+ }
349
+ const patterns = [];
350
+ for (const addr of address) {
351
+ if (typeof addr !== 'string') {
352
+ throw new Error(`Invalid address in rule "${ruleId}": all values must be strings`);
353
+ }
354
+ const trimmed = addr.trim();
355
+ if (!trimmed) {
356
+ throw new Error(`Invalid address in rule "${ruleId}": values must not be empty`);
357
+ }
358
+ try {
359
+ patterns.push((0, pattern_matcher_js_1.compileGlobPattern)(trimmed, context));
360
+ }
361
+ catch (error) {
362
+ throw new Error(`Invalid address in rule "${ruleId}": ${error instanceof Error ? error.message : String(error)}`);
363
+ }
364
+ }
365
+ return patterns;
366
+ }
367
+ /**
368
+ * Compiles frame_type field into a Set of normalized frame types.
369
+ * Supports single string or array of strings (implicit any-of).
370
+ * Returns undefined if not specified (no frame type gating).
371
+ */
372
+ compileFrameTypes(frameType, ruleId) {
373
+ if (frameType === undefined) {
374
+ return undefined;
375
+ }
376
+ // Handle single frame type
377
+ if (typeof frameType === 'string') {
378
+ const normalized = frameType.trim().toLowerCase();
379
+ if (!normalized) {
380
+ throw new Error(`Invalid frame_type in rule "${ruleId}": value must not be empty`);
381
+ }
382
+ return new Set([normalized]);
383
+ }
384
+ // Handle array of frame types
385
+ if (!Array.isArray(frameType)) {
386
+ throw new Error(`Invalid frame_type in rule "${ruleId}": must be a string or array of strings`);
387
+ }
388
+ if (frameType.length === 0) {
389
+ throw new Error(`Invalid frame_type in rule "${ruleId}": array must not be empty`);
390
+ }
391
+ const frameTypes = new Set();
392
+ for (const ft of frameType) {
393
+ if (typeof ft !== 'string') {
394
+ throw new Error(`Invalid frame_type in rule "${ruleId}": all values must be strings`);
395
+ }
396
+ const normalized = ft.trim().toLowerCase();
397
+ if (!normalized) {
398
+ throw new Error(`Invalid frame_type in rule "${ruleId}": values must not be empty`);
399
+ }
400
+ frameTypes.add(normalized);
401
+ }
402
+ return frameTypes;
403
+ }
404
+ /**
405
+ * Compiles origin_type field into a Set of normalized origin types.
406
+ * Supports single string or array of strings (implicit any-of).
407
+ * Returns undefined if not specified (no origin type gating).
408
+ * Valid values: 'downstream', 'upstream', 'peer', 'local' (case-insensitive).
409
+ */
410
+ compileOriginTypes(originType, ruleId) {
411
+ if (originType === undefined) {
412
+ return undefined;
413
+ }
414
+ // Handle single origin type
415
+ if (typeof originType === 'string') {
416
+ const normalized = originType.trim().toLowerCase();
417
+ if (!normalized) {
418
+ throw new Error(`Invalid origin_type in rule "${ruleId}": value must not be empty`);
419
+ }
420
+ if (!authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.includes(normalized)) {
421
+ throw new Error(`Invalid origin_type in rule "${ruleId}": "${originType}". Must be one of: ${authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.join(', ')}`);
422
+ }
423
+ return new Set([normalized]);
424
+ }
425
+ // Handle array of origin types
426
+ if (!Array.isArray(originType)) {
427
+ throw new Error(`Invalid origin_type in rule "${ruleId}": must be a string or array of strings`);
428
+ }
429
+ if (originType.length === 0) {
430
+ throw new Error(`Invalid origin_type in rule "${ruleId}": array must not be empty`);
431
+ }
432
+ const originTypes = new Set();
433
+ for (const ot of originType) {
434
+ if (typeof ot !== 'string') {
435
+ throw new Error(`Invalid origin_type in rule "${ruleId}": all values must be strings`);
436
+ }
437
+ const normalized = ot.trim().toLowerCase();
438
+ if (!normalized) {
439
+ throw new Error(`Invalid origin_type in rule "${ruleId}": values must not be empty`);
440
+ }
441
+ if (!authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.includes(normalized)) {
442
+ throw new Error(`Invalid origin_type in rule "${ruleId}": "${ot}". Must be one of: ${authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.join(', ')}`);
443
+ }
444
+ originTypes.add(normalized);
445
+ }
446
+ return originTypes;
447
+ }
448
+ }
449
+ exports.BasicAuthorizationPolicy = BasicAuthorizationPolicy;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Authorization policy module exports.
4
+ *
5
+ * This module provides interfaces and factories for pluggable authorization policies.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.BasicAuthorizationPolicyFactory = exports.BasicAuthorizationPolicy = exports.AuthorizationPolicySourceFactory = exports.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE = exports.AuthorizationPolicyFactory = exports.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE = exports.compileGlobOnlyScopeRequirement = exports.normalizeScopeRequirement = exports.compileScopeRequirement = exports.evaluateScopeRequirement = exports.assertNotRegexPattern = exports.isRegexPattern = exports.matchPattern = exports.getCompiledGlobPattern = exports.compileGlobPattern = exports.compilePattern = void 0;
9
+ const tslib_1 = require("tslib");
10
+ // Core interfaces and types
11
+ tslib_1.__exportStar(require("./authorization-policy.js"), exports);
12
+ tslib_1.__exportStar(require("./authorization-policy-source.js"), exports);
13
+ tslib_1.__exportStar(require("./authorization-policy-definition.js"), exports);
14
+ // Pattern and scope matchers
15
+ var pattern_matcher_js_1 = require("./pattern-matcher.js");
16
+ Object.defineProperty(exports, "compilePattern", { enumerable: true, get: function () { return pattern_matcher_js_1.compilePattern; } });
17
+ Object.defineProperty(exports, "compileGlobPattern", { enumerable: true, get: function () { return pattern_matcher_js_1.compileGlobPattern; } });
18
+ Object.defineProperty(exports, "getCompiledGlobPattern", { enumerable: true, get: function () { return pattern_matcher_js_1.getCompiledGlobPattern; } });
19
+ Object.defineProperty(exports, "matchPattern", { enumerable: true, get: function () { return pattern_matcher_js_1.matchPattern; } });
20
+ Object.defineProperty(exports, "isRegexPattern", { enumerable: true, get: function () { return pattern_matcher_js_1.isRegexPattern; } });
21
+ Object.defineProperty(exports, "assertNotRegexPattern", { enumerable: true, get: function () { return pattern_matcher_js_1.assertNotRegexPattern; } });
22
+ var scope_matcher_js_1 = require("./scope-matcher.js");
23
+ Object.defineProperty(exports, "evaluateScopeRequirement", { enumerable: true, get: function () { return scope_matcher_js_1.evaluateScopeRequirement; } });
24
+ Object.defineProperty(exports, "compileScopeRequirement", { enumerable: true, get: function () { return scope_matcher_js_1.compileScopeRequirement; } });
25
+ Object.defineProperty(exports, "normalizeScopeRequirement", { enumerable: true, get: function () { return scope_matcher_js_1.normalizeScopeRequirement; } });
26
+ Object.defineProperty(exports, "compileGlobOnlyScopeRequirement", { enumerable: true, get: function () { return scope_matcher_js_1.compileGlobOnlyScopeRequirement; } });
27
+ // Factory base classes
28
+ var authorization_policy_factory_js_1 = require("./authorization-policy-factory.js");
29
+ Object.defineProperty(exports, "AUTHORIZATION_POLICY_FACTORY_BASE_TYPE", { enumerable: true, get: function () { return authorization_policy_factory_js_1.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE; } });
30
+ Object.defineProperty(exports, "AuthorizationPolicyFactory", { enumerable: true, get: function () { return authorization_policy_factory_js_1.AuthorizationPolicyFactory; } });
31
+ var authorization_policy_source_factory_js_1 = require("./authorization-policy-source-factory.js");
32
+ Object.defineProperty(exports, "AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE", { enumerable: true, get: function () { return authorization_policy_source_factory_js_1.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE; } });
33
+ Object.defineProperty(exports, "AuthorizationPolicySourceFactory", { enumerable: true, get: function () { return authorization_policy_source_factory_js_1.AuthorizationPolicySourceFactory; } });
34
+ // Basic authorization policy (browser and node)
35
+ var basic_authorization_policy_js_1 = require("./basic-authorization-policy.js");
36
+ Object.defineProperty(exports, "BasicAuthorizationPolicy", { enumerable: true, get: function () { return basic_authorization_policy_js_1.BasicAuthorizationPolicy; } });
37
+ var basic_authorization_policy_factory_js_1 = require("./basic-authorization-policy-factory.js");
38
+ Object.defineProperty(exports, "BasicAuthorizationPolicyFactory", { enumerable: true, get: function () { return basic_authorization_policy_factory_js_1.BasicAuthorizationPolicyFactory; } });
39
+ // Note: LocalFileAuthorizationPolicySource and its factory are node-only
40
+ // and are registered via the factory manifest, not exported here directly.