@o3co/auth.policy-verifier.builtins 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.ja.md +104 -2
  2. package/README.md +102 -0
  3. package/dist/__tests__/rules/AttrLiteralCompare.test.d.mts +2 -0
  4. package/dist/__tests__/rules/AttrLiteralCompare.test.d.mts.map +1 -0
  5. package/dist/__tests__/rules/AttrLiteralCompare.test.mjs +253 -0
  6. package/dist/__tests__/rules/AttrLiteralEqual.test.d.mts +2 -0
  7. package/dist/__tests__/rules/AttrLiteralEqual.test.d.mts.map +1 -0
  8. package/dist/__tests__/rules/AttrLiteralEqual.test.mjs +138 -0
  9. package/dist/__tests__/rules/AttrLiteralIn.test.d.mts +2 -0
  10. package/dist/__tests__/rules/AttrLiteralIn.test.d.mts.map +1 -0
  11. package/dist/__tests__/rules/AttrLiteralIn.test.mjs +160 -0
  12. package/dist/__tests__/rules/AttrLiteralNotEqual.test.d.mts +2 -0
  13. package/dist/__tests__/rules/AttrLiteralNotEqual.test.d.mts.map +1 -0
  14. package/dist/__tests__/rules/AttrLiteralNotEqual.test.mjs +157 -0
  15. package/dist/__tests__/rules/AttrLiteralNotIn.test.d.mts +2 -0
  16. package/dist/__tests__/rules/AttrLiteralNotIn.test.d.mts.map +1 -0
  17. package/dist/__tests__/rules/AttrLiteralNotIn.test.mjs +168 -0
  18. package/dist/__tests__/rules/AttrMatchRule.test.mjs +8 -0
  19. package/dist/__tests__/rules/AttrPairCompare.test.d.mts +2 -0
  20. package/dist/__tests__/rules/AttrPairCompare.test.d.mts.map +1 -0
  21. package/dist/__tests__/rules/AttrPairCompare.test.mjs +319 -0
  22. package/dist/__tests__/rules/AttrPairEqual.test.d.mts +2 -0
  23. package/dist/__tests__/rules/AttrPairEqual.test.d.mts.map +1 -0
  24. package/dist/__tests__/rules/AttrPairEqual.test.mjs +155 -0
  25. package/dist/__tests__/rules/AttrPairNotEqual.test.d.mts +2 -0
  26. package/dist/__tests__/rules/AttrPairNotEqual.test.d.mts.map +1 -0
  27. package/dist/__tests__/rules/AttrPairNotEqual.test.mjs +155 -0
  28. package/dist/__tests__/rules/_sharedValidation.test.d.mts +2 -0
  29. package/dist/__tests__/rules/_sharedValidation.test.d.mts.map +1 -0
  30. package/dist/__tests__/rules/_sharedValidation.test.mjs +325 -0
  31. package/dist/__tests__/rules/collectors/ResourceActionPermissionRuleCollector.test.d.mts.map +1 -0
  32. package/dist/__tests__/rules/{ResourceActionPermissionRuleCollector.test.mjs → collectors/ResourceActionPermissionRuleCollector.test.mjs} +1 -1
  33. package/dist/__tests__/rules/collectors/ResourceActionScopeRuleCollector.test.d.mts.map +1 -0
  34. package/dist/__tests__/rules/{ResourceActionScopeRuleCollector.test.mjs → collectors/ResourceActionScopeRuleCollector.test.mjs} +1 -1
  35. package/dist/index.d.mts +10 -2
  36. package/dist/index.d.mts.map +1 -1
  37. package/dist/index.mjs +10 -2
  38. package/dist/module.mjs +2 -2
  39. package/dist/rules/AttrLiteralCompare.d.mts +31 -0
  40. package/dist/rules/AttrLiteralCompare.d.mts.map +1 -0
  41. package/dist/rules/AttrLiteralCompare.mjs +36 -0
  42. package/dist/rules/AttrLiteralEqual.d.mts +37 -0
  43. package/dist/rules/AttrLiteralEqual.d.mts.map +1 -0
  44. package/dist/rules/AttrLiteralEqual.mjs +43 -0
  45. package/dist/rules/AttrLiteralIn.d.mts +38 -0
  46. package/dist/rules/AttrLiteralIn.d.mts.map +1 -0
  47. package/dist/rules/AttrLiteralIn.mjs +46 -0
  48. package/dist/rules/AttrLiteralNotEqual.d.mts +36 -0
  49. package/dist/rules/AttrLiteralNotEqual.d.mts.map +1 -0
  50. package/dist/rules/AttrLiteralNotEqual.mjs +42 -0
  51. package/dist/rules/AttrLiteralNotIn.d.mts +33 -0
  52. package/dist/rules/AttrLiteralNotIn.d.mts.map +1 -0
  53. package/dist/rules/AttrLiteralNotIn.mjs +41 -0
  54. package/dist/rules/AttrMatchRule.d.mts +7 -34
  55. package/dist/rules/AttrMatchRule.d.mts.map +1 -1
  56. package/dist/rules/AttrMatchRule.mjs +7 -32
  57. package/dist/rules/AttrPairCompare.d.mts +35 -0
  58. package/dist/rules/AttrPairCompare.d.mts.map +1 -0
  59. package/dist/rules/AttrPairCompare.mjs +43 -0
  60. package/dist/rules/AttrPairEqual.d.mts +35 -0
  61. package/dist/rules/AttrPairEqual.d.mts.map +1 -0
  62. package/dist/rules/AttrPairEqual.mjs +44 -0
  63. package/dist/rules/AttrPairNotEqual.d.mts +34 -0
  64. package/dist/rules/AttrPairNotEqual.d.mts.map +1 -0
  65. package/dist/rules/AttrPairNotEqual.mjs +43 -0
  66. package/dist/rules/_sharedValidation.d.mts +87 -0
  67. package/dist/rules/_sharedValidation.d.mts.map +1 -0
  68. package/dist/rules/_sharedValidation.mjs +189 -0
  69. package/dist/rules/collectors/ResourceActionPermissionRuleCollector.d.mts.map +1 -0
  70. package/dist/rules/{ResourceActionPermissionRuleCollector.mjs → collectors/ResourceActionPermissionRuleCollector.mjs} +1 -1
  71. package/dist/rules/collectors/ResourceActionScopeRuleCollector.d.mts.map +1 -0
  72. package/dist/rules/{ResourceActionScopeRuleCollector.mjs → collectors/ResourceActionScopeRuleCollector.mjs} +1 -1
  73. package/package.json +5 -2
  74. package/dist/__tests__/rules/ResourceActionPermissionRuleCollector.test.d.mts.map +0 -1
  75. package/dist/__tests__/rules/ResourceActionScopeRuleCollector.test.d.mts.map +0 -1
  76. package/dist/rules/ResourceActionPermissionRuleCollector.d.mts.map +0 -1
  77. package/dist/rules/ResourceActionScopeRuleCollector.d.mts.map +0 -1
  78. /package/dist/__tests__/rules/{ResourceActionPermissionRuleCollector.test.d.mts → collectors/ResourceActionPermissionRuleCollector.test.d.mts} +0 -0
  79. /package/dist/__tests__/rules/{ResourceActionScopeRuleCollector.test.d.mts → collectors/ResourceActionScopeRuleCollector.test.d.mts} +0 -0
  80. /package/dist/rules/{ResourceActionPermissionRuleCollector.d.mts → collectors/ResourceActionPermissionRuleCollector.d.mts} +0 -0
  81. /package/dist/rules/{ResourceActionScopeRuleCollector.d.mts → collectors/ResourceActionScopeRuleCollector.d.mts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { ResourceActionPermissionRuleCollector } from "#/rules/ResourceActionPermissionRuleCollector.mjs";
2
+ import { ResourceActionPermissionRuleCollector } from "#/rules/collectors/ResourceActionPermissionRuleCollector.mjs";
3
3
  describe("ResourceActionPermissionRuleCollector", () => {
4
4
  const collector = new ResourceActionPermissionRuleCollector();
5
5
  it("creates a HasPermission rule with resource.perm:action", async () => {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResourceActionScopeRuleCollector.test.d.mts","sourceRoot":"","sources":["../../../../src/__tests__/rules/collectors/ResourceActionScopeRuleCollector.test.mts"],"names":[],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { ResourceActionScopeRuleCollector } from "#/rules/ResourceActionScopeRuleCollector.mjs";
2
+ import { ResourceActionScopeRuleCollector } from "#/rules/collectors/ResourceActionScopeRuleCollector.mjs";
3
3
  const makeContext = (resourceType, action, scope) => ({
4
4
  payload: { ...(scope !== undefined ? { scope } : {}) },
5
5
  resource: { raw: `${resourceType}:1`, resourceType, resourceId: "1" },
package/dist/index.d.mts CHANGED
@@ -4,9 +4,17 @@ export { StaticPermissionCollector } from "./collectors/StaticPermissionCollecto
4
4
  export { StaticRoleCollector } from "./collectors/StaticRoleCollector.mjs";
5
5
  export { builtinCollectorsModule } from "./module.mjs";
6
6
  export { DotNotationResourceParser } from "./resource/DotNotationResourceParser.mjs";
7
+ export { AttrLiteralCompare, type AttrLiteralCompareConfig } from "./rules/AttrLiteralCompare.mjs";
8
+ export { AttrLiteralEqual, type AttrLiteralEqualConfig } from "./rules/AttrLiteralEqual.mjs";
9
+ export { AttrLiteralIn, type AttrLiteralInConfig } from "./rules/AttrLiteralIn.mjs";
10
+ export { AttrLiteralNotEqual, type AttrLiteralNotEqualConfig, } from "./rules/AttrLiteralNotEqual.mjs";
11
+ export { AttrLiteralNotIn, type AttrLiteralNotInConfig } from "./rules/AttrLiteralNotIn.mjs";
7
12
  export { AttrMatchRule, type AttrMatchRuleConfig } from "./rules/AttrMatchRule.mjs";
13
+ export { AttrPairCompare, type AttrPairCompareConfig } from "./rules/AttrPairCompare.mjs";
14
+ export { AttrPairEqual, type AttrPairEqualConfig } from "./rules/AttrPairEqual.mjs";
15
+ export { AttrPairNotEqual, type AttrPairNotEqualConfig } from "./rules/AttrPairNotEqual.mjs";
16
+ export { ResourceActionPermissionRuleCollector } from "./rules/collectors/ResourceActionPermissionRuleCollector.mjs";
17
+ export { ResourceActionScopeRuleCollector } from "./rules/collectors/ResourceActionScopeRuleCollector.mjs";
8
18
  export { HasPermission } from "./rules/HasPermission.mjs";
9
19
  export { HasScope } from "./rules/HasScope.mjs";
10
- export { ResourceActionPermissionRuleCollector } from "./rules/ResourceActionPermissionRuleCollector.mjs";
11
- export { ResourceActionScopeRuleCollector } from "./rules/ResourceActionScopeRuleCollector.mjs";
12
20
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AAErF,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,qCAAqC,EAAE,MAAM,mDAAmD,CAAC;AAC1G,OAAO,EAAE,gCAAgC,EAAE,MAAM,8CAA8C,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AAErF,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EACN,mBAAmB,EACnB,KAAK,yBAAyB,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,qCAAqC,EAAE,MAAM,8DAA8D,CAAC;AACrH,OAAO,EAAE,gCAAgC,EAAE,MAAM,yDAAyD,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.mjs CHANGED
@@ -8,8 +8,16 @@ export { builtinCollectorsModule } from "./module.mjs";
8
8
  // Resource
9
9
  export { DotNotationResourceParser } from "./resource/DotNotationResourceParser.mjs";
10
10
  // Rules
11
+ export { AttrLiteralCompare } from "./rules/AttrLiteralCompare.mjs";
12
+ export { AttrLiteralEqual } from "./rules/AttrLiteralEqual.mjs";
13
+ export { AttrLiteralIn } from "./rules/AttrLiteralIn.mjs";
14
+ export { AttrLiteralNotEqual, } from "./rules/AttrLiteralNotEqual.mjs";
15
+ export { AttrLiteralNotIn } from "./rules/AttrLiteralNotIn.mjs";
11
16
  export { AttrMatchRule } from "./rules/AttrMatchRule.mjs";
17
+ export { AttrPairCompare } from "./rules/AttrPairCompare.mjs";
18
+ export { AttrPairEqual } from "./rules/AttrPairEqual.mjs";
19
+ export { AttrPairNotEqual } from "./rules/AttrPairNotEqual.mjs";
20
+ export { ResourceActionPermissionRuleCollector } from "./rules/collectors/ResourceActionPermissionRuleCollector.mjs";
21
+ export { ResourceActionScopeRuleCollector } from "./rules/collectors/ResourceActionScopeRuleCollector.mjs";
12
22
  export { HasPermission } from "./rules/HasPermission.mjs";
13
23
  export { HasScope } from "./rules/HasScope.mjs";
14
- export { ResourceActionPermissionRuleCollector } from "./rules/ResourceActionPermissionRuleCollector.mjs";
15
- export { ResourceActionScopeRuleCollector } from "./rules/ResourceActionScopeRuleCollector.mjs";
package/dist/module.mjs CHANGED
@@ -3,8 +3,8 @@ import { PayloadSubjectIdCollector } from "./collectors/PayloadSubjectIdCollecto
3
3
  import { StaticPermissionCollector } from "./collectors/StaticPermissionCollector.mjs";
4
4
  import { StaticRoleCollector } from "./collectors/StaticRoleCollector.mjs";
5
5
  import { DotNotationResourceParser } from "./resource/DotNotationResourceParser.mjs";
6
- import { ResourceActionPermissionRuleCollector } from "./rules/ResourceActionPermissionRuleCollector.mjs";
7
- import { ResourceActionScopeRuleCollector } from "./rules/ResourceActionScopeRuleCollector.mjs";
6
+ import { ResourceActionPermissionRuleCollector } from "./rules/collectors/ResourceActionPermissionRuleCollector.mjs";
7
+ import { ResourceActionScopeRuleCollector } from "./rules/collectors/ResourceActionScopeRuleCollector.mjs";
8
8
  export const builtinCollectorsModule = {
9
9
  name: "builtin-collectors",
10
10
  async init(context) {
@@ -0,0 +1,31 @@
1
+ import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
+ import { type CompareOp } from "./_sharedValidation.mjs";
3
+ export interface AttrLiteralCompareConfig {
4
+ a: string;
5
+ op: CompareOp;
6
+ v: number;
7
+ group?: string;
8
+ }
9
+ /**
10
+ * Rule that passes when a named attribute is present, is a number, and
11
+ * satisfies the configured comparison operator against the configured literal
12
+ * number `v`. NaN attributes always return false. Missing, null, or non-number
13
+ * attributes return false (safe-deny). NaN is rejected at construction time.
14
+ *
15
+ * ## Grouping and the default ruleType
16
+ *
17
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
18
+ * across groups. The default `ruleType` is derived from `a`, `op`, and `v`:
19
+ * `attr_literal_compare:{a}:{op}:{String(v)}`
20
+ *
21
+ * Pass an explicit `group` string to override the default ruleType entirely.
22
+ */
23
+ export declare class AttrLiteralCompare implements Rule {
24
+ private readonly config;
25
+ readonly ruleType: string;
26
+ readonly code = "attr_compare_violated";
27
+ readonly message: string;
28
+ constructor(config: AttrLiteralCompareConfig);
29
+ verify(attrs: Attributes): boolean;
30
+ }
31
+ //# sourceMappingURL=AttrLiteralCompare.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttrLiteralCompare.d.mts","sourceRoot":"","sources":["../../src/rules/AttrLiteralCompare.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAEN,KAAK,SAAS,EAKd,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,wBAAwB;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,SAAS,CAAC;IACd,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,YAAW,IAAI;IAKlC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,2BAA2B;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEI,MAAM,EAAE,wBAAwB;IAU7D,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;CAKlC"}
@@ -0,0 +1,36 @@
1
+ import { applyCompare, requireAttrName, requireCompareOp, requireNumber, requireOptionalGroup, } from "./_sharedValidation.mjs";
2
+ /**
3
+ * Rule that passes when a named attribute is present, is a number, and
4
+ * satisfies the configured comparison operator against the configured literal
5
+ * number `v`. NaN attributes always return false. Missing, null, or non-number
6
+ * attributes return false (safe-deny). NaN is rejected at construction time.
7
+ *
8
+ * ## Grouping and the default ruleType
9
+ *
10
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
11
+ * across groups. The default `ruleType` is derived from `a`, `op`, and `v`:
12
+ * `attr_literal_compare:{a}:{op}:{String(v)}`
13
+ *
14
+ * Pass an explicit `group` string to override the default ruleType entirely.
15
+ */
16
+ export class AttrLiteralCompare {
17
+ config;
18
+ ruleType;
19
+ code = "attr_compare_violated";
20
+ message;
21
+ constructor(config) {
22
+ this.config = config;
23
+ requireAttrName("AttrLiteralCompare", "a", config.a);
24
+ requireNumber("AttrLiteralCompare", "v", config.v);
25
+ requireCompareOp("AttrLiteralCompare", config.op);
26
+ const group = requireOptionalGroup("AttrLiteralCompare", config.group);
27
+ this.ruleType = group ?? `attr_literal_compare:${config.a}:${config.op}:${String(config.v)}`;
28
+ this.message = `Attribute constraint not satisfied: ${config.a} must be ${config.op} ${String(config.v)}.`;
29
+ }
30
+ verify(attrs) {
31
+ const x = attrs.get(this.config.a);
32
+ if (typeof x !== "number")
33
+ return false;
34
+ return applyCompare(this.config.op, x, this.config.v);
35
+ }
36
+ }
@@ -0,0 +1,37 @@
1
+ import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
+ import { type LiteralValue } from "./_sharedValidation.mjs";
3
+ export interface AttrLiteralEqualConfig {
4
+ a: string;
5
+ v: LiteralValue;
6
+ group?: string;
7
+ }
8
+ /**
9
+ * Rule that passes when a named attribute is present and strictly equal to a
10
+ * configured literal value (string, number, or boolean). No type coercion is
11
+ * performed: the attribute value must be the same type and value as `v`.
12
+ *
13
+ * ## Grouping and the default ruleType
14
+ *
15
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
16
+ * across groups. The default `ruleType` is derived from `a`, `typeof v`, and
17
+ * `String(v)` so that distinct literal requirements are AND-combined by default:
18
+ * `attr_literal_equal:{a}:{typeof v}:{String(v)}`
19
+ *
20
+ * The `typeof v` segment is required because `String(v)` collapses distinct-
21
+ * type literals that stringify the same way (e.g. `true` vs `"true"`, `1` vs
22
+ * `"1"`). Without it, two rules on the same attribute with different-type
23
+ * literals would share a `ruleType` and be OR-combined by the evaluator,
24
+ * silently weakening authorization.
25
+ *
26
+ * Pass a shared `group` string to two instances to opt into OR semantics
27
+ * (e.g. "role is admin" OR "role is superuser" under one group).
28
+ */
29
+ export declare class AttrLiteralEqual implements Rule {
30
+ private readonly config;
31
+ readonly ruleType: string;
32
+ readonly code = "attr_not_equal";
33
+ readonly message: string;
34
+ constructor(config: AttrLiteralEqualConfig);
35
+ verify(attrs: Attributes): boolean;
36
+ }
37
+ //# sourceMappingURL=AttrLiteralEqual.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttrLiteralEqual.d.mts","sourceRoot":"","sources":["../../src/rules/AttrLiteralEqual.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EACN,KAAK,YAAY,EAIjB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,sBAAsB;IACtC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,YAAY,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAiB,YAAW,IAAI;IAKhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEI,MAAM,EAAE,sBAAsB;IAU3D,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;CAKlC"}
@@ -0,0 +1,43 @@
1
+ import { requireAttrName, requireLiteralValue, requireOptionalGroup, } from "./_sharedValidation.mjs";
2
+ /**
3
+ * Rule that passes when a named attribute is present and strictly equal to a
4
+ * configured literal value (string, number, or boolean). No type coercion is
5
+ * performed: the attribute value must be the same type and value as `v`.
6
+ *
7
+ * ## Grouping and the default ruleType
8
+ *
9
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
10
+ * across groups. The default `ruleType` is derived from `a`, `typeof v`, and
11
+ * `String(v)` so that distinct literal requirements are AND-combined by default:
12
+ * `attr_literal_equal:{a}:{typeof v}:{String(v)}`
13
+ *
14
+ * The `typeof v` segment is required because `String(v)` collapses distinct-
15
+ * type literals that stringify the same way (e.g. `true` vs `"true"`, `1` vs
16
+ * `"1"`). Without it, two rules on the same attribute with different-type
17
+ * literals would share a `ruleType` and be OR-combined by the evaluator,
18
+ * silently weakening authorization.
19
+ *
20
+ * Pass a shared `group` string to two instances to opt into OR semantics
21
+ * (e.g. "role is admin" OR "role is superuser" under one group).
22
+ */
23
+ export class AttrLiteralEqual {
24
+ config;
25
+ ruleType;
26
+ code = "attr_not_equal";
27
+ message;
28
+ constructor(config) {
29
+ this.config = config;
30
+ requireAttrName("AttrLiteralEqual", "a", config.a);
31
+ requireLiteralValue("AttrLiteralEqual", "v", config.v);
32
+ const group = requireOptionalGroup("AttrLiteralEqual", config.group);
33
+ this.ruleType =
34
+ group ?? `attr_literal_equal:${config.a}:${typeof config.v}:${String(config.v)}`;
35
+ this.message = `Attribute constraint not satisfied: ${config.a} must equal ${String(config.v)}.`;
36
+ }
37
+ verify(attrs) {
38
+ const x = attrs.get(this.config.a);
39
+ if (typeof x !== typeof this.config.v)
40
+ return false;
41
+ return x === this.config.v;
42
+ }
43
+ }
@@ -0,0 +1,38 @@
1
+ import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
+ import { type LiteralValue } from "./_sharedValidation.mjs";
3
+ export interface AttrLiteralInConfig {
4
+ a: string;
5
+ values: LiteralValue[];
6
+ group?: string;
7
+ }
8
+ /**
9
+ * Rule that passes when a named attribute is present, matches the element type
10
+ * of the configured values array, and is included in that array. No type
11
+ * coercion is performed. If the attribute is missing, null, or of the wrong
12
+ * type the rule returns false (safe-deny).
13
+ *
14
+ * ## Grouping and the default ruleType
15
+ *
16
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
17
+ * across groups. The default `ruleType` is derived from `a` and a stable
18
+ * content-hash key over the values array:
19
+ * `attr_literal_in:{a}:{valuesKey}`
20
+ *
21
+ * Two instances with the same `a` but different `values` will produce distinct
22
+ * ruleTypes and thus be AND-combined by the evaluator. Two instances with the
23
+ * same `a` and logically equivalent `values` (regardless of insertion order)
24
+ * will share a ruleType and be OR-combined.
25
+ *
26
+ * Pass an explicit `group` string to override the default ruleType entirely.
27
+ */
28
+ export declare class AttrLiteralIn implements Rule {
29
+ private readonly config;
30
+ readonly ruleType: string;
31
+ readonly code = "attr_not_in_set";
32
+ readonly message: string;
33
+ private readonly elementType;
34
+ private readonly valuesSet;
35
+ constructor(config: AttrLiteralInConfig);
36
+ verify(attrs: Attributes): boolean;
37
+ }
38
+ //# sourceMappingURL=AttrLiteralIn.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttrLiteralIn.d.mts","sourceRoot":"","sources":["../../src/rules/AttrLiteralIn.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAEN,KAAK,YAAY,EAIjB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,mBAAmB;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAc,YAAW,IAAI;IAQ7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;gBAEjB,MAAM,EAAE,mBAAmB;IAaxD,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;CAKlC"}
@@ -0,0 +1,46 @@
1
+ import { computeValuesKey, requireAttrName, requireHomogeneousLiteralArray, requireOptionalGroup, } from "./_sharedValidation.mjs";
2
+ /**
3
+ * Rule that passes when a named attribute is present, matches the element type
4
+ * of the configured values array, and is included in that array. No type
5
+ * coercion is performed. If the attribute is missing, null, or of the wrong
6
+ * type the rule returns false (safe-deny).
7
+ *
8
+ * ## Grouping and the default ruleType
9
+ *
10
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
11
+ * across groups. The default `ruleType` is derived from `a` and a stable
12
+ * content-hash key over the values array:
13
+ * `attr_literal_in:{a}:{valuesKey}`
14
+ *
15
+ * Two instances with the same `a` but different `values` will produce distinct
16
+ * ruleTypes and thus be AND-combined by the evaluator. Two instances with the
17
+ * same `a` and logically equivalent `values` (regardless of insertion order)
18
+ * will share a ruleType and be OR-combined.
19
+ *
20
+ * Pass an explicit `group` string to override the default ruleType entirely.
21
+ */
22
+ export class AttrLiteralIn {
23
+ config;
24
+ ruleType;
25
+ code = "attr_not_in_set";
26
+ message;
27
+ elementType;
28
+ valuesSet;
29
+ constructor(config) {
30
+ this.config = config;
31
+ requireAttrName("AttrLiteralIn", "a", config.a);
32
+ const values = requireHomogeneousLiteralArray("AttrLiteralIn", config.values);
33
+ const group = requireOptionalGroup("AttrLiteralIn", config.group);
34
+ this.elementType = typeof values[0];
35
+ this.valuesSet = new Set(values);
36
+ const valuesKey = computeValuesKey(values);
37
+ this.ruleType = group ?? `attr_literal_in:${config.a}:${valuesKey}`;
38
+ this.message = `Attribute constraint not satisfied: ${config.a} must be one of [${values.map(String).join(", ")}].`;
39
+ }
40
+ verify(attrs) {
41
+ const x = attrs.get(this.config.a);
42
+ if (typeof x !== this.elementType)
43
+ return false;
44
+ return this.valuesSet.has(x);
45
+ }
46
+ }
@@ -0,0 +1,36 @@
1
+ import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
+ import { type LiteralValue } from "./_sharedValidation.mjs";
3
+ export interface AttrLiteralNotEqualConfig {
4
+ a: string;
5
+ v: LiteralValue;
6
+ group?: string;
7
+ }
8
+ /**
9
+ * Rule that passes when a named attribute is present, matches the type of the
10
+ * configured literal value, and is strictly NOT equal to it. No type coercion
11
+ * is performed. If the attribute is missing, null, or of the wrong type the
12
+ * rule returns false (safe-deny).
13
+ *
14
+ * ## Grouping and the default ruleType
15
+ *
16
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
17
+ * across groups. The default `ruleType` is derived from `a`, `typeof v`, and
18
+ * `String(v)`:
19
+ * `attr_literal_not_equal:{a}:{typeof v}:{String(v)}`
20
+ *
21
+ * The `typeof v` segment prevents silent `ruleType` collisions between
22
+ * different-type literals that stringify the same way (e.g. `1` vs `"1"`),
23
+ * which would otherwise be OR-combined by the evaluator against the intent
24
+ * of two independent constraints. See AttrLiteralEqual for the same rationale.
25
+ *
26
+ * Pass a shared `group` string to two instances to opt into OR semantics.
27
+ */
28
+ export declare class AttrLiteralNotEqual implements Rule {
29
+ private readonly config;
30
+ readonly ruleType: string;
31
+ readonly code = "attr_equal";
32
+ readonly message: string;
33
+ constructor(config: AttrLiteralNotEqualConfig);
34
+ verify(attrs: Attributes): boolean;
35
+ }
36
+ //# sourceMappingURL=AttrLiteralNotEqual.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttrLiteralNotEqual.d.mts","sourceRoot":"","sources":["../../src/rules/AttrLiteralNotEqual.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EACN,KAAK,YAAY,EAIjB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,yBAAyB;IACzC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,YAAY,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,mBAAoB,YAAW,IAAI;IAKnC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEI,MAAM,EAAE,yBAAyB;IAU9D,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;CAKlC"}
@@ -0,0 +1,42 @@
1
+ import { requireAttrName, requireLiteralValue, requireOptionalGroup, } from "./_sharedValidation.mjs";
2
+ /**
3
+ * Rule that passes when a named attribute is present, matches the type of the
4
+ * configured literal value, and is strictly NOT equal to it. No type coercion
5
+ * is performed. If the attribute is missing, null, or of the wrong type the
6
+ * rule returns false (safe-deny).
7
+ *
8
+ * ## Grouping and the default ruleType
9
+ *
10
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
11
+ * across groups. The default `ruleType` is derived from `a`, `typeof v`, and
12
+ * `String(v)`:
13
+ * `attr_literal_not_equal:{a}:{typeof v}:{String(v)}`
14
+ *
15
+ * The `typeof v` segment prevents silent `ruleType` collisions between
16
+ * different-type literals that stringify the same way (e.g. `1` vs `"1"`),
17
+ * which would otherwise be OR-combined by the evaluator against the intent
18
+ * of two independent constraints. See AttrLiteralEqual for the same rationale.
19
+ *
20
+ * Pass a shared `group` string to two instances to opt into OR semantics.
21
+ */
22
+ export class AttrLiteralNotEqual {
23
+ config;
24
+ ruleType;
25
+ code = "attr_equal";
26
+ message;
27
+ constructor(config) {
28
+ this.config = config;
29
+ requireAttrName("AttrLiteralNotEqual", "a", config.a);
30
+ requireLiteralValue("AttrLiteralNotEqual", "v", config.v);
31
+ const group = requireOptionalGroup("AttrLiteralNotEqual", config.group);
32
+ this.ruleType =
33
+ group ?? `attr_literal_not_equal:${config.a}:${typeof config.v}:${String(config.v)}`;
34
+ this.message = `Attribute constraint not satisfied: ${config.a} must not equal ${String(config.v)}.`;
35
+ }
36
+ verify(attrs) {
37
+ const x = attrs.get(this.config.a);
38
+ if (typeof x !== typeof this.config.v)
39
+ return false;
40
+ return x !== this.config.v;
41
+ }
42
+ }
@@ -0,0 +1,33 @@
1
+ import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
+ import { type LiteralValue } from "./_sharedValidation.mjs";
3
+ export interface AttrLiteralNotInConfig {
4
+ a: string;
5
+ values: LiteralValue[];
6
+ group?: string;
7
+ }
8
+ /**
9
+ * Rule that passes when a named attribute is present, matches the element type
10
+ * of the configured values array, and is NOT included in that array. No type
11
+ * coercion is performed. If the attribute is missing, null, or of the wrong
12
+ * type the rule returns false (safe-deny).
13
+ *
14
+ * ## Grouping and the default ruleType
15
+ *
16
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
17
+ * across groups. The default `ruleType` is derived from `a` and a stable
18
+ * content-hash key over the values array:
19
+ * `attr_literal_not_in:{a}:{valuesKey}`
20
+ *
21
+ * Pass an explicit `group` string to override the default ruleType entirely.
22
+ */
23
+ export declare class AttrLiteralNotIn implements Rule {
24
+ private readonly config;
25
+ readonly ruleType: string;
26
+ readonly code = "attr_in_set";
27
+ readonly message: string;
28
+ private readonly elementType;
29
+ private readonly valuesSet;
30
+ constructor(config: AttrLiteralNotInConfig);
31
+ verify(attrs: Attributes): boolean;
32
+ }
33
+ //# sourceMappingURL=AttrLiteralNotIn.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttrLiteralNotIn.d.mts","sourceRoot":"","sources":["../../src/rules/AttrLiteralNotIn.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAEN,KAAK,YAAY,EAIjB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,sBAAsB;IACtC,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAiB,YAAW,IAAI;IAQhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;gBAEjB,MAAM,EAAE,sBAAsB;IAa3D,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;CAKlC"}
@@ -0,0 +1,41 @@
1
+ import { computeValuesKey, requireAttrName, requireHomogeneousLiteralArray, requireOptionalGroup, } from "./_sharedValidation.mjs";
2
+ /**
3
+ * Rule that passes when a named attribute is present, matches the element type
4
+ * of the configured values array, and is NOT included in that array. No type
5
+ * coercion is performed. If the attribute is missing, null, or of the wrong
6
+ * type the rule returns false (safe-deny).
7
+ *
8
+ * ## Grouping and the default ruleType
9
+ *
10
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
11
+ * across groups. The default `ruleType` is derived from `a` and a stable
12
+ * content-hash key over the values array:
13
+ * `attr_literal_not_in:{a}:{valuesKey}`
14
+ *
15
+ * Pass an explicit `group` string to override the default ruleType entirely.
16
+ */
17
+ export class AttrLiteralNotIn {
18
+ config;
19
+ ruleType;
20
+ code = "attr_in_set";
21
+ message;
22
+ elementType;
23
+ valuesSet;
24
+ constructor(config) {
25
+ this.config = config;
26
+ requireAttrName("AttrLiteralNotIn", "a", config.a);
27
+ const values = requireHomogeneousLiteralArray("AttrLiteralNotIn", config.values);
28
+ const group = requireOptionalGroup("AttrLiteralNotIn", config.group);
29
+ this.elementType = typeof values[0];
30
+ this.valuesSet = new Set(values);
31
+ const valuesKey = computeValuesKey(values);
32
+ this.ruleType = group ?? `attr_literal_not_in:${config.a}:${valuesKey}`;
33
+ this.message = `Attribute constraint not satisfied: ${config.a} must not be one of [${values.map(String).join(", ")}].`;
34
+ }
35
+ verify(attrs) {
36
+ const x = attrs.get(this.config.a);
37
+ if (typeof x !== this.elementType)
38
+ return false;
39
+ return !this.valuesSet.has(x);
40
+ }
41
+ }
@@ -1,42 +1,15 @@
1
- import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
- export interface AttrMatchRuleConfig {
3
- a: string;
4
- b: string;
5
- /**
6
- * Optional grouping key used as `ruleType`. See the class comment for
7
- * how this interacts with the evaluator's OR-within-group /
8
- * AND-across-groups semantics.
9
- */
10
- group?: string;
11
- }
1
+ import { AttrPairEqual, type AttrPairEqualConfig } from "./AttrPairEqual.mjs";
2
+ export type AttrMatchRuleConfig = AttrPairEqualConfig;
12
3
  /**
13
- * Rule that passes when two named attributes are present, are non-empty
14
- * strings, and are equal. A pure predicate over the attributes map —
15
- * `verify(attrs)` does not touch `CollectorContext` and does not close
16
- * over request state.
17
- *
18
- * ## Grouping and the default ruleType
19
- *
20
- * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
21
- * across groups. If every `AttrMatchRule` shared one fixed `ruleType`,
22
- * two instances collected for different comparisons (e.g. subject vs.
23
- * subscriber AND tenant vs. request-tenant) would be OR'd together and
24
- * authorization would weaken silently.
25
- *
26
- * To default to the safe reading of "each distinct pair of attributes
27
- * is a separate AND-combined requirement", `ruleType` is derived from
28
- * `a` and `b` when `group` is not given: `attr_match:{a}:{b}`.
4
+ * @deprecated Use {@link AttrPairEqual}. Scheduled for removal in a future major version.
29
5
  *
30
- * When callers actually want two comparisons to be OR-combined
31
- * (alternative identities, for example), they opt in explicitly by
32
- * passing the same `group` to both rule instances.
6
+ * Kept as a thin wrapper that preserves the legacy `ruleType` (`attr_match:{a}:{b}`)
7
+ * and legacy `message` wording. `verify()` semantics are inherited unchanged from
8
+ * `AttrPairEqual`: both named attributes must be non-empty strings and equal.
33
9
  */
34
- export declare class AttrMatchRule implements Rule {
35
- private readonly config;
10
+ export declare class AttrMatchRule extends AttrPairEqual {
36
11
  readonly ruleType: string;
37
- readonly code = "attr_mismatch";
38
12
  readonly message: string;
39
13
  constructor(config: AttrMatchRuleConfig);
40
- verify(attrs: Attributes): boolean;
41
14
  }
42
15
  //# sourceMappingURL=AttrMatchRule.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AttrMatchRule.d.mts","sourceRoot":"","sources":["../../src/rules/AttrMatchRule.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,WAAW,mBAAmB;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAc,YAAW,IAAI;IAK7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEI,MAAM,EAAE,mBAAmB;IAKxD,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;CAOlC"}
1
+ {"version":3,"file":"AttrMatchRule.d.mts","sourceRoot":"","sources":["../../src/rules/AttrMatchRule.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE9E,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAEtD;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,aAAa;IAC/C,SAAkB,QAAQ,EAAE,MAAM,CAAC;IACnC,SAAkB,OAAO,EAAE,MAAM,CAAC;gBAEtB,MAAM,EAAE,mBAAmB;CAKvC"}
@@ -1,42 +1,17 @@
1
+ import { AttrPairEqual } from "./AttrPairEqual.mjs";
1
2
  /**
2
- * Rule that passes when two named attributes are present, are non-empty
3
- * strings, and are equal. A pure predicate over the attributes map —
4
- * `verify(attrs)` does not touch `CollectorContext` and does not close
5
- * over request state.
3
+ * @deprecated Use {@link AttrPairEqual}. Scheduled for removal in a future major version.
6
4
  *
7
- * ## Grouping and the default ruleType
8
- *
9
- * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
10
- * across groups. If every `AttrMatchRule` shared one fixed `ruleType`,
11
- * two instances collected for different comparisons (e.g. subject vs.
12
- * subscriber AND tenant vs. request-tenant) would be OR'd together and
13
- * authorization would weaken silently.
14
- *
15
- * To default to the safe reading of "each distinct pair of attributes
16
- * is a separate AND-combined requirement", `ruleType` is derived from
17
- * `a` and `b` when `group` is not given: `attr_match:{a}:{b}`.
18
- *
19
- * When callers actually want two comparisons to be OR-combined
20
- * (alternative identities, for example), they opt in explicitly by
21
- * passing the same `group` to both rule instances.
5
+ * Kept as a thin wrapper that preserves the legacy `ruleType` (`attr_match:{a}:{b}`)
6
+ * and legacy `message` wording. `verify()` semantics are inherited unchanged from
7
+ * `AttrPairEqual`: both named attributes must be non-empty strings and equal.
22
8
  */
23
- export class AttrMatchRule {
24
- config;
9
+ export class AttrMatchRule extends AttrPairEqual {
25
10
  ruleType;
26
- code = "attr_mismatch";
27
11
  message;
28
12
  constructor(config) {
29
- this.config = config;
13
+ super(config);
30
14
  this.ruleType = config.group ?? `attr_match:${config.a}:${config.b}`;
31
15
  this.message = `Attribute constraint not satisfied: ${config.a} and ${config.b} must both be non-empty strings and equal.`;
32
16
  }
33
- verify(attrs) {
34
- const a = attrs.get(this.config.a);
35
- const b = attrs.get(this.config.b);
36
- if (typeof a !== "string" || a.length === 0)
37
- return false;
38
- if (typeof b !== "string" || b.length === 0)
39
- return false;
40
- return a === b;
41
- }
42
17
  }
@@ -0,0 +1,35 @@
1
+ import type { Attributes, Rule } from "@o3co/auth.policy-verifier.core";
2
+ import { type CompareOp } from "./_sharedValidation.mjs";
3
+ export interface AttrPairCompareConfig {
4
+ a: string;
5
+ op: CompareOp;
6
+ b: string;
7
+ group?: string;
8
+ }
9
+ /**
10
+ * Rule that passes when two named attributes are present, are both numbers,
11
+ * and satisfy the configured comparison operator. NaN on either side always
12
+ * returns false (JS native comparison semantics). Missing, null, or non-number
13
+ * attributes return false (safe-deny).
14
+ *
15
+ * Unlike AttrLiteralCompare, the right-hand side comes from the attributes map
16
+ * at evaluation time rather than from a static config value — so NaN is not
17
+ * rejected at construction time.
18
+ *
19
+ * ## Grouping and the default ruleType
20
+ *
21
+ * The evaluator groups rules by `ruleType`, ORs within a group, and ANDs
22
+ * across groups. The default `ruleType` is derived from `a`, `op`, and `b`:
23
+ * `attr_pair_compare:{a}:{op}:{b}`
24
+ *
25
+ * Pass an explicit `group` string to override the default ruleType entirely.
26
+ */
27
+ export declare class AttrPairCompare implements Rule {
28
+ private readonly config;
29
+ readonly ruleType: string;
30
+ readonly code = "attr_compare_violated";
31
+ readonly message: string;
32
+ constructor(config: AttrPairCompareConfig);
33
+ verify(attrs: Attributes): boolean;
34
+ }
35
+ //# sourceMappingURL=AttrPairCompare.d.mts.map