@vess-id/ai-identity 0.3.2 → 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.
@@ -2,7 +2,7 @@
2
2
  * ConstraintEvaluator
3
3
  * Grant制約の評価ロジック
4
4
  */
5
- import { GrantConstraints, TimeWindowConstraint, EvaluationContext, ConstraintEvaluationResult, ConstraintViolation, ConstraintWarning } from '@vess-id/ai-identity-types';
5
+ import { GrantConstraints, TimeWindowConstraint, EvaluationContext, ConstraintEvaluationResult, ConstraintViolation, ConstraintWarning, PermissionConstraints, PermissionTimeConstraint } from '@vess-id/ai-identity-types';
6
6
  export interface ConstraintEvaluatorOptions {
7
7
  /** 警告を発する残り実行回数の閾値 */
8
8
  invocationWarningThreshold?: number;
@@ -54,11 +54,42 @@ export declare class ConstraintEvaluator {
54
54
  violation?: ConstraintViolation;
55
55
  warning?: ConstraintWarning;
56
56
  };
57
+ /**
58
+ * Evaluate PermissionConstraints from a PermissionRule.
59
+ *
60
+ * This is the VC-level constraint evaluator that works with the
61
+ * normalized PermissionConstraints format (as opposed to GrantConstraints).
62
+ *
63
+ * Used by the PolicyEvaluator after rule matching to verify
64
+ * rule-level constraints are satisfied.
65
+ */
66
+ evaluatePermissionConstraints(constraints: PermissionConstraints, context: {
67
+ now: number;
68
+ ipAddress?: string;
69
+ riskScore?: number;
70
+ invocationCount?: number;
71
+ }): {
72
+ allowed: boolean;
73
+ violations: ConstraintViolation[];
74
+ warnings: ConstraintWarning[];
75
+ };
76
+ /**
77
+ * Check PermissionTimeConstraint (supports both absolute and recurring)
78
+ */
79
+ checkPermissionTimeConstraint(time: PermissionTimeConstraint, currentTime: Date): {
80
+ violation?: ConstraintViolation;
81
+ warning?: ConstraintWarning;
82
+ };
57
83
  private getDayOfWeekInTimezone;
58
84
  private getTimeInTimezone;
59
85
  private getDayName;
60
86
  private timeToMinutes;
61
- private isIpInCidr;
87
+ /**
88
+ * Check if an IP address is within a CIDR range or matches exactly.
89
+ * Uses unsigned 32-bit arithmetic to avoid sign-bit issues.
90
+ * Public for reuse by other services (e.g., LocalPolicyEvaluatorService).
91
+ */
92
+ isIpInCidr(ip: string, cidr: string): boolean;
62
93
  private ipToNumber;
63
94
  }
