@spacefast/common 0.0.11 → 0.0.12
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/agents/connect-targets.d.ts +4 -4
- package/dist/agents/connect-targets.js +3 -3
- package/dist/agents/private-key-oauth.d.ts +37 -0
- package/dist/agents/private-key-oauth.js +158 -0
- package/dist/config/domains.js +1 -1
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +1 -0
- package/dist/config/postgres-budget.d.ts +126 -0
- package/dist/config/postgres-budget.js +135 -0
- package/dist/config/postgres-budget.json +50 -0
- package/dist/contracts/access.d.ts +42 -24
- package/dist/contracts/access.js +73 -34
- package/dist/contracts/activity.d.ts +1 -1
- package/dist/contracts/activity.js +5 -5
- package/dist/contracts/api-keys.d.ts +53 -45
- package/dist/contracts/api-keys.js +1 -0
- package/dist/contracts/archives.d.ts +8 -8
- package/dist/contracts/builds.d.ts +8 -8
- package/dist/contracts/builds.js +28 -48
- package/dist/contracts/channels.js +1 -2
- package/dist/contracts/comments.d.ts +55 -19
- package/dist/contracts/comments.js +56 -17
- package/dist/contracts/common.d.ts +4 -3
- package/dist/contracts/common.js +2 -0
- package/dist/contracts/deployments.d.ts +3 -3
- package/dist/contracts/device-auth.d.ts +14 -12
- package/dist/contracts/docs.d.ts +5 -5
- package/dist/contracts/domains.d.ts +261 -1330
- package/dist/contracts/domains.js +39 -301
- package/dist/contracts/email-preferences.d.ts +50 -0
- package/dist/contracts/email-preferences.js +44 -0
- package/dist/contracts/enums.d.ts +1 -1
- package/dist/contracts/error-code-meta.d.ts +84 -15
- package/dist/contracts/error-code-meta.js +28 -4
- package/dist/contracts/error-codes.d.ts +1 -1
- package/dist/contracts/error-codes.js +24 -6
- package/dist/contracts/events.d.ts +13 -13
- package/dist/contracts/feature-lifecycle.d.ts +644 -2
- package/dist/contracts/feature-lifecycle.js +685 -2
- package/dist/contracts/features.d.ts +236 -24
- package/dist/contracts/features.js +3 -272
- package/dist/contracts/ids.d.ts +1 -2
- package/dist/contracts/ids.js +1 -2
- package/dist/contracts/internal.d.ts +3 -3
- package/dist/contracts/mcp.d.ts +6 -6
- package/dist/contracts/me.js +1 -1
- package/dist/contracts/mounts.d.ts +142 -0
- package/dist/contracts/mounts.js +56 -0
- package/dist/contracts/oauth-resources.d.ts +5 -5
- package/dist/contracts/oauth-resources.js +1 -0
- package/dist/contracts/operations.d.ts +2 -2
- package/dist/contracts/pages.d.ts +2 -2
- package/dist/contracts/pages.js +8 -3
- package/dist/contracts/plan-policy.d.ts +1 -1
- package/dist/contracts/platform.d.ts +3 -3
- package/dist/contracts/resources.d.ts +12 -20
- package/dist/contracts/resources.js +13 -37
- package/dist/contracts/runtime-api.d.ts +330 -16
- package/dist/contracts/runtime-api.js +58 -14
- package/dist/contracts/sf-config-v1.js +1 -1
- package/dist/contracts/sites.d.ts +12 -12
- package/dist/contracts/sites.js +18 -11
- package/dist/contracts/space-config.d.ts +2 -3
- package/dist/contracts/space-config.js +3 -1
- package/dist/contracts/spaces.d.ts +143 -102
- package/dist/contracts/spaces.js +109 -43
- package/dist/contracts/superadmin-emails.d.ts +25 -1
- package/dist/contracts/superadmin-emails.js +10 -15
- package/dist/contracts/superadmin-runtime.d.ts +2 -2
- package/dist/contracts/superadmin-spaces.d.ts +6 -14
- package/dist/contracts/tags.d.ts +43 -13
- package/dist/contracts/tags.js +195 -11
- package/dist/contracts/transfers.d.ts +1 -1
- package/dist/contracts/variables.d.ts +4 -4
- package/dist/contracts/variables.js +4 -3
- package/dist/contracts/webhooks.d.ts +2 -2
- package/dist/contracts/zero.d.ts +329 -7
- package/dist/contracts/zero.js +121 -2
- package/dist/dashboard-paths/index.d.ts +1 -1
- package/dist/docs/agent-setup.d.ts +4 -2
- package/dist/docs/agent-setup.js +15 -7
- package/dist/docs/agent-solutions.js +1 -1
- package/dist/docs/catalog.d.ts +8 -10
- package/dist/docs/catalog.js +8 -10
- package/dist/docs/error-docs.js +86 -18
- package/dist/utils/access-grant.d.ts +14 -0
- package/dist/utils/access-grant.js +88 -0
- package/dist/utils/access-match.d.ts +7 -0
- package/dist/utils/access-match.fixtures.json +513 -0
- package/dist/utils/access-match.js +32 -16
- package/dist/utils/access-verdict.fixtures.json +421 -0
- package/dist/utils/credential-policy.d.ts +1 -1
- package/dist/utils/dns-instructions.d.ts +29 -0
- package/dist/utils/dns-instructions.js +78 -0
- package/dist/utils/domain-diagnostics.d.ts +29 -0
- package/dist/utils/domain-diagnostics.js +63 -0
- package/dist/utils/egress-policy.fixtures.json +51 -0
- package/dist/utils/id-hints.d.ts +1 -0
- package/dist/utils/id-hints.js +55 -13
- package/dist/utils/page-colors.d.ts +50 -0
- package/dist/utils/page-colors.js +167 -0
- package/dist/utils/page-fonts.d.ts +2 -0
- package/dist/utils/page-fonts.js +4 -0
- package/dist/utils/pages.d.ts +8 -1
- package/dist/utils/pages.js +123 -37
- package/dist/utils/production-runtime.d.ts +18 -0
- package/dist/utils/production-runtime.js +28 -0
- package/dist/utils/query-keys.d.ts +6 -7
- package/dist/utils/query-keys.js +11 -12
- package/dist/utils/sf-config-v1.fixtures.json +9 -0
- package/dist/utils/sf-config-v1.js +28 -19
- package/dist/utils/source-archive-policy.d.ts +2 -0
- package/dist/utils/source-archive-policy.js +2 -0
- package/dist/utils/static-runtime-policy.fixtures.json +57 -0
- package/dist/utils/static-runtime-policy.js +1 -1
- package/package.json +5 -4
- package/dist/contracts/annotations.d.ts +0 -327
- package/dist/contracts/annotations.js +0 -235
- package/dist/contracts/generated-feature-launch-entries.d.ts +0 -2
- package/dist/contracts/generated-feature-launch-entries.js +0 -518
- package/dist/contracts/publishes.d.ts +0 -135
- package/dist/contracts/publishes.js +0 -162
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
{
|
|
2
|
+
"namespaceFilter": [
|
|
3
|
+
{
|
|
4
|
+
"name": "platform namespaces keep platform grants",
|
|
5
|
+
"grants": ["user:usr_1", "email:carol@acme.com", "team:team_1:member"],
|
|
6
|
+
"namespaces": [
|
|
7
|
+
"team:",
|
|
8
|
+
"sub-team:",
|
|
9
|
+
"user:",
|
|
10
|
+
"email:",
|
|
11
|
+
"space:",
|
|
12
|
+
"link:",
|
|
13
|
+
"invite:",
|
|
14
|
+
"svc:",
|
|
15
|
+
"sso:"
|
|
16
|
+
],
|
|
17
|
+
"expected": ["user:usr_1", "email:carol@acme.com", "team:team_1:member"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "external key drops everything outside its ext binding",
|
|
21
|
+
"grants": ["ext:acn_1:wc-subscriber", "team:team_1:owner", "user:usr_1", "email:x@y.z"],
|
|
22
|
+
"namespaces": ["ext:acn_1:"],
|
|
23
|
+
"expected": ["ext:acn_1:wc-subscriber"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "an external token minting team grants is fully dropped",
|
|
27
|
+
"grants": ["team:team_1:owner", "team:team_1:admin"],
|
|
28
|
+
"namespaces": ["ext:acn_1:"],
|
|
29
|
+
"expected": []
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "local pw key signs only pw grants",
|
|
33
|
+
"grants": ["pw:space-password", "team:team_1:viewer", "email:a@b.c"],
|
|
34
|
+
"namespaces": ["pw:"],
|
|
35
|
+
"expected": ["pw:space-password"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "prefix match is a plain startsWith, not a segment match",
|
|
39
|
+
"grants": ["sub-team:sub_1:member", "team:team_1:member"],
|
|
40
|
+
"namespaces": ["team:"],
|
|
41
|
+
"expected": ["team:team_1:member"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "empty namespace entries never match",
|
|
45
|
+
"grants": ["user:usr_1"],
|
|
46
|
+
"namespaces": [""],
|
|
47
|
+
"expected": []
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "email-domain namespace is dead: nothing carries it, nothing keeps it",
|
|
51
|
+
"grants": ["email-domain:acme.com"],
|
|
52
|
+
"namespaces": [
|
|
53
|
+
"team:",
|
|
54
|
+
"sub-team:",
|
|
55
|
+
"user:",
|
|
56
|
+
"email:",
|
|
57
|
+
"space:",
|
|
58
|
+
"link:",
|
|
59
|
+
"invite:",
|
|
60
|
+
"svc:",
|
|
61
|
+
"sso:"
|
|
62
|
+
],
|
|
63
|
+
"expected": []
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "empty grant strings are dropped",
|
|
67
|
+
"grants": ["", "user:usr_1"],
|
|
68
|
+
"namespaces": ["user:"],
|
|
69
|
+
"expected": ["user:usr_1"]
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"glob": [
|
|
73
|
+
{
|
|
74
|
+
"pattern": "email:carol@acme.com",
|
|
75
|
+
"grant": "email:carol@acme.com",
|
|
76
|
+
"expected": true
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"pattern": "email:carol@acme.com",
|
|
80
|
+
"grant": "email:mallory@acme.com",
|
|
81
|
+
"expected": false
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"pattern": "email:*@acme.com",
|
|
85
|
+
"grant": "email:carol@acme.com",
|
|
86
|
+
"expected": true
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"pattern": "email:*@acme.com",
|
|
90
|
+
"grant": "email:carol@evil.com",
|
|
91
|
+
"expected": false
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"pattern": "email:*@acme.com",
|
|
95
|
+
"grant": "email:carol@sub.acme.com",
|
|
96
|
+
"expected": false
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"pattern": "email:*acme.com",
|
|
100
|
+
"grant": "email:carol@sub.acme.com",
|
|
101
|
+
"expected": true
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"pattern": "email:*@acme.com",
|
|
105
|
+
"grant": "email:@acme.com",
|
|
106
|
+
"expected": true
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"pattern": "team:*",
|
|
110
|
+
"grant": "team:team_1:member",
|
|
111
|
+
"expected": true
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"pattern": "team:team_1:*",
|
|
115
|
+
"grant": "team:team_1:viewer",
|
|
116
|
+
"expected": true
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"pattern": "team:team_1:*",
|
|
120
|
+
"grant": "team:team_2:viewer",
|
|
121
|
+
"expected": false
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"pattern": "user:*",
|
|
125
|
+
"grant": "user:usr_1",
|
|
126
|
+
"expected": true
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"pattern": "user:*",
|
|
130
|
+
"grant": "email:x@y.z",
|
|
131
|
+
"expected": false
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"pattern": "space:spc_1:*",
|
|
135
|
+
"grant": "space:spc_1:commenter",
|
|
136
|
+
"expected": true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"pattern": "*",
|
|
140
|
+
"grant": "anything:at:all",
|
|
141
|
+
"expected": true
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"pattern": "pw:space-password",
|
|
145
|
+
"grant": "pw:space-password",
|
|
146
|
+
"expected": true
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"pattern": "pw:space-password",
|
|
150
|
+
"grant": "pw:other-rule",
|
|
151
|
+
"expected": false
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"pattern": "email:*@a*.com",
|
|
155
|
+
"grant": "email:x@acme.com",
|
|
156
|
+
"expected": true
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"pattern": "email:*@a*.com",
|
|
160
|
+
"grant": "email:x@bcme.com",
|
|
161
|
+
"expected": false
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"pattern": "email:a.b@acme.com",
|
|
165
|
+
"grant": "email:aXb@acme.com",
|
|
166
|
+
"expected": false
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"pattern": "svc:stk_1",
|
|
170
|
+
"grant": "svc:stk_1",
|
|
171
|
+
"expected": true
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"pattern": "link:lnk_*",
|
|
175
|
+
"grant": "link:lnk_abc",
|
|
176
|
+
"expected": true
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"pattern": "",
|
|
180
|
+
"grant": "user:usr_1",
|
|
181
|
+
"expected": false
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"intersect": [
|
|
185
|
+
{
|
|
186
|
+
"name": "single exact hit",
|
|
187
|
+
"grants": ["user:usr_1", "email:carol@acme.com"],
|
|
188
|
+
"requiredGrants": ["email:carol@acme.com"],
|
|
189
|
+
"expected": true
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "no overlap",
|
|
193
|
+
"grants": ["user:usr_1", "team:team_1:member"],
|
|
194
|
+
"requiredGrants": ["email:*@acme.com", "link:lnk_1"],
|
|
195
|
+
"expected": false
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"name": "glob run crosses separators",
|
|
199
|
+
"grants": ["team:team_1:member"],
|
|
200
|
+
"requiredGrants": ["team:*:member"],
|
|
201
|
+
"expected": true
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"name": "any-of over requiredGrants",
|
|
205
|
+
"grants": ["invite:sin_1"],
|
|
206
|
+
"requiredGrants": ["email:x@y.z", "invite:sin_1", "team:team_1:viewer"],
|
|
207
|
+
"expected": true
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"name": "empty grants never pass",
|
|
211
|
+
"grants": [],
|
|
212
|
+
"requiredGrants": ["user:*"],
|
|
213
|
+
"expected": false
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"name": "empty requiredGrants never pass",
|
|
217
|
+
"grants": ["user:usr_1"],
|
|
218
|
+
"requiredGrants": [],
|
|
219
|
+
"expected": false
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"name": "empty-string entries are ignored on both sides",
|
|
223
|
+
"grants": [""],
|
|
224
|
+
"requiredGrants": [""],
|
|
225
|
+
"expected": false
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"name": "concrete grant does not glob against a concrete requirement",
|
|
229
|
+
"grants": ["email:carol@acme.com"],
|
|
230
|
+
"requiredGrants": ["email:carol@acme.co"],
|
|
231
|
+
"expected": false
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
"satisfy": [
|
|
235
|
+
{
|
|
236
|
+
"name": "platform token passes an email-domain wall",
|
|
237
|
+
"grants": ["user:usr_1", "email:carol@acme.com", "team:team_1:member"],
|
|
238
|
+
"grantNamespaces": [
|
|
239
|
+
"team:",
|
|
240
|
+
"sub-team:",
|
|
241
|
+
"user:",
|
|
242
|
+
"email:",
|
|
243
|
+
"space:",
|
|
244
|
+
"link:",
|
|
245
|
+
"invite:",
|
|
246
|
+
"svc:",
|
|
247
|
+
"sso:"
|
|
248
|
+
],
|
|
249
|
+
"requiredGrants": ["email:*@acme.com"],
|
|
250
|
+
"expected": true
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"name": "external token cannot satisfy a team wall (namespace drop first)",
|
|
254
|
+
"grants": ["team:team_1:member"],
|
|
255
|
+
"grantNamespaces": ["ext:acn_1:"],
|
|
256
|
+
"requiredGrants": ["team:team_1:member"],
|
|
257
|
+
"expected": false
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"name": "local pw token satisfies exactly its wall",
|
|
261
|
+
"grants": ["pw:space-password"],
|
|
262
|
+
"grantNamespaces": ["pw:"],
|
|
263
|
+
"requiredGrants": ["pw:space-password"],
|
|
264
|
+
"expected": true
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "pw token cannot satisfy an identity wall",
|
|
268
|
+
"grants": ["pw:space-password"],
|
|
269
|
+
"grantNamespaces": ["pw:"],
|
|
270
|
+
"requiredGrants": ["email:*@acme.com", "team:team_1:viewer"],
|
|
271
|
+
"expected": false
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"name": "external token satisfies its own owner-defined tag",
|
|
275
|
+
"grants": ["ext:acn_1:wc-subscriber"],
|
|
276
|
+
"grantNamespaces": ["ext:acn_1:"],
|
|
277
|
+
"requiredGrants": ["ext:acn_1:wc-subscriber"],
|
|
278
|
+
"expected": true
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"name": "external token minting team:* wildcard grants fails the namespace filter",
|
|
282
|
+
"grants": [
|
|
283
|
+
"ext:acn_1:wc-subscriber",
|
|
284
|
+
"team:*",
|
|
285
|
+
"team:team_1:owner",
|
|
286
|
+
"user:usr_1",
|
|
287
|
+
"email:carol@acme.com"
|
|
288
|
+
],
|
|
289
|
+
"grantNamespaces": ["ext:acn_1:"],
|
|
290
|
+
"requiredGrants": ["team:*"],
|
|
291
|
+
"expected": false
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"name": "external token cannot cross into another connection's ext namespace",
|
|
295
|
+
"grants": ["ext:acn_2:wc-subscriber"],
|
|
296
|
+
"grantNamespaces": ["ext:acn_1:"],
|
|
297
|
+
"requiredGrants": ["ext:acn_2:wc-subscriber"],
|
|
298
|
+
"expected": false
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"name": "sso token passes the connection audience and its verified email glob",
|
|
302
|
+
"grants": ["sso:acn_9", "email:carol@acme.com"],
|
|
303
|
+
"grantNamespaces": [
|
|
304
|
+
"team:",
|
|
305
|
+
"sub-team:",
|
|
306
|
+
"user:",
|
|
307
|
+
"email:",
|
|
308
|
+
"space:",
|
|
309
|
+
"link:",
|
|
310
|
+
"invite:",
|
|
311
|
+
"svc:",
|
|
312
|
+
"sso:"
|
|
313
|
+
],
|
|
314
|
+
"requiredGrants": ["email:*@acme.com"],
|
|
315
|
+
"expected": true
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"name": "same-space grant cannot satisfy an identity-bound reviewer rule",
|
|
319
|
+
"grants": ["space:spc_review:viewer"],
|
|
320
|
+
"grantNamespaces": ["email:", "space:"],
|
|
321
|
+
"requiredGrants": ["email:reviewer.a@example.com"],
|
|
322
|
+
"expected": false
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"name": "the exact reviewer identity satisfies its identity-bound rule",
|
|
326
|
+
"grants": ["email:reviewer.a@example.com", "space:spc_review:viewer"],
|
|
327
|
+
"grantNamespaces": ["email:", "space:"],
|
|
328
|
+
"requiredGrants": ["email:reviewer.a@example.com"],
|
|
329
|
+
"expected": true
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"name": "a different reviewer remains denied despite a same-space grant",
|
|
333
|
+
"grants": ["email:reviewer.b@example.com", "space:spc_review:viewer"],
|
|
334
|
+
"grantNamespaces": ["email:", "space:"],
|
|
335
|
+
"requiredGrants": ["email:reviewer.a@example.com"],
|
|
336
|
+
"expected": false
|
|
337
|
+
}
|
|
338
|
+
],
|
|
339
|
+
"pathGlob": [
|
|
340
|
+
{
|
|
341
|
+
"pattern": "",
|
|
342
|
+
"path": "/anything",
|
|
343
|
+
"expected": true
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"pattern": "/x.html",
|
|
347
|
+
"path": "/x.html",
|
|
348
|
+
"expected": true
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"pattern": "/x.html",
|
|
352
|
+
"path": "/x.htm",
|
|
353
|
+
"expected": false
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"pattern": "/docs/**",
|
|
357
|
+
"path": "/docs/",
|
|
358
|
+
"expected": true
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"pattern": "/docs/**",
|
|
362
|
+
"path": "/docs/a/b/c.html",
|
|
363
|
+
"expected": true
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"pattern": "/docs/**",
|
|
367
|
+
"path": "/docs",
|
|
368
|
+
"expected": false
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"pattern": "/docs/*",
|
|
372
|
+
"path": "/docs/a.html",
|
|
373
|
+
"expected": true
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"pattern": "/docs/*",
|
|
377
|
+
"path": "/docs/a/b.html",
|
|
378
|
+
"expected": false
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"pattern": "/docs/*",
|
|
382
|
+
"path": "/docs/",
|
|
383
|
+
"expected": true
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"pattern": "/report/**",
|
|
387
|
+
"path": "/report/q2/deck.pdf",
|
|
388
|
+
"expected": true
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"pattern": "/report/**",
|
|
392
|
+
"path": "/reports/q2.pdf",
|
|
393
|
+
"expected": false
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"pattern": "/*.html",
|
|
397
|
+
"path": "/index.html",
|
|
398
|
+
"expected": true
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"pattern": "/*.html",
|
|
402
|
+
"path": "/a/index.html",
|
|
403
|
+
"expected": false
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"pattern": "/**",
|
|
407
|
+
"path": "/",
|
|
408
|
+
"expected": true
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"pattern": "/**",
|
|
412
|
+
"path": "/deep/path/file.txt",
|
|
413
|
+
"expected": true
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"pattern": "/a+b/**",
|
|
417
|
+
"path": "/a+b/x",
|
|
418
|
+
"expected": true
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"pattern": "/a.b/**",
|
|
422
|
+
"path": "/axb/x",
|
|
423
|
+
"expected": false
|
|
424
|
+
}
|
|
425
|
+
],
|
|
426
|
+
"cidr": [
|
|
427
|
+
{
|
|
428
|
+
"ip": "1.2.3.4",
|
|
429
|
+
"cidr": "1.2.3.0/24",
|
|
430
|
+
"expected": true
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"ip": "1.2.4.4",
|
|
434
|
+
"cidr": "1.2.3.0/24",
|
|
435
|
+
"expected": false
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"ip": "1.2.3.4",
|
|
439
|
+
"cidr": "1.2.3.4",
|
|
440
|
+
"expected": true
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
"ip": "1.2.3.4",
|
|
444
|
+
"cidr": "1.2.3.5",
|
|
445
|
+
"expected": false
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"ip": "10.0.0.1",
|
|
449
|
+
"cidr": "10.0.0.0/8",
|
|
450
|
+
"expected": true
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"ip": "10.128.0.1",
|
|
454
|
+
"cidr": "10.0.0.0/9",
|
|
455
|
+
"expected": false
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"ip": "10.127.255.255",
|
|
459
|
+
"cidr": "10.0.0.0/9",
|
|
460
|
+
"expected": true
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"ip": "1.2.3.4",
|
|
464
|
+
"cidr": "0.0.0.0/0",
|
|
465
|
+
"expected": true
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"ip": "1.2.3.4",
|
|
469
|
+
"cidr": "1.2.3.0/33",
|
|
470
|
+
"expected": false
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"ip": "1.2.3.4",
|
|
474
|
+
"cidr": "",
|
|
475
|
+
"expected": false
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"ip": "not-an-ip",
|
|
479
|
+
"cidr": "1.2.3.0/24",
|
|
480
|
+
"expected": false
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"ip": "2001:db8::1",
|
|
484
|
+
"cidr": "2001:db8::/32",
|
|
485
|
+
"expected": true
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"ip": "2001:db9::1",
|
|
489
|
+
"cidr": "2001:db8::/32",
|
|
490
|
+
"expected": false
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"ip": "2001:db8::1",
|
|
494
|
+
"cidr": "1.2.3.0/24",
|
|
495
|
+
"expected": false
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"ip": "1.2.3.4",
|
|
499
|
+
"cidr": "2001:db8::/32",
|
|
500
|
+
"expected": false
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"ip": "::ffff:1.2.3.4",
|
|
504
|
+
"cidr": "::ffff:1.2.3.0/120",
|
|
505
|
+
"expected": true
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
"ip": "fe80::aaaa:bbbb",
|
|
509
|
+
"cidr": "fe80::/10",
|
|
510
|
+
"expected": true
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
}
|
|
@@ -60,6 +60,18 @@ export function grantsIntersect(grants, requiredGrants) {
|
|
|
60
60
|
}
|
|
61
61
|
return false;
|
|
62
62
|
}
|
|
63
|
+
// Managed reviewer rules are identity bindings. Policies compiled before the
|
|
64
|
+
// identity-only cutover may still contain a generic `space:` grant beside the
|
|
65
|
+
// reviewer's email. Treating that legacy entry as another ANY-OF alternative
|
|
66
|
+
// recreates the cross-reviewer bypass, so every evaluator derives the effective
|
|
67
|
+
// requirement from the trusted managed-block owner before intersecting.
|
|
68
|
+
export function requiredGrantsForRule(rule) {
|
|
69
|
+
const requiredGrants = rule.auth?.requiredGrants ?? [];
|
|
70
|
+
if (rule.managedBy !== "cast_reviewer") {
|
|
71
|
+
return requiredGrants;
|
|
72
|
+
}
|
|
73
|
+
return requiredGrants.filter((grant) => grant.startsWith("email:"));
|
|
74
|
+
}
|
|
63
75
|
// The composed satisfaction test the authorize pre-flight runs: namespace-drop
|
|
64
76
|
// the visitor's grants by the signing key, then intersect with the rule's
|
|
65
77
|
// requiredGrants — exactly what the runtime does after verifying a signature.
|
|
@@ -146,6 +158,19 @@ export function agentMatches(needle, agent) {
|
|
|
146
158
|
}
|
|
147
159
|
return agent.toLowerCase().includes(needle.toLowerCase());
|
|
148
160
|
}
|
|
161
|
+
function parseIpv6Groups(raw) {
|
|
162
|
+
if (raw === "") {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
const groups = [];
|
|
166
|
+
for (const part of raw.split(":")) {
|
|
167
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(part)) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
groups.push(Number.parseInt(part, 16));
|
|
171
|
+
}
|
|
172
|
+
return groups;
|
|
173
|
+
}
|
|
149
174
|
// inet_pton equivalent: dotted-quad IPv4 or RFC 4291 IPv6 (including "::"
|
|
150
175
|
// compression and an embedded IPv4 tail) → bytes, or null when unparseable.
|
|
151
176
|
function ipToBytes(ip) {
|
|
@@ -175,30 +200,17 @@ function ipToBytes(ip) {
|
|
|
175
200
|
if (doubleColonSplits.length > 2) {
|
|
176
201
|
return null;
|
|
177
202
|
}
|
|
178
|
-
const parseGroups = (raw) => {
|
|
179
|
-
if (raw === "") {
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
const groups = [];
|
|
183
|
-
for (const part of raw.split(":")) {
|
|
184
|
-
if (!/^[0-9a-fA-F]{1,4}$/.test(part)) {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
groups.push(Number.parseInt(part, 16));
|
|
188
|
-
}
|
|
189
|
-
return groups;
|
|
190
|
-
};
|
|
191
203
|
let groups;
|
|
192
204
|
if (doubleColonSplits.length === 2) {
|
|
193
|
-
const left =
|
|
194
|
-
const right =
|
|
205
|
+
const left = parseIpv6Groups(doubleColonSplits[0] ?? "");
|
|
206
|
+
const right = parseIpv6Groups(doubleColonSplits[1] ?? "");
|
|
195
207
|
if (left === null || right === null || left.length + right.length > 8) {
|
|
196
208
|
return null;
|
|
197
209
|
}
|
|
198
210
|
groups = [...left, ...Array(8 - left.length - right.length).fill(0), ...right];
|
|
199
211
|
}
|
|
200
212
|
else {
|
|
201
|
-
groups =
|
|
213
|
+
groups = parseIpv6Groups(head);
|
|
202
214
|
if (groups === null || groups.length !== 8) {
|
|
203
215
|
return null;
|
|
204
216
|
}
|
|
@@ -285,6 +297,10 @@ export function ruleMatchApplies(match, context) {
|
|
|
285
297
|
if (match.country !== undefined && match.country.toUpperCase() !== (context.country ?? "")) {
|
|
286
298
|
return false;
|
|
287
299
|
}
|
|
300
|
+
if (match.countryNotIn !== undefined &&
|
|
301
|
+
match.countryNotIn.some((country) => country.toUpperCase() === (context.country ?? "").toUpperCase())) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
288
304
|
if (match.header !== undefined) {
|
|
289
305
|
const name = match.header.name.toLowerCase();
|
|
290
306
|
const actual = Object.entries(context.headers ?? {}).find(([key]) => key.toLowerCase() === name)?.[1];
|