AryonForge
v1.0.0 · Release candidate

License Guardian for Confluence

Confluence   v1.0.0 · Release candidate

Governed Confluence licence cleanup with a first-class, auditable ignore list — so you can prove automated cleanup did not remove access it shouldn’t have.

Confluence · Forge app 1 external host No sale of customer data Global page
01

Overview

License Guardian finds inactive and never-logged-in Confluence users, applies rule-based deactivation policy, and enforces a governed ignore list so IT, security and compliance teams can answer the hardest question in licence cleanup: why wasn’t this account touched?

A flat skip-list cannot answer it. It has no reason, no owner, no expiry and no review. The temporary exemption someone added for a contractor in 2021 is still silently protecting a seat today, and nobody remembers why.

Every exemption here carries a required reason, a named owner, timestamps, an optional expiry and a recurring review obligation — and every change to it is itself audited.

02

Highlights

Exceptions as a governed object

User pins, group exemptions and pattern exemptions all share one record format: subject, required reason (minimum 10 characters), category, who added it, who last updated it, timestamps, optional expiry, last-reviewed date and reviewer, and notes.

“No expiry” means recurring review, not permanent

After the cadence (default 90 days) the entry surfaces as Review due. Re-confirming writes an audited event with the reviewer’s name. Expired entries stop shielding immediately — and are never deleted, because the record of why an exemption once existed is itself audit evidence.

Service accounts are held, not guessed

Seven weak signals are scored and weighted so no single one can clear the threshold alone. A high score does not exempt the account: it excludes it from bulk selection and prompts an administrator to create a real ignore-list entry with a reason and an owner — routing accounts into the governance process rather than around it.

Separation of duties in the RBAC model

Ignore-List Admin deliberately does not imply Approver. A compliance owner can govern exceptions while IT keeps execution rights, so nobody can both write themselves an exemption and run the job that honours it.

Every batch is reversible

Each action records an undo instruction before it runs. Rollback replays them in reverse — re-adding removed groups by group id, not name — and is itself audited. Deactivation means suspend, never delete.

Billable-path clarity without a key

Even before an organization API key is supplied, the app can enumerate every group and its members, read space-level permission grants, and show who holds a licence and how they became billable.

03

Why an organization API key is required

This is the most important thing to understand before installing. Installing a Forge app grants product scopes. No Confluence product scope exposes when a user last logged in or last touched Confluence. That data lives only in the Atlassian Organization admin API, which authenticates with an organization API key created by an organization admin — a completely separate credential from the app’s Forge scopes.

Without a key the app can enumerate groups and members, read space permission grants, show billable paths, and manage the ignore list, rules, RBAC and audit log. With a key it can additionally measure activity, run scans, and suspend or restore accounts.

The key is written with Forge’s encrypted secret storage (kvs.setSecret), which keeps it at rest inside Atlassian’s own infrastructure. It is never returned to the browser, never logged, and the vendor cannot read it — resolvers only ever expose a boolean hasOrgCredential.

Scale matters here. For 5,000 users the bulk user endpoint costs about 50 requests; the per-user activity endpoint would cost 5,000, which is roughly 25 minutes of wall clock at its 200-requests-per-60-seconds limit. The app therefore always prefers the bulk path and only falls back per-user where activity data is genuinely absent. Its client applies a token-bucket limiter at 80% of the documented budget, so the app never consumes the organization’s entire quota — other tools and vendors share it.

Managed accounts only. The Organization API returns activity only for managed accounts on a verified domain. Unmanaged and external accounts are classified UNKNOWN and are never acted on.

04

User guide

Who this is forConfluence site administrators, plus whoever they grant a role to. Everyone else starts with no access at all — site admins resolve automatically and hold every permission.

Installing the app is not enough to measure anything. An organization admin must also supply an organization API key, because no Confluence product scope exposes when a user last logged in. Without a key the app still maps billable paths and governs the ignore list; it just cannot tell you who is idle.

