@aigrc/core 0.1.0 → 0.2.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.
- package/dist/air/index.d.mts +1669 -0
- package/dist/air/index.d.ts +1669 -0
- package/dist/air/index.js +450 -0
- package/dist/air/index.js.map +1 -0
- package/dist/air/index.mjs +410 -0
- package/dist/air/index.mjs.map +1 -0
- package/dist/governance-lock/index.d.mts +903 -0
- package/dist/governance-lock/index.d.ts +903 -0
- package/dist/governance-lock/index.js +444 -0
- package/dist/governance-lock/index.js.map +1 -0
- package/dist/governance-lock/index.mjs +389 -0
- package/dist/governance-lock/index.mjs.map +1 -0
- package/dist/index.d.mts +467 -4
- package/dist/index.d.ts +467 -4
- package/dist/index.js +2213 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2114 -2
- package/dist/index.mjs.map +1 -1
- package/dist/schemas/index.d.mts +1950 -29
- package/dist/schemas/index.d.ts +1950 -29
- package/dist/schemas/index.js +354 -1
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/index.mjs +332 -1
- package/dist/schemas/index.mjs.map +1 -1
- package/package.json +11 -1
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
6
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
7
|
+
}) : x)(function(x) {
|
|
8
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
9
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
10
|
+
});
|
|
5
11
|
var __esm = (fn, res) => function __init() {
|
|
6
12
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
13
|
};
|
|
@@ -1072,6 +1078,311 @@ var ConstraintsSchema = z.object({
|
|
|
1072
1078
|
logToolInvocations: z.boolean().default(true)
|
|
1073
1079
|
}).optional()
|
|
1074
1080
|
});
|
|
1081
|
+
var RiskLevelSchema = z.enum(["minimal", "limited", "high", "unacceptable"]);
|
|
1082
|
+
var GoldenThreadSchema = z.object({
|
|
1083
|
+
/** Ticket ID from approval system (e.g., "FIN-1234") */
|
|
1084
|
+
ticket_id: z.string().min(1),
|
|
1085
|
+
/** Email of approver (e.g., "ciso@corp.com") */
|
|
1086
|
+
approved_by: z.string().email(),
|
|
1087
|
+
/** ISO 8601 timestamp of approval (e.g., "2025-01-15T10:30:00Z") */
|
|
1088
|
+
approved_at: z.string().datetime(),
|
|
1089
|
+
/** SHA-256 hash of canonical string: sha256:{64 hex chars} */
|
|
1090
|
+
hash: z.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
|
|
1091
|
+
/** Optional cryptographic signature: {ALGORITHM}:{BASE64_SIGNATURE} */
|
|
1092
|
+
signature: z.string().regex(/^(RSA-SHA256|ECDSA-P256):[A-Za-z0-9+/=]+$/).optional()
|
|
1093
|
+
});
|
|
1094
|
+
var LineageSchema = z.object({
|
|
1095
|
+
/** Parent agent's instance_id, null for root agents */
|
|
1096
|
+
parent_instance_id: z.string().uuid().nullable(),
|
|
1097
|
+
/** Depth in spawn tree: 0 for root, 1 for first child, etc. */
|
|
1098
|
+
generation_depth: z.number().int().min(0),
|
|
1099
|
+
/** Chain of ancestor instance_ids from root to parent */
|
|
1100
|
+
ancestor_chain: z.array(z.string().uuid()),
|
|
1101
|
+
/** When this agent was spawned */
|
|
1102
|
+
spawned_at: z.string().datetime(),
|
|
1103
|
+
/** Root agent's instance_id for tracing entire tree */
|
|
1104
|
+
root_instance_id: z.string().uuid()
|
|
1105
|
+
});
|
|
1106
|
+
var CapabilitiesManifestSchema = z.object({
|
|
1107
|
+
/** List of allowed tool/action identifiers (supports wildcards: *, prefix_*) */
|
|
1108
|
+
allowed_tools: z.array(z.string()).default([]),
|
|
1109
|
+
/** List of explicitly denied tools (takes precedence over allowed) */
|
|
1110
|
+
denied_tools: z.array(z.string()).default([]),
|
|
1111
|
+
/** Allowed domain patterns (regex) for external resources */
|
|
1112
|
+
allowed_domains: z.array(z.string()).default([]),
|
|
1113
|
+
/** Denied domain patterns (takes precedence over allowed) */
|
|
1114
|
+
denied_domains: z.array(z.string()).default([]),
|
|
1115
|
+
/** Maximum cost per session in USD */
|
|
1116
|
+
max_cost_per_session: z.number().positive().nullable().optional(),
|
|
1117
|
+
/** Maximum cost per day in USD */
|
|
1118
|
+
max_cost_per_day: z.number().positive().nullable().optional(),
|
|
1119
|
+
/** Maximum tokens per single API call */
|
|
1120
|
+
max_tokens_per_call: z.number().int().positive().nullable().optional(),
|
|
1121
|
+
/** Whether this agent can spawn child agents */
|
|
1122
|
+
may_spawn_children: z.boolean().default(false),
|
|
1123
|
+
/** Maximum depth of child agent spawning (0 = cannot spawn) */
|
|
1124
|
+
max_child_depth: z.number().int().min(0).default(0),
|
|
1125
|
+
/** Capability decay mode for children: decay, explicit, inherit */
|
|
1126
|
+
capability_mode: z.enum(["decay", "explicit", "inherit"]).default("decay"),
|
|
1127
|
+
/** Custom extension fields */
|
|
1128
|
+
custom: z.record(z.unknown()).optional()
|
|
1129
|
+
});
|
|
1130
|
+
var OperatingModeSchema = z.enum(["NORMAL", "SANDBOX", "RESTRICTED"]);
|
|
1131
|
+
var RuntimeIdentitySchema = z.object({
|
|
1132
|
+
/** Unique UUIDv4 for this runtime instance */
|
|
1133
|
+
instance_id: z.string().uuid(),
|
|
1134
|
+
/** Asset ID from the Asset Card (e.g., "aigrc-2024-a1b2c3d4") */
|
|
1135
|
+
asset_id: z.string().regex(/^aigrc-\d{4}-[a-f0-9]{8}$/),
|
|
1136
|
+
/** Human-readable name from Asset Card */
|
|
1137
|
+
asset_name: z.string().min(1).max(100),
|
|
1138
|
+
/** Semantic version from Asset Card */
|
|
1139
|
+
asset_version: z.string().regex(/^\d+\.\d+\.\d+/),
|
|
1140
|
+
/** SHA-256 hash of Golden Thread data */
|
|
1141
|
+
golden_thread_hash: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
1142
|
+
/** Full Golden Thread authorization data */
|
|
1143
|
+
golden_thread: GoldenThreadSchema,
|
|
1144
|
+
/** Risk level from classification */
|
|
1145
|
+
risk_level: RiskLevelSchema,
|
|
1146
|
+
/** Agent lineage for spawned agents */
|
|
1147
|
+
lineage: LineageSchema,
|
|
1148
|
+
/** Capabilities manifest defining permissions */
|
|
1149
|
+
capabilities_manifest: CapabilitiesManifestSchema,
|
|
1150
|
+
/** When this identity was created */
|
|
1151
|
+
created_at: z.string().datetime(),
|
|
1152
|
+
/** Whether Golden Thread hash has been verified */
|
|
1153
|
+
verified: z.boolean().default(false),
|
|
1154
|
+
/** Current operating mode */
|
|
1155
|
+
mode: OperatingModeSchema.default("NORMAL")
|
|
1156
|
+
});
|
|
1157
|
+
var KillSwitchCommandTypeSchema = z.enum(["TERMINATE", "PAUSE", "RESUME"]);
|
|
1158
|
+
var KillSwitchCommandSchema = z.object({
|
|
1159
|
+
/** Unique command ID for idempotency and replay prevention */
|
|
1160
|
+
command_id: z.string().uuid(),
|
|
1161
|
+
/** Type of command */
|
|
1162
|
+
type: KillSwitchCommandTypeSchema,
|
|
1163
|
+
/** Target instance_id (optional, for specific instance) */
|
|
1164
|
+
instance_id: z.string().uuid().optional(),
|
|
1165
|
+
/** Target asset_id (optional, for all instances of an asset) */
|
|
1166
|
+
asset_id: z.string().regex(/^aigrc-\d{4}-[a-f0-9]{8}$/).optional(),
|
|
1167
|
+
/** Target organization (optional, for org-wide kill) */
|
|
1168
|
+
organization: z.string().optional(),
|
|
1169
|
+
/** Cryptographic signature for verification */
|
|
1170
|
+
signature: z.string(),
|
|
1171
|
+
/** ISO 8601 timestamp for replay prevention */
|
|
1172
|
+
timestamp: z.string().datetime(),
|
|
1173
|
+
/** Human-readable reason for audit trail */
|
|
1174
|
+
reason: z.string().max(500),
|
|
1175
|
+
/** Issuer of the command (email or system ID) */
|
|
1176
|
+
issued_by: z.string()
|
|
1177
|
+
});
|
|
1178
|
+
var GovernanceTokenIdentityClaimsSchema = z.object({
|
|
1179
|
+
instance_id: z.string().uuid(),
|
|
1180
|
+
asset_id: z.string(),
|
|
1181
|
+
asset_name: z.string(),
|
|
1182
|
+
asset_version: z.string()
|
|
1183
|
+
});
|
|
1184
|
+
var GovernanceTokenGovernanceClaimsSchema = z.object({
|
|
1185
|
+
risk_level: RiskLevelSchema,
|
|
1186
|
+
golden_thread: z.object({
|
|
1187
|
+
hash: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
1188
|
+
verified: z.boolean(),
|
|
1189
|
+
ticket_id: z.string()
|
|
1190
|
+
}),
|
|
1191
|
+
mode: OperatingModeSchema
|
|
1192
|
+
});
|
|
1193
|
+
var GovernanceTokenControlClaimsSchema = z.object({
|
|
1194
|
+
kill_switch: z.object({
|
|
1195
|
+
enabled: z.boolean(),
|
|
1196
|
+
channel: z.enum(["sse", "polling", "file"])
|
|
1197
|
+
}),
|
|
1198
|
+
paused: z.boolean(),
|
|
1199
|
+
termination_pending: z.boolean()
|
|
1200
|
+
});
|
|
1201
|
+
var GovernanceTokenCapabilityClaimsSchema = z.object({
|
|
1202
|
+
hash: z.string(),
|
|
1203
|
+
tools: z.array(z.string()),
|
|
1204
|
+
max_budget_usd: z.number().nullable(),
|
|
1205
|
+
can_spawn: z.boolean(),
|
|
1206
|
+
max_child_depth: z.number().int().min(0)
|
|
1207
|
+
});
|
|
1208
|
+
var GovernanceTokenLineageClaimsSchema = z.object({
|
|
1209
|
+
generation_depth: z.number().int().min(0),
|
|
1210
|
+
parent_instance_id: z.string().uuid().nullable(),
|
|
1211
|
+
root_instance_id: z.string().uuid()
|
|
1212
|
+
});
|
|
1213
|
+
var GovernanceTokenPayloadSchema = z.object({
|
|
1214
|
+
// Standard JWT claims
|
|
1215
|
+
/** Issuer: "aigos-runtime" */
|
|
1216
|
+
iss: z.literal("aigos-runtime"),
|
|
1217
|
+
/** Subject: instance_id of the agent */
|
|
1218
|
+
sub: z.string().uuid(),
|
|
1219
|
+
/** Audience: "aigos-agents" or specific agent */
|
|
1220
|
+
aud: z.union([z.string(), z.array(z.string())]),
|
|
1221
|
+
/** Expiration timestamp (Unix epoch) */
|
|
1222
|
+
exp: z.number().int().positive(),
|
|
1223
|
+
/** Issued at timestamp (Unix epoch) */
|
|
1224
|
+
iat: z.number().int().positive(),
|
|
1225
|
+
/** Not before timestamp (Unix epoch) */
|
|
1226
|
+
nbf: z.number().int().positive(),
|
|
1227
|
+
/** Unique JWT ID */
|
|
1228
|
+
jti: z.string().uuid(),
|
|
1229
|
+
// AIGOS-specific claims
|
|
1230
|
+
aigos: z.object({
|
|
1231
|
+
identity: GovernanceTokenIdentityClaimsSchema,
|
|
1232
|
+
governance: GovernanceTokenGovernanceClaimsSchema,
|
|
1233
|
+
control: GovernanceTokenControlClaimsSchema,
|
|
1234
|
+
capabilities: GovernanceTokenCapabilityClaimsSchema,
|
|
1235
|
+
lineage: GovernanceTokenLineageClaimsSchema
|
|
1236
|
+
})
|
|
1237
|
+
});
|
|
1238
|
+
var AssetCardRuntimeSchema = z.object({
|
|
1239
|
+
/** Path to policy file for this asset */
|
|
1240
|
+
policy_path: z.string().optional(),
|
|
1241
|
+
/** Behavior when Golden Thread verification fails */
|
|
1242
|
+
verification_failure_mode: z.enum(["SANDBOX", "FAIL"]).default("SANDBOX"),
|
|
1243
|
+
/** Whether telemetry is enabled for this asset */
|
|
1244
|
+
telemetry_enabled: z.boolean().default(true),
|
|
1245
|
+
/** Kill switch configuration */
|
|
1246
|
+
kill_switch: z.object({
|
|
1247
|
+
enabled: z.boolean().default(true),
|
|
1248
|
+
channel: z.enum(["sse", "polling", "file"]).default("sse"),
|
|
1249
|
+
endpoint: z.string().url().optional()
|
|
1250
|
+
}).optional()
|
|
1251
|
+
});
|
|
1252
|
+
var PolicyRuleEffectSchema = z.enum(["allow", "deny", "audit"]);
|
|
1253
|
+
var PolicyRuleSchema = z.object({
|
|
1254
|
+
/** Unique identifier for this rule */
|
|
1255
|
+
id: z.string().min(1),
|
|
1256
|
+
/** Human-readable description */
|
|
1257
|
+
description: z.string().optional(),
|
|
1258
|
+
/** Effect when rule matches: allow, deny, or audit */
|
|
1259
|
+
effect: PolicyRuleEffectSchema,
|
|
1260
|
+
/** Actions/tools this rule applies to (supports wildcards) */
|
|
1261
|
+
actions: z.array(z.string()).default(["*"]),
|
|
1262
|
+
/** Resources/domains this rule applies to (supports patterns) */
|
|
1263
|
+
resources: z.array(z.string()).default(["*"]),
|
|
1264
|
+
/** Conditions that must be true for rule to apply */
|
|
1265
|
+
conditions: z.object({
|
|
1266
|
+
/** Required risk levels for this rule to apply */
|
|
1267
|
+
risk_levels: z.array(RiskLevelSchema).optional(),
|
|
1268
|
+
/** Required operating modes */
|
|
1269
|
+
modes: z.array(OperatingModeSchema).optional(),
|
|
1270
|
+
/** Time-based conditions (ISO 8601 time ranges) */
|
|
1271
|
+
time_ranges: z.array(z.object({
|
|
1272
|
+
start: z.string(),
|
|
1273
|
+
end: z.string()
|
|
1274
|
+
})).optional(),
|
|
1275
|
+
/** Custom condition expressions */
|
|
1276
|
+
custom: z.record(z.unknown()).optional()
|
|
1277
|
+
}).optional(),
|
|
1278
|
+
/** Priority for rule ordering (higher = evaluated first) */
|
|
1279
|
+
priority: z.number().int().default(0)
|
|
1280
|
+
});
|
|
1281
|
+
var PolicyCapabilitiesSchema = z.object({
|
|
1282
|
+
/** Default effect when no rule matches */
|
|
1283
|
+
default_effect: PolicyRuleEffectSchema.default("deny"),
|
|
1284
|
+
/** Allowed tools (supports wildcards: *, prefix_*) */
|
|
1285
|
+
allowed_tools: z.array(z.string()).default([]),
|
|
1286
|
+
/** Denied tools (takes precedence) */
|
|
1287
|
+
denied_tools: z.array(z.string()).default([]),
|
|
1288
|
+
/** Allowed domain patterns */
|
|
1289
|
+
allowed_domains: z.array(z.string()).default([]),
|
|
1290
|
+
/** Denied domain patterns */
|
|
1291
|
+
denied_domains: z.array(z.string()).default([]),
|
|
1292
|
+
/** Maximum budget per session in USD */
|
|
1293
|
+
max_budget_per_session: z.number().positive().nullable().optional(),
|
|
1294
|
+
/** Maximum budget per day in USD */
|
|
1295
|
+
max_budget_per_day: z.number().positive().nullable().optional(),
|
|
1296
|
+
/** Whether agent can spawn children */
|
|
1297
|
+
may_spawn: z.boolean().default(false),
|
|
1298
|
+
/** Maximum spawn depth */
|
|
1299
|
+
max_spawn_depth: z.number().int().min(0).default(0)
|
|
1300
|
+
});
|
|
1301
|
+
var PolicyFileSchema = z.object({
|
|
1302
|
+
/** Schema version for forward compatibility */
|
|
1303
|
+
version: z.literal("1.0"),
|
|
1304
|
+
/** Unique policy identifier */
|
|
1305
|
+
id: z.string().min(1),
|
|
1306
|
+
/** Human-readable name */
|
|
1307
|
+
name: z.string().min(1).max(100),
|
|
1308
|
+
/** Description of this policy */
|
|
1309
|
+
description: z.string().max(500).optional(),
|
|
1310
|
+
/** Parent policy to inherit from */
|
|
1311
|
+
extends: z.string().optional(),
|
|
1312
|
+
/** Target asset IDs or patterns this policy applies to */
|
|
1313
|
+
applies_to: z.array(z.string()).default(["*"]),
|
|
1314
|
+
/** Default capabilities when no rules match */
|
|
1315
|
+
capabilities: PolicyCapabilitiesSchema.optional(),
|
|
1316
|
+
/** Ordered list of policy rules */
|
|
1317
|
+
rules: z.array(PolicyRuleSchema).default([]),
|
|
1318
|
+
/** Metadata */
|
|
1319
|
+
metadata: z.object({
|
|
1320
|
+
created_at: z.string().datetime().optional(),
|
|
1321
|
+
updated_at: z.string().datetime().optional(),
|
|
1322
|
+
created_by: z.string().optional(),
|
|
1323
|
+
tags: z.array(z.string()).optional()
|
|
1324
|
+
}).optional()
|
|
1325
|
+
});
|
|
1326
|
+
var AigrcRuntimeConfigSchema = z.object({
|
|
1327
|
+
/** Default policy file path */
|
|
1328
|
+
default_policy: z.string().optional(),
|
|
1329
|
+
/** Policy search paths */
|
|
1330
|
+
policy_paths: z.array(z.string()).default([".aigrc/policies"]),
|
|
1331
|
+
/** Asset card search paths */
|
|
1332
|
+
asset_paths: z.array(z.string()).default([".aigrc/assets"]),
|
|
1333
|
+
/** Default verification failure mode */
|
|
1334
|
+
verification_failure_mode: z.enum(["SANDBOX", "FAIL"]).default("SANDBOX"),
|
|
1335
|
+
/** Telemetry configuration */
|
|
1336
|
+
telemetry: z.object({
|
|
1337
|
+
enabled: z.boolean().default(true),
|
|
1338
|
+
endpoint: z.string().url().optional(),
|
|
1339
|
+
sample_rate: z.number().min(0).max(1).default(1)
|
|
1340
|
+
}).optional(),
|
|
1341
|
+
/** Kill switch configuration */
|
|
1342
|
+
kill_switch: z.object({
|
|
1343
|
+
enabled: z.boolean().default(true),
|
|
1344
|
+
channel: z.enum(["sse", "polling", "file"]).default("sse"),
|
|
1345
|
+
endpoint: z.string().url().optional(),
|
|
1346
|
+
poll_interval_ms: z.number().int().positive().default(5e3)
|
|
1347
|
+
}).optional()
|
|
1348
|
+
});
|
|
1349
|
+
var AigrcIntegrationsConfigSchema = z.object({
|
|
1350
|
+
/** JIRA integration */
|
|
1351
|
+
jira: z.object({
|
|
1352
|
+
enabled: z.boolean().default(false),
|
|
1353
|
+
url: z.string().url().optional(),
|
|
1354
|
+
project_key: z.string().optional()
|
|
1355
|
+
}).optional(),
|
|
1356
|
+
/** Azure DevOps integration */
|
|
1357
|
+
azure_devops: z.object({
|
|
1358
|
+
enabled: z.boolean().default(false),
|
|
1359
|
+
organization: z.string().optional(),
|
|
1360
|
+
project: z.string().optional()
|
|
1361
|
+
}).optional(),
|
|
1362
|
+
/** GitHub integration */
|
|
1363
|
+
github: z.object({
|
|
1364
|
+
enabled: z.boolean().default(false),
|
|
1365
|
+
owner: z.string().optional(),
|
|
1366
|
+
repo: z.string().optional()
|
|
1367
|
+
}).optional()
|
|
1368
|
+
});
|
|
1369
|
+
var AigrcConfigSchema = z.object({
|
|
1370
|
+
/** Schema version */
|
|
1371
|
+
version: z.literal("1.0"),
|
|
1372
|
+
/** Project name */
|
|
1373
|
+
name: z.string().min(1).max(100).optional(),
|
|
1374
|
+
/** Project description */
|
|
1375
|
+
description: z.string().max(500).optional(),
|
|
1376
|
+
/** Runtime governance configuration */
|
|
1377
|
+
runtime: AigrcRuntimeConfigSchema.optional(),
|
|
1378
|
+
/** External integrations */
|
|
1379
|
+
integrations: AigrcIntegrationsConfigSchema.optional(),
|
|
1380
|
+
/** Environment-specific overrides */
|
|
1381
|
+
environments: z.record(z.object({
|
|
1382
|
+
runtime: AigrcRuntimeConfigSchema.partial().optional(),
|
|
1383
|
+
integrations: AigrcIntegrationsConfigSchema.partial().optional()
|
|
1384
|
+
})).optional()
|
|
1385
|
+
});
|
|
1075
1386
|
var AssetCardSchema = z.object({
|
|
1076
1387
|
$schema: z.string().optional(),
|
|
1077
1388
|
id: z.string().regex(/^aigrc-\d{4}-[a-f0-9]{8}$/),
|
|
@@ -1088,7 +1399,11 @@ var AssetCardSchema = z.object({
|
|
|
1088
1399
|
classification: ClassificationSchema,
|
|
1089
1400
|
intent: IntentSchema,
|
|
1090
1401
|
governance: GovernanceSchema,
|
|
1091
|
-
constraints: ConstraintsSchema.optional()
|
|
1402
|
+
constraints: ConstraintsSchema.optional(),
|
|
1403
|
+
/** Golden Thread authorization data (SPEC-PRT-001) */
|
|
1404
|
+
golden_thread: GoldenThreadSchema.optional(),
|
|
1405
|
+
/** Runtime governance configuration (SPEC-RT) */
|
|
1406
|
+
runtime: AssetCardRuntimeSchema.optional()
|
|
1092
1407
|
});
|
|
1093
1408
|
|
|
1094
1409
|
// src/classification.ts
|
|
@@ -1159,6 +1474,73 @@ function validateRiskFactors(factors) {
|
|
|
1159
1474
|
return true;
|
|
1160
1475
|
}
|
|
1161
1476
|
|
|
1477
|
+
// src/risk-utils.ts
|
|
1478
|
+
var RISK_ORDINALS = {
|
|
1479
|
+
minimal: 0,
|
|
1480
|
+
limited: 1,
|
|
1481
|
+
high: 2,
|
|
1482
|
+
unacceptable: 3
|
|
1483
|
+
};
|
|
1484
|
+
var EU_AI_ACT_MAP = {
|
|
1485
|
+
minimal: "minimal_risk",
|
|
1486
|
+
limited: "limited_risk",
|
|
1487
|
+
high: "high_risk",
|
|
1488
|
+
unacceptable: "prohibited"
|
|
1489
|
+
};
|
|
1490
|
+
function compareRiskLevels(a, b) {
|
|
1491
|
+
const ordA = RISK_ORDINALS[a];
|
|
1492
|
+
const ordB = RISK_ORDINALS[b];
|
|
1493
|
+
if (ordA < ordB) return -1;
|
|
1494
|
+
if (ordA > ordB) return 1;
|
|
1495
|
+
return 0;
|
|
1496
|
+
}
|
|
1497
|
+
function isRiskLevelAtLeast(level, threshold) {
|
|
1498
|
+
return RISK_ORDINALS[level] >= RISK_ORDINALS[threshold];
|
|
1499
|
+
}
|
|
1500
|
+
function isRiskLevelAtMost(level, threshold) {
|
|
1501
|
+
return RISK_ORDINALS[level] <= RISK_ORDINALS[threshold];
|
|
1502
|
+
}
|
|
1503
|
+
function getRiskLevelOrdinal(level) {
|
|
1504
|
+
return RISK_ORDINALS[level];
|
|
1505
|
+
}
|
|
1506
|
+
function getMaxRiskLevel(levels) {
|
|
1507
|
+
if (levels.length === 0) {
|
|
1508
|
+
return "minimal";
|
|
1509
|
+
}
|
|
1510
|
+
return levels.reduce(
|
|
1511
|
+
(max, current) => RISK_ORDINALS[current] > RISK_ORDINALS[max] ? current : max
|
|
1512
|
+
);
|
|
1513
|
+
}
|
|
1514
|
+
function getMinRiskLevel(levels) {
|
|
1515
|
+
if (levels.length === 0) {
|
|
1516
|
+
return "minimal";
|
|
1517
|
+
}
|
|
1518
|
+
return levels.reduce(
|
|
1519
|
+
(min, current) => RISK_ORDINALS[current] < RISK_ORDINALS[min] ? current : min
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
function mapToEuAiActCategory(level) {
|
|
1523
|
+
return EU_AI_ACT_MAP[level];
|
|
1524
|
+
}
|
|
1525
|
+
function getRiskLevelsAtLeast(threshold) {
|
|
1526
|
+
const thresholdOrd = RISK_ORDINALS[threshold];
|
|
1527
|
+
return Object.entries(RISK_ORDINALS).filter(([, ord]) => ord >= thresholdOrd).map(([level]) => level);
|
|
1528
|
+
}
|
|
1529
|
+
function getRiskLevelsAtMost(threshold) {
|
|
1530
|
+
const thresholdOrd = RISK_ORDINALS[threshold];
|
|
1531
|
+
return Object.entries(RISK_ORDINALS).filter(([, ord]) => ord <= thresholdOrd).map(([level]) => level);
|
|
1532
|
+
}
|
|
1533
|
+
function parseRiskLevel(value) {
|
|
1534
|
+
const normalized = value.toLowerCase();
|
|
1535
|
+
if (normalized in RISK_ORDINALS) {
|
|
1536
|
+
return normalized;
|
|
1537
|
+
}
|
|
1538
|
+
return void 0;
|
|
1539
|
+
}
|
|
1540
|
+
function isValidRiskLevel(value) {
|
|
1541
|
+
return typeof value === "string" && value in RISK_ORDINALS;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1162
1544
|
// src/asset-card.ts
|
|
1163
1545
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
1164
1546
|
import { dirname } from "path";
|
|
@@ -1308,6 +1690,115 @@ function validateAssetCard(card) {
|
|
|
1308
1690
|
}
|
|
1309
1691
|
|
|
1310
1692
|
// src/golden-thread.ts
|
|
1693
|
+
function computeCanonicalString(components) {
|
|
1694
|
+
const normalizedTimestamp = normalizeTimestamp(components.approved_at);
|
|
1695
|
+
const pairs = [
|
|
1696
|
+
`approved_at=${normalizedTimestamp}`,
|
|
1697
|
+
`approved_by=${components.approved_by}`,
|
|
1698
|
+
`ticket_id=${components.ticket_id}`
|
|
1699
|
+
];
|
|
1700
|
+
return pairs.join("|");
|
|
1701
|
+
}
|
|
1702
|
+
function normalizeTimestamp(timestamp) {
|
|
1703
|
+
const date = new Date(timestamp);
|
|
1704
|
+
if (isNaN(date.getTime())) {
|
|
1705
|
+
throw new Error(`Invalid timestamp: ${timestamp}`);
|
|
1706
|
+
}
|
|
1707
|
+
return date.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
1708
|
+
}
|
|
1709
|
+
async function computeGoldenThreadHash(components) {
|
|
1710
|
+
const canonicalString = computeCanonicalString(components);
|
|
1711
|
+
const encoder = new TextEncoder();
|
|
1712
|
+
const data = encoder.encode(canonicalString);
|
|
1713
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
1714
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
1715
|
+
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1716
|
+
return {
|
|
1717
|
+
canonical_string: canonicalString,
|
|
1718
|
+
hash: `sha256:${hashHex}`
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
function computeGoldenThreadHashSync(components) {
|
|
1722
|
+
const canonicalString = computeCanonicalString(components);
|
|
1723
|
+
const crypto2 = __require("crypto");
|
|
1724
|
+
const hash = crypto2.createHash("sha256").update(canonicalString).digest("hex");
|
|
1725
|
+
return {
|
|
1726
|
+
canonical_string: canonicalString,
|
|
1727
|
+
hash: `sha256:${hash}`
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
async function verifyGoldenThreadHash(components, expectedHash) {
|
|
1731
|
+
const { hash: computedHash } = await computeGoldenThreadHash(components);
|
|
1732
|
+
const verified = constantTimeEqual(computedHash, expectedHash);
|
|
1733
|
+
return {
|
|
1734
|
+
verified,
|
|
1735
|
+
computed: computedHash,
|
|
1736
|
+
expected: expectedHash,
|
|
1737
|
+
mismatch_reason: verified ? void 0 : "Hash mismatch"
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
function verifyGoldenThreadHashSync(components, expectedHash) {
|
|
1741
|
+
const { hash: computedHash } = computeGoldenThreadHashSync(components);
|
|
1742
|
+
const verified = constantTimeEqual(computedHash, expectedHash);
|
|
1743
|
+
return {
|
|
1744
|
+
verified,
|
|
1745
|
+
computed: computedHash,
|
|
1746
|
+
expected: expectedHash,
|
|
1747
|
+
mismatch_reason: verified ? void 0 : "Hash mismatch"
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
function constantTimeEqual(a, b) {
|
|
1751
|
+
if (a.length !== b.length) {
|
|
1752
|
+
return false;
|
|
1753
|
+
}
|
|
1754
|
+
let result = 0;
|
|
1755
|
+
for (let i = 0; i < a.length; i++) {
|
|
1756
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
1757
|
+
}
|
|
1758
|
+
return result === 0;
|
|
1759
|
+
}
|
|
1760
|
+
function extractGoldenThreadComponents(asset) {
|
|
1761
|
+
if (asset.golden_thread) {
|
|
1762
|
+
return {
|
|
1763
|
+
ticket_id: asset.golden_thread.ticket_id,
|
|
1764
|
+
approved_by: asset.golden_thread.approved_by,
|
|
1765
|
+
approved_at: asset.golden_thread.approved_at
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
if (!asset.intent.ticketId) {
|
|
1769
|
+
return null;
|
|
1770
|
+
}
|
|
1771
|
+
const approvals = asset.governance.approvals;
|
|
1772
|
+
if (approvals.length === 0) {
|
|
1773
|
+
return null;
|
|
1774
|
+
}
|
|
1775
|
+
const latestApproval = approvals.reduce(
|
|
1776
|
+
(latest, current) => new Date(current.date) > new Date(latest.date) ? current : latest
|
|
1777
|
+
);
|
|
1778
|
+
return {
|
|
1779
|
+
ticket_id: asset.intent.ticketId,
|
|
1780
|
+
approved_by: latestApproval.email || latestApproval.name,
|
|
1781
|
+
approved_at: latestApproval.date
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
async function createGoldenThread(components) {
|
|
1785
|
+
const { hash } = await computeGoldenThreadHash(components);
|
|
1786
|
+
return {
|
|
1787
|
+
ticket_id: components.ticket_id,
|
|
1788
|
+
approved_by: components.approved_by,
|
|
1789
|
+
approved_at: components.approved_at,
|
|
1790
|
+
hash
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
function createGoldenThreadSync(components) {
|
|
1794
|
+
const { hash } = computeGoldenThreadHashSync(components);
|
|
1795
|
+
return {
|
|
1796
|
+
ticket_id: components.ticket_id,
|
|
1797
|
+
approved_by: components.approved_by,
|
|
1798
|
+
approved_at: components.approved_at,
|
|
1799
|
+
hash
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1311
1802
|
function linkAssetToTicket(asset, ticket) {
|
|
1312
1803
|
const warnings = [];
|
|
1313
1804
|
const intent = {
|
|
@@ -1356,6 +1847,144 @@ function validateGoldenThread(asset) {
|
|
|
1356
1847
|
issues
|
|
1357
1848
|
};
|
|
1358
1849
|
}
|
|
1850
|
+
function parseSignature(signature) {
|
|
1851
|
+
const match = signature.match(/^(RSA-SHA256|ECDSA-P256):([A-Za-z0-9+/=]+)$/);
|
|
1852
|
+
if (!match) {
|
|
1853
|
+
return null;
|
|
1854
|
+
}
|
|
1855
|
+
const algorithm = match[1];
|
|
1856
|
+
const base64Data = match[2];
|
|
1857
|
+
try {
|
|
1858
|
+
const binaryString = atob(base64Data);
|
|
1859
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
1860
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
1861
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
1862
|
+
}
|
|
1863
|
+
return { algorithm, data: bytes };
|
|
1864
|
+
} catch {
|
|
1865
|
+
return null;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
async function verifyGoldenThreadSignature(components, signature, publicKey) {
|
|
1869
|
+
const parsed = parseSignature(signature);
|
|
1870
|
+
if (!parsed) {
|
|
1871
|
+
return {
|
|
1872
|
+
verified: false,
|
|
1873
|
+
algorithm: null,
|
|
1874
|
+
error: "Invalid signature format. Expected {ALGORITHM}:{BASE64_SIGNATURE}"
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
if (parsed.algorithm !== publicKey.algorithm) {
|
|
1878
|
+
return {
|
|
1879
|
+
verified: false,
|
|
1880
|
+
algorithm: parsed.algorithm,
|
|
1881
|
+
error: `Algorithm mismatch: signature uses ${parsed.algorithm}, key is ${publicKey.algorithm}`
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
const canonicalString = computeCanonicalString(components);
|
|
1885
|
+
const encoder = new TextEncoder();
|
|
1886
|
+
const data = encoder.encode(canonicalString);
|
|
1887
|
+
try {
|
|
1888
|
+
const cryptoKey = await importPublicKey(publicKey);
|
|
1889
|
+
const algorithmParams = getVerifyAlgorithm(parsed.algorithm);
|
|
1890
|
+
const verified = await crypto.subtle.verify(
|
|
1891
|
+
algorithmParams,
|
|
1892
|
+
cryptoKey,
|
|
1893
|
+
parsed.data,
|
|
1894
|
+
data
|
|
1895
|
+
);
|
|
1896
|
+
return {
|
|
1897
|
+
verified,
|
|
1898
|
+
algorithm: parsed.algorithm,
|
|
1899
|
+
signedData: canonicalString,
|
|
1900
|
+
error: verified ? void 0 : "Signature verification failed"
|
|
1901
|
+
};
|
|
1902
|
+
} catch (error) {
|
|
1903
|
+
return {
|
|
1904
|
+
verified: false,
|
|
1905
|
+
algorithm: parsed.algorithm,
|
|
1906
|
+
error: `Verification error: ${error instanceof Error ? error.message : String(error)}`
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
function verifyGoldenThreadSignatureSync(components, signature, publicKeyPem) {
|
|
1911
|
+
const parsed = parseSignature(signature);
|
|
1912
|
+
if (!parsed) {
|
|
1913
|
+
return {
|
|
1914
|
+
verified: false,
|
|
1915
|
+
algorithm: null,
|
|
1916
|
+
error: "Invalid signature format"
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
const canonicalString = computeCanonicalString(components);
|
|
1920
|
+
try {
|
|
1921
|
+
const crypto2 = __require("crypto");
|
|
1922
|
+
const verifier = crypto2.createVerify(
|
|
1923
|
+
parsed.algorithm === "RSA-SHA256" ? "RSA-SHA256" : "SHA256"
|
|
1924
|
+
);
|
|
1925
|
+
verifier.update(canonicalString);
|
|
1926
|
+
verifier.end();
|
|
1927
|
+
const verified = verifier.verify(publicKeyPem, Buffer.from(parsed.data));
|
|
1928
|
+
return {
|
|
1929
|
+
verified,
|
|
1930
|
+
algorithm: parsed.algorithm,
|
|
1931
|
+
signedData: canonicalString,
|
|
1932
|
+
error: verified ? void 0 : "Signature verification failed"
|
|
1933
|
+
};
|
|
1934
|
+
} catch (error) {
|
|
1935
|
+
return {
|
|
1936
|
+
verified: false,
|
|
1937
|
+
algorithm: parsed.algorithm,
|
|
1938
|
+
error: `Verification error: ${error instanceof Error ? error.message : String(error)}`
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
async function signGoldenThread(components, privateKey, algorithm) {
|
|
1943
|
+
const canonicalString = computeCanonicalString(components);
|
|
1944
|
+
const encoder = new TextEncoder();
|
|
1945
|
+
const data = encoder.encode(canonicalString);
|
|
1946
|
+
const signatureBuffer = await crypto.subtle.sign(
|
|
1947
|
+
getSignAlgorithm(algorithm),
|
|
1948
|
+
privateKey,
|
|
1949
|
+
data
|
|
1950
|
+
);
|
|
1951
|
+
const signatureArray = new Uint8Array(signatureBuffer);
|
|
1952
|
+
const base64 = btoa(String.fromCharCode(...signatureArray));
|
|
1953
|
+
return `${algorithm}:${base64}`;
|
|
1954
|
+
}
|
|
1955
|
+
async function importPublicKey(publicKey) {
|
|
1956
|
+
const pemHeader = "-----BEGIN PUBLIC KEY-----";
|
|
1957
|
+
const pemFooter = "-----END PUBLIC KEY-----";
|
|
1958
|
+
let keyData;
|
|
1959
|
+
if (publicKey.key.includes(pemHeader)) {
|
|
1960
|
+
const pemContents = publicKey.key.replace(pemHeader, "").replace(pemFooter, "").replace(/\s/g, "");
|
|
1961
|
+
const binaryString = atob(pemContents);
|
|
1962
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
1963
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
1964
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
1965
|
+
}
|
|
1966
|
+
keyData = bytes.buffer;
|
|
1967
|
+
} else {
|
|
1968
|
+
const binaryString = atob(publicKey.key);
|
|
1969
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
1970
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
1971
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
1972
|
+
}
|
|
1973
|
+
keyData = bytes.buffer;
|
|
1974
|
+
}
|
|
1975
|
+
const algorithm = publicKey.algorithm === "RSA-SHA256" ? { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" } : { name: "ECDSA", namedCurve: "P-256" };
|
|
1976
|
+
return crypto.subtle.importKey("spki", keyData, algorithm, true, ["verify"]);
|
|
1977
|
+
}
|
|
1978
|
+
function getVerifyAlgorithm(algorithm) {
|
|
1979
|
+
if (algorithm === "RSA-SHA256") {
|
|
1980
|
+
return { name: "RSASSA-PKCS1-v1_5" };
|
|
1981
|
+
} else {
|
|
1982
|
+
return { name: "ECDSA", hash: "SHA-256" };
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
function getSignAlgorithm(algorithm) {
|
|
1986
|
+
return getVerifyAlgorithm(algorithm);
|
|
1987
|
+
}
|
|
1359
1988
|
|
|
1360
1989
|
// src/detection/types.ts
|
|
1361
1990
|
import { z as z2 } from "zod";
|
|
@@ -2194,6 +2823,1385 @@ init_javascript();
|
|
|
2194
2823
|
init_model_files();
|
|
2195
2824
|
init_risk_indicators();
|
|
2196
2825
|
|
|
2826
|
+
// src/config.ts
|
|
2827
|
+
import * as fs from "fs";
|
|
2828
|
+
import * as path from "path";
|
|
2829
|
+
import * as yaml from "yaml";
|
|
2830
|
+
var CONFIG_FILE_NAMES = [
|
|
2831
|
+
".aigrc.yaml",
|
|
2832
|
+
".aigrc.yml",
|
|
2833
|
+
"aigrc.yaml",
|
|
2834
|
+
"aigrc.yml"
|
|
2835
|
+
];
|
|
2836
|
+
var CONFIG_ENV_VAR = "AIGRC_CONFIG_PATH";
|
|
2837
|
+
function discoverConfig(options = {}) {
|
|
2838
|
+
const { startDir = process.cwd(), maxDepth = 10 } = options;
|
|
2839
|
+
if (options.configPath) {
|
|
2840
|
+
const result = loadConfigFromPath(options.configPath);
|
|
2841
|
+
if (result) {
|
|
2842
|
+
return { ...result, fromEnv: false };
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
const envPath = process.env[CONFIG_ENV_VAR];
|
|
2846
|
+
if (envPath) {
|
|
2847
|
+
const result = loadConfigFromPath(envPath);
|
|
2848
|
+
if (result) {
|
|
2849
|
+
return { ...result, fromEnv: true };
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
let currentDir = path.resolve(startDir);
|
|
2853
|
+
let depth = 0;
|
|
2854
|
+
while (depth < maxDepth) {
|
|
2855
|
+
for (const fileName of CONFIG_FILE_NAMES) {
|
|
2856
|
+
const filePath = path.join(currentDir, fileName);
|
|
2857
|
+
if (fs.existsSync(filePath)) {
|
|
2858
|
+
const config = loadConfigFile(filePath);
|
|
2859
|
+
if (config) {
|
|
2860
|
+
return {
|
|
2861
|
+
config,
|
|
2862
|
+
configPath: filePath,
|
|
2863
|
+
configDir: currentDir,
|
|
2864
|
+
fromEnv: false
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
const parentDir = path.dirname(currentDir);
|
|
2870
|
+
if (parentDir === currentDir) {
|
|
2871
|
+
break;
|
|
2872
|
+
}
|
|
2873
|
+
currentDir = parentDir;
|
|
2874
|
+
depth++;
|
|
2875
|
+
}
|
|
2876
|
+
return null;
|
|
2877
|
+
}
|
|
2878
|
+
function loadConfigFromPath(configPath) {
|
|
2879
|
+
const resolvedPath = path.resolve(configPath);
|
|
2880
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
2881
|
+
return null;
|
|
2882
|
+
}
|
|
2883
|
+
const config = loadConfigFile(resolvedPath);
|
|
2884
|
+
if (!config) {
|
|
2885
|
+
return null;
|
|
2886
|
+
}
|
|
2887
|
+
return {
|
|
2888
|
+
config,
|
|
2889
|
+
configPath: resolvedPath,
|
|
2890
|
+
configDir: path.dirname(resolvedPath)
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2893
|
+
function loadConfigFile(filePath) {
|
|
2894
|
+
try {
|
|
2895
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
2896
|
+
const parsed = yaml.parse(content);
|
|
2897
|
+
return AigrcConfigSchema.parse(parsed);
|
|
2898
|
+
} catch {
|
|
2899
|
+
return null;
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
function discoverConfigSync(options = {}) {
|
|
2903
|
+
return discoverConfig(options);
|
|
2904
|
+
}
|
|
2905
|
+
function discoverPolicies(options = {}) {
|
|
2906
|
+
const {
|
|
2907
|
+
config,
|
|
2908
|
+
baseDir = process.cwd(),
|
|
2909
|
+
additionalPaths = []
|
|
2910
|
+
} = options;
|
|
2911
|
+
const policies = /* @__PURE__ */ new Map();
|
|
2912
|
+
const loadedPaths = [];
|
|
2913
|
+
const errors = [];
|
|
2914
|
+
const searchPaths = [
|
|
2915
|
+
...config?.runtime?.policy_paths ?? [".aigrc/policies"],
|
|
2916
|
+
...additionalPaths
|
|
2917
|
+
];
|
|
2918
|
+
for (const searchPath of searchPaths) {
|
|
2919
|
+
const absolutePath = path.isAbsolute(searchPath) ? searchPath : path.join(baseDir, searchPath);
|
|
2920
|
+
if (!fs.existsSync(absolutePath)) {
|
|
2921
|
+
continue;
|
|
2922
|
+
}
|
|
2923
|
+
const stat = fs.statSync(absolutePath);
|
|
2924
|
+
if (stat.isDirectory()) {
|
|
2925
|
+
const files = fs.readdirSync(absolutePath);
|
|
2926
|
+
for (const file of files) {
|
|
2927
|
+
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
2928
|
+
const filePath = path.join(absolutePath, file);
|
|
2929
|
+
const result = loadPolicyFile(filePath);
|
|
2930
|
+
if (result.policy) {
|
|
2931
|
+
policies.set(result.policy.id, result.policy);
|
|
2932
|
+
loadedPaths.push(filePath);
|
|
2933
|
+
} else if (result.error) {
|
|
2934
|
+
errors.push({ path: filePath, error: result.error });
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
} else if (stat.isFile()) {
|
|
2939
|
+
const result = loadPolicyFile(absolutePath);
|
|
2940
|
+
if (result.policy) {
|
|
2941
|
+
policies.set(result.policy.id, result.policy);
|
|
2942
|
+
loadedPaths.push(absolutePath);
|
|
2943
|
+
} else if (result.error) {
|
|
2944
|
+
errors.push({ path: absolutePath, error: result.error });
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
return { policies, loadedPaths, errors };
|
|
2949
|
+
}
|
|
2950
|
+
function loadPolicyFile(filePath) {
|
|
2951
|
+
try {
|
|
2952
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
2953
|
+
const parsed = yaml.parse(content);
|
|
2954
|
+
const policy = PolicyFileSchema.parse(parsed);
|
|
2955
|
+
return { policy, error: null };
|
|
2956
|
+
} catch (err) {
|
|
2957
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2958
|
+
return { policy: null, error: message };
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
function loadPolicy(policyId, options = {}) {
|
|
2962
|
+
const { policies } = discoverPolicies(options);
|
|
2963
|
+
return policies.get(policyId) ?? null;
|
|
2964
|
+
}
|
|
2965
|
+
function discoverAssets(options = {}) {
|
|
2966
|
+
const {
|
|
2967
|
+
config,
|
|
2968
|
+
baseDir = process.cwd(),
|
|
2969
|
+
additionalPaths = []
|
|
2970
|
+
} = options;
|
|
2971
|
+
const assets = /* @__PURE__ */ new Map();
|
|
2972
|
+
const loadedPaths = [];
|
|
2973
|
+
const errors = [];
|
|
2974
|
+
const searchPaths = [
|
|
2975
|
+
...config?.runtime?.asset_paths ?? [".aigrc/assets"],
|
|
2976
|
+
...additionalPaths
|
|
2977
|
+
];
|
|
2978
|
+
for (const searchPath of searchPaths) {
|
|
2979
|
+
const absolutePath = path.isAbsolute(searchPath) ? searchPath : path.join(baseDir, searchPath);
|
|
2980
|
+
if (!fs.existsSync(absolutePath)) {
|
|
2981
|
+
continue;
|
|
2982
|
+
}
|
|
2983
|
+
const stat = fs.statSync(absolutePath);
|
|
2984
|
+
if (stat.isDirectory()) {
|
|
2985
|
+
const files = fs.readdirSync(absolutePath);
|
|
2986
|
+
for (const file of files) {
|
|
2987
|
+
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
2988
|
+
const filePath = path.join(absolutePath, file);
|
|
2989
|
+
const result = loadAssetFile(filePath);
|
|
2990
|
+
if (result.asset) {
|
|
2991
|
+
assets.set(result.asset.id, result.asset);
|
|
2992
|
+
loadedPaths.push(filePath);
|
|
2993
|
+
} else if (result.error) {
|
|
2994
|
+
errors.push({ path: filePath, error: result.error });
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
} else if (stat.isFile()) {
|
|
2999
|
+
const result = loadAssetFile(absolutePath);
|
|
3000
|
+
if (result.asset) {
|
|
3001
|
+
assets.set(result.asset.id, result.asset);
|
|
3002
|
+
loadedPaths.push(absolutePath);
|
|
3003
|
+
} else if (result.error) {
|
|
3004
|
+
errors.push({ path: absolutePath, error: result.error });
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
return { assets, loadedPaths, errors };
|
|
3009
|
+
}
|
|
3010
|
+
function loadAssetFile(filePath) {
|
|
3011
|
+
try {
|
|
3012
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3013
|
+
const parsed = yaml.parse(content);
|
|
3014
|
+
const asset = AssetCardSchema.parse(parsed);
|
|
3015
|
+
return { asset, error: null };
|
|
3016
|
+
} catch (err) {
|
|
3017
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3018
|
+
return { asset: null, error: message };
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
function loadAsset(assetId, options = {}) {
|
|
3022
|
+
const { assets } = discoverAssets(options);
|
|
3023
|
+
return assets.get(assetId) ?? null;
|
|
3024
|
+
}
|
|
3025
|
+
function loadAssetFromPath(filePath) {
|
|
3026
|
+
const result = loadAssetFile(filePath);
|
|
3027
|
+
return result.asset;
|
|
3028
|
+
}
|
|
3029
|
+
function getEnvironmentConfig(config, environment) {
|
|
3030
|
+
const envOverrides = config.environments?.[environment];
|
|
3031
|
+
if (!envOverrides) {
|
|
3032
|
+
return config;
|
|
3033
|
+
}
|
|
3034
|
+
const result = { ...config };
|
|
3035
|
+
if (config.runtime || envOverrides.runtime) {
|
|
3036
|
+
result.runtime = {
|
|
3037
|
+
...config.runtime,
|
|
3038
|
+
...filterUndefined(envOverrides.runtime ?? {})
|
|
3039
|
+
};
|
|
3040
|
+
}
|
|
3041
|
+
if (config.integrations || envOverrides.integrations) {
|
|
3042
|
+
result.integrations = {
|
|
3043
|
+
...config.integrations,
|
|
3044
|
+
...filterUndefined(envOverrides.integrations ?? {})
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
return result;
|
|
3048
|
+
}
|
|
3049
|
+
function filterUndefined(obj) {
|
|
3050
|
+
const result = {};
|
|
3051
|
+
for (const key of Object.keys(obj)) {
|
|
3052
|
+
if (obj[key] !== void 0) {
|
|
3053
|
+
result[key] = obj[key];
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
return result;
|
|
3057
|
+
}
|
|
3058
|
+
function getCurrentEnvironment() {
|
|
3059
|
+
return process.env.AIGRC_ENV ?? process.env.NODE_ENV ?? "development";
|
|
3060
|
+
}
|
|
3061
|
+
function createDefaultConfig() {
|
|
3062
|
+
return AigrcConfigSchema.parse({
|
|
3063
|
+
version: "1.0",
|
|
3064
|
+
runtime: {},
|
|
3065
|
+
integrations: {}
|
|
3066
|
+
});
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
// src/policy.ts
|
|
3070
|
+
var MAX_INHERITANCE_DEPTH = 10;
|
|
3071
|
+
var PolicyResolutionError = class extends Error {
|
|
3072
|
+
constructor(message, policyId, cause) {
|
|
3073
|
+
super(message);
|
|
3074
|
+
this.policyId = policyId;
|
|
3075
|
+
this.cause = cause;
|
|
3076
|
+
this.name = "PolicyResolutionError";
|
|
3077
|
+
}
|
|
3078
|
+
};
|
|
3079
|
+
function createPolicyRepository(policies) {
|
|
3080
|
+
return {
|
|
3081
|
+
get: (id) => policies.get(id),
|
|
3082
|
+
has: (id) => policies.has(id)
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
function resolvePolicy(policyId, repository) {
|
|
3086
|
+
const chain = [];
|
|
3087
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
3088
|
+
let currentId = policyId;
|
|
3089
|
+
while (currentId) {
|
|
3090
|
+
if (seenIds.has(currentId)) {
|
|
3091
|
+
throw new PolicyResolutionError(
|
|
3092
|
+
`Circular inheritance detected: ${currentId}`,
|
|
3093
|
+
policyId
|
|
3094
|
+
);
|
|
3095
|
+
}
|
|
3096
|
+
if (chain.length >= MAX_INHERITANCE_DEPTH) {
|
|
3097
|
+
throw new PolicyResolutionError(
|
|
3098
|
+
`Maximum inheritance depth (${MAX_INHERITANCE_DEPTH}) exceeded`,
|
|
3099
|
+
policyId
|
|
3100
|
+
);
|
|
3101
|
+
}
|
|
3102
|
+
const policy = repository.get(currentId);
|
|
3103
|
+
if (!policy) {
|
|
3104
|
+
throw new PolicyResolutionError(
|
|
3105
|
+
`Policy not found: ${currentId}`,
|
|
3106
|
+
policyId
|
|
3107
|
+
);
|
|
3108
|
+
}
|
|
3109
|
+
seenIds.add(currentId);
|
|
3110
|
+
chain.push(policy);
|
|
3111
|
+
currentId = policy.extends;
|
|
3112
|
+
}
|
|
3113
|
+
chain.reverse();
|
|
3114
|
+
const mergedPolicy = chain.reduce(
|
|
3115
|
+
(accumulated, current) => mergePolicies(accumulated, current),
|
|
3116
|
+
createEmptyPolicy(chain[0]?.id ?? policyId)
|
|
3117
|
+
);
|
|
3118
|
+
mergedPolicy.id = policyId;
|
|
3119
|
+
return {
|
|
3120
|
+
policy: mergedPolicy,
|
|
3121
|
+
inheritanceChain: chain.map((p) => p.id),
|
|
3122
|
+
depth: chain.length
|
|
3123
|
+
};
|
|
3124
|
+
}
|
|
3125
|
+
function createEmptyPolicy(id) {
|
|
3126
|
+
return {
|
|
3127
|
+
version: "1.0",
|
|
3128
|
+
id,
|
|
3129
|
+
name: "",
|
|
3130
|
+
applies_to: [],
|
|
3131
|
+
rules: []
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
3134
|
+
function mergePolicies(parent, child) {
|
|
3135
|
+
return {
|
|
3136
|
+
version: child.version,
|
|
3137
|
+
id: child.id,
|
|
3138
|
+
name: child.name || parent.name,
|
|
3139
|
+
description: child.description ?? parent.description,
|
|
3140
|
+
extends: child.extends,
|
|
3141
|
+
// Keep child's extends for reference
|
|
3142
|
+
applies_to: child.applies_to.length > 0 && child.applies_to[0] !== "*" ? child.applies_to : parent.applies_to,
|
|
3143
|
+
capabilities: mergeCapabilities(parent.capabilities, child.capabilities),
|
|
3144
|
+
rules: mergeRules(parent.rules, child.rules),
|
|
3145
|
+
metadata: {
|
|
3146
|
+
...parent.metadata,
|
|
3147
|
+
...child.metadata,
|
|
3148
|
+
// Merge tags
|
|
3149
|
+
tags: mergeArrays(parent.metadata?.tags, child.metadata?.tags)
|
|
3150
|
+
}
|
|
3151
|
+
};
|
|
3152
|
+
}
|
|
3153
|
+
function mergeCapabilities(parent, child) {
|
|
3154
|
+
if (!parent && !child) {
|
|
3155
|
+
return void 0;
|
|
3156
|
+
}
|
|
3157
|
+
if (!parent) {
|
|
3158
|
+
return child;
|
|
3159
|
+
}
|
|
3160
|
+
if (!child) {
|
|
3161
|
+
return parent;
|
|
3162
|
+
}
|
|
3163
|
+
return {
|
|
3164
|
+
default_effect: child.default_effect ?? parent.default_effect,
|
|
3165
|
+
allowed_tools: mergeArrays(parent.allowed_tools, child.allowed_tools),
|
|
3166
|
+
denied_tools: mergeArrays(parent.denied_tools, child.denied_tools),
|
|
3167
|
+
allowed_domains: mergeArrays(parent.allowed_domains, child.allowed_domains),
|
|
3168
|
+
denied_domains: mergeArrays(parent.denied_domains, child.denied_domains),
|
|
3169
|
+
max_budget_per_session: child.max_budget_per_session ?? parent.max_budget_per_session,
|
|
3170
|
+
max_budget_per_day: child.max_budget_per_day ?? parent.max_budget_per_day,
|
|
3171
|
+
may_spawn: child.may_spawn ?? parent.may_spawn,
|
|
3172
|
+
max_spawn_depth: child.max_spawn_depth ?? parent.max_spawn_depth
|
|
3173
|
+
};
|
|
3174
|
+
}
|
|
3175
|
+
function mergeRules(parentRules, childRules) {
|
|
3176
|
+
const allRules = [...parentRules, ...childRules];
|
|
3177
|
+
return allRules.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
3178
|
+
}
|
|
3179
|
+
function mergeArrays(parent, child) {
|
|
3180
|
+
const combined = [...parent ?? [], ...child ?? []];
|
|
3181
|
+
return [...new Set(combined)];
|
|
3182
|
+
}
|
|
3183
|
+
function evaluatePolicy(policy, action, resource, context) {
|
|
3184
|
+
for (const rule of policy.rules) {
|
|
3185
|
+
if (ruleMatches(rule, action, resource, context)) {
|
|
3186
|
+
return {
|
|
3187
|
+
allowed: rule.effect === "allow",
|
|
3188
|
+
effect: rule.effect,
|
|
3189
|
+
matchedRule: rule,
|
|
3190
|
+
matched: true,
|
|
3191
|
+
reason: `Rule "${rule.id}" matched: ${rule.description ?? rule.effect}`
|
|
3192
|
+
};
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
const defaultEffect = policy.capabilities?.default_effect ?? "deny";
|
|
3196
|
+
return {
|
|
3197
|
+
allowed: defaultEffect === "allow",
|
|
3198
|
+
effect: defaultEffect,
|
|
3199
|
+
matchedRule: void 0,
|
|
3200
|
+
matched: false,
|
|
3201
|
+
reason: `No rule matched, using default effect: ${defaultEffect}`
|
|
3202
|
+
};
|
|
3203
|
+
}
|
|
3204
|
+
function ruleMatches(rule, action, resource, context) {
|
|
3205
|
+
if (!matchesPattern(action, rule.actions)) {
|
|
3206
|
+
return false;
|
|
3207
|
+
}
|
|
3208
|
+
if (!matchesPattern(resource, rule.resources)) {
|
|
3209
|
+
return false;
|
|
3210
|
+
}
|
|
3211
|
+
if (rule.conditions) {
|
|
3212
|
+
if (!evaluateConditions(rule.conditions, context)) {
|
|
3213
|
+
return false;
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
return true;
|
|
3217
|
+
}
|
|
3218
|
+
function matchesPattern(value, patterns) {
|
|
3219
|
+
for (const pattern of patterns) {
|
|
3220
|
+
if (pattern === "*") {
|
|
3221
|
+
return true;
|
|
3222
|
+
}
|
|
3223
|
+
if (pattern.endsWith("*")) {
|
|
3224
|
+
const prefix = pattern.slice(0, -1);
|
|
3225
|
+
if (value.startsWith(prefix)) {
|
|
3226
|
+
return true;
|
|
3227
|
+
}
|
|
3228
|
+
} else if (pattern.startsWith("*")) {
|
|
3229
|
+
const suffix = pattern.slice(1);
|
|
3230
|
+
if (value.endsWith(suffix)) {
|
|
3231
|
+
return true;
|
|
3232
|
+
}
|
|
3233
|
+
} else if (pattern === value) {
|
|
3234
|
+
return true;
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
return false;
|
|
3238
|
+
}
|
|
3239
|
+
function evaluateConditions(conditions, context) {
|
|
3240
|
+
if (conditions.risk_levels && conditions.risk_levels.length > 0) {
|
|
3241
|
+
if (!conditions.risk_levels.includes(context.riskLevel)) {
|
|
3242
|
+
return false;
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
if (conditions.modes && conditions.modes.length > 0) {
|
|
3246
|
+
if (!conditions.modes.includes(context.mode)) {
|
|
3247
|
+
return false;
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
if (conditions.time_ranges && conditions.time_ranges.length > 0 && context.timestamp) {
|
|
3251
|
+
const currentTime = new Date(context.timestamp);
|
|
3252
|
+
const timeStr = currentTime.toTimeString().slice(0, 5);
|
|
3253
|
+
const inRange = conditions.time_ranges.some((range) => {
|
|
3254
|
+
return timeStr >= range.start && timeStr <= range.end;
|
|
3255
|
+
});
|
|
3256
|
+
if (!inRange) {
|
|
3257
|
+
return false;
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
return true;
|
|
3261
|
+
}
|
|
3262
|
+
function isToolAllowed(tool, capabilities) {
|
|
3263
|
+
if (!capabilities) {
|
|
3264
|
+
return false;
|
|
3265
|
+
}
|
|
3266
|
+
if (capabilities.denied_tools.length > 0 && matchesPattern(tool, capabilities.denied_tools)) {
|
|
3267
|
+
return false;
|
|
3268
|
+
}
|
|
3269
|
+
if (capabilities.allowed_tools.length > 0 && matchesPattern(tool, capabilities.allowed_tools)) {
|
|
3270
|
+
return true;
|
|
3271
|
+
}
|
|
3272
|
+
return capabilities.default_effect === "allow";
|
|
3273
|
+
}
|
|
3274
|
+
function isDomainAllowed(domain, capabilities) {
|
|
3275
|
+
if (!capabilities) {
|
|
3276
|
+
return false;
|
|
3277
|
+
}
|
|
3278
|
+
if (capabilities.denied_domains.length > 0 && matchesDomainPattern(domain, capabilities.denied_domains)) {
|
|
3279
|
+
return false;
|
|
3280
|
+
}
|
|
3281
|
+
if (capabilities.allowed_domains.length > 0 && matchesDomainPattern(domain, capabilities.allowed_domains)) {
|
|
3282
|
+
return true;
|
|
3283
|
+
}
|
|
3284
|
+
return capabilities.default_effect === "allow";
|
|
3285
|
+
}
|
|
3286
|
+
function matchesDomainPattern(domain, patterns) {
|
|
3287
|
+
for (const pattern of patterns) {
|
|
3288
|
+
if (pattern === "*") {
|
|
3289
|
+
return true;
|
|
3290
|
+
}
|
|
3291
|
+
if (pattern.startsWith("*.")) {
|
|
3292
|
+
const suffix = pattern.slice(1);
|
|
3293
|
+
if (domain === pattern.slice(2) || domain.endsWith(suffix)) {
|
|
3294
|
+
return true;
|
|
3295
|
+
}
|
|
3296
|
+
} else if (pattern === domain) {
|
|
3297
|
+
return true;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
return false;
|
|
3301
|
+
}
|
|
3302
|
+
function selectPolicy(criteria, repository, defaultPolicyId) {
|
|
3303
|
+
const candidatePolicies = [];
|
|
3304
|
+
const scoredPolicies = [];
|
|
3305
|
+
const policies = getAllPoliciesFromRepository(repository);
|
|
3306
|
+
for (const [policyId, policy] of policies) {
|
|
3307
|
+
candidatePolicies.push(policyId);
|
|
3308
|
+
const appliesToResult = checkAppliesTo(policy.applies_to, criteria.assetId);
|
|
3309
|
+
if (!appliesToResult.applies) {
|
|
3310
|
+
continue;
|
|
3311
|
+
}
|
|
3312
|
+
const score = scorePolicy(policy, criteria, appliesToResult.isExplicit);
|
|
3313
|
+
const reason = determineSelectionReason(appliesToResult, score);
|
|
3314
|
+
scoredPolicies.push({ policyId, policy, score, reason });
|
|
3315
|
+
}
|
|
3316
|
+
scoredPolicies.sort((a, b) => b.score.total - a.score.total);
|
|
3317
|
+
if (scoredPolicies.length > 0) {
|
|
3318
|
+
const best = scoredPolicies[0];
|
|
3319
|
+
return {
|
|
3320
|
+
policy: best.policy,
|
|
3321
|
+
policyId: best.policyId,
|
|
3322
|
+
selectionReason: best.reason,
|
|
3323
|
+
candidatePolicies,
|
|
3324
|
+
score: best.score
|
|
3325
|
+
};
|
|
3326
|
+
}
|
|
3327
|
+
if (defaultPolicyId && repository.has(defaultPolicyId)) {
|
|
3328
|
+
const defaultPolicy = repository.get(defaultPolicyId);
|
|
3329
|
+
if (defaultPolicy) {
|
|
3330
|
+
return {
|
|
3331
|
+
policy: defaultPolicy,
|
|
3332
|
+
policyId: defaultPolicyId,
|
|
3333
|
+
selectionReason: "default_policy",
|
|
3334
|
+
candidatePolicies
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
return {
|
|
3339
|
+
policy: null,
|
|
3340
|
+
policyId: null,
|
|
3341
|
+
selectionReason: "no_policy_found",
|
|
3342
|
+
candidatePolicies
|
|
3343
|
+
};
|
|
3344
|
+
}
|
|
3345
|
+
function getAllPoliciesFromRepository(repository) {
|
|
3346
|
+
if (repository instanceof Map) {
|
|
3347
|
+
return repository;
|
|
3348
|
+
}
|
|
3349
|
+
const result = /* @__PURE__ */ new Map();
|
|
3350
|
+
const anyRepo = repository;
|
|
3351
|
+
if (anyRepo.policies instanceof Map) {
|
|
3352
|
+
return anyRepo.policies;
|
|
3353
|
+
}
|
|
3354
|
+
return result;
|
|
3355
|
+
}
|
|
3356
|
+
function checkAppliesTo(appliesTo, assetId) {
|
|
3357
|
+
for (const pattern of appliesTo) {
|
|
3358
|
+
if (pattern === "*") {
|
|
3359
|
+
return { applies: true, isExplicit: false };
|
|
3360
|
+
}
|
|
3361
|
+
if (pattern === assetId) {
|
|
3362
|
+
return { applies: true, isExplicit: true };
|
|
3363
|
+
}
|
|
3364
|
+
if (pattern.endsWith("*") && assetId.startsWith(pattern.slice(0, -1))) {
|
|
3365
|
+
return { applies: true, isExplicit: false };
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
return { applies: false, isExplicit: false };
|
|
3369
|
+
}
|
|
3370
|
+
function scorePolicy(policy, criteria, isExplicitMatch) {
|
|
3371
|
+
let total = 0;
|
|
3372
|
+
let explicitMatch = 0;
|
|
3373
|
+
let riskLevelMatch = 0;
|
|
3374
|
+
let tagMatches = 0;
|
|
3375
|
+
if (isExplicitMatch) {
|
|
3376
|
+
explicitMatch = 100;
|
|
3377
|
+
total += 100;
|
|
3378
|
+
}
|
|
3379
|
+
const hasRiskLevelRule = policy.rules.some(
|
|
3380
|
+
(rule) => rule.conditions?.risk_levels?.includes(criteria.riskLevel)
|
|
3381
|
+
);
|
|
3382
|
+
if (hasRiskLevelRule) {
|
|
3383
|
+
riskLevelMatch = 50;
|
|
3384
|
+
total += 50;
|
|
3385
|
+
}
|
|
3386
|
+
const policyTags = policy.metadata?.tags ?? [];
|
|
3387
|
+
const criteriaTags = criteria.tags ?? [];
|
|
3388
|
+
for (const tag of criteriaTags) {
|
|
3389
|
+
if (policyTags.includes(tag)) {
|
|
3390
|
+
tagMatches++;
|
|
3391
|
+
total += 10;
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
const maxPriority = Math.max(...policy.rules.map((r) => r.priority ?? 0), 0);
|
|
3395
|
+
total += maxPriority;
|
|
3396
|
+
return {
|
|
3397
|
+
total,
|
|
3398
|
+
explicitMatch,
|
|
3399
|
+
riskLevelMatch,
|
|
3400
|
+
tagMatches,
|
|
3401
|
+
priority: maxPriority
|
|
3402
|
+
};
|
|
3403
|
+
}
|
|
3404
|
+
function determineSelectionReason(appliesToResult, score) {
|
|
3405
|
+
if (appliesToResult.isExplicit) {
|
|
3406
|
+
return "explicit_match";
|
|
3407
|
+
}
|
|
3408
|
+
if (score.riskLevelMatch > 0) {
|
|
3409
|
+
return "risk_level_match";
|
|
3410
|
+
}
|
|
3411
|
+
if (score.tagMatches > 0) {
|
|
3412
|
+
return "tag_match";
|
|
3413
|
+
}
|
|
3414
|
+
return "wildcard_match";
|
|
3415
|
+
}
|
|
3416
|
+
function createPolicySelector(repository, defaultPolicyId, cacheSize = 100) {
|
|
3417
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3418
|
+
let hits = 0;
|
|
3419
|
+
let misses = 0;
|
|
3420
|
+
function getCacheKey(criteria) {
|
|
3421
|
+
return `${criteria.assetId}|${criteria.riskLevel}|${criteria.mode}|${(criteria.tags ?? []).sort().join(",")}|${criteria.environment ?? ""}`;
|
|
3422
|
+
}
|
|
3423
|
+
function select(criteria) {
|
|
3424
|
+
const key = getCacheKey(criteria);
|
|
3425
|
+
if (cache.has(key)) {
|
|
3426
|
+
hits++;
|
|
3427
|
+
return cache.get(key);
|
|
3428
|
+
}
|
|
3429
|
+
misses++;
|
|
3430
|
+
const result = selectPolicy(criteria, repository, defaultPolicyId);
|
|
3431
|
+
if (cache.size >= cacheSize) {
|
|
3432
|
+
const firstKey = cache.keys().next().value;
|
|
3433
|
+
if (firstKey) {
|
|
3434
|
+
cache.delete(firstKey);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
cache.set(key, result);
|
|
3438
|
+
return result;
|
|
3439
|
+
}
|
|
3440
|
+
return {
|
|
3441
|
+
select,
|
|
3442
|
+
clearCache: () => cache.clear(),
|
|
3443
|
+
getCacheStats: () => ({ hits, misses, size: cache.size })
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
|
|
3447
|
+
// src/air/index.ts
|
|
3448
|
+
import { z as z3 } from "zod";
|
|
3449
|
+
var AIRVendorSchema = z3.object({
|
|
3450
|
+
/** Vendor identifier (e.g., "openai", "anthropic", "google") */
|
|
3451
|
+
id: z3.string().min(1),
|
|
3452
|
+
/** Human-readable vendor name */
|
|
3453
|
+
name: z3.string().optional(),
|
|
3454
|
+
/** Status of this vendor */
|
|
3455
|
+
status: z3.enum(["approved", "pending", "blocked"]).default("pending"),
|
|
3456
|
+
/** Optional approval ticket ID (Golden Thread) */
|
|
3457
|
+
approval_ticket: z3.string().optional(),
|
|
3458
|
+
/** When approval was granted */
|
|
3459
|
+
approved_at: z3.string().datetime().optional(),
|
|
3460
|
+
/** Who approved this vendor */
|
|
3461
|
+
approved_by: z3.string().email().optional(),
|
|
3462
|
+
/** Expiration date for approval */
|
|
3463
|
+
expires_at: z3.string().datetime().optional(),
|
|
3464
|
+
/** Vendor-specific notes */
|
|
3465
|
+
notes: z3.string().optional()
|
|
3466
|
+
});
|
|
3467
|
+
var AIRModelSchema = z3.object({
|
|
3468
|
+
/** Model identifier (e.g., "gpt-4", "claude-3-opus") */
|
|
3469
|
+
id: z3.string().min(1),
|
|
3470
|
+
/** Vendor that provides this model */
|
|
3471
|
+
vendor_id: z3.string().min(1),
|
|
3472
|
+
/** Human-readable model name */
|
|
3473
|
+
name: z3.string().optional(),
|
|
3474
|
+
/** Model version pattern (supports wildcards like "gpt-4*") */
|
|
3475
|
+
version_pattern: z3.string().optional(),
|
|
3476
|
+
/** Status of this model */
|
|
3477
|
+
status: z3.enum(["approved", "pending", "blocked"]).default("pending"),
|
|
3478
|
+
/** Maximum allowed parameters (for on-premise deployment considerations) */
|
|
3479
|
+
max_parameters: z3.number().positive().optional(),
|
|
3480
|
+
/** Risk level assigned to this model */
|
|
3481
|
+
risk_level: z3.enum(["minimal", "limited", "high", "unacceptable"]).optional(),
|
|
3482
|
+
/** Optional approval ticket ID */
|
|
3483
|
+
approval_ticket: z3.string().optional(),
|
|
3484
|
+
/** When approval was granted */
|
|
3485
|
+
approved_at: z3.string().datetime().optional(),
|
|
3486
|
+
/** Expiration date for approval */
|
|
3487
|
+
expires_at: z3.string().datetime().optional(),
|
|
3488
|
+
/** Model-specific notes */
|
|
3489
|
+
notes: z3.string().optional()
|
|
3490
|
+
});
|
|
3491
|
+
var AIRRegionSchema = z3.object({
|
|
3492
|
+
/** Region code (e.g., "us-east-1", "eu-west-1", "EU", "US") */
|
|
3493
|
+
code: z3.string().min(1),
|
|
3494
|
+
/** Human-readable region name */
|
|
3495
|
+
name: z3.string().optional(),
|
|
3496
|
+
/** Status of this region */
|
|
3497
|
+
status: z3.enum(["allowed", "restricted", "blocked"]).default("allowed"),
|
|
3498
|
+
/** Jurisdictions this region falls under (e.g., ["GDPR", "EU-AI-ACT"]) */
|
|
3499
|
+
jurisdictions: z3.array(z3.string()).default([]),
|
|
3500
|
+
/** Data residency requirements */
|
|
3501
|
+
data_residency: z3.enum(["required", "preferred", "none"]).default("none"),
|
|
3502
|
+
/** Notes about this region */
|
|
3503
|
+
notes: z3.string().optional()
|
|
3504
|
+
});
|
|
3505
|
+
var AIRRegistryConstraintsSchema = z3.object({
|
|
3506
|
+
/** List of approved vendors */
|
|
3507
|
+
allowed_vendors: z3.array(AIRVendorSchema).default([]),
|
|
3508
|
+
/** List of blocked vendors */
|
|
3509
|
+
blocked_vendors: z3.array(z3.string()).default([]),
|
|
3510
|
+
/** List of approved regions */
|
|
3511
|
+
allowed_regions: z3.array(AIRRegionSchema).default([]),
|
|
3512
|
+
/** List of blocked regions */
|
|
3513
|
+
blocked_regions: z3.array(z3.string()).default([]),
|
|
3514
|
+
/** List of approved models */
|
|
3515
|
+
allowed_models: z3.array(AIRModelSchema).default([]),
|
|
3516
|
+
/** List of blocked models (patterns supported) */
|
|
3517
|
+
blocked_models: z3.array(z3.string()).default([]),
|
|
3518
|
+
/** Maximum model parameters allowed */
|
|
3519
|
+
max_model_parameters: z3.number().positive().optional(),
|
|
3520
|
+
/** Require vendor approval before use */
|
|
3521
|
+
require_vendor_approval: z3.boolean().default(true),
|
|
3522
|
+
/** Require model approval before use */
|
|
3523
|
+
require_model_approval: z3.boolean().default(true),
|
|
3524
|
+
/** Default behavior for unknown vendors: "block" or "request_approval" */
|
|
3525
|
+
unknown_vendor_behavior: z3.enum(["block", "request_approval"]).default("request_approval"),
|
|
3526
|
+
/** Default behavior for unknown models */
|
|
3527
|
+
unknown_model_behavior: z3.enum(["block", "request_approval"]).default("request_approval")
|
|
3528
|
+
});
|
|
3529
|
+
var AIRPIIFilterConfigSchema = z3.object({
|
|
3530
|
+
/** Whether PII filtering is enabled */
|
|
3531
|
+
enabled: z3.boolean().default(false),
|
|
3532
|
+
/** PII types to filter (e.g., ["email", "phone", "ssn", "credit_card"]) */
|
|
3533
|
+
filter_types: z3.array(z3.string()).default([]),
|
|
3534
|
+
/** Action when PII is detected: "redact", "block", "warn", "audit" */
|
|
3535
|
+
action: z3.enum(["redact", "block", "warn", "audit"]).default("warn"),
|
|
3536
|
+
/** Custom patterns to detect (regex) */
|
|
3537
|
+
custom_patterns: z3.array(z3.object({
|
|
3538
|
+
name: z3.string(),
|
|
3539
|
+
pattern: z3.string(),
|
|
3540
|
+
action: z3.enum(["redact", "block", "warn", "audit"]).optional()
|
|
3541
|
+
})).default([])
|
|
3542
|
+
});
|
|
3543
|
+
var AIRToxicityFilterConfigSchema = z3.object({
|
|
3544
|
+
/** Whether toxicity filtering is enabled */
|
|
3545
|
+
enabled: z3.boolean().default(false),
|
|
3546
|
+
/** Toxicity threshold (0-1) */
|
|
3547
|
+
threshold: z3.number().min(0).max(1).default(0.7),
|
|
3548
|
+
/** Categories to filter (e.g., ["hate", "violence", "sexual"]) */
|
|
3549
|
+
categories: z3.array(z3.string()).default([]),
|
|
3550
|
+
/** Action when toxicity is detected */
|
|
3551
|
+
action: z3.enum(["block", "warn", "audit"]).default("warn")
|
|
3552
|
+
});
|
|
3553
|
+
var AIRRuntimeConstraintsSchema = z3.object({
|
|
3554
|
+
/** PII filtering configuration */
|
|
3555
|
+
pii_filter: AIRPIIFilterConfigSchema.optional(),
|
|
3556
|
+
/** Toxicity filtering configuration */
|
|
3557
|
+
toxicity_filter: AIRToxicityFilterConfigSchema.optional(),
|
|
3558
|
+
/** Data retention period in days (0 = no retention) */
|
|
3559
|
+
data_retention_days: z3.number().int().min(0).default(90),
|
|
3560
|
+
/** Whether to enable output watermarking */
|
|
3561
|
+
watermark_enabled: z3.boolean().default(false),
|
|
3562
|
+
/** Logging level: "none", "errors", "all" */
|
|
3563
|
+
logging_level: z3.enum(["none", "errors", "all"]).default("all"),
|
|
3564
|
+
/** Maximum tokens per request */
|
|
3565
|
+
max_tokens_per_request: z3.number().int().positive().optional(),
|
|
3566
|
+
/** Maximum requests per minute */
|
|
3567
|
+
max_requests_per_minute: z3.number().int().positive().optional(),
|
|
3568
|
+
/** Maximum cost per request in USD */
|
|
3569
|
+
max_cost_per_request_usd: z3.number().positive().optional(),
|
|
3570
|
+
/** Maximum cost per day in USD */
|
|
3571
|
+
max_cost_per_day_usd: z3.number().positive().optional(),
|
|
3572
|
+
/** Session timeout in seconds */
|
|
3573
|
+
session_timeout_seconds: z3.number().int().positive().optional(),
|
|
3574
|
+
/** Require human approval for specific actions */
|
|
3575
|
+
human_approval_required: z3.array(z3.string()).default([]),
|
|
3576
|
+
/** Kill switch configuration */
|
|
3577
|
+
kill_switch: z3.object({
|
|
3578
|
+
enabled: z3.boolean().default(true),
|
|
3579
|
+
channel: z3.enum(["sse", "polling", "file"]).default("sse"),
|
|
3580
|
+
poll_interval_ms: z3.number().int().positive().default(5e3)
|
|
3581
|
+
}).optional(),
|
|
3582
|
+
/** Grounding check configuration (prevent hallucination) */
|
|
3583
|
+
grounding_check: z3.object({
|
|
3584
|
+
enabled: z3.boolean().default(false),
|
|
3585
|
+
confidence_threshold: z3.number().min(0).max(1).default(0.8),
|
|
3586
|
+
action: z3.enum(["block", "warn", "audit"]).default("warn")
|
|
3587
|
+
}).optional()
|
|
3588
|
+
});
|
|
3589
|
+
var AIRBuildConstraintsSchema = z3.object({
|
|
3590
|
+
/** Require Golden Thread linkage (business justification) */
|
|
3591
|
+
require_golden_thread: z3.boolean().default(true),
|
|
3592
|
+
/** Require asset card for all AI assets */
|
|
3593
|
+
require_asset_card: z3.boolean().default(true),
|
|
3594
|
+
/** Require risk classification */
|
|
3595
|
+
require_risk_classification: z3.boolean().default(true),
|
|
3596
|
+
/** Require model card documentation */
|
|
3597
|
+
require_model_card: z3.boolean().default(false),
|
|
3598
|
+
/** Require security review for high-risk assets */
|
|
3599
|
+
require_security_review: z3.boolean().default(false),
|
|
3600
|
+
/** Minimum risk levels that require security review */
|
|
3601
|
+
security_review_risk_levels: z3.array(z3.enum(["high", "unacceptable"])).default(["high", "unacceptable"]),
|
|
3602
|
+
/** Require governance.lock file */
|
|
3603
|
+
require_governance_lock: z3.boolean().default(true),
|
|
3604
|
+
/** governance.lock must be signed */
|
|
3605
|
+
require_lock_signature: z3.boolean().default(false),
|
|
3606
|
+
/** Block merge on validation failure */
|
|
3607
|
+
block_on_failure: z3.boolean().default(true),
|
|
3608
|
+
/** Generate SARIF report for GitHub Security tab */
|
|
3609
|
+
generate_sarif: z3.boolean().default(true),
|
|
3610
|
+
/** Required approvals before deployment */
|
|
3611
|
+
required_approvals: z3.array(z3.object({
|
|
3612
|
+
role: z3.string(),
|
|
3613
|
+
count: z3.number().int().positive().default(1)
|
|
3614
|
+
})).default([]),
|
|
3615
|
+
/** Allowed deployment environments */
|
|
3616
|
+
allowed_environments: z3.array(z3.string()).default(["development", "staging", "production"]),
|
|
3617
|
+
/** Environment-specific constraints */
|
|
3618
|
+
environment_constraints: z3.record(z3.object({
|
|
3619
|
+
require_approval: z3.boolean().default(false),
|
|
3620
|
+
approvers: z3.array(z3.string()).default([]),
|
|
3621
|
+
require_testing: z3.boolean().default(false),
|
|
3622
|
+
test_coverage_threshold: z3.number().min(0).max(100).optional()
|
|
3623
|
+
})).optional()
|
|
3624
|
+
});
|
|
3625
|
+
var AIRPolicySourceSchema = z3.object({
|
|
3626
|
+
/** Unique identifier for this source */
|
|
3627
|
+
id: z3.string().min(1),
|
|
3628
|
+
/** Type of source: "pdf", "url", "confluence", "jira", "manual" */
|
|
3629
|
+
type: z3.enum(["pdf", "url", "confluence", "jira", "manual"]),
|
|
3630
|
+
/** URI to the source document */
|
|
3631
|
+
uri: z3.string(),
|
|
3632
|
+
/** SHA-256 hash of the source content */
|
|
3633
|
+
content_hash: z3.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
3634
|
+
/** When the source was last fetched */
|
|
3635
|
+
fetched_at: z3.string().datetime(),
|
|
3636
|
+
/** Title of the policy document */
|
|
3637
|
+
title: z3.string().optional(),
|
|
3638
|
+
/** Version of the policy document */
|
|
3639
|
+
version: z3.string().optional(),
|
|
3640
|
+
/** Confidence score of extraction (0-1) */
|
|
3641
|
+
extraction_confidence: z3.number().min(0).max(1).optional()
|
|
3642
|
+
});
|
|
3643
|
+
var AIRMetadataSchema = z3.object({
|
|
3644
|
+
/** When this AIR was generated */
|
|
3645
|
+
generated_at: z3.string().datetime(),
|
|
3646
|
+
/** Tool/system that generated this AIR */
|
|
3647
|
+
generated_by: z3.string().default("aigrc-policy-compiler"),
|
|
3648
|
+
/** Version of the policy compiler */
|
|
3649
|
+
compiler_version: z3.string(),
|
|
3650
|
+
/** Organization this AIR belongs to */
|
|
3651
|
+
organization: z3.string().optional(),
|
|
3652
|
+
/** Environment this AIR is for (e.g., "production", "staging") */
|
|
3653
|
+
environment: z3.string().optional(),
|
|
3654
|
+
/** Human-readable description */
|
|
3655
|
+
description: z3.string().optional(),
|
|
3656
|
+
/** Tags for categorization */
|
|
3657
|
+
tags: z3.array(z3.string()).default([]),
|
|
3658
|
+
/** Custom metadata fields */
|
|
3659
|
+
custom: z3.record(z3.unknown()).optional()
|
|
3660
|
+
});
|
|
3661
|
+
var AIRSchema = z3.object({
|
|
3662
|
+
/** Schema version for forward compatibility */
|
|
3663
|
+
version: z3.literal("1.0"),
|
|
3664
|
+
/** Unique identifier for this AIR */
|
|
3665
|
+
id: z3.string().uuid(),
|
|
3666
|
+
/** Human-readable name */
|
|
3667
|
+
name: z3.string().min(1).max(200),
|
|
3668
|
+
/** SHA-256 hash of this AIR (computed after serialization) */
|
|
3669
|
+
hash: z3.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
|
|
3670
|
+
/** Policy sources that contributed to this AIR */
|
|
3671
|
+
policy_sources: z3.array(AIRPolicySourceSchema).default([]),
|
|
3672
|
+
/** Registry constraints (vendor/model/region governance) */
|
|
3673
|
+
registry: AIRRegistryConstraintsSchema.default({}),
|
|
3674
|
+
/** Runtime constraints (execution-time governance) */
|
|
3675
|
+
runtime: AIRRuntimeConstraintsSchema.default({}),
|
|
3676
|
+
/** Build constraints (CI/CD governance) */
|
|
3677
|
+
build: AIRBuildConstraintsSchema.default({}),
|
|
3678
|
+
/** Metadata about this AIR */
|
|
3679
|
+
metadata: AIRMetadataSchema,
|
|
3680
|
+
/** When this AIR expires (forces re-compilation) */
|
|
3681
|
+
expires_at: z3.string().datetime().optional(),
|
|
3682
|
+
/** Digital signatures for verification */
|
|
3683
|
+
signatures: z3.array(z3.object({
|
|
3684
|
+
/** Signer identity (email or system ID) */
|
|
3685
|
+
signer: z3.string(),
|
|
3686
|
+
/** Algorithm used (RS256, ES256) */
|
|
3687
|
+
algorithm: z3.enum(["RS256", "ES256"]),
|
|
3688
|
+
/** Base64-encoded signature */
|
|
3689
|
+
signature: z3.string(),
|
|
3690
|
+
/** When the signature was created */
|
|
3691
|
+
signed_at: z3.string().datetime(),
|
|
3692
|
+
/** Key ID for verification */
|
|
3693
|
+
key_id: z3.string().optional()
|
|
3694
|
+
})).default([])
|
|
3695
|
+
});
|
|
3696
|
+
function createEmptyAIR(name, compilerVersion = "1.0.0") {
|
|
3697
|
+
return {
|
|
3698
|
+
version: "1.0",
|
|
3699
|
+
id: crypto.randomUUID(),
|
|
3700
|
+
name,
|
|
3701
|
+
policy_sources: [],
|
|
3702
|
+
registry: {
|
|
3703
|
+
allowed_vendors: [],
|
|
3704
|
+
blocked_vendors: [],
|
|
3705
|
+
allowed_regions: [],
|
|
3706
|
+
blocked_regions: [],
|
|
3707
|
+
allowed_models: [],
|
|
3708
|
+
blocked_models: [],
|
|
3709
|
+
require_vendor_approval: true,
|
|
3710
|
+
require_model_approval: true,
|
|
3711
|
+
unknown_vendor_behavior: "request_approval",
|
|
3712
|
+
unknown_model_behavior: "request_approval"
|
|
3713
|
+
},
|
|
3714
|
+
runtime: {
|
|
3715
|
+
data_retention_days: 90,
|
|
3716
|
+
watermark_enabled: false,
|
|
3717
|
+
logging_level: "all",
|
|
3718
|
+
human_approval_required: []
|
|
3719
|
+
},
|
|
3720
|
+
build: {
|
|
3721
|
+
require_golden_thread: true,
|
|
3722
|
+
require_asset_card: true,
|
|
3723
|
+
require_risk_classification: true,
|
|
3724
|
+
require_model_card: false,
|
|
3725
|
+
require_security_review: false,
|
|
3726
|
+
security_review_risk_levels: ["high", "unacceptable"],
|
|
3727
|
+
require_governance_lock: true,
|
|
3728
|
+
require_lock_signature: false,
|
|
3729
|
+
block_on_failure: true,
|
|
3730
|
+
generate_sarif: true,
|
|
3731
|
+
required_approvals: [],
|
|
3732
|
+
allowed_environments: ["development", "staging", "production"]
|
|
3733
|
+
},
|
|
3734
|
+
metadata: {
|
|
3735
|
+
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3736
|
+
generated_by: "aigrc-policy-compiler",
|
|
3737
|
+
compiler_version: compilerVersion,
|
|
3738
|
+
tags: []
|
|
3739
|
+
},
|
|
3740
|
+
signatures: []
|
|
3741
|
+
};
|
|
3742
|
+
}
|
|
3743
|
+
function validateAIR(air) {
|
|
3744
|
+
const result = AIRSchema.safeParse(air);
|
|
3745
|
+
if (result.success) {
|
|
3746
|
+
return { valid: true, errors: [] };
|
|
3747
|
+
}
|
|
3748
|
+
return {
|
|
3749
|
+
valid: false,
|
|
3750
|
+
errors: result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`)
|
|
3751
|
+
};
|
|
3752
|
+
}
|
|
3753
|
+
function isVendorAllowed(vendorId, registry2) {
|
|
3754
|
+
if (registry2.blocked_vendors.includes(vendorId)) {
|
|
3755
|
+
return { allowed: false, reason: "Vendor is blocked", requiresApproval: false };
|
|
3756
|
+
}
|
|
3757
|
+
const allowedVendor = registry2.allowed_vendors.find((v) => v.id === vendorId);
|
|
3758
|
+
if (allowedVendor) {
|
|
3759
|
+
if (allowedVendor.status === "approved") {
|
|
3760
|
+
if (allowedVendor.expires_at && new Date(allowedVendor.expires_at) < /* @__PURE__ */ new Date()) {
|
|
3761
|
+
return { allowed: false, reason: "Vendor approval has expired", requiresApproval: true };
|
|
3762
|
+
}
|
|
3763
|
+
return { allowed: true, reason: "Vendor is approved", requiresApproval: false };
|
|
3764
|
+
}
|
|
3765
|
+
if (allowedVendor.status === "pending") {
|
|
3766
|
+
return { allowed: false, reason: "Vendor approval is pending", requiresApproval: true };
|
|
3767
|
+
}
|
|
3768
|
+
return { allowed: false, reason: "Vendor is blocked", requiresApproval: false };
|
|
3769
|
+
}
|
|
3770
|
+
if (registry2.unknown_vendor_behavior === "block") {
|
|
3771
|
+
return { allowed: false, reason: "Unknown vendor (blocked by policy)", requiresApproval: false };
|
|
3772
|
+
}
|
|
3773
|
+
return { allowed: false, reason: "Unknown vendor (requires approval)", requiresApproval: true };
|
|
3774
|
+
}
|
|
3775
|
+
function isModelAllowed(modelId, vendorId, registry2) {
|
|
3776
|
+
for (const pattern of registry2.blocked_models) {
|
|
3777
|
+
if (matchesPattern2(modelId, pattern)) {
|
|
3778
|
+
return { allowed: false, reason: `Model matches blocked pattern: ${pattern}`, requiresApproval: false };
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
const allowedModel = registry2.allowed_models.find(
|
|
3782
|
+
(m) => m.id === modelId && m.vendor_id === vendorId
|
|
3783
|
+
);
|
|
3784
|
+
if (allowedModel) {
|
|
3785
|
+
if (allowedModel.status === "approved") {
|
|
3786
|
+
if (allowedModel.expires_at && new Date(allowedModel.expires_at) < /* @__PURE__ */ new Date()) {
|
|
3787
|
+
return { allowed: false, reason: "Model approval has expired", requiresApproval: true };
|
|
3788
|
+
}
|
|
3789
|
+
return { allowed: true, reason: "Model is approved", requiresApproval: false };
|
|
3790
|
+
}
|
|
3791
|
+
if (allowedModel.status === "pending") {
|
|
3792
|
+
return { allowed: false, reason: "Model approval is pending", requiresApproval: true };
|
|
3793
|
+
}
|
|
3794
|
+
return { allowed: false, reason: "Model is blocked", requiresApproval: false };
|
|
3795
|
+
}
|
|
3796
|
+
const matchingModel = registry2.allowed_models.find(
|
|
3797
|
+
(m) => m.vendor_id === vendorId && m.version_pattern && matchesPattern2(modelId, m.version_pattern)
|
|
3798
|
+
);
|
|
3799
|
+
if (matchingModel && matchingModel.status === "approved") {
|
|
3800
|
+
return { allowed: true, reason: `Model matches approved pattern: ${matchingModel.version_pattern}`, requiresApproval: false };
|
|
3801
|
+
}
|
|
3802
|
+
if (registry2.unknown_model_behavior === "block") {
|
|
3803
|
+
return { allowed: false, reason: "Unknown model (blocked by policy)", requiresApproval: false };
|
|
3804
|
+
}
|
|
3805
|
+
return { allowed: false, reason: "Unknown model (requires approval)", requiresApproval: true };
|
|
3806
|
+
}
|
|
3807
|
+
function isRegionAllowed(regionCode, registry2) {
|
|
3808
|
+
if (registry2.blocked_regions.includes(regionCode)) {
|
|
3809
|
+
return { allowed: false, reason: "Region is blocked", dataResidency: "none" };
|
|
3810
|
+
}
|
|
3811
|
+
const allowedRegion = registry2.allowed_regions.find((r) => r.code === regionCode);
|
|
3812
|
+
if (allowedRegion) {
|
|
3813
|
+
if (allowedRegion.status === "blocked") {
|
|
3814
|
+
return { allowed: false, reason: "Region is blocked", dataResidency: "none" };
|
|
3815
|
+
}
|
|
3816
|
+
if (allowedRegion.status === "restricted") {
|
|
3817
|
+
return { allowed: true, reason: "Region is restricted (requires approval)", dataResidency: allowedRegion.data_residency };
|
|
3818
|
+
}
|
|
3819
|
+
return { allowed: true, reason: "Region is allowed", dataResidency: allowedRegion.data_residency };
|
|
3820
|
+
}
|
|
3821
|
+
if (registry2.allowed_regions.length === 0) {
|
|
3822
|
+
return { allowed: true, reason: "No region restrictions", dataResidency: "none" };
|
|
3823
|
+
}
|
|
3824
|
+
return { allowed: false, reason: "Region not in allowed list", dataResidency: "none" };
|
|
3825
|
+
}
|
|
3826
|
+
function matchesPattern2(value, pattern) {
|
|
3827
|
+
if (pattern === "*") {
|
|
3828
|
+
return true;
|
|
3829
|
+
}
|
|
3830
|
+
if (pattern.endsWith("*")) {
|
|
3831
|
+
return value.startsWith(pattern.slice(0, -1));
|
|
3832
|
+
}
|
|
3833
|
+
if (pattern.startsWith("*")) {
|
|
3834
|
+
return value.endsWith(pattern.slice(1));
|
|
3835
|
+
}
|
|
3836
|
+
return value === pattern;
|
|
3837
|
+
}
|
|
3838
|
+
|
|
3839
|
+
// src/governance-lock/index.ts
|
|
3840
|
+
import { z as z4 } from "zod";
|
|
3841
|
+
import * as yaml2 from "yaml";
|
|
3842
|
+
var GovernanceLockSignatureSchema = z4.object({
|
|
3843
|
+
/** Signer identity (email or system ID) */
|
|
3844
|
+
signer: z4.string().min(1),
|
|
3845
|
+
/** Role of the signer (e.g., "CISO", "PolicyOwner", "SecurityLead") */
|
|
3846
|
+
role: z4.string().optional(),
|
|
3847
|
+
/** Algorithm used: RS256 (RSA-SHA256) or ES256 (ECDSA-P256) */
|
|
3848
|
+
algorithm: z4.enum(["RS256", "ES256"]),
|
|
3849
|
+
/** Base64-encoded signature */
|
|
3850
|
+
signature: z4.string().min(1),
|
|
3851
|
+
/** When the signature was created */
|
|
3852
|
+
signed_at: z4.string().datetime(),
|
|
3853
|
+
/** Key ID for key rotation support */
|
|
3854
|
+
key_id: z4.string().optional(),
|
|
3855
|
+
/** Expiration of this signature (optional, separate from lock expiration) */
|
|
3856
|
+
expires_at: z4.string().datetime().optional(),
|
|
3857
|
+
/** Certificate chain for verification (optional) */
|
|
3858
|
+
certificate_chain: z4.array(z4.string()).optional()
|
|
3859
|
+
});
|
|
3860
|
+
var GovernanceLockPolicySourceSchema = z4.object({
|
|
3861
|
+
/** Unique identifier for this source */
|
|
3862
|
+
id: z4.string().min(1),
|
|
3863
|
+
/** Type of source */
|
|
3864
|
+
type: z4.enum(["pdf", "url", "confluence", "jira", "manual"]),
|
|
3865
|
+
/** URI to the source document */
|
|
3866
|
+
uri: z4.string(),
|
|
3867
|
+
/** SHA-256 hash of the source content at time of compilation */
|
|
3868
|
+
content_hash: z4.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
3869
|
+
/** When the source was fetched */
|
|
3870
|
+
fetched_at: z4.string().datetime(),
|
|
3871
|
+
/** Title of the policy document */
|
|
3872
|
+
title: z4.string().optional(),
|
|
3873
|
+
/** Version of the policy document */
|
|
3874
|
+
version: z4.string().optional()
|
|
3875
|
+
});
|
|
3876
|
+
var GovernanceLockRegistryConstraintsSchema = z4.object({
|
|
3877
|
+
/** List of approved vendor IDs */
|
|
3878
|
+
allowed_vendor_ids: z4.array(z4.string()).default([]),
|
|
3879
|
+
/** List of blocked vendor IDs */
|
|
3880
|
+
blocked_vendor_ids: z4.array(z4.string()).default([]),
|
|
3881
|
+
/** List of approved region codes */
|
|
3882
|
+
allowed_region_codes: z4.array(z4.string()).default([]),
|
|
3883
|
+
/** List of blocked region codes */
|
|
3884
|
+
blocked_region_codes: z4.array(z4.string()).default([]),
|
|
3885
|
+
/** List of approved model patterns */
|
|
3886
|
+
allowed_model_patterns: z4.array(z4.string()).default([]),
|
|
3887
|
+
/** List of blocked model patterns */
|
|
3888
|
+
blocked_model_patterns: z4.array(z4.string()).default([]),
|
|
3889
|
+
/** Maximum model parameters allowed */
|
|
3890
|
+
max_model_parameters: z4.number().positive().optional()
|
|
3891
|
+
});
|
|
3892
|
+
var GovernanceLockRuntimeConstraintsSchema = z4.object({
|
|
3893
|
+
/** Whether PII filtering is required */
|
|
3894
|
+
pii_filter_enabled: z4.boolean().default(false),
|
|
3895
|
+
/** PII filter action */
|
|
3896
|
+
pii_filter_action: z4.enum(["redact", "block", "warn", "audit"]).optional(),
|
|
3897
|
+
/** Whether toxicity filtering is required */
|
|
3898
|
+
toxicity_filter_enabled: z4.boolean().default(false),
|
|
3899
|
+
/** Toxicity threshold */
|
|
3900
|
+
toxicity_threshold: z4.number().min(0).max(1).optional(),
|
|
3901
|
+
/** Data retention period in days */
|
|
3902
|
+
data_retention_days: z4.number().int().min(0).default(90),
|
|
3903
|
+
/** Whether watermarking is required */
|
|
3904
|
+
watermark_enabled: z4.boolean().default(false),
|
|
3905
|
+
/** Logging level */
|
|
3906
|
+
logging_level: z4.enum(["none", "errors", "all"]).default("all"),
|
|
3907
|
+
/** Maximum tokens per request */
|
|
3908
|
+
max_tokens_per_request: z4.number().int().positive().optional(),
|
|
3909
|
+
/** Maximum cost per day in USD */
|
|
3910
|
+
max_cost_per_day_usd: z4.number().positive().optional(),
|
|
3911
|
+
/** Kill switch enabled */
|
|
3912
|
+
kill_switch_enabled: z4.boolean().default(true)
|
|
3913
|
+
});
|
|
3914
|
+
var GovernanceLockBuildConstraintsSchema = z4.object({
|
|
3915
|
+
/** Require Golden Thread linkage */
|
|
3916
|
+
require_golden_thread: z4.boolean().default(true),
|
|
3917
|
+
/** Require asset card */
|
|
3918
|
+
require_asset_card: z4.boolean().default(true),
|
|
3919
|
+
/** Require risk classification */
|
|
3920
|
+
require_risk_classification: z4.boolean().default(true),
|
|
3921
|
+
/** Require model card */
|
|
3922
|
+
require_model_card: z4.boolean().default(false),
|
|
3923
|
+
/** Require security review for high risk */
|
|
3924
|
+
require_security_review: z4.boolean().default(false),
|
|
3925
|
+
/** Block merge on validation failure */
|
|
3926
|
+
block_on_failure: z4.boolean().default(true),
|
|
3927
|
+
/** Generate SARIF report */
|
|
3928
|
+
generate_sarif: z4.boolean().default(true),
|
|
3929
|
+
/** Allowed environments */
|
|
3930
|
+
allowed_environments: z4.array(z4.string()).default(["development", "staging", "production"])
|
|
3931
|
+
});
|
|
3932
|
+
var GovernanceLockConstraintsSchema = z4.object({
|
|
3933
|
+
/** Registry constraints (vendor/model/region) */
|
|
3934
|
+
registry: GovernanceLockRegistryConstraintsSchema.default({}),
|
|
3935
|
+
/** Runtime constraints */
|
|
3936
|
+
runtime: GovernanceLockRuntimeConstraintsSchema.default({}),
|
|
3937
|
+
/** Build constraints */
|
|
3938
|
+
build: GovernanceLockBuildConstraintsSchema.default({})
|
|
3939
|
+
});
|
|
3940
|
+
var GovernanceLockSchema = z4.object({
|
|
3941
|
+
/** Schema version for forward compatibility */
|
|
3942
|
+
version: z4.literal("1.0"),
|
|
3943
|
+
/** When this lock file was generated */
|
|
3944
|
+
generated_at: z4.string().datetime(),
|
|
3945
|
+
/** SHA-256 hash of the compiled policy (AIR) */
|
|
3946
|
+
policy_hash: z4.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
3947
|
+
/** Name of this policy lock */
|
|
3948
|
+
name: z4.string().min(1).max(200).optional(),
|
|
3949
|
+
/** Description of this lock file */
|
|
3950
|
+
description: z4.string().max(500).optional(),
|
|
3951
|
+
/** Policy sources that contributed to this lock */
|
|
3952
|
+
policy_sources: z4.array(GovernanceLockPolicySourceSchema).default([]),
|
|
3953
|
+
/** Compiled constraints (subset of AIR) */
|
|
3954
|
+
constraints: GovernanceLockConstraintsSchema.default({}),
|
|
3955
|
+
/** Digital signatures from policy owners */
|
|
3956
|
+
signatures: z4.array(GovernanceLockSignatureSchema).default([]),
|
|
3957
|
+
/** When this lock file expires (forces re-compilation) */
|
|
3958
|
+
expires_at: z4.string().datetime(),
|
|
3959
|
+
/** Tool/system that generated this lock */
|
|
3960
|
+
generated_by: z4.string().default("aigrc-policy-compiler"),
|
|
3961
|
+
/** Version of the generator */
|
|
3962
|
+
generator_version: z4.string().default("1.0.0"),
|
|
3963
|
+
/** Organization this lock belongs to */
|
|
3964
|
+
organization: z4.string().optional(),
|
|
3965
|
+
/** Environment this lock is for */
|
|
3966
|
+
environment: z4.string().optional(),
|
|
3967
|
+
/** Reference to the full AIR document (optional) */
|
|
3968
|
+
air_reference: z4.object({
|
|
3969
|
+
/** AIR document ID */
|
|
3970
|
+
id: z4.string().uuid(),
|
|
3971
|
+
/** AIR document location (URI) */
|
|
3972
|
+
location: z4.string().optional(),
|
|
3973
|
+
/** AIR document hash */
|
|
3974
|
+
hash: z4.string().regex(/^sha256:[a-f0-9]{64}$/)
|
|
3975
|
+
}).optional(),
|
|
3976
|
+
/** Custom metadata fields */
|
|
3977
|
+
metadata: z4.record(z4.unknown()).optional()
|
|
3978
|
+
});
|
|
3979
|
+
async function computeHash(data) {
|
|
3980
|
+
const encoder = new TextEncoder();
|
|
3981
|
+
const dataBuffer = encoder.encode(data);
|
|
3982
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
|
|
3983
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
3984
|
+
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3985
|
+
return `sha256:${hashHex}`;
|
|
3986
|
+
}
|
|
3987
|
+
async function createGovernanceLock(air, options = {}) {
|
|
3988
|
+
const now = /* @__PURE__ */ new Date();
|
|
3989
|
+
const expiresAt = new Date(now);
|
|
3990
|
+
expiresAt.setDate(expiresAt.getDate() + (options.expiresInDays ?? 30));
|
|
3991
|
+
const airForHashing = { ...air, signatures: [] };
|
|
3992
|
+
const policyHash = await computeHash(JSON.stringify(airForHashing));
|
|
3993
|
+
const constraints = {
|
|
3994
|
+
registry: {
|
|
3995
|
+
allowed_vendor_ids: air.registry.allowed_vendors.map((v) => v.id),
|
|
3996
|
+
blocked_vendor_ids: air.registry.blocked_vendors,
|
|
3997
|
+
allowed_region_codes: air.registry.allowed_regions.map((r) => r.code),
|
|
3998
|
+
blocked_region_codes: air.registry.blocked_regions,
|
|
3999
|
+
allowed_model_patterns: air.registry.allowed_models.map((m) => m.version_pattern ?? m.id),
|
|
4000
|
+
blocked_model_patterns: air.registry.blocked_models,
|
|
4001
|
+
max_model_parameters: air.registry.max_model_parameters
|
|
4002
|
+
},
|
|
4003
|
+
runtime: {
|
|
4004
|
+
pii_filter_enabled: air.runtime.pii_filter?.enabled ?? false,
|
|
4005
|
+
pii_filter_action: air.runtime.pii_filter?.action,
|
|
4006
|
+
toxicity_filter_enabled: air.runtime.toxicity_filter?.enabled ?? false,
|
|
4007
|
+
toxicity_threshold: air.runtime.toxicity_filter?.threshold,
|
|
4008
|
+
data_retention_days: air.runtime.data_retention_days,
|
|
4009
|
+
watermark_enabled: air.runtime.watermark_enabled,
|
|
4010
|
+
logging_level: air.runtime.logging_level,
|
|
4011
|
+
max_tokens_per_request: air.runtime.max_tokens_per_request,
|
|
4012
|
+
max_cost_per_day_usd: air.runtime.max_cost_per_day_usd,
|
|
4013
|
+
kill_switch_enabled: air.runtime.kill_switch?.enabled ?? true
|
|
4014
|
+
},
|
|
4015
|
+
build: {
|
|
4016
|
+
require_golden_thread: air.build.require_golden_thread,
|
|
4017
|
+
require_asset_card: air.build.require_asset_card,
|
|
4018
|
+
require_risk_classification: air.build.require_risk_classification,
|
|
4019
|
+
require_model_card: air.build.require_model_card,
|
|
4020
|
+
require_security_review: air.build.require_security_review,
|
|
4021
|
+
block_on_failure: air.build.block_on_failure,
|
|
4022
|
+
generate_sarif: air.build.generate_sarif,
|
|
4023
|
+
allowed_environments: air.build.allowed_environments
|
|
4024
|
+
}
|
|
4025
|
+
};
|
|
4026
|
+
const policySources = air.policy_sources.map((s) => ({
|
|
4027
|
+
id: s.id,
|
|
4028
|
+
type: s.type,
|
|
4029
|
+
uri: s.uri,
|
|
4030
|
+
content_hash: s.content_hash,
|
|
4031
|
+
fetched_at: s.fetched_at,
|
|
4032
|
+
title: s.title,
|
|
4033
|
+
version: s.version
|
|
4034
|
+
}));
|
|
4035
|
+
return {
|
|
4036
|
+
version: "1.0",
|
|
4037
|
+
generated_at: now.toISOString(),
|
|
4038
|
+
policy_hash: policyHash,
|
|
4039
|
+
name: options.name ?? air.name,
|
|
4040
|
+
description: options.description,
|
|
4041
|
+
policy_sources: policySources,
|
|
4042
|
+
constraints,
|
|
4043
|
+
signatures: [],
|
|
4044
|
+
expires_at: expiresAt.toISOString(),
|
|
4045
|
+
generated_by: air.metadata.generated_by,
|
|
4046
|
+
generator_version: air.metadata.compiler_version,
|
|
4047
|
+
organization: options.organization ?? air.metadata.organization,
|
|
4048
|
+
environment: options.environment ?? air.metadata.environment,
|
|
4049
|
+
air_reference: {
|
|
4050
|
+
id: air.id,
|
|
4051
|
+
hash: policyHash
|
|
4052
|
+
}
|
|
4053
|
+
};
|
|
4054
|
+
}
|
|
4055
|
+
function validateGovernanceLock(lock, options = {}) {
|
|
4056
|
+
const errors = [];
|
|
4057
|
+
const warnings = [];
|
|
4058
|
+
const parseResult = GovernanceLockSchema.safeParse(lock);
|
|
4059
|
+
if (!parseResult.success) {
|
|
4060
|
+
return {
|
|
4061
|
+
valid: false,
|
|
4062
|
+
errors: parseResult.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`),
|
|
4063
|
+
warnings: [],
|
|
4064
|
+
expired: false,
|
|
4065
|
+
daysUntilExpiration: 0,
|
|
4066
|
+
signed: false,
|
|
4067
|
+
validSignatureCount: 0,
|
|
4068
|
+
policyHashValid: false
|
|
4069
|
+
};
|
|
4070
|
+
}
|
|
4071
|
+
const parsed = parseResult.data;
|
|
4072
|
+
const now = /* @__PURE__ */ new Date();
|
|
4073
|
+
const expiresAt = new Date(parsed.expires_at);
|
|
4074
|
+
const daysUntilExpiration = Math.ceil((expiresAt.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24));
|
|
4075
|
+
const expired = expiresAt < now;
|
|
4076
|
+
if (options.checkExpiration !== false && expired) {
|
|
4077
|
+
errors.push(`Lock file expired on ${parsed.expires_at}`);
|
|
4078
|
+
}
|
|
4079
|
+
if (daysUntilExpiration > 0 && daysUntilExpiration <= 7) {
|
|
4080
|
+
warnings.push(`Lock file expires in ${daysUntilExpiration} days`);
|
|
4081
|
+
}
|
|
4082
|
+
const signed = parsed.signatures.length > 0;
|
|
4083
|
+
if (options.requireSignatures && !signed) {
|
|
4084
|
+
errors.push("Lock file requires at least one signature");
|
|
4085
|
+
}
|
|
4086
|
+
let validSignatureCount = 0;
|
|
4087
|
+
for (const sig of parsed.signatures) {
|
|
4088
|
+
if (sig.expires_at) {
|
|
4089
|
+
const sigExpiresAt = new Date(sig.expires_at);
|
|
4090
|
+
if (sigExpiresAt < now) {
|
|
4091
|
+
warnings.push(`Signature from ${sig.signer} has expired`);
|
|
4092
|
+
} else {
|
|
4093
|
+
validSignatureCount++;
|
|
4094
|
+
}
|
|
4095
|
+
} else {
|
|
4096
|
+
validSignatureCount++;
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
let policyHashValid = true;
|
|
4100
|
+
if (options.expectedPolicyHash) {
|
|
4101
|
+
if (parsed.policy_hash !== options.expectedPolicyHash) {
|
|
4102
|
+
errors.push(`Policy hash mismatch: expected ${options.expectedPolicyHash}, got ${parsed.policy_hash}`);
|
|
4103
|
+
policyHashValid = false;
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
return {
|
|
4107
|
+
valid: errors.length === 0,
|
|
4108
|
+
errors,
|
|
4109
|
+
warnings,
|
|
4110
|
+
expired,
|
|
4111
|
+
daysUntilExpiration,
|
|
4112
|
+
signed,
|
|
4113
|
+
validSignatureCount,
|
|
4114
|
+
policyHashValid
|
|
4115
|
+
};
|
|
4116
|
+
}
|
|
4117
|
+
function parseGovernanceLockYAML(content) {
|
|
4118
|
+
const parsed = yaml2.parse(content);
|
|
4119
|
+
return GovernanceLockSchema.parse(parsed);
|
|
4120
|
+
}
|
|
4121
|
+
function parseGovernanceLockJSON(content) {
|
|
4122
|
+
const parsed = JSON.parse(content);
|
|
4123
|
+
return GovernanceLockSchema.parse(parsed);
|
|
4124
|
+
}
|
|
4125
|
+
function serializeGovernanceLockYAML(lock) {
|
|
4126
|
+
return yaml2.stringify(lock, {
|
|
4127
|
+
indent: 2,
|
|
4128
|
+
lineWidth: 120
|
|
4129
|
+
});
|
|
4130
|
+
}
|
|
4131
|
+
function serializeGovernanceLockJSON(lock, pretty = true) {
|
|
4132
|
+
return pretty ? JSON.stringify(lock, null, 2) : JSON.stringify(lock);
|
|
4133
|
+
}
|
|
4134
|
+
function isGovernanceLockExpired(lock) {
|
|
4135
|
+
return new Date(lock.expires_at) < /* @__PURE__ */ new Date();
|
|
4136
|
+
}
|
|
4137
|
+
function getDaysUntilExpiration(lock) {
|
|
4138
|
+
const now = /* @__PURE__ */ new Date();
|
|
4139
|
+
const expiresAt = new Date(lock.expires_at);
|
|
4140
|
+
return Math.ceil((expiresAt.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24));
|
|
4141
|
+
}
|
|
4142
|
+
function isVendorAllowedByLock(vendorId, lock) {
|
|
4143
|
+
const { registry: registry2 } = lock.constraints;
|
|
4144
|
+
if (registry2.blocked_vendor_ids.includes(vendorId)) {
|
|
4145
|
+
return false;
|
|
4146
|
+
}
|
|
4147
|
+
if (registry2.allowed_vendor_ids.length > 0) {
|
|
4148
|
+
return registry2.allowed_vendor_ids.includes(vendorId);
|
|
4149
|
+
}
|
|
4150
|
+
return true;
|
|
4151
|
+
}
|
|
4152
|
+
function isModelAllowedByLock(modelId, lock) {
|
|
4153
|
+
const { registry: registry2 } = lock.constraints;
|
|
4154
|
+
for (const pattern of registry2.blocked_model_patterns) {
|
|
4155
|
+
if (matchesPattern3(modelId, pattern)) {
|
|
4156
|
+
return false;
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
if (registry2.allowed_model_patterns.length > 0) {
|
|
4160
|
+
return registry2.allowed_model_patterns.some(
|
|
4161
|
+
(pattern) => matchesPattern3(modelId, pattern)
|
|
4162
|
+
);
|
|
4163
|
+
}
|
|
4164
|
+
return true;
|
|
4165
|
+
}
|
|
4166
|
+
function isRegionAllowedByLock(regionCode, lock) {
|
|
4167
|
+
const { registry: registry2 } = lock.constraints;
|
|
4168
|
+
if (registry2.blocked_region_codes.includes(regionCode)) {
|
|
4169
|
+
return false;
|
|
4170
|
+
}
|
|
4171
|
+
if (registry2.allowed_region_codes.length > 0) {
|
|
4172
|
+
return registry2.allowed_region_codes.includes(regionCode);
|
|
4173
|
+
}
|
|
4174
|
+
return true;
|
|
4175
|
+
}
|
|
4176
|
+
function matchesPattern3(value, pattern) {
|
|
4177
|
+
if (pattern === "*") {
|
|
4178
|
+
return true;
|
|
4179
|
+
}
|
|
4180
|
+
if (pattern.endsWith("*")) {
|
|
4181
|
+
return value.startsWith(pattern.slice(0, -1));
|
|
4182
|
+
}
|
|
4183
|
+
if (pattern.startsWith("*")) {
|
|
4184
|
+
return value.endsWith(pattern.slice(1));
|
|
4185
|
+
}
|
|
4186
|
+
return value === pattern;
|
|
4187
|
+
}
|
|
4188
|
+
function createSigningPayload(lock) {
|
|
4189
|
+
const forSigning = {
|
|
4190
|
+
version: lock.version,
|
|
4191
|
+
generated_at: lock.generated_at,
|
|
4192
|
+
policy_hash: lock.policy_hash,
|
|
4193
|
+
expires_at: lock.expires_at,
|
|
4194
|
+
constraints: lock.constraints
|
|
4195
|
+
};
|
|
4196
|
+
return JSON.stringify(forSigning);
|
|
4197
|
+
}
|
|
4198
|
+
function addSignature(lock, signature) {
|
|
4199
|
+
return {
|
|
4200
|
+
...lock,
|
|
4201
|
+
signatures: [...lock.signatures, signature]
|
|
4202
|
+
};
|
|
4203
|
+
}
|
|
4204
|
+
|
|
2197
4205
|
// src/utils.ts
|
|
2198
4206
|
function formatDate(date) {
|
|
2199
4207
|
return date.toISOString();
|
|
@@ -2205,60 +4213,164 @@ function slugify(text) {
|
|
|
2205
4213
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
2206
4214
|
}
|
|
2207
4215
|
export {
|
|
4216
|
+
AIRBuildConstraintsSchema,
|
|
4217
|
+
AIRMetadataSchema,
|
|
4218
|
+
AIRModelSchema,
|
|
4219
|
+
AIRPIIFilterConfigSchema,
|
|
4220
|
+
AIRPolicySourceSchema,
|
|
4221
|
+
AIRRegionSchema,
|
|
4222
|
+
AIRRegistryConstraintsSchema,
|
|
4223
|
+
AIRRuntimeConstraintsSchema,
|
|
4224
|
+
AIRSchema,
|
|
4225
|
+
AIRToxicityFilterConfigSchema,
|
|
4226
|
+
AIRVendorSchema,
|
|
4227
|
+
AigrcConfigSchema,
|
|
4228
|
+
AigrcIntegrationsConfigSchema,
|
|
4229
|
+
AigrcRuntimeConfigSchema,
|
|
2208
4230
|
ApprovalSchema,
|
|
4231
|
+
AssetCardRuntimeSchema,
|
|
2209
4232
|
AssetCardSchema,
|
|
4233
|
+
CONFIG_ENV_VAR,
|
|
4234
|
+
CONFIG_FILE_NAMES,
|
|
4235
|
+
CapabilitiesManifestSchema,
|
|
2210
4236
|
ClassificationSchema,
|
|
2211
4237
|
ConfidenceLevelSchema,
|
|
2212
4238
|
ConstraintsSchema,
|
|
2213
4239
|
ControlStatusSchema,
|
|
2214
4240
|
DetectionStrategySchema,
|
|
2215
4241
|
FrameworkCategorySchema,
|
|
4242
|
+
GoldenThreadSchema,
|
|
4243
|
+
GovernanceLockBuildConstraintsSchema,
|
|
4244
|
+
GovernanceLockConstraintsSchema,
|
|
4245
|
+
GovernanceLockPolicySourceSchema,
|
|
4246
|
+
GovernanceLockRegistryConstraintsSchema,
|
|
4247
|
+
GovernanceLockRuntimeConstraintsSchema,
|
|
4248
|
+
GovernanceLockSchema,
|
|
4249
|
+
GovernanceLockSignatureSchema,
|
|
2216
4250
|
GovernanceSchema,
|
|
4251
|
+
GovernanceTokenCapabilityClaimsSchema,
|
|
4252
|
+
GovernanceTokenControlClaimsSchema,
|
|
4253
|
+
GovernanceTokenGovernanceClaimsSchema,
|
|
4254
|
+
GovernanceTokenIdentityClaimsSchema,
|
|
4255
|
+
GovernanceTokenLineageClaimsSchema,
|
|
4256
|
+
GovernanceTokenPayloadSchema,
|
|
2217
4257
|
IntentSchema,
|
|
2218
4258
|
JurisdictionClassificationSchema,
|
|
4259
|
+
KillSwitchCommandSchema,
|
|
4260
|
+
KillSwitchCommandTypeSchema,
|
|
4261
|
+
LineageSchema,
|
|
4262
|
+
MAX_INHERITANCE_DEPTH,
|
|
2219
4263
|
MODEL_EXTENSIONS,
|
|
4264
|
+
OperatingModeSchema,
|
|
2220
4265
|
OwnerSchema,
|
|
4266
|
+
PolicyCapabilitiesSchema,
|
|
4267
|
+
PolicyFileSchema,
|
|
4268
|
+
PolicyResolutionError,
|
|
4269
|
+
PolicyRuleEffectSchema,
|
|
4270
|
+
PolicyRuleSchema,
|
|
2221
4271
|
RiskFactorsSchema,
|
|
4272
|
+
RiskLevelSchema,
|
|
4273
|
+
RuntimeIdentitySchema,
|
|
2222
4274
|
TechnicalSchema,
|
|
2223
4275
|
TrustworthinessCharacteristicSchema,
|
|
2224
4276
|
TrustworthinessSchema,
|
|
2225
4277
|
addJurisdiction,
|
|
4278
|
+
addSignature,
|
|
2226
4279
|
analyzeImports,
|
|
2227
4280
|
applyImplicationChains,
|
|
2228
4281
|
classifyRisk,
|
|
2229
4282
|
clearRegistry,
|
|
4283
|
+
compareRiskLevels,
|
|
4284
|
+
computeCanonicalString,
|
|
4285
|
+
computeGoldenThreadHash,
|
|
4286
|
+
computeGoldenThreadHashSync,
|
|
4287
|
+
computeHash,
|
|
2230
4288
|
createAssetCard,
|
|
4289
|
+
createDefaultConfig,
|
|
4290
|
+
createEmptyAIR,
|
|
4291
|
+
createGoldenThread,
|
|
4292
|
+
createGoldenThreadSync,
|
|
4293
|
+
createGovernanceLock,
|
|
2231
4294
|
createImplication,
|
|
4295
|
+
createPolicyRepository,
|
|
4296
|
+
createPolicySelector,
|
|
4297
|
+
createSigningPayload,
|
|
2232
4298
|
detectAnnotations,
|
|
4299
|
+
discoverAssets,
|
|
4300
|
+
discoverConfig,
|
|
4301
|
+
discoverConfigSync,
|
|
4302
|
+
discoverPolicies,
|
|
4303
|
+
evaluatePolicy,
|
|
4304
|
+
extractGoldenThreadComponents,
|
|
2233
4305
|
formatDate,
|
|
2234
4306
|
generateAssetId,
|
|
2235
4307
|
getAllPatterns,
|
|
4308
|
+
getCurrentEnvironment,
|
|
4309
|
+
getDaysUntilExpiration,
|
|
4310
|
+
getEnvironmentConfig,
|
|
4311
|
+
getMaxRiskLevel,
|
|
4312
|
+
getMinRiskLevel,
|
|
2236
4313
|
getPattern,
|
|
2237
4314
|
getPatternsByCategory,
|
|
2238
4315
|
getPatternsByLanguage,
|
|
4316
|
+
getRiskLevelOrdinal,
|
|
4317
|
+
getRiskLevelsAtLeast,
|
|
4318
|
+
getRiskLevelsAtMost,
|
|
2239
4319
|
inferRiskFactors,
|
|
2240
4320
|
initializePatterns,
|
|
4321
|
+
isDomainAllowed,
|
|
4322
|
+
isGovernanceLockExpired,
|
|
4323
|
+
isModelAllowed,
|
|
4324
|
+
isModelAllowedByLock,
|
|
2241
4325
|
isModelFile,
|
|
4326
|
+
isRegionAllowed,
|
|
4327
|
+
isRegionAllowedByLock,
|
|
2242
4328
|
isRegistryInitialized,
|
|
4329
|
+
isRiskLevelAtLeast,
|
|
4330
|
+
isRiskLevelAtMost,
|
|
4331
|
+
isToolAllowed,
|
|
4332
|
+
isValidRiskLevel,
|
|
4333
|
+
isVendorAllowed,
|
|
4334
|
+
isVendorAllowedByLock,
|
|
2243
4335
|
javascriptPatterns,
|
|
2244
4336
|
linkAssetToTicket,
|
|
4337
|
+
loadAsset,
|
|
2245
4338
|
loadAssetCard,
|
|
4339
|
+
loadAssetFromPath,
|
|
4340
|
+
loadPolicy,
|
|
4341
|
+
mapToEuAiActCategory,
|
|
2246
4342
|
matchPatterns,
|
|
4343
|
+
mergePolicies,
|
|
2247
4344
|
modelFilePatterns,
|
|
2248
4345
|
parseDate,
|
|
4346
|
+
parseGovernanceLockJSON,
|
|
4347
|
+
parseGovernanceLockYAML,
|
|
4348
|
+
parseRiskLevel,
|
|
4349
|
+
parseSignature,
|
|
2249
4350
|
pythonPatterns,
|
|
2250
4351
|
registerPattern,
|
|
2251
4352
|
resetPatterns,
|
|
4353
|
+
resolvePolicy,
|
|
2252
4354
|
riskIndicatorPatterns,
|
|
2253
4355
|
saveAssetCard,
|
|
2254
4356
|
scan,
|
|
2255
4357
|
scanFileExtension,
|
|
2256
4358
|
scanSync,
|
|
4359
|
+
selectPolicy,
|
|
4360
|
+
serializeGovernanceLockJSON,
|
|
4361
|
+
serializeGovernanceLockYAML,
|
|
4362
|
+
signGoldenThread,
|
|
2257
4363
|
slugify,
|
|
2258
4364
|
suggestAssetCard,
|
|
2259
4365
|
updateJurisdictionCompliance,
|
|
4366
|
+
validateAIR,
|
|
2260
4367
|
validateAssetCard,
|
|
2261
4368
|
validateGoldenThread,
|
|
2262
|
-
|
|
4369
|
+
validateGovernanceLock,
|
|
4370
|
+
validateRiskFactors,
|
|
4371
|
+
verifyGoldenThreadHash,
|
|
4372
|
+
verifyGoldenThreadHashSync,
|
|
4373
|
+
verifyGoldenThreadSignature,
|
|
4374
|
+
verifyGoldenThreadSignatureSync
|
|
2263
4375
|
};
|
|
2264
4376
|
//# sourceMappingURL=index.mjs.map
|