Commit 972422f
committed
feat(knowledge): mirror Confluence space permissions and page restrictions
Confluence joins Drive as a source an administrator crawl can mirror, and it is
the case that shaped the contract.
A page's restrictions come back only when that page is asked for, so they cannot
ride along with the listing the way Drive's permissions do. `getDocumentAcls`
resolves them for the whole listing at once, after it — round trips bounded by
the corpus rather than by the page size, with the space's principals, each
page's restriction, and every address resolved once per run and reused. Only an
unrestricted page pays for its ancestry, which is the expensive lookup.
A restriction replaces the space's permissions rather than narrowing them. Real
Confluence access is the intersection, so this over-grants in exactly one case:
somebody named on a page restriction who cannot view the space at all. That is a
misconfiguration in the source, it errs toward a page they were deliberately
named on, and it is what Onyx does. Representing the true intersection would
mean expanding both principal sets to member addresses, which our group tables
could do — but it emits one token per member, and a five-thousand-person space
would carry five-thousand-token ACLs on every restricted page.
`null` and `[]` are different answers throughout: no restriction means inherit
from the nearest restricted ancestor, then the space; a restriction naming
nobody means readable by nobody. Confluence itself only ever produces the first,
but collapsing them would publish every deliberately locked page.
One departure from the plan, which said to identify groups by name as Onyx does.
Onyx uses names because its membership sync is keyed by name; ours is keyed by
whatever the permissions API returns, and that is the id. Using it costs no
lookup per group and survives a rename, which a name-keyed ACL would not.
Directory enumeration moves behind one connector hook. The tenant is baked into
every stored group token, and only the connector knows what a tenant is for its
source — a Workspace domain for Drive, a site's cloud id for Confluence. The
engine previously derived it from the impersonation subject, which Confluence
does not have: its service account authenticates with an API token and
impersonates nobody, so directory refresh would have silently skipped.
The limit worth knowing: Confluence Cloud withholds an address whose owner's
profile hides it, and a person we cannot name cannot be granted access. Those
grants are dropped and counted rather than guessed at, and a group with a
withheld member is reported incomplete so it never replaces a stored membership
with a subset.1 parent faab96f commit 972422f
11 files changed
Lines changed: 1099 additions & 56 deletions
File tree
- apps/sim
- connectors
- confluence
- google-drive
- lib/knowledge
- access
- connectors
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
8 | 13 | | |
9 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
10 | 22 | | |
11 | 23 | | |
12 | 24 | | |
| |||
298 | 310 | | |
299 | 311 | | |
300 | 312 | | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
301 | 444 | | |
302 | 445 | | |
303 | 446 | | |
| |||
379 | 522 | | |
380 | 523 | | |
381 | 524 | | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
382 | 537 | | |
383 | 538 | | |
384 | 539 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
23 | 41 | | |
24 | 42 | | |
25 | 43 | | |
| |||
34 | 52 | | |
35 | 53 | | |
36 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
37 | 63 | | |
38 | 64 | | |
39 | 65 | | |
| |||
0 commit comments