SurfaceWhere to find it
The dashboardApps → License Guardian in Confluence
Credential, roles, rules, notificationsThe Setup tab
RollbackAudit → Action runs → Roll back
The API key itselfadmin.atlassian.comSettings → API keys, as an organization admin
  1. Create the organization API key

    At admin.atlassian.com → Settings → API keys, create a key. Note its expiry — new keys default to one week and can never exceed a year.

  2. Store it, and record the expiry

    In Confluence, open Apps → License Guardian → Setup. Paste the key, record the expiry date, click Verify key, choose your organization and directory, then Save key securely.

    The directory is required and validated before the key is stored, so suspend and restore can never target an unknown directory. The key is written with Forge’s encrypted secret storage, is never returned to the browser, is never logged, and the vendor cannot read it.

  3. Grant roles so approval is a real second pair of eyes

    Five roles: Viewer (read), Operator (dry-run scans), Approver (execute live), Ignore-List Admin (govern exemptions) and Site Admin (everything).

    Ignore-List Admin deliberately does not imply Approver. A compliance owner can govern exceptions while IT keeps execution rights, so nobody can both write themselves an exemption and run the job that honours it.

  4. Populate the ignore list before your first live run

    Three mechanisms, one governed record format: a user pin (matched by account id or email), a group exemption, or a pattern (a regular expression against email or display name, for integration and service accounts).

    Every entry requires a reason of at least ten characters, a named owner, and optionally an expiry. A pattern that exempts everything is a silent opt-out from the whole product, so catch-alls, expressions that do not compile, anything broad enough to match ordinary human addresses, and expressions with catastrophic-backtracking characteristics are all rejected.

  5. Run a scan in safe mode

    Safe mode is on by default and is checked server-side: a crafted resolver call asking for live: true is still simulated while safe mode is on.

    Review what came back. Accounts scored as suspected service accounts are marked REVIEW_REQUIRED and excluded from “select all actionable” — they are held, not guessed at. Confirm each one, then give it a real ignore-list entry with a reason and an owner.

  6. Execute a live run

    Two independent gates: safe mode must be off and you must type EXECUTE in the confirm dialog.

    The server reloads targets from a completed scan and applies each account’s exact scan outcome, so the selection made in the UI cannot override policy; mismatches are skipped. The ignore list is re-checked at execution time, so an exemption added between the scan and the click is still honoured.

  7. Know the rollback path before you need it

    Audit → Action runs → Roll back replays each recorded undo instruction in reverse order: a removed licence re-adds the exact groups it removed by group id, not name, and a deactivation restores the account along with its prior roles and group memberships.

    Rollback is refused for safe-mode runs (nothing changed) and for runs already rolled back. A rollback is itself an access change, so it writes its own audit events.

Good to know

  • Deactivate means suspend, never delete. Deleting a Confluence user breaks page history, authorship and every @mention. Deletion is not implemented at all.
  • Absent data is never treated as absent activity. An account the app could not measure is UNKNOWN, never INACTIVE, and no rule matches it. Unmanaged and external accounts — outside your verified domains — are exactly this case.
  • Defaults: inactive threshold 90 days, never-logged-in grace 30 days, notice period 14 days, ignore review cadence 90 days, expiring-soon warning 14 days, daily scan at 02:00 UTC, API-key expiry warning 21 days. Safe mode on, scheduled scans require approval, auto-restore on return, notifications off.
  • Shipped rules, first match wins: exclude members of site-admins/org-admins/confluence-admins; remove licence for never-logged-in accounts created 30+ days ago; deactivate accounts dormant 180+ days; remove licence for accounts inactive 90+ days. Protective exclude rules sort above destructive ones on purpose.
  • The credential is monitored, not assumed. A lapsed key finds zero inactive users, which looks exactly like a clean site — so the daily governance trigger probes it with one request and re-checks that it still has access to the configured organization. Rejected (401/403) and unreachable (5xx, network) are reported separately, because a transient outage must not send an admin off to rotate a perfectly good key. Setup → Check key now runs the same probe on demand.
  • Notifications are off until you configure a destination, and can only point at Slack or Microsoft Teams webhooks — Forge blocks any host not declared in the manifest, and the app validates the URL against that same list when you save it. Use Send a test message; it uses the saved webhook, so it proves what the scheduled triggers will actually do.
  • The self-service “I’m still active” path is simply logging in. Any Confluence activity during a notice window cancels the pending action automatically on the next scan.

