Sealed attachments, locked page sections and enforced approvals for Confluence — tampering reverts automatically.
Confluence tracks who changed a document. Sentinel Vault decides whether the change stands: seal attachments and page sections, require multi-approver sign-off with an enforced Approved state, and let unauthorized edits revert automatically.
Seal a file and the seal defends itself: another user's overwrite is restored to the sealed version, a trashed file comes back, and a sealed image keeps its size and layout on the page.
Lock a section of a page — a decision log, a budget table — while the rest stays editable. Tampering with the sealed content is restored from a snapshot.
Pages move Draft → In Review → Approved → Expired with multi-approver sign-off. Approved is enforced: a non-approver's edit demotes or reverts the page automatically.
Deterministic content rules — advisory, gated or hard-revert — plus semantic AI review on Atlassian-hosted Claude. No API keys, no data egress, off by default.

Confluence has no native file locking — any user with edit access can overwrite any attachment at any time. Seal an attachment and Sentinel Vault stands guard: violations are detected and reverted automatically, and everyone involved is notified.
If someone uploads a new version of a sealed attachment, the file is restored to the sealed version — with version history preserved, so nothing is lost.
A trashed sealed file comes back through one unified restore path: the attachment is un-trashed first, then its page embed re-inserted. An unrecoverable file produces an honest notice, not silence.
Sealing an image also seals its presentation: a resize or layout change by a non-owner reverts to the sealed appearance. Applies to seals created from the current release on.

Need to change a file someone else sealed? Request edit access with a reason. The seal owner approves, denies or later revokes it — and approved editors work under the seal, without it ever being lifted for everyone else.
Click Watch on a sealed file and Sentinel Vault posts a Confluence comment that @mentions you the moment the seal is released. Confluence's own notification engine emails you according to your personal settings.
Protection goes beyond attachments. Wrap the part of a page that must not drift — a decision log, an approved budget, a compliance statement — in a sealed section, and leave the rest of the page open for everyday editing.
Sealed sections live directly in the page body. Seal a section from the panel, and it is listed with its owner and expiry alongside your sealed files.
If anyone tampers with sealed content, it is restored from the sealed snapshot — while the rest of the page keeps every other change intact.
Edit requests work here too: approve a named colleague to edit the sealed section, deny or revoke later — without unsealing it for everyone.
Every wiki has status chips that record intent. Sentinel Vault puts an engine behind them: pages move through a document workflow with the sign-off you require, and the Approved state is defended after the fact.
After sign-off, a non-approver's edit to an Approved page is demoted or reverted automatically — the choice of behavior is a per-space admin setting. The state chip on the page ribbon reflects what the engine guarantees, not what someone last remembered to update.
Name individual approvers or whole groups, then pick the decision rule: any one approver, all of them, or a minimum-N quorum. Approvers act right where they read — the ribbon flag opens an approve / deny popover with an optional reason.

Set a re-review period and approvals age honestly: every Approved page carries a review-due date, overdue reviews are flagged, and stale approvals expire to the Expired state instead of quietly staying green forever.
The space Workflow tab shows approvals waiting on you, live counts per state, and every page under workflow with its state, entry date and review-due date — exportable to CSV for audits.

Define what a page in this space must contain — required headings, tables, labels, length limits — and pick how hard the rule bites. Results surface as chips on the page ribbon and detailed findings in the panel, with one-click re-checks.
Findings are reported on the page so authors see what is missing — the page stands as saved.
The page is marked as failing its checks — a clear pass/fail signal on the ribbon until the content meets the rules.
An edit that breaks the rules is reverted automatically — the strictest mode, for content that must never regress.
Give the AI your rules, style guide, tone and compliance standards; a review returns severity-ranked findings with concrete suggestions. Atlassian-hosted Claude — no API keys, no data egress, off by default.