64
95
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"constraint-evaluator.d.ts","sourceRoot":"","sources":["../../src/constraint/constraint-evaluator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,4BAA4B,CAAA;AAEnC,MAAM,WAAW,0BAA0B;IACzC,sBAAsB;IACtB,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,kBAAkB;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAQD;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAA4B;gBAE/B,OAAO,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC;IAIzD;;OAEG;IACH,QAAQ,CACN,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,iBAAiB,EAC1B,kBAAkB,EAAE,MAAM,EAC1B,SAAS,CAAC,EAAE,IAAI,GACf,0BAA0B;IAgE7B;;OAEG;IACH,eAAe,CACb,cAAc,CAAC,EAAE,IAAI,EACrB,mBAAmB,CAAC,EAAE,MAAM,GAC3B;QAAE,SAAS,CAAC,EAAE,mBAAmB,CAAA;KAAE;IA4BtC;;OAEG;IACH,oBAAoB,CAClB,cAAc,CAAC,EAAE,MAAM,EACvB,kBAAkB,CAAC,EAAE,MAAM,GAC1B;QAAE,SAAS,CAAC,EAAE,mBAAmB,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE;IA8BnE;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,oBAAoB,EAChC,WAAW,EAAE,IAAI,GAChB;QAAE,SAAS,CAAC,EAAE,mBAAmB,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE;IAoEnE;;OAEG;IACH,gBAAgB,CACd,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,MAAM,GAChB;QAAE,SAAS,CAAC,EAAE,mBAAmB,CAAA;KAAE;IA6BtC;;OAEG;IACH,kBAAkB,CAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB;QAAE,SAAS,CAAC,EAAE,mBAAmB,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE;IA6BnE,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,UAAU;CAInB;AAED;;GAEG;AACH,eAAO,MAAM,0BAA0B,qBAA4B,CAAA;AAEnE;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,iBAAiB,EAC1B,kBAAkB,EAAE,MAAM,EAC1B,SAAS,CAAC,EAAE,IAAI,GACf,0BAA0B,CAE5B"}
1
+ {"version":3,"file":"constraint-evaluator.d.ts","sourceRoot":"","sources":["../../src/constraint/constraint-evaluator.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3977,6 +3977,98 @@ var ConstraintEvaluator = class {
3977
3977
  return {};
3978
3978
  }
3979
3979
  // ============================================================================
3980
+ // PermissionConstraints evaluation (VC-level constraints from PermissionRule)
3981
+ // ============================================================================
3982
+ /**
3983
+ * Evaluate PermissionConstraints from a PermissionRule.
3984
+ *
3985
+ * This is the VC-level constraint evaluator that works with the
3986
+ * normalized PermissionConstraints format (as opposed to GrantConstraints).
3987
+ *
3988
+ * Used by the PolicyEvaluator after rule matching to verify
3989
+ * rule-level constraints are satisfied.
3990
+ */
3991
+ evaluatePermissionConstraints(constraints, context) {
3992
+ const violations = [];
3993
+ const warnings = [];
3994
+ if (constraints.time) {
3995
+ const timeResult = this.checkPermissionTimeConstraint(
3996
+ constraints.time,
3997
+ new Date(context.now * 1e3)
3998
+ );
3999
+ if (timeResult.violation) violations.push(timeResult.violation);
4000
+ if (timeResult.warning) warnings.push(timeResult.warning);
4001
+ }
4002
+ if (constraints.max_invocations !== void 0 && context.invocationCount !== void 0) {
4003
+ const invResult = this.checkInvocationLimit(
4004
+ constraints.max_invocations,
4005
+ context.invocationCount
4006
+ );
4007
+ if (invResult.violation) violations.push(invResult.violation);
4008
+ if (invResult.warning) warnings.push(invResult.warning);
4009
+ }
4010
+ if (constraints.ip_allowlist && constraints.ip_allowlist.length > 0 && context.ipAddress) {
4011
+ const ipResult = this.checkIpAllowlist(constraints.ip_allowlist, context.ipAddress);
4012
+ if (ipResult.violation) violations.push(ipResult.violation);
4013
+ }
4014
+ if (constraints.risk_threshold !== void 0 && context.riskScore !== void 0) {
4015
+ const riskResult = this.checkRiskThreshold(constraints.risk_threshold, context.riskScore);
4016
+ if (riskResult.violation) violations.push(riskResult.violation);
4017
+ if (riskResult.warning) warnings.push(riskResult.warning);
4018
+ }
4019
+ return {
4020
+ allowed: violations.length === 0,
4021
+ violations,
4022
+ warnings
4023
+ };
4024
+ }
4025
+ /**
4026
+ * Check PermissionTimeConstraint (supports both absolute and recurring)
4027
+ */
4028
+ checkPermissionTimeConstraint(time, currentTime) {
4029
+ const nowUnix = Math.floor(currentTime.getTime() / 1e3);
4030
+ if (time.not_before !== void 0 && nowUnix < time.not_before) {
4031
+ return {
4032
+ violation: {
4033
+ type: "time_window",
4034
+ message: `Current time is before not_before (${new Date(time.not_before * 1e3).toISOString()})`,
4035
+ details: { now: nowUnix, not_before: time.not_before }
4036
+ }
4037
+ };
4038
+ }
4039
+ if (time.not_after !== void 0 && nowUnix > time.not_after) {
4040
+ return {
4041
+ violation: {
4042
+ type: "time_window",
4043
+ message: `Current time is after not_after (${new Date(time.not_after * 1e3).toISOString()})`,
4044
+ details: { now: nowUnix, not_after: time.not_after }
4045
+ }
4046
+ };
4047
+ }
4048
+ const timezone = time.timezone || this.options.defaultTimezone;
4049
+ if (time.days_of_week && time.days_of_week.length > 0) {
4050
+ const currentDay = this.getDayOfWeekInTimezone(currentTime, timezone);
4051
+ if (!time.days_of_week.includes(currentDay)) {
4052
+ return {
4053
+ violation: {
4054
+ type: "time_window",
4055
+ message: `Current day (${this.getDayName(currentDay)}) is not in allowed days`,
4056
+ details: { currentDay, allowedDays: time.days_of_week }
4057
+ }
4058
+ };
4059
+ }
4060
+ }
4061
+ if (time.recurring_start && time.recurring_end) {
4062
+ const tw = {
4063
+ start: time.recurring_start,
4064
+ end: time.recurring_end,
4065
+ timezone
4066
+ };
4067
+ return this.checkTimeWindow(tw, currentTime);
4068
+ }
4069
+ return {};
4070
+ }
4071
+ // ============================================================================
3980
4072
  // Helper Methods
3981
4073
  // ============================================================================
3982
4074
  getDayOfWeekInTimezone(date, timezone) {
@@ -4010,21 +4102,38 @@ var ConstraintEvaluator = class {
4010
4102
  const [hours, minutes] = time.split(":").map(Number);
4011
4103
  return hours * 60 + minutes;
4012
4104
  }
4105
+ /**
4106
+ * Check if an IP address is within a CIDR range or matches exactly.
4107
+ * Uses unsigned 32-bit arithmetic to avoid sign-bit issues.
4108
+ * Public for reuse by other services (e.g., LocalPolicyEvaluatorService).
4109
+ */
4013
4110
  isIpInCidr(ip, cidr) {
4014
4111
  try {
4112
+ if (!cidr.includes("/")) {
4113
+ return ip === cidr;
4114
+ }
4015
4115
  const [range, bits] = cidr.split("/");
4016
- const mask = parseInt(bits, 10);
4116
+ const prefix = parseInt(bits, 10);
4117
+ if (isNaN(prefix)) return false;
4017
4118
  const ipNum = this.ipToNumber(ip);
4018
4119
  const rangeNum = this.ipToNumber(range);
4019
- const maskNum = ~(2 ** (32 - mask) - 1);
4020
- return (ipNum & maskNum) === (rangeNum & maskNum);
4120
+ if (ipNum === null || rangeNum === null) return false;
4121
+ const mask = prefix === 0 ? 0 : ~0 << 32 - prefix >>> 0;
4122
+ return (ipNum & mask) === (rangeNum & mask);
4021
4123
  } catch {
4022
4124
  return false;
4023
4125
  }
4024
4126
  }
4025
4127
  ipToNumber(ip) {
4026
- const parts = ip.split(".").map(Number);
4027
- return (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3];
4128
+ const parts = ip.split(".");
4129
+ if (parts.length !== 4) return null;
4130
+ let result = 0;
4131
+ for (const part of parts) {
4132
+ const n = parseInt(part, 10);
4133
+ if (isNaN(n) || n < 0 || n > 255) return null;
4134
+ result = result << 8 | n;
4135
+ }
4136
+ return result >>> 0;
4028
4137
  }
4029
4138
  };
4030
4139
  var defaultConstraintEvaluator = new ConstraintEvaluator();