@rsconcept/rstool 1.7.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +7 -7
  2. package/dist/index.js +1 -1
  3. package/dist/mappers/model-adapter.d.ts +6 -2
  4. package/dist/mappers/model-adapter.js +28 -3
  5. package/dist/mappers/model-adapter.js.map +1 -1
  6. package/dist/mappers/schema-adapter.d.ts +1 -2
  7. package/dist/mappers/schema-adapter.js +1 -1
  8. package/dist/mappers/types.d.ts +4 -5
  9. package/dist/models/index.js +1 -1
  10. package/dist/models/rstool-agent.js +1 -2
  11. package/dist/{models-DG2uTaV_.js → models-D06g8LId.js} +6 -5
  12. package/dist/{models-DG2uTaV_.js.map → models-D06g8LId.js.map} +1 -1
  13. package/dist/{rsform-builder-DKwZfJvN.js → rsform-builder-BlXEe5Ow.js} +2 -2
  14. package/dist/{rsform-builder-DKwZfJvN.js.map → rsform-builder-BlXEe5Ow.js.map} +1 -1
  15. package/dist/session/session-store.d.ts +3 -3
  16. package/dist/session/session-store.js +1 -2
  17. package/dist/wrapper/client.d.ts +15 -9
  18. package/dist/wrapper/client.js +79 -12
  19. package/dist/wrapper/client.js.map +1 -1
  20. package/dist/wrapper/stdio-wrapper.d.ts +1 -1
  21. package/dist/wrapper/stdio-wrapper.js +18 -10
  22. package/dist/wrapper/stdio-wrapper.js.map +1 -1
  23. package/docs/BRIEF.md +93 -0
  24. package/docs/CONCEPTUAL-SCHEMA.md +17 -2
  25. package/docs/CONSTRUCTIONS.md +384 -0
  26. package/docs/DIAGNOSTICS.md +9 -8
  27. package/docs/DOMAIN.md +12 -0
  28. package/docs/METHOD.md +208 -0
  29. package/docs/MODEL-TESTING.md +48 -0
  30. package/docs/PORTAL-API.md +38 -285
  31. package/docs/PORTAL-MODELS.md +24 -0
  32. package/docs/PORTAL-OSS.md +56 -0
  33. package/docs/PORTAL-PUBLISH.md +39 -0
  34. package/docs/PORTAL-READ.md +301 -0
  35. package/docs/README.md +8 -4
  36. package/docs/REQUIREMENTS.md +61 -0
  37. package/docs/SYNTAX.md +5 -4
  38. package/docs/TYPIFICATION.md +12 -3
  39. package/docs/brief.schema.json +173 -0
  40. package/examples/README.md +16 -2
  41. package/examples/access-control/NOTES.md +23 -0
  42. package/examples/access-control/anti/collapsed.json +439 -0
  43. package/examples/access-control/anti/weakened.json +439 -0
  44. package/examples/access-control/brief-v1.json +231 -0
  45. package/examples/access-control/brief.json +310 -0
  46. package/examples/access-control/build-rsform.ts +151 -0
  47. package/examples/access-control/requirements-v1.md +9 -0
  48. package/examples/access-control/requirements-v2.md +4 -0
  49. package/examples/access-control/rsform-session-v1.json +439 -0
  50. package/examples/access-control/rsform-session.json +523 -0
  51. package/examples/audit-diagnostics.ts +9 -1
  52. package/examples/briefs.test.ts +126 -0
  53. package/examples/clinic-booking/NOTES.md +24 -0
  54. package/examples/clinic-booking/anti/collapsed.json +615 -0
  55. package/examples/clinic-booking/anti/species-as-genus.json +568 -0
  56. package/examples/clinic-booking/brief-v1.json +332 -0
  57. package/examples/clinic-booking/brief.json +405 -0
  58. package/examples/clinic-booking/build-rsform.ts +174 -0
  59. package/examples/clinic-booking/requirements-v1.md +9 -0
  60. package/examples/clinic-booking/requirements-v2.md +4 -0
  61. package/examples/clinic-booking/rsform-session-v1.json +615 -0
  62. package/examples/clinic-booking/rsform-session.json +700 -0
  63. package/examples/diagnostics-utils.ts +26 -0
  64. package/examples/kinship/brief.json +337 -0
  65. package/examples/kinship/build-rsform.ts +7 -4
  66. package/examples/kinship/rsform-session.json +20 -63
  67. package/examples/kinship/rsmodel-session.json +14 -14
  68. package/examples/kinship-subordination/NOTES.md +49 -0
  69. package/examples/kinship-subordination/brief.json +161 -0
  70. package/examples/kinship-subordination/build-rsform.ts +100 -0
  71. package/examples/kinship-subordination/rsform-session.json +795 -0
  72. package/examples/library-loans/NOTES.md +46 -0
  73. package/examples/library-loans/anti/collapsed.json +481 -0
  74. package/examples/library-loans/anti/species-as-genus.json +334 -0
  75. package/examples/library-loans/anti/uncovered.json +406 -0
  76. package/examples/library-loans/anti/weakened.json +464 -0
  77. package/examples/library-loans/brief-v1.json +340 -0
  78. package/examples/library-loans/brief.json +502 -0
  79. package/examples/library-loans/build-rsform.ts +239 -0
  80. package/examples/library-loans/requirements-v1.md +11 -0
  81. package/examples/library-loans/requirements-v2.md +5 -0
  82. package/examples/library-loans/rsform-session-v1.json +481 -0
  83. package/examples/library-loans/rsform-session.json +652 -0
  84. package/examples/library-loans/source-markup.md +18 -0
  85. package/examples/movd/brief.json +220 -0
  86. package/examples/movd/build-rsform.ts +5 -2
  87. package/examples/movd/rsform-session.json +14 -46
  88. package/examples/subordination/NOTES.md +59 -0
  89. package/examples/subordination/anti/collapsed.json +556 -0
  90. package/examples/subordination/anti/single-relation.json +125 -0
  91. package/examples/subordination/anti/transitive.json +573 -0
  92. package/examples/subordination/anti/weakened.json +539 -0
  93. package/examples/subordination/brief.json +386 -0
  94. package/examples/subordination/build-rsform.ts +63 -0
  95. package/examples/subordination/constants.ts +115 -0
  96. package/examples/subordination/rsform-session.json +556 -0
  97. package/examples/subordination/source-markup.md +19 -0
  98. package/examples/subordination/source.md +40 -0
  99. package/package.json +29 -20
  100. package/skills/INSTALL.md +28 -29
  101. package/skills/README.md +25 -10
  102. package/skills/rs-core/SKILL.md +56 -0
  103. package/skills/rs-explain/SKILL.md +28 -0
  104. package/skills/rs-explicate/SKILL.md +71 -0
  105. package/skills/rs-interpret/SKILL.md +67 -0
  106. package/skills/rs-portal/SKILL.md +51 -0
  107. package/skills/rs-review/SKILL.md +79 -0
  108. package/skills/rs-scope/SKILL.md +67 -0
  109. package/skills/rs-synthesis/SKILL.md +52 -0
  110. package/skills/rstool/SKILL.md +70 -0
  111. package/skills/rstool-helper/GUIDE.md +18 -272
  112. package/skills/rstool-helper/SKILL.md +8 -55
  113. package/skills/{rstool-helper → rstool-runtime}/EXAMPLES.md +40 -12
  114. package/skills/{rstool-helper → rstool-runtime}/REFERENCE.md +28 -7
  115. package/skills/rstool-runtime/SKILL.md +96 -0
  116. package/skills/scripts/brief-check.test.ts +165 -0
  117. package/skills/scripts/brief-check.ts +826 -0
  118. package/skills/scripts/check-brief.ts +94 -0
  119. package/skills/scripts/rstool-skills.mjs +119 -0
  120. package/skills/scripts/skill-stubs.test.ts +48 -0
  121. package/src/mappers/model-adapter.ts +34 -1
  122. package/src/models/rstool-agent.test.ts +95 -0
  123. package/src/wrapper/client.test.ts +43 -4
  124. package/src/wrapper/client.ts +95 -16
  125. package/src/wrapper/stdio-handler.test.ts +43 -0
  126. package/src/wrapper/stdio-handler.ts +19 -5
