Skip to content

fix(confluence): index inherited page restrictions for DLS (#4095) - #4297

Merged
Jan-Kazlouski-elastic merged 4 commits into
mainfrom
fix/4095-confluence-inherited-page-restrictions
Jul 30, 2026
Merged

fix(confluence): index inherited page restrictions for DLS (#4095)#4297
Jan-Kazlouski-elastic merged 4 commits into
mainfrom
fix/4095-confluence-inherited-page-restrictions

Conversation

@Jan-Kazlouski-elastic

@Jan-Kazlouski-elastic Jan-Kazlouski-elastic commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Closes #4095

When a Confluence page has no page-level restrictions of its own but inherits view restrictions from ancestors — or has its own restrictions that must also satisfy parent restrictions — the connector previously either ignored inherited ACL or used only the nearest restricted ancestor / the child's list alone, then fell back to broad space-level permissions. That over-granted access in _allow_access_control (a Document Level Security gap).

Confluence's documented view model requires users to satisfy both parent and child view restrictions (CONF57). This change resolves the effective read ACL as the intersection of:

  1. The child's explicit read restrictions (when non-empty), and
  2. Every ancestor's explicit read restrictions (full chain, not nearest-only).

Behavior details:

  • Fetch each ancestor via rest/api/content/{id}/restriction/byOperation/read (Confluence does not expose inherited restrictions inline; expanding ancestors.restrictions... on content/search 404s the whole batch on unreadable drafts — CONFCLOUD-77618).
  • 200 + empty → no restriction layer on that content; keep walking.
  • 404 → skip that ancestor; keep walking.
  • 403 / 401 / 5xx / other → fail closed: index _allow_access_control = [] and do not fall back to space ACL (sync continues).
  • No restriction layers after a successful walk → fall back to space VIEWSPACE permissions (unchanged Cloud / Server / DC paths).
  • Always runs this resolver even when the child has its own restrictions (child list alone is not the effective ACL).
  • Attachments continue to reuse the page's resolved ACL.

Applies to Confluence Cloud, Server, and Data Center. Advanced Sync Rules / search_by_query ACL is unchanged (out of scope).

Checklists

Pre-Review Checklist

  • this PR does NOT contain credentials of any kind, such as API keys or username/passwords (double check config.yml.example)
  • this PR has a meaningful title
  • this PR links to all relevant github issues that it fixes or partially addresses
  • if there is no GH issue, please create it. Each PR should have a link to an issue
  • this PR has a thorough description
  • Covered the changes with automated tests
  • Tested the changes locally
  • Added a label for each target release version (example: v7.13.2, v7.14.0, v8.0.0)
  • For bugfixes: backport safely to all minor branches still receiving patch releases
  • Considered corresponding documentation changes
  • Contributed any configuration settings changes to the configuration reference
  • if you added or changed Rich Configurable Fields for a Native Connector, you made a corresponding PR in Kibana

Changes Requiring Extra Attention

  • Security-related changes (encryption, TLS, SSRF, etc)
  • New external service dependencies added.

Related Pull Requests

Release Note

Confluence connector Document Level Security now indexes effective page view restrictions by intersecting the child's and all ancestors' explicit read restrictions, instead of falling back to broader space-level permissions when a child page has no restrictions of its own (or only its own list). Ambiguous ancestor restriction fetches fail closed without over-granting via space ACL.

A Confluence page with "No restrictions" of its own still inherits the
view restrictions of its ancestors, but the connector ignored them and
fell back to the broader space-level permissions. This over-granted
access in indexed _allow_access_control values.

Resolve the effective inherited ACL by walking a page's ancestors
(nearest parent first) and using the restrictions of the nearest
restricted ancestor before falling back to space permissions. Inherited
restrictions are fetched per ancestor via the restriction/byOperation
endpoint, since Confluence does not expose them inline (and expanding
ancestor restrictions on content/search 404s the whole batch on
unreadable drafts, per CONFCLOUD-77618). Unreadable ancestors are
treated as having no inheritable restriction.

Closes #4095

Co-authored-by: Cursor <cursoragent@cursor.com>
Shorten verbose docstrings/comments and dedupe unit-test setup with a
shared helper and parametrization, without dropping coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Jan-Kazlouski-elastic and others added 2 commits July 29, 2026 15:52
Intersect child and all ancestor read restrictions so effective ACL matches
Confluence's both-must-satisfy model; fail closed on ambiguous fetches and
only fall back to space when the whole chain is unrestricted.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Jan-Kazlouski-elastic
Jan-Kazlouski-elastic marked this pull request as ready for review July 29, 2026 13:32
continue

try:
restrictions = await self.confluence_client.fetch_content_restrictions(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this introduce another permission the auth must have? If it does, we should document it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to their docs: https://developer.atlassian.com/cloud/confluence/rest/v1/api-group-content-restrictions/
it doesn't require anything on top of what we already have. We're allowed to get the restrictions for the child as part of the content during the search https://developer.atlassian.com/cloud/confluence/rest/v1/api-group-content/#api-wiki-rest-api-content-search-get, it's the same as getting restrictions for the parents https://developer.atlassian.com/cloud/confluence/rest/v1/api-group-content-restrictions/#api-wiki-rest-api-content-id-restriction-byoperation-get, but we focus on restrictions alone. Which is the same level of permission.
The wording is a bit confusing in their API reference, but I think it is safe to say that we don't have to get another permission for that. No admin/write ones for sure.

@github-actions

Copy link
Copy Markdown

💔 Failed to create backport PR(s)

Status Branch Result
9.4 #4302
8.19 Commit could not be cherrypicked due to conflicts
9.5 #4303
9.3 #4304

Successful backport PRs will be merged automatically after passing CI.

To backport manually run:
backport --pr 4297 --autoMerge --autoMergeMethod squash

Jan-Kazlouski-elastic added a commit that referenced this pull request Jul 30, 2026
…) (#4297) (#4304)

Backports the following commits to 9.3:
- fix(confluence): index inherited page restrictions for DLS (#4095)
(#4297)

Co-authored-by: Jan-Kazlouski-elastic <jan.kazlouski@elastic.co>
Co-authored-by: Cursor <cursoragent@cursor.com>
Jan-Kazlouski-elastic added a commit that referenced this pull request Jul 30, 2026
…) (#4297) (#4302)

Backports the following commits to 9.4:
- fix(confluence): index inherited page restrictions for DLS (#4095)
(#4297)

Co-authored-by: Jan-Kazlouski-elastic <jan.kazlouski@elastic.co>
Co-authored-by: Cursor <cursoragent@cursor.com>
Jan-Kazlouski-elastic added a commit that referenced this pull request Jul 30, 2026
…) (#4297) (#4303)

Backports the following commits to 9.5:
- fix(confluence): index inherited page restrictions for DLS (#4095)
(#4297)

Co-authored-by: Jan-Kazlouski-elastic <jan.kazlouski@elastic.co>
Co-authored-by: Cursor <cursoragent@cursor.com>
Jan-Kazlouski-elastic added a commit that referenced this pull request Jul 30, 2026
) (#4297) (#4305)

Backports the following commits to 8.19:
- fix(confluence): index inherited page restrictions for DLS (#4095)
(#4297)

Manual backport: auto-cherry-pick failed due to conflicts from the
monolithic → `atlassian/confluence/` package split. Same DLS behavior as
#4297, applied to `connectors/sources/confluence.py` on 8.19.

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confluence Data Center Connector does not index inherited page restrictions

2 participants