If something looks wrong

A scan finds zero inactive users on a site you know has some.

Almost always the credential. Check Setup → Check key now: an expired or rejected key produces exactly this silence, which is why the app probes for it daily and banners the result.

Users show as UNKNOWN and are never actioned.

The Organization API returns activity only for managed accounts on a verified domain. External collaborators and contractors on personal accounts return nothing, and the app refuses to act on an account it could not measure.

An account you expected to be selected is not selectable in bulk.

It scored as a suspected service account and is marked REVIEW_REQUIRED. Confirm ownership, then add a real ignore-list entry — that routes it into the governance process rather than around it.

An exemption stopped protecting an account.

Its expiry passed. Expired entries stop shielding immediately and the very next scan treats the subject as in-scope again — but they are never deleted, because the record of why an exemption existed is itself audit evidence.

What it does not do

  • Delete a user account. Only suspend, remove a group membership, or revoke a licence — all reversible.
  • Email an end user. Forge has no platform API for it; the app posts the affected list to your configured channel so whoever owns the mailbox can send the warning.
  • Act on an account it could not measure, or on one an ignore-list entry covers.
  • Consume the organization’s whole API quota — the client is limited to 80% of the documented budget, because other tools share it.
05

Permissions & scopes

ScopeWhy it's needed
read:confluence-userRead users to build the billable-path breakdown
read:group:confluenceRead group membership — the most common billable path
write:group:confluenceRemove a user from a licence-granting group: the least destructive way to reclaim a seat, and the only write scope the app needs against Confluence
read:space:confluenceEnumerate spaces for space-level permission attribution
read:space.permission:confluenceSpace-level permission grants — the billable path administrators most often miss
storage:appSettings, rules, the ignore list, scans and the audit log
06

External access

HostWhy
api.atlassian.comThe Atlassian Organization admin API — the only source of org-wide last-active data. Declared as a Forge remote with operations: [fetch] and no storage block, because nothing is ever persisted remotely. Account activity metadata is read here and kept in Forge storage on Atlassian infrastructure.

This is the only external host the app contacts, and the app only reads from it. Requests are authenticated with the organization API key an administrator supplies in-app, not with Forge’s own credentials.

07

Data stored

RecordKeyContentsRetention
Organization API keyForge encrypted secret storeThe credential itselfUntil replaced or removed. Never returned to the browser or logged; resolvers expose only a boolean
Audit eventsaudit:bucket:<YYYY-MM>Every access change, ignore-list edit, review, rollback and access denialAppended into month buckets, sharded at 400 events per value
Scan resultschunked, 200 users per pagePer-user classification, billable paths and activity datesReplaced on each scan
Ignore list, rules, RBAC, settingsstructured KVS keysGovernance configuration and its full change historyWhile the app is installed; expired ignore entries are retained as evidence, never deleted

Forge KVS with structured keys was chosen over custom entities to keep the manifest simple and the failure modes obvious. Month bucketing keeps each stored value well under the KVS size ceiling while letting a date-range export read a small, predictable number of keys. If server-side querying of the audit log is ever needed, custom entities with indexes are the migration path.

08

Security notes

Safety model

  • Safe mode (dry run) is the default, and it is checked server-side. A crafted resolver call asking for live: true is still simulated while safe mode is on.
  • Live execution needs two independent gates: safe mode must be off and the administrator must type EXECUTE in the confirm dialog.
  • Deactivate means suspend, never delete. Deleting a Confluence user breaks page history, authorship and every @mention. Deletion is not implemented at all — there is no code path for it.
  • Absent data is never treated as absent activity. An account the app could not measure is UNKNOWN, never INACTIVE, and no rule matches it.
  • Exemptions beat policy, always. The ignore list is evaluated before any rule, and re-checked at execution time — an exemption added between the scan and the click is still honoured.
  • Every batch is reversible. Each action records an undo instruction before it runs. Rollback is refused for safe-mode runs and for runs already rolled back, and writes its own audit events because a rollback is itself an access change.

