kavachos 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import { D as Database, A as AgentIdentity, i as AuthorizeRequest, j as AuthorizeResult, P as Permission } from '../types-B02D3kZy.js';
2
- export { an as PermissionConstraints } from '../types-B02D3kZy.js';
1
+ import { D as Database, A as AgentIdentity, i as AuthorizeRequest, j as AuthorizeResult, P as Permission } from '../types-RJPOU4un.js';
2
+ export { ar as PermissionConstraints } from '../types-RJPOU4un.js';
3
3
  import 'drizzle-orm/sqlite-core';
4
- import '../types-BuHrZcjE.js';
4
+ import '../types-BiUe9e8u.js';
5
5
  import 'zod';
6
6
  import '../redirect/index.js';
7
7
 
@@ -11,6 +11,11 @@ interface PermissionEngineConfig {
11
11
  }
12
12
  /**
13
13
  * Create the permission/authorization engine.
14
+ *
15
+ * This remains the public entry point used by adapters. The constraint and
16
+ * matching primitives now live in policy/abac.ts so the new unified policy
17
+ * engine can reuse them. A follow-on patch rewires this function to delegate
18
+ * to policy/engine.ts; today it still performs direct-permission evaluation.
14
19
  */
15
20
  declare function createPermissionEngine(config: PermissionEngineConfig): {
16
21
  authorize: (agent: AgentIdentity, request: AuthorizeRequest) => Promise<AuthorizeResult>;
@@ -1,7 +1,5 @@
1
- import { and, eq, gte } from 'drizzle-orm';
2
1
  import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
3
-
4
- // src/permission/engine.ts
2
+ import { and, eq, gte } from 'drizzle-orm';
5
3
 
6
4
  // src/crypto/web-crypto.ts
7
5
  function generateId() {
@@ -76,6 +74,8 @@ sqliteTable("kavach_permissions", {
76
74
  actions: text("actions", { mode: "json" }).notNull().$type(),
77
75
  // ["read", "write", "execute"]
78
76
  constraints: text("constraints", { mode: "json" }).$type(),
77
+ // When set, the policy engine consults the ReBAC graph for this permission.
78
+ relation: text("relation"),
79
79
  createdAt: integer("created_at", { mode: "timestamp" }).notNull()
80
80
  });
81
81
  sqliteTable("kavach_delegation_chains", {
@@ -105,6 +105,8 @@ var auditLogs = sqliteTable("kavach_audit_logs", {
105
105
  tokensCost: integer("tokens_cost"),
106
106
  ip: text("ip"),
107
107
  userAgent: text("user_agent"),
108
+ // True when this audit row corresponds to a policy-engine cache-hit evaluation.
109
+ cacheHit: integer("cache_hit", { mode: "boolean" }).notNull().default(false),
108
110
  timestamp: integer("timestamp", { mode: "timestamp" }).notNull()
109
111
  });
110
112
  var rateLimits = sqliteTable("kavach_rate_limits", {
@@ -541,8 +543,6 @@ sqliteTable("kavach_refresh_tokens", {
541
543
  expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
542
544
  createdAt: integer("created_at", { mode: "timestamp" }).notNull()
543
545
  });
544
-
545
- // src/permission/engine.ts
546
546
  function matchResource(pattern, resource) {
547
547
  if (pattern === "*") return true;
548
548
  const patternParts = pattern.split(":");
@@ -600,6 +600,9 @@ function validateArgPatterns(patterns, args) {
600
600
  return { valid: true };
601
601
  }
602
602
  async function checkRateLimit(db, agentId, resource, maxCallsPerHour) {
603
+ if (!agentId) {
604
+ return { allowed: true };
605
+ }
603
606
  const oneHourAgo = new Date(Date.now() - 60 * 60 * 1e3);
604
607
  const rows = await db.select().from(rateLimits).where(
605
608
  and(
@@ -630,66 +633,20 @@ async function checkRateLimit(db, agentId, resource, maxCallsPerHour) {
630
633
  }
631
634
  return { allowed: true };
632
635
  }
633
- function createPermissionEngine(config) {
634
- const { db, auditAll } = config;
635
- async function authorize(agent, request) {
636
- const startTime = performance.now();
637
- const auditId = generateId();
638
- const matchingPermission = agent.permissions.find(
639
- (p) => matchResource(p.resource, request.resource) && matchAction(p.actions, request.action)
640
- );
641
- if (!matchingPermission) {
642
- const result2 = {
643
- allowed: false,
644
- reason: `No permission grants agent "${agent.name}" access to "${request.action}" on "${request.resource}"`,
645
- auditId
646
- };
647
- if (auditAll) {
648
- await writeAuditLog(db, agent, request, result2, startTime, auditId);
649
- }
650
- return result2;
651
- }
652
- if (matchingPermission.constraints) {
653
- const constraintResult = await evaluateConstraints(
654
- db,
655
- agent,
656
- request,
657
- matchingPermission.constraints
658
- );
659
- if (!constraintResult.allowed) {
660
- const result2 = {
661
- allowed: false,
662
- reason: constraintResult.reason,
663
- auditId
664
- };
665
- if (auditAll) {
666
- await writeAuditLog(db, agent, request, result2, startTime, auditId);
667
- }
668
- return result2;
669
- }
670
- }
671
- const result = { allowed: true, auditId };
672
- if (auditAll) {
673
- await writeAuditLog(db, agent, request, result, startTime, auditId);
674
- }
675
- return result;
676
- }
677
- return { authorize };
678
- }
679
- async function evaluateConstraints(db, agent, request, constraints) {
636
+ async function evaluateConstraints(db, input, constraints) {
680
637
  if (constraints.maxCallsPerHour) {
681
638
  const rateResult = await checkRateLimit(
682
639
  db,
683
- agent.id,
684
- request.resource,
640
+ input.subjectId,
641
+ input.resource,
685
642
  constraints.maxCallsPerHour
686
643
  );
687
644
  if (!rateResult.allowed) {
688
645
  return rateResult;
689
646
  }
690
647
  }
691
- if (constraints.allowedArgPatterns && request.arguments) {
692
- const patternResult = validateArgPatterns(constraints.allowedArgPatterns, request.arguments);
648
+ if (constraints.allowedArgPatterns && input.arguments) {
649
+ const patternResult = validateArgPatterns(constraints.allowedArgPatterns, input.arguments);
693
650
  if (!patternResult.valid) {
694
651
  return { allowed: false, reason: patternResult.reason };
695
652
  }
@@ -713,21 +670,73 @@ async function evaluateConstraints(db, agent, request, constraints) {
713
670
  }
714
671
  }
715
672
  if (constraints.ipAllowlist && constraints.ipAllowlist.length > 0) {
716
- if (!request.ip) {
673
+ if (!input.ip) {
717
674
  return {
718
675
  allowed: false,
719
676
  reason: "IP_NOT_ALLOWED: No IP address provided; resource requires an IP allowlist match"
720
677
  };
721
678
  }
722
- if (!isIPAllowed(constraints.ipAllowlist, request.ip)) {
679
+ if (!isIPAllowed(constraints.ipAllowlist, input.ip)) {
723
680
  return {
724
681
  allowed: false,
725
- reason: `IP_NOT_ALLOWED: IP "${request.ip}" is not in the allowlist for this resource`
682
+ reason: `IP_NOT_ALLOWED: IP "${input.ip}" is not in the allowlist for this resource`
726
683
  };
727
684
  }
728
685
  }
729
686
  return { allowed: true };
730
687
  }
688
+
689
+ // src/permission/engine.ts
690
+ function createPermissionEngine(config) {
691
+ const { db, auditAll } = config;
692
+ async function authorize(agent, request) {
693
+ const startTime = performance.now();
694
+ const auditId = generateId();
695
+ const matchingPermission = agent.permissions.find(
696
+ (p) => matchResource(p.resource, request.resource) && matchAction(p.actions, request.action)
697
+ );
698
+ if (!matchingPermission) {
699
+ const result2 = {
700
+ allowed: false,
701
+ reason: `No permission grants agent "${agent.name}" access to "${request.action}" on "${request.resource}"`,
702
+ auditId
703
+ };
704
+ if (auditAll) {
705
+ await writeAuditLog(db, agent, request, result2, startTime, auditId);
706
+ }
707
+ return result2;
708
+ }
709
+ if (matchingPermission.constraints) {
710
+ const constraintResult = await evaluateConstraints(
711
+ db,
712
+ {
713
+ subjectId: agent.id,
714
+ resource: request.resource,
715
+ arguments: request.arguments,
716
+ ip: request.ip
717
+ },
718
+ matchingPermission.constraints
719
+ );
720
+ if (!constraintResult.allowed) {
721
+ const result2 = {
722
+ allowed: false,
723
+ reason: constraintResult.reason,
724
+ auditId
725
+ };
726
+ if (auditAll) {
727
+ await writeAuditLog(db, agent, request, result2, startTime, auditId);
728
+ }
729
+ return result2;
730
+ }
731
+ }
732
+ const result = { allowed: true, auditId };
733
+ if (auditAll) {
734
+ await writeAuditLog(db, agent, request, result, startTime, auditId);
735
+ }
736
+ return result;
737
+ }
738
+ return { authorize };
739
+ }
731
740
  async function writeAuditLog(db, agent, request, result, startTime, auditId) {
732
741
  const durationMs = Math.round(performance.now() - startTime);
733
742
  await db.insert(auditLogs).values({