keelapps

keelapps/AccessLens for Confluence/Documentation

Documentation

AccessLens reads your site's permission state and hands it back in the shape an auditor asks for: who can reach what, what is locked, what changed, and who signed for it. It writes nothing — there is no write scope in the manifest — so everything below is a read, a stored copy of a read, or a decision recorded about one.

Where AccessLens lives

A daily scheduled trigger drives scheduled scans, and a queue consumer runs the scan itself in resumable shards so a large site finishes rather than timing out.

Reverse lookup

Confluence indexes permissions by space: open a space and it will tell you who has what. AccessLens inverts the index, so you can start from any of three subjects:

Expansion is the point. A grant list that says “Engineering can read this space” is not an answer; “these 148 named people can read this space” is. On sites that use role-based space permissions, the role assignments carrying the same information are read as well.

The page restriction audit

This is the piece Confluence makes hardest to self-check, and it is where the app differs most from everything else in the category.

Per space, AccessLens lists:

And five classes of finding, each of which is a real mistake rather than a statistic:

FindingWhy it matters
Restriction grants nothing Restrictions can only narrow space permissions, never widen them. A restriction naming a group with no view permission on the space gives that group nothing — the reverse of what whoever typed it believed.
Only one person can read it A page one leaver away from being unreachable.
Edit-only restriction Frequently a mistake for a page that was meant to be private, not merely read-only.
Named individuals rather than groups Access that no longer tracks anybody's role, and that nobody will remember to revoke.
Hidden by an ancestor Removing the restriction on the page itself will change nothing; the restriction is further up.

Reading a page's restrictions is one request per page, which is the only cost in the app that grows with the size of your content. The restriction audit therefore has three modes — off, sampled and full — and sampled is the default, with a per-space page ceiling. The interface distinguishes “checked and found nothing” from “not checked”; it never lets a sample look like a complete pass.

Snapshots

A snapshot is the whole site's permission state at a point in time: for each space its identifiers and its permission grants, for each restricted page its identity and the principals its restrictions name, and for each group referenced by a grant its name and its members.

Snapshots run manually or on a schedule. The scan is sharded and checkpointed and the cursor reaches inside a single space, page by page — a space can hold tens of thousands of pages, and a scan that can only resume at space boundaries would never finish on one of them.

If AccessLens could not read something it needed, the snapshot is marked partial and says which part is missing. It never quietly reports less than it found.

Diffs

Compare any two snapshots. The diff is reported one row per space and subject, which is the unit an administrator actually acted in: granting a contractor group read, comment and export on one space is one administrative action and reads as one row, not three permission lines.

That is a deliberate aggregation. A diff that lists every changed permission separately is technically complete and practically unreadable — the reviewer's job is to recognise the change somebody made, not to reassemble it.

Access reviews and sign-off

A review is pinned to one snapshot, so it cannot drift while it is being conducted. Space by space, a reviewer confirms or flags, with an optional note.

Each decision records:

Changing a decision does not erase the old one: superseded decisions are kept alongside the current one. Once a review is signed off it freezes.

Risk flags, and what is not observable

AccessLens flags three site-level risks:

The first of these depends on your tenant's permission model. On sites using role-based space permissions, anonymous access is readable as an access-class principal in the role assignments. On the older model it is not readable at all — the only endpoint that ever reported it has been removed from the API.

So AccessLens measures whether it could observe anonymous access on your site, and where it could not, the interface says “not observable here” rather than “none found”. Those are different statements, and only one of them is true. In the same spirit, when the app cannot recognise any access class on a space, that fact is itself a finding — a permission audit whose risk checks silently never fire is the most dangerous kind of clean report.

Cost estimates and the API budget

Confluence Cloud charges apps for API calls in points, and the hourly allowance is shared across every site running the app rather than granted per site. Before a scan runs, AccessLens shows what it will cost in points and what share of that hourly allowance it represents. Shard size and the restriction mode are both settings, so a large site can be scanned within a budget you chose rather than one you discovered.

CSV export

Every view exports as CSV. The file is assembled in your own browser from data delivered over the Forge bridge — it never passes through a server of ours, because there is not one. Exports carry a byte-order mark so spreadsheets open them in the right encoding, and leading formula characters are neutralised so a cell of your data cannot execute in somebody's spreadsheet.

Settings

Permissions the app requests

Eight scopes, and not one of them is a write:

ScopeWhy
read:space:confluencethe space list, and space permission grants
read:space.permission:confluencespace roles and role assignments, on tenants that use them
read:page:confluencepage id, title and parent id, so a restricted page can be named and its inheritance walked — never page content
read:content-details:confluencea page's view and edit restrictions
read:content.restriction:confluencedeclared alongside the above so the restriction audit works across API shapes
read:user:confluenceresolve account ids to display names
read:group:confluencegroups and their members, so a group-level answer becomes a person-level one
storage:appsnapshots, reviews and settings, in Atlassian-hosted storage on your own site

There is no permissions.external block: the app cannot make an outbound call even if it tried to, which Atlassian enforces at the platform level. And with no write scope at all, it cannot change a permission, a restriction, a page or a comment.

Not in this release

Support

Questions, bug reports and feature requests: raise a support request. Security issues: report privately.