@@ -0,0 +1,310 @@
1
+ {
2
+ "version": 1,
3
+ "status": "confirmed",
4
+ "approach": "project",
5
+ "object": "Ролевое управление доступом",
6
+ "task": "Эксплицировать роли, иерархию и эффективные права для проектирования подсистемы доступа и проверок при назначении ролей",
7
+ "source": "requirements-v1.md, requirements-v2.md",
8
+ "restrictions": [
9
+ {
10
+ "id": "L1",
11
+ "excludes": "журнал изменений и сроки хранения (п. 6)",
12
+ "inexpressible": ["кто и когда выдал право", "права на прошлую дату"]
13
+ },
14
+ {
15
+ "id": "L2",
16
+ "excludes": "аутентификация (п. 7)",
17
+ "inexpressible": ["способ входа", "учётная запись SSO"]
18
+ },
19
+ {
20
+ "id": "L3",
21
+ "excludes": "ресурсы как объекты: право — неделимый элемент",
22
+ "inexpressible": ["права на конкретный документ"]
23
+ }
24
+ ],
25
+ "expressiveness": [
26
+ {
27
+ "id": "E1",
28
+ "concept": "младшие роли (замыкание иерархии)",
29
+ "ref": "п. 2",
30
+ "via": "замыкание S3 через R{}",
31
+ "constituent": "F1"
32
+ },
33
+ {
34
+ "id": "E2",
35
+ "concept": "прямые роли пользователя",
36
+ "ref": "п. 3",
37
+ "via": "постоянные назначения ∪ временные с действующим периодом",
38
+ "constituent": "F2"
39
+ },
40
+ {
41
+ "id": "E3",
42
+ "concept": "унаследованные роли пользователя",
43
+ "ref": "п. 5",
44
+ "via": "объединение младших ролей прямых ролей минус прямые",
45
+ "constituent": "F3"
46
+ },
47
+ {
48
+ "id": "E4",
49
+ "concept": "назначенные права",
50
+ "ref": "п. 3",
51
+ "via": "права прямых ролей",
52
+ "constituent": "F5"
53
+ },
54
+ {
55
+ "id": "E5",
56
+ "concept": "эффективные права",
57
+ "ref": "п. 3",
58
+ "via": "права прямых и унаследованных ролей",
59
+ "constituent": "F6"
60
+ },
61
+ {
62
+ "id": "E6",
63
+ "concept": "временные назначения",
64
+ "ref": "v2 п. 1",
65
+ "via": "родовая структура (пользователь, роль, с, по)",
66
+ "constituent": "S5"
67
+ }
68
+ ],
69
+ "distinctions": [
70
+ {
71
+ "id": "V1",
72
+ "between": ["E4", "E5"],
73
+ "text": "назначенные права ≠ эффективные",
74
+ "witness": "SC1"
75
+ },
76
+ {
77
+ "id": "V2",
78
+ "between": ["E2", "E3"],
79
+ "text": "прямая роль ≠ унаследованная",
80
+ "witness": "SC1"
81
+ }
82
+ ],
83
+ "invariants": [
84
+ {
85
+ "id": "I1",
86
+ "text": "В иерархии ролей нет циклов",
87
+ "ref": "п. 2",
88
+ "constituent": "A1",
89
+ "positive": "SC1",
90
+ "negative": "SC2"
91
+ },
92
+ {
93
+ "id": "I2",
94
+ "text": "Нет пользователя с обеими ролями несовместимой пары, в том числе через иерархию",
95
+ "ref": "п. 4",
96
+ "constituent": "A2",
97
+ "positive": "SC1",
98
+ "negative": "SC3"
99
+ },
100
+ {
101
+ "id": "I3",
102
+ "text": "Период временного назначения корректен",
103
+ "constituent": "A3",
104
+ "positive": "SC4",
105
+ "negative": "SC6"
106
+ }
107
+ ],
108
+ "decisions": [
109
+ {
110
+ "id": "DC1",
111
+ "topic": "иерархия ролей",
112
+ "alternatives": ["плоские роли без иерархии", "дерево: у роли одна старшая", "отношение S3 (старшая, младшая)"],
113
+ "choice": "отношение S3",
114
+ "rationale": "п. 2; роль может входить в несколько старших — дерево избыточно ограничивает"
115
+ },
116
+ {
117
+ "id": "DC2",
118
+ "topic": "права пользователя",
119
+ "alternatives": ["структура «права пользователя» S#", "вывод через роли"],
120
+ "choice": "вывод через роли (F5, F6)",
121
+ "rationale": "права пользователя не задаются отдельно — иначе разойдутся с ролями"
122
+ },
123
+ {
124
+ "id": "DC3",
125
+ "topic": "разделение обязанностей",
126
+ "alternatives": ["по прямым ролям", "по эффективным ролям"],
127
+ "choice": "по эффективным ролям (A2)",
128
+ "rationale": "п. 4: «в том числе через иерархию»"
129
+ },
130
+ {
131
+ "id": "DC4",
132
+ "topic": "симметричность несовместимости",
133
+ "choice": "без аксиомы",
134
+ "rationale": "A2 запрещает пару в любом порядке; достаточно записать пару один раз"
135
+ },
136
+ {
137
+ "id": "DC5",
138
+ "topic": "ацикличность иерархии",
139
+ "choice": "аксиома A1 через замыкание F1",
140
+ "rationale": "п. 2"
141
+ },
142
+ {
143
+ "id": "DC6",
144
+ "topic": "прямые роли с временными назначениями",
145
+ "supersedes": "DC2",
146
+ "choice": "F2 включает временные роли с действующим периодом",
147
+ "rationale": "v2 п. 1; без временных назначений совпадает с v1"
148
+ },
149
+ {
150
+ "id": "DC7",
151
+ "topic": "временное назначение",
152
+ "alternatives": ["период как компонента S1 (ломает v1)", "отдельная структура S5"],
153
+ "choice": "S5 (пользователь, роль, первый день, последний день) и текущий день S6",
154
+ "rationale": "S1 и сценарии v1 не меняются; E6 — родовая структура по DC7"
155
+ }
156
+ ],
157
+ "scenarios": [
158
+ {
159
+ "id": "SC1",
160
+ "title": "Администратор и наблюдатель-аудитор",
161
+ "values": {
162
+ "X1": ["ann", "bob"],
163
+ "X2": ["admin", "editor", "viewer", "auditor"],
164
+ "X3": ["read", "write", "delete", "audit"],
165
+ "S1": [
166
+ ["ann", "admin"],
167
+ ["bob", "viewer"],
168
+ ["bob", "auditor"]
169
+ ],
170
+ "S2": [
171
+ ["viewer", "read"],
172
+ ["editor", "write"],
173
+ ["admin", "delete"],
174
+ ["auditor", "audit"]
175
+ ],
176
+ "S3": [
177
+ ["admin", "editor"],
178
+ ["editor", "viewer"]
179
+ ],
180
+ "S4": [["admin", "auditor"]],
181
+ "S6": 1
182
+ },
183
+ "expect": [
184
+ {
185
+ "of": "F1",
186
+ "args": ["admin"],
187
+ "value": ["editor", "viewer"]
188
+ },
189
+ {
190
+ "of": "F3",
191
+ "args": ["ann"],
192
+ "value": ["editor", "viewer"]
193
+ },
194
+ {
195
+ "of": "F3",
196
+ "args": ["bob"],
197
+ "value": []
198
+ },
199
+ {
200
+ "of": "F5",
201
+ "args": ["ann"],
202
+ "value": ["delete"]
203
+ },
204
+ {
205
+ "of": "F6",
206
+ "args": ["ann"],
207
+ "value": ["read", "write", "delete"]
208
+ },
209
+ {
210
+ "of": "F6",
211
+ "args": ["bob"],
212
+ "value": ["read", "audit"]
213
+ }
214
+ ]
215
+ },
216
+ {
217
+ "id": "SC2",
218
+ "title": "Цикл в иерархии",
219
+ "base": "SC1",
220
+ "values": {
221
+ "S3": [
222
+ ["admin", "editor"],
223
+ ["editor", "viewer"],
224
+ ["viewer", "admin"]
225
+ ]
226
+ },
227
+ "expect": [
228
+ {
229
+ "of": "A1",
230
+ "holds": false
231
+ }
232
+ ]
233
+ },
234
+ {
235
+ "id": "SC3",
236
+ "title": "Несовместимость через наследование",
237
+ "base": "SC1",
238
+ "values": {
239
+ "S1": [
240
+ ["ann", "admin"],
241
+ ["ann", "auditor"]
242
+ ],
243
+ "S4": [["editor", "auditor"]]
244
+ },
245
+ "expect": [
246
+ {
247
+ "of": "A2",
248
+ "holds": false
249
+ },
250
+ {
251
+ "of": "F2",
252
+ "args": ["ann"],
253
+ "value": ["admin", "auditor"]
254
+ }
255
+ ]
256
+ },
257
+ {
258
+ "id": "SC4",
259
+ "title": "Временная роль действует",
260
+ "base": "SC1",
261
+ "values": {
262
+ "S5": [["bob", "editor", 5, 10]],
263
+ "S6": 7
264
+ },
265
+ "expect": [
266
+ {
267
+ "of": "F2",
268
+ "args": ["bob"],
269
+ "value": ["editor", "viewer", "auditor"]
270
+ },
271
+ {
272
+ "of": "F6",
273
+ "args": ["bob"],
274
+ "contains": ["write"]
275
+ }
276
+ ]
277
+ },
278
+ {
279
+ "id": "SC5",
280
+ "title": "Временная роль истекла",
281
+ "base": "SC4",
282
+ "values": {
283
+ "S6": 12
284
+ },
285
+ "expect": [
286
+ {
287
+ "of": "F6",
288
+ "args": ["bob"],
289
+ "excludes": ["write"]
290
+ }
291
+ ]
292
+ },
293
+ {
294
+ "id": "SC6",
295
+ "title": "Период задом наперёд",
296
+ "base": "SC1",
297
+ "values": {
298
+ "S5": [["bob", "editor", 10, 5]]
299
+ },
300
+ "expect": [
301
+ {
302
+ "of": "A3",
303
+ "holds": false
304
+ }
305
+ ]
306
+ }
307
+ ],
308
+ "assumptions": ["право — неделимый элемент, без привязки к конкретному ресурсу"],
309
+ "openQuestions": []
310
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * «Ролевой доступ»: RBAC with role hierarchy and separation of duties (v1), temporary roles (v2); anti-examples.
3
+ * Run from the package root: `pnpm run example:build-access-control-schema`.
4
+ */
5
+ import { mkdirSync, writeFileSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+
8
+ import { type AgentConstituentaPatch, RSToolAgent } from '../../src';
9
+
10
+ import { describeBrief, formatDiagnostics } from '../diagnostics-utils';
11
+
12
+ const V1_ITEMS: AgentConstituentaPatch[] = [
13
+ { alias: 'X1', term: 'пользователи', convention: 'Учётные записи пользователей системы.' },
14
+ { alias: 'X2', term: 'роли', convention: 'Роли доступа (администратор, редактор, …).' },
15
+ { alias: 'X3', term: 'права', convention: 'Элементарные права: действие над видом ресурса (чтение документов, …).' },
16
+ {
17
+ alias: 'S1',
18
+ term: 'назначения ролей',
19
+ definitionFormal: 'ℬ(X1×X2)',
20
+ convention: 'Пара (пользователь, роль): роль назначена пользователю напрямую.'
21
+ },
22
+ {
23
+ alias: 'S2',
24
+ term: 'права роли',
25
+ definitionFormal: 'ℬ(X2×X3)',
26
+ convention: 'Пара (роль, право): право дано роли напрямую.'
27
+ },
28
+ {
29
+ alias: 'S3',
30
+ term: 'иерархия ролей',
31
+ definitionFormal: 'ℬ(X2×X2)',
32
+ convention: 'Пара (старшая, младшая): старшая роль включает права младшей.'
33
+ },
34
+ {
35
+ alias: 'S4',
36
+ term: 'несовместимые роли',
37
+ definitionFormal: 'ℬ(X2×X2)',
38
+ convention: 'Пара ролей, которые нельзя иметь одному пользователю (разделение обязанностей).'
39
+ },
40
+ {
41
+ alias: 'F1',
42
+ term: 'младшие роли',
43
+ definitionFormal: '[ρ∈X2] R{σ:=Pr2(Fi1[{ρ}](S3)) | σ∪Pr2(Fi1[σ](S3))}',
44
+ definitionText: 'Роли, которые данная роль включает напрямую или через цепочку.'
45
+ },
46
+ {
47
+ alias: 'F2',
48
+ term: 'прямые роли',
49
+ definitionFormal: '[ξ∈X1] Pr2(Fi1[{ξ}](S1))',
50
+ definitionText: 'Роли, назначенные пользователю напрямую.'
51
+ },
52
+ {
53
+ alias: 'F3',
54
+ term: 'унаследованные роли',
55
+ definitionFormal: '[ξ∈X1] red(I{F1[ρ] | ρ:∈F2[ξ]})\\F2[ξ]',
56
+ definitionText: 'Роли, которые пользователь получает только через иерархию.'
57
+ },
58
+ {
59
+ alias: 'F4',
60
+ term: 'эффективные роли',
61
+ definitionFormal: '[ξ∈X1] F2[ξ]∪F3[ξ]',
62
+ definitionText: 'Прямые и унаследованные роли пользователя.'
63
+ },
64
+ {
65
+ alias: 'F5',
66
+ term: 'назначенные права',
67
+ definitionFormal: '[ξ∈X1] Pr2(Fi1[F2[ξ]](S2))',
68
+ definitionText: 'Права прямых ролей пользователя.'
69
+ },
70
+ {
71
+ alias: 'F6',
72
+ term: 'эффективные права',
73
+ definitionFormal: '[ξ∈X1] Pr2(Fi1[F4[ξ]](S2))',
74
+ definitionText: 'Права всех ролей пользователя, включая унаследованные.'
75
+ },
76
+ {
77
+ alias: 'A1',
78
+ term: 'иерархия без циклов',
79
+ definitionFormal: '∀ρ∈X2 ρ∉F1[ρ]',
80
+ definitionText: 'Роль не включает саму себя ни напрямую, ни через цепочку.'
81
+ },
82
+ {
83
+ alias: 'A2',
84
+ term: 'разделение обязанностей',
85
+ definitionFormal: '∀ξ∈X1 ∀(α,β)∈S4 ¬(α∈F4[ξ] & β∈F4[ξ])',
86
+ definitionText: 'Ни у одного пользователя нет обеих ролей несовместимой пары, в том числе через иерархию.'
87
+ }
88
+ ];
89
+
90
+ /** Change request v2: temporary role assignments; F2 is redefined by decision DC6. */
91
+ const V2_ITEMS: AgentConstituentaPatch[] = [
92
+ {
93
+ alias: 'S5',
94
+ term: 'временные назначения',
95
+ definitionFormal: 'ℬ(X1×X2×Z×Z)',
96
+ convention: 'Четвёрка (пользователь, роль, первый день, последний день): роль действует в эти дни включительно.'
97
+ },
98
+ {
99
+ alias: 'S6',
100
+ term: 'текущий день',
101
+ definitionFormal: 'Z',
102
+ convention: 'Номер текущего дня в той же нумерации, что и периоды назначений.'
103
+ },
104
+ {
105
+ alias: 'F2',
106
+ definitionFormal: '[ξ∈X1] Pr2(Fi1[{ξ}](S1)) ∪ I{pr2(τ) | τ:∈Fi1[{ξ}](S5); pr3(τ)≤S6; S6≤pr4(τ)}',
107
+ definitionText: 'Роли, назначенные пользователю напрямую: постоянно или временно с действующим сегодня периодом.'
108
+ },
109
+ {
110
+ alias: 'A3',
111
+ term: 'период назначения корректен',
112
+ definitionFormal: '∀τ∈S5 pr3(τ)≤pr4(τ)',
113
+ definitionText: 'Первый день периода не позже последнего.'
114
+ }
115
+ ];
116
+
117
+ const ANTI_EXAMPLES: Record<string, AgentConstituentaPatch[]> = {
118
+ weakened: V1_ITEMS.map(item =>
119
+ item.alias === 'A2' ? { ...item, definitionFormal: '∀ξ∈X1 ∀(α,β)∈S4 ¬(α∈F2[ξ] & β∈F2[ξ])' } : item
120
+ ),
121
+ collapsed: V1_ITEMS.map(item => (item.alias === 'F6' ? { ...item, definitionFormal: '[ξ∈X1] F5[ξ]' } : item))
122
+ };
123
+
124
+ function build(title: string, brief: string, ...batches: AgentConstituentaPatch[][]): string {
125
+ const tool = new RSToolAgent();
126
+ tool.createSession({ alias: 'RBAC', title, comment: describeBrief(resolve(import.meta.dirname, brief)) });
127
+ for (const [index, items] of batches.entries()) {
128
+ const result = tool.applySchemaPatch({ items, commitMessage: `${title}: шаг ${index + 1}` });
129
+ if (!result.success) {
130
+ throw new Error(`${title}: ${formatDiagnostics(result.diagnostics)}`);
131
+ }
132
+ }
133
+ const diagnostics = tool.listDiagnostics();
134
+ if (diagnostics.length > 0) {
135
+ throw new Error(`${title}: ${formatDiagnostics(diagnostics)}`);
136
+ }
137
+ return tool.exportSession() + '\n';
138
+ }
139
+
140
+ function run() {
141
+ const root = import.meta.dirname;
142
+ writeFileSync(resolve(root, 'rsform-session-v1.json'), build('Ролевой доступ', 'brief-v1.json', V1_ITEMS));
143
+ writeFileSync(resolve(root, 'rsform-session.json'), build('Ролевой доступ', 'brief.json', V1_ITEMS, V2_ITEMS));
144
+ mkdirSync(resolve(root, 'anti'), { recursive: true });
145
+ for (const [name, items] of Object.entries(ANTI_EXAMPLES)) {
146
+ writeFileSync(resolve(root, 'anti', `${name}.json`), build(`Антипример: ${name}`, 'brief-v1.json', items));
147
+ }
148
+ console.log(`access-control: v1, v2 + ${Object.keys(ANTI_EXAMPLES).length} anti-examples`);
149
+ }
150
+
151
+ run();
@@ -0,0 +1,9 @@
1
+ # Требования «Ролевой доступ», v1 (фрагмент)
2
+
3
+ 1. Пользователю назначают роли. Роли дают права.
4
+ 2. Роли образуют иерархию: старшая роль включает права младших. Циклов в иерархии быть не может.
5
+ 3. Права, назначенные пользователю, — права его прямых ролей. Эффективные права — права всех ролей, прямых и унаследованных по иерархии.
6
+ 4. Разделение обязанностей: некоторые пары ролей несовместимы; пользователь не может иметь (в том числе через иерархию) обе роли пары.
7
+ 5. Администратор видит, откуда у пользователя право: от прямой или унаследованной роли.
8
+ 6. Все изменения прав журналируются; журнал хранится 3 года.
9
+ 7. Вход по паролю или через корпоративный SSO.
@@ -0,0 +1,4 @@
1
+ # Запрос на изменение v2
2
+
3
+ 1. Роль можно назначить временно: с дня по день включительно. Вне периода временная роль не действует.
4
+ 2. Постоянные назначения и всё остальное из v1 работают как раньше.