RBAC

  • Five roles: Viewer, Operator, Approver, Ignore-List Admin and Site Admin. Confluence site admins resolve to Site Admin automatically and hold every permission — the app must never lock a real administrator out of the tool that governs it. Everyone else starts with no access at all.
  • RBAC is enforced in the resolver layer, not in the UI. Hidden buttons are a convenience; the guard() wrapper is the actual boundary.
  • Every denial is audited as ACCESS_DENIED. If group membership cannot be read, admin status fails closed.

Pattern guardrails

  • A pattern that exempts everything is a silent opt-out from the whole product, so the app rejects expressions that do not compile, catch-alls such as .* or ^.*$, and anything broad enough to match ordinary human addresses — validated against sample addresses.

Credential handling

  • The organization API key is stored with kvs.setSecret, validated against the live API before it is stored, and never returned to the browser.
  • The app is the only party that can use it, and the vendor cannot read it. Resolvers expose only hasOrgCredential.
  • Note that org API keys expire. Scans stop working silently when a key lapses — the expiry is worth recording when the key is created.

Testing

  • 81 unit tests covering the safety-critical domain layer: classification, rule evaluation and ordering, ignore-list validation, matching and expiry, service-account scoring and its false-positive resistance, RBAC including fail-closed behaviour, audit CSV escaping, and the execution gates including safe-mode enforcement and rollback.
  • Service-account weights are tuned so no single signal clears the threshold alone — “Roberta Botticelli” and “Sync Patel” do not get flagged.
09

Known limitations

  • An organization API key is required for any activity data. Without it the app can show who holds a seat but not whether they use it. This shapes the install flow: an administrator must do something after installing.
  • Managed accounts only. Activity data is unavailable for accounts outside a verified domain. These are reported as UNKNOWN and never acted on — safe, but it means external collaborators are invisible to the rule engine.
  • CSV export renders for copy, not download. UI Kit runs sandboxed with no filesystem access. The bytes are identical; for very large exports, call the export resolver directly.
  • No email delivery. Forge cannot send arbitrary mail. Grace-period notices are tracked, auditable and exportable, but the app does not deliver them. Wiring this to an existing notification channel is the intended integration point.
  • Space-permission scanning is capped at the first 200 spaces per scan to stay within invocation budgets. Larger sites see partial space attribution; group-based billable paths are unaffected.
  • Cloud only. Data Center and Server are out of scope.
  • Deletion is not implemented. If you genuinely need it, do it through Atlassian admin, deliberately, one account at a time.
10

Release notes

Version history for License Guardian for Confluence. The most recent release is listed first.

  1. v1.0.0 Current

    Initial release.

    Governance

    • A governed ignore list with three mechanisms — user pin, group, and pattern — sharing one record format that requires a reason, an owner and timestamps.
    • An enforced lifecycle: entries expire, expired entries stop shielding immediately and are retained as evidence, and entries with no expiry surface for recurring re-confirmation on a configurable cadence (default 90 days).
    • Pattern guardrails that reject catch-alls and anything broad enough to match ordinary human addresses.
    • Five RBAC roles with deliberate separation of duties, enforced in the resolver layer with every denial audited.

    Detection

    • Weighted service-account scoring across seven signals, tuned so no single signal can clear the threshold alone. Flagged accounts are excluded from bulk selection and routed into the ignore-list process rather than silently spared.
    • Billable-path breakdown showing how each user became licensed — group membership or space-level permission grant.
    • A resumable scan state machine: PENDING → COLLECTING_GROUPS → COLLECTING_USERS → ENRICHING → EVALUATING → COMPLETED. A timeout costs one chunk of progress, never the whole scan.

    Safety

    • Safe mode on by default and enforced server-side; live execution behind two independent gates.
    • Suspend, never delete. Every batch records undo instructions before it runs, and rollback is available from the Audit tab.
    • Auto-restore and grace-period release run after every completed scan regardless of mode, because both only ever restore access.
    • A conservative default policy: 90-day inactivity threshold, 30-day never-logged-in grace, 14-day notice period, 90-day ignore review cadence, scheduled scans requiring approval.
11

Get it & contact

Marketplace link coming soon Contact support

Vendor

AryonForge

App ID

ari:cloud:ecosystem::app/e4b618c7-fc77-439e-9e92-df1aecbd99cd