AI review uses Atlassian-hosted Claude via the Forge LLM. No external API keys, no BYOK, no egress — the Runs on Atlassian posture holds even with AI on.
AI review is opt-in per space, limited to Claude Haiku to control token cost, and capped by a monthly token budget you set.
Findings are ranked high / medium / low with suggested fixes, and can notify the page author above a severity threshold. The deterministic engines do the enforcing — the AI advises.
Day-to-day control lives with the space; site-wide policy lives with site administrators. Sentinel Vault keeps the two cleanly separated.
Per-space console with tabs for Sealed Files, Access Control, Seal Duration, Macro, Validations and Workflow. Stewards see every sealed file in the space — including when one is in the trash, missing, or overdue — and manage who holds steward access.
The Workflow tab doubles as the space dashboard: approvals inbox, per-state counts, review dates and CSV export.
The global console for site administrators: default seal duration (spaces can override), steward force-unseal, expiry notifications, attachment removal / restore / cleanup, page-body protection and macro auto-insertion — plus global Alerts and Validations tabs.
Site-wide workflow configuration requires a site admin — space stewards cannot change site policy.

Every notification is delivered through native Confluence surfaces — the app sends no email of its own and calls no external service.
Immediate in-app feedback on seal, unseal, approval and validation actions.
The always-visible status bar on every protected page: sealed count, approval flag, validation and AI chips, and Manage Attachments.
Lifecycle events post a Confluence comment mentioning the right person. Confluence's own notification engine emails them per their personal settings.
Under the hood, Sentinel Vault is a Custom UI Forge app with real-time product triggers on attachment and page-content events, an hourly expiry sweep, an hourly index rebuild and a daily reminder task. Long-running work — space-wide seal audits and AI reviews — runs on async queues with extended timeouts instead of blocking the page.
All data lives in Forge key-value storage inside Atlassian's platform. The manifest declares no external endpoints at all, which is what makes the zero-egress claim checkable rather than aspirational.
| Task | When | Purpose |
|---|---|---|
| Attachment & page triggers | Real-time | Detect overwrites, trashing, deletions and page-content tampering the moment Confluence reports them |
| Expiry sweep | Hourly | Process seal expiries and review dates, and send the related notifications |
| Space audit queue | On demand | Space-wide seal auditing on an extended background timeout, triggered by stewards |
| AI review queue | On demand | Runs AI reviews asynchronously so the page never waits on a model |
Sentinel Vault is licensed through the Atlassian Marketplace — billing, trials and subscription management are all handled by Atlassian, in the same place as the rest of your apps.
If a subscription lapses, seals, sections, workflows and validations keep enforcing. Admin consoles show a renewal banner with a Manage subscription link — your content is never held hostage to a billing hiccup.
The complete reference: what every surface shows, what each seal defends against and how the restore works, the full approval and validation rulebooks, the permission model, every notification and the toggle that gates it, the limits, and what to do when something does not behave the way you expected. 74 sections.
Every rule, key and number here is taken from the app's own source and checked against it.
A Forge app for Confluence Cloud that does not just record who changed sealed content — it decides whether the change stands, and reverts it when it should not.
Sentinel Vault is a content-protection app for Confluence Cloud (Forge app id ari:cloud:ecosystem::app/c30bf71e-4287-4872-954d-db49cc68f0ff, Node.js 22 runtime, Custom UI on every surface). Confluence itself already tracks everything: version history says who changed a page, an approval macro says a document was signed off. What none of that does is act. A status chip stays green while the page under it drifts; an attachment anyone relied on gets silently overwritten. Sentinel Vault's premise is that tracking intent and enforcing it are different products — it is the second one.
The app runs entirely on Atlassian infrastructure: no external servers, no data egress, AI through the Forge-hosted LLM module. See "How the app stores data" below for the full storage and Runs-on-Atlassian picture.
Seven concepts carry the whole product; each is a KVS record family with a stable key pattern, and this manual refers to them by these names throughout.
protection-{attachmentId} with a per-space index leg space-protection-{spaceId}-{attachmentId} and a global change stamp protections-last-modified touched on every seal mutation. The record carries the owner (lockedBy), the expiry (expiresAt), the revert target (sealedVersion + sealedFileId), and — for files embedded on the page at seal time — a presentation baseline (mediaBaseline) of the embed's layout and width. The page also gets a protection- content property so seals are CQL-searchable and triggers can probe cheaply.sectionId. Stored as section-protection-{sectionId} (including a content hash of the canonicalized body), with the restore source in section-snapshot-{sectionId} (the wrapper node plus body ADF captured at seal or re-baseline time) and a space index space-section-protection-{spaceId}-{sectionId}. Mirrored to the section-protection- content property.edit-request-{attachmentId}-{requesterAccountId} (reason capped at 300 characters, one per file per requester; a denial leaves a 48-hour cooldown). Approval converts it to edit-grant-{attachmentId}-{editorAccountId}, written with a KVS TTL equal to the seal's expiry so no grant outlives its seal. Sections have parallel section-edit-request-… / section-edit-grant-… keys.workflow-state-{pageId} is the source of truth; definitions live in workflow-def-global / workflow-def-space-{key} (falling back to the built-in Document Approval workflow: Draft, In Review, Approved, Expired), a by-state index workflow-idx-{spaceKey}-{stateId}-{pageId} feeds the dashboard, and every transition appends workflow-log-{pageId}-{ts} — deliberately with no TTL, as a compliance artifact. Per-space activation lives in workflow-settings-{key}; the page carries a sentinel-vault-workflow content property.block or warn severity, stored in validation-config-global / validation-config-space-{sanitizedKey}. Results use validation-lastgood-{pageId} (the revert target), the dedup key validation-checked-{pageId}-{version}, and the sentinel-vault-validation content property for gate state. AI review adds the ai-* family (findings, status, monthly usage).notify-request-{attachmentId}-{accountId}, TTL 7 days. The notification is a Confluence comment @mention — email arrives only through Confluence's own notification settings.adminUsers / adminGroups in admin-settings-global or admin-settings-space-{sanitizedKey}. Stewards get the administrative tabs and can unseal on behalf of owners. Users can apply via the steward-request flow (steward-request-{spaceKey}-{accountId}, 48-hour cooldown after a denial).Five user-facing manifest modules — two macros, a page banner, a global settings page and a space page — all served by one shared resolver, plus a full-screen overlay opened at runtime.
| Module | Manifest key | Title shown in Confluence | What you get |
|---|---|---|---|
| macro (block) | sentinel-vault-panel | Sentinel Vault | The inline attachment panel on a page: sealed and available files with Seal / Unseal / Watch / Request Edit, uploads, labels, the edit-requests inbox, the Sealed Sections group, and the Validation and AI Review groups. Macro-browser description: "Shows reservation status for every file on this page". Config resource panel-setup-ui; openOnInsert: false. |
| macro (bodied) | sentinel-vault-sealed-section | Sentinel Vault Sealed Section | The content-sealing primitive: wraps the page content it protects and carries the stable app-issued sectionId the tamper-detection trigger keys on. Description: "Locks the content inside this section against unauthorized edits". openOnInsert: true — the config opens the moment you insert it. |
| confluence:pageBanner | sentinel-vault-ribbon | (banner — no title) | The always-visible ribbon under the page title: seal count, workflow state pill, approval flag, validation and AI chips, violation/expiry alerts, and the Manage Attachments button. |
| confluence:globalSettings | steward-console | Sentinel Vault Admin | Site-wide administration under Confluence settings: General, Alerts, and Validations (including Semantic AI configuration) tabs. Confluence itself gates this placement to site admins. |
| confluence:spacePage | realm-console | Sentinel Vault | The space console (route realm-console) in the space sidebar. Every user gets My Sealed Files (with their edit requests); stewards get Sealed Files, Access Control, Seal Duration, Macro, Validations, and Workflow tabs instead. |
overlay) is referenced by no manifest module. It is opened at runtime — new Modal({ resource: "overlay", size: "max" }) — from the ribbon's Manage Attachments button, and its modal is titled "Sentinel Vault" with a column picker (Name, Status, Held by, Expires, Watch for Unseal, Actions on by default; File Size, File Type, Labels, Comment, Created, Version opt-in, remembered in localStorage).All surfaces call one shared resolver (action-router), which aggregates the action tables of ten backend capsules — sealing, section-seals, editreq, panels, policies, realms, operators, bulletins, entitlements, validations — plus the workflow engine. There is no per-surface backend: the panel, ribbon, overlay and both consoles are different windows onto the same actions.
confluence:spacePage, not confluence:spaceSettings — the page itself is reachable by any user who can see the space. Steward-only tabs are gated app-side (the UI asks check-user-role, and every steward action is re-authorized server-side), not by a manifest condition.A banner on every content page that reports seal, workflow, validation and AI status — and stays out of the way when there is nothing to say.
The ribbon renders only on real content (pages and blog posts — it bails out on space apps and settings locations) and hides itself entirely when the page has nothing to report: no attachments, no alerts, no validation state, no AI findings and no workflow. On a page with attachments, the status line reads exactly one of: "N attachments sealed on this page", "N attachments on this page — none sealed", or "No attachments on this page".
The ribbon keeps itself current by polling check-seal-stamp every 5 seconds and refetching only when the stamp actually moved — a seal made in the inline panel or the overlay shows up on the ribbon within one poll tick.
Three event triggers, four hourly/daily scheduled tasks, two queue consumers and the Forge LLM module — the machinery that makes seals self-enforcing.
| Kind | Key | Fires on / cadence | What it does |
|---|---|---|---|
| trigger | attachment-events | avi:confluence:updated:attachment, trashed:attachment, deleted:attachment | Seal enforcement for files: a non-owner's new version is reverted to the sealed one; a non-owner's trash is undone (file set back to "current"); a permanent delete cleans up the seal state and notifies the owner honestly that the file cannot be restored. |
| trigger | page-content-events | avi:confluence:updated:page, created:page | The page pipeline: one body read → sealed-sections restore pass → sealed-media restore pass → one write, then the validation phase. On created:page it also auto-assigns the space's workflow when the space is configured for it. |
| trigger | app-lifecycle-events | avi:forge:installed:app, uninstalled:app | Uninstall enumerates and deletes every KVS key the app owns — no tenant state survives a reinstall. |
| scheduledTrigger | expiry-sweep-scheduled | hourly | Notify-only: posts the seal-expiry notice and the halfway reminder, each at most once per seal. It never deletes a seal — actual release on expiry happens lazily, on the next read or interaction. |
| scheduledTrigger | recurring-nudge-scheduled | daily | When automatic expiry is disabled: banner-only periodic reminders about long-held seals, on the configured Reminder Frequency cadence (no comments, to avoid page clutter). |
| scheduledTrigger | seal-index-cron | hourly | Queues per-space rebuilds of the seal index — and skips entirely when protections-last-modified hasn't moved past protections-last-scanned, so an idle instance costs two KVS reads an hour. |
| scheduledTrigger | workflow-sweep-scheduled | hourly | The workflow integrity sweep: auto-expires Approved pages past their review-due date, self-heals missing approved-version baselines, and catches enforced-page drift that a dropped event missed — checking the edit's author first so an authorized editor is never reverted. |
| consumer | realm-audit-queue | queue, 900 s budget | Rebuilds a space's space-protection-* index off the resolver's ~25 s limit. |
| consumer | ai-validation-queue | queue, 120 s budget | Runs the Semantic AI review — the LLM call exceeds the 25 s resolver limit, so it is queued. |
| llm | sentinel-vault-llm | model: claude | The Atlassian-hosted Forge LLM behind Semantic AI Validations — no API keys, no egress. Runtime use is clamped to Claude Haiku. |
| webtrigger | harness-test-state | dev only | The test harness endpoint, gated by a HARNESS_SECRET environment variable that exists only in the development environment — it returns 404 in production. |
app-account-id) and return immediately on a match. The page trigger fails CLOSED when that id cannot be resolved — it skips all body-mutating work rather than risk a revert loop.protection- / section-protection- probes) and never touches the page body; an attachment event for an unsealed file costs one KVS get. Pages you never sealed do not pay for the app's existence.31 Confluence scopes, all of them earned by a concrete feature — and no external permissions block at all.
read:page:confluence, write:page:confluence, read:content:confluence, write:content:confluence, read:confluence-content.all, read:confluence-content.summary, write:confluence-content, read:content-details:confluence — reading page bodies (ADF) and writing the surgical restores: sealed-section and sealed-media re-insertion, validation reverts, and the enforced-Approved revert.read:attachment:confluence, write:attachment:confluence, delete:attachment:confluence, write:confluence-file, readonly:content.attachment:confluence — downloading a sealed binary and re-uploading it as a new version, un-trashing a sealed file (status back to "current"), and the panel's delete action (which is double-gated by policy and ownership).read:comment:confluence, write:comment:confluence — every outbound notification is a native Confluence footer comment with an @mention; Confluence's own notification engine does the emailing. The app sends no email of its own.read:content.property:confluence, write:content.property:confluence, read:confluence-props, write:confluence-props — the content-property mirrors (protection-, section-protection-, sentinel-vault-validation, sentinel-vault-workflow, sentinel-vault-page-settings) that make seals CQL-searchable and give the triggers their cheap fast-path probes.read:confluence-user, read:confluence-groups — steward checks (group cohorts, site-admin detection), the approver picker, and resolving display names for @mentions.read:space:confluence, read:confluence-space.summary, search:confluence, read:label:confluence — space resolution for the per-space index and policies, and the required-label validation rule.read:content.restriction:confluence, write:content.restriction:confluence, read:confluence-content.permission, read:content.permission:confluence, read:content.metadata:confluence — permission checks (space ADMINISTER probes behind the steward role) and content restriction handling.storage:app — the Forge KVS where every record in this manual lives.llm module — its addition already forced one major bump. Scope and model changes are planned releases here, never patch content.permissions.external block of any kind — no fetch domains, no external scripts, images, styles or fonts. That is the Runs on Atlassian eligibility line, and everything in the app (including AI and file previews) is built to stay on the right side of it.From opening a page to a self-defending attachment — what you click, what gets recorded, and how to prove the seal is real.
sealedVersion — the exact version every future revert restores — its sealedFileId, and, if the file is embedded in the page body, a presentation baseline of the embed's layout, width and dimensions. It also stamps protections-last-modified, writes the space index leg, and mirrors the seal to the page's protection- content property.holdPeriod =
payload.lockDuration (API callers only — the UI does not send one)
overridden by space policy admin-settings-space-{key}.autoUnlockTimeoutHours × 3600
else global policy admin-settings-global.defaultLockDuration (seconds)
else the built-in baseline BASELINE_HOLD_SPAN = 2 × 24 × 60 × 60 (48 hours)
expiresAt = now + holdPeriod (the final value is re-sanitized at the seal
boundary — negative, zero, NaN or absurd
stored policy values fall back to 48 h)One deliberate asymmetry to know from day one: if you, the owner, trash your own sealed file, the app reads that as intent and releases the seal — the record converts to an inert tracking entry so the file stays findable in trash listings, and no live seal is left behind to blame the next editor for the file's absence. A non-owner trashing the same file is simply reverted.
Four effective roles — user, seal owner, space steward, site admin — with every steward power re-checked on the server, not just hidden in the UI.
| Role | Who qualifies | What they can do |
|---|---|---|
| User | Anyone who can see the page | Seal an attachment, unseal their own, upload files, watch a sealed file, request edit access, seal a page section they are editing, run a manual validation check, see the My Sealed Files tab (with their own edit requests) in the space console, and move a page along workflow transitions that need no approval. |
| Seal owner | The account that created a seal (lockedBy) | Everything a user can, plus: their own edits to the sealed thing always pass and become the new baseline (new attachment version, re-captured section snapshot, sanctioned embed removal); unseal; approve, deny and revoke edit requests on their seals; refresh a sealed section's snapshot; and release a seal by trashing their own file. |
| Space steward | A site/org admin, anyone with the space's ADMINISTER permission, or an account/group listed under adminUsers / adminGroups in the global or space settings | The steward tabs in the space console (Sealed Files, Access Control, Seal Duration, Macro, Validations, Workflow), unsealing other users' seals (when the admin-override policy allows), approving edit requests, assigning workflows to pages and bulk-assigning them across the space, editing the space workflow definition and settings, approving steward requests, and driving enforce-state transitions. |
| Site admin | Confluence application administrator | Everything above in every space, plus the Sentinel Vault Admin global settings page (General / Alerts / Validations — Confluence gates the globalSettings placement itself) and the global workflow definition — store-workflow-config at global scope refuses everyone else with "Only a site admin can edit the global workflow definition". |
The steward check is deliberately implemented twice: interactive surfaces resolve the caller with their own credentials, while triggers and the hourly sweeps — which have no user context — use an app-identity variant that checks the same three arms (explicit list, group cohorts plus site admin, space ADMINISTER) for an arbitrary account. That is what lets the workflow sweep decide "this dropped-event edit was made by a steward, do not revert it" without a user session.
Everything lives in Forge KVS under storage:app, mirrored to a handful of content properties — no external database, zero egress, complete wipe on uninstall.
There is no server and no database outside Atlassian. Every seal, section, grant, workflow record, validation config and finding is a key in the Forge Key-Value Store, accessed under the storage:app scope, with the key families listed in "The objects you will meet". Listings work by key-prefix queries; the per-space indexes (space-protection-*, space-section-protection-*, workflow-idx-*) are hand-maintained secondary keys rebuilt by the hourly cron so space consoles never need an instance-wide scan.
| Property key | Contents | Why it exists |
|---|---|---|
| protection- | The full seal payload of the page's most recent seal | CQL discoverability + the attachment-pass fast-path probe |
| section-protection- | Compact array of {sectionId, lockedBy, expiresAt}, rebuilt from KVS | The sections-pass fast-path probe |
| sentinel-vault-validation | Gate state: {state, violations, version, checkedAt, approvedBy?} | Ribbon/panel validation chips and gate approval |
| sentinel-vault-workflow | {workflowId, stateId, enteredAt, enforce, approvedVersion} | CQL + cheap workflow probe without a KVS read |
| sentinel-vault-page-settings | {macroDisabled} | Per-page panel visibility preference |
permissions.external block: no fetch domains, no CDN scripts, no external fonts or images. AI goes through the Forge llm module (Atlassian-hosted Claude); notifications are native Confluence comments whose @mentions make Confluence's own engine send the email; file previews that would need a cross-origin fetch are shipped through the resolver as base64 data-URIs (capped at 5 MB) instead. Your content never leaves Atlassian.Short-lived state expires by itself: TTL'd keys (edit grants, dedup markers, notification events, AI status) go through one shared helper that enforces Forge's TTL shape with a 60-second floor and a 364-day ceiling — an edit grant, for instance, is written with a TTL equal to its seal's expiry so it can never outlive it. The one deliberate exception is the workflow transition log, which carries no TTL because it is a compliance history.
A lapsed license shows a renewal banner on the admin consoles — it never stops protecting sealed content.
Sentinel Vault is Paid via Atlassian: app.licensing.enabled: true in the manifest, with the actual price and tiers set in the Marketplace, and Atlassian's billing doing the real payment enforcement. Inside the app, the check-license action reads the platform's license state off the invocation context.
When the license is explicitly inactive, the admin surfaces (space console and global settings) show a non-blocking banner: "Sentinel Vault is unlicensed. Your sealed content stays protected — please renew your subscription to keep using the app." with a Manage subscription button that opens Confluence's app management screen. Nothing else changes: triggers keep reverting tampering, seals keep expiring on schedule, and no data is withheld — a content-protection app that stopped protecting content the day a PO lapsed would be worse than no app at all.
Yes. Sealing prevents modification, not viewing. All users with page access can still download and view sealed attachments.
The attachment is restored to the sealed version automatically, with version history preserved. A comment records the violation on the page — and repeated violations of the same kind post one comment, not a stream of duplicates.
Sealing an image also seals its presentation. A resize or layout change by a non-owner reverts to the sealed appearance. This applies to seals created from the current release on — earlier seals carry no presentation baseline.
No — and any app that claims to is overselling. Forge events fire after Confluence saves, so violations are detected and reverted automatically after the fact. The result is the same: the sealed content stands.
Anyone can request edit access to a sealed file or section, with a reason. The seal owner approves, denies, or later revokes the access. Approved editors work under the seal — it is never lifted for everyone else.
Once a page reaches Approved through your sign-off rules, an edit by a non-approver demotes or reverts the page automatically — which of the two is a per-space admin choice. Review dates then expire stale approvals so an old green chip cannot masquerade as current.
AI review runs on Atlassian-hosted Claude via the Forge LLM — no external API keys, no BYOK, and no data egress. It is off by default, limited to Claude Haiku, and capped by a monthly token budget you set per space.
No. All seal, section, workflow and validation records live in Forge storage inside the Atlassian platform, and the app makes zero external network calls.
Protection keeps running — seals, sections, workflow enforcement and validations all continue. Admin consoles show a renewal banner with a Manage subscription link until the license is restored.
Lifecycle events post a Confluence comment that @mentions the relevant person — seal owner, editor, watcher or approver. Confluence's built-in notification engine then emails them according to their personal notification settings. The app itself sends no email and calls no external service.
Paid via Atlassian on the Marketplace — install it in minutes and give your Confluence documents control with teeth. The source is on GitHub for transparency.