jira-confluence-full-instance-backup 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jira_confluence_full_instance_backup-0.1.0/LICENSE +21 -0
- jira_confluence_full_instance_backup-0.1.0/PKG-INFO +343 -0
- jira_confluence_full_instance_backup-0.1.0/README.md +304 -0
- jira_confluence_full_instance_backup-0.1.0/backup/__init__.py +8 -0
- jira_confluence_full_instance_backup-0.1.0/backup/__main__.py +7 -0
- jira_confluence_full_instance_backup-0.1.0/backup/archive.py +112 -0
- jira_confluence_full_instance_backup-0.1.0/backup/cli.py +414 -0
- jira_confluence_full_instance_backup-0.1.0/backup/config.py +136 -0
- jira_confluence_full_instance_backup-0.1.0/backup/confluence.py +230 -0
- jira_confluence_full_instance_backup-0.1.0/backup/jira.py +314 -0
- jira_confluence_full_instance_backup-0.1.0/backup/manifest.py +130 -0
- jira_confluence_full_instance_backup-0.1.0/backup/naming.py +63 -0
- jira_confluence_full_instance_backup-0.1.0/backup/notify.py +232 -0
- jira_confluence_full_instance_backup-0.1.0/backup/ui.py +140 -0
- jira_confluence_full_instance_backup-0.1.0/backup/upload.py +167 -0
- jira_confluence_full_instance_backup-0.1.0/jira_confluence_full_instance_backup.egg-info/PKG-INFO +343 -0
- jira_confluence_full_instance_backup-0.1.0/jira_confluence_full_instance_backup.egg-info/SOURCES.txt +21 -0
- jira_confluence_full_instance_backup-0.1.0/jira_confluence_full_instance_backup.egg-info/dependency_links.txt +1 -0
- jira_confluence_full_instance_backup-0.1.0/jira_confluence_full_instance_backup.egg-info/entry_points.txt +2 -0
- jira_confluence_full_instance_backup-0.1.0/jira_confluence_full_instance_backup.egg-info/requires.txt +19 -0
- jira_confluence_full_instance_backup-0.1.0/jira_confluence_full_instance_backup.egg-info/top_level.txt +1 -0
- jira_confluence_full_instance_backup-0.1.0/pyproject.toml +58 -0
- jira_confluence_full_instance_backup-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Malko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jira-confluence-full-instance-backup
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Full-instance backup of Jira & Confluence Cloud (Standard plan) to pluggable cloud storage
|
|
5
|
+
Author-email: David Malko <davidmalko87@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/davidmalko87/jira-confluence-full-instance-backup
|
|
8
|
+
Project-URL: Repository, https://github.com/davidmalko87/jira-confluence-full-instance-backup
|
|
9
|
+
Project-URL: Changelog, https://github.com/davidmalko87/jira-confluence-full-instance-backup/blob/master/CHANGELOG.md
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/davidmalko87/jira-confluence-full-instance-backup/issues
|
|
11
|
+
Keywords: jira,confluence,backup,atlassian,atlassian-cloud,jenkins,gcs,s3,azure
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: System :: Archiving :: Backup
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: requests>=2.31
|
|
25
|
+
Provides-Extra: gcs
|
|
26
|
+
Requires-Dist: google-cloud-storage>=2.14; extra == "gcs"
|
|
27
|
+
Provides-Extra: s3
|
|
28
|
+
Requires-Dist: boto3>=1.34; extra == "s3"
|
|
29
|
+
Provides-Extra: azure
|
|
30
|
+
Requires-Dist: azure-storage-blob>=12.19; extra == "azure"
|
|
31
|
+
Provides-Extra: ui
|
|
32
|
+
Requires-Dist: rich>=13.0; extra == "ui"
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: google-cloud-storage>=2.14; extra == "all"
|
|
35
|
+
Requires-Dist: boto3>=1.34; extra == "all"
|
|
36
|
+
Requires-Dist: azure-storage-blob>=12.19; extra == "all"
|
|
37
|
+
Requires-Dist: rich>=13.0; extra == "all"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# Jira & Confluence Full-Instance Backup
|
|
41
|
+
|
|
42
|
+
[](https://github.com/davidmalko87/jira-confluence-full-instance-backup/actions/workflows/ci.yml)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
[](https://www.python.org/)
|
|
45
|
+
[](https://www.atlassian.com/software/jira)
|
|
46
|
+
[](https://www.atlassian.com/software/confluence)
|
|
47
|
+
[](#storage-backends)
|
|
48
|
+
[](#notification-channels)
|
|
49
|
+
[](https://github.com/davidmalko87/jira-confluence-full-instance-backup/commits/master)
|
|
50
|
+
|
|
51
|
+
Automated **full-instance backup** of **Jira Cloud** and **Confluence Cloud** for
|
|
52
|
+
the Atlassian **Standard plan**. Run it by hand from an interactive menu, or
|
|
53
|
+
unattended from Jenkins/cron. Backups are encrypted and shipped to **the cloud
|
|
54
|
+
of your choice** — Google Cloud Storage, AWS S3 (and S3-compatible stores),
|
|
55
|
+
Azure Blob, or a local/mounted directory — with notifications to **any channel**
|
|
56
|
+
you use: Slack, Microsoft Teams, Discord, Google Chat, email, or a generic
|
|
57
|
+
webhook.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Why?
|
|
62
|
+
|
|
63
|
+
On **March 30, 2026**, Atlassian [deprecated the Backup Manager API](https://community.atlassian.com/forums/Jira-questions/Backup-Manager-API-deprecation-is-there-going-to-be-a/qaq-p/3120079) for Jira Cloud. Direct API-token calls to the backup endpoint now return:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
HTTP 403
|
|
67
|
+
{"error":"This feature is only accessible from the UI."}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The replacement [v2 Backup & Restore API](https://developer.atlassian.com/cloud/admin/backup/) is Premium/Enterprise only, leaving Standard-plan customers with no automation path for full-instance backup — only the manual UI button. This tool restores that automation by **replaying the browser UI session** for Jira, while Confluence uses the OBM REST API (which still accepts API tokens). Both flow into one pipeline that archives, encrypts, uploads, and notifies.
|
|
71
|
+
|
|
72
|
+
For per-project Jira backup/restore, see the sibling project [`jira-project-backup-restore`](https://github.com/davidmalko87/jira-project-backup-restore).
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
| Feature | Description |
|
|
79
|
+
|---|---|
|
|
80
|
+
| **Full-instance backup** | Jira (all projects, attachments, avatars, logos) + Confluence (all spaces, attachments) in one run |
|
|
81
|
+
| **Run anywhere** | Interactive **menu** for VMs/manual use **and** **CLI flags** for Jenkins/cron — same codebase |
|
|
82
|
+
| **Pluggable storage** | **GCS · AWS S3 / S3-compatible (R2, B2, MinIO, Spaces) · Azure Blob · local** — pick one flag; only that SDK is needed |
|
|
83
|
+
| **Pluggable notifications** | **Slack · Teams · Discord · Google Chat · email (SMTP) · generic webhook** — any combination, no extra deps |
|
|
84
|
+
| **Optional encryption** | 7-Zip AES-256 with encrypted headers — on by default, switch off with `--no-encrypt` |
|
|
85
|
+
| **Configurable compression** | `0` (store) … `9` (ultra) |
|
|
86
|
+
| **Custom filenames** | Name templates: `{product} {site} {date} {time} {datetime} {timestamp}` |
|
|
87
|
+
| **Integrity & housekeeping** | `manifest.json` with sha256 + `--validate`, `--cleanup`, `--skip-existing`, `--dry-run` |
|
|
88
|
+
| **Cooldown-aware** | Atlassian's 48h throttle (HTTP 412) is detected and skipped cleanly — no false failures |
|
|
89
|
+
| **Connection test** | Validates Jira cookies + Confluence token, warns when the Jira session is near expiry |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Install
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install jira-confluence-full-instance-backup # core (requests)
|
|
97
|
+
# add the storage backend you use:
|
|
98
|
+
pip install "jira-confluence-full-instance-backup[s3]" # or [gcs] / [azure]
|
|
99
|
+
# optional nicer interactive output (progress bars, color):
|
|
100
|
+
pip install "jira-confluence-full-instance-backup[ui]"
|
|
101
|
+
# everything:
|
|
102
|
+
pip install "jira-confluence-full-instance-backup[all]"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or from source:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
git clone https://github.com/davidmalko87/jira-confluence-full-instance-backup.git
|
|
109
|
+
cd jira-confluence-full-instance-backup
|
|
110
|
+
pip install -r requirements.txt # + requirements-<provider>.txt as needed
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Requirements: Python 3.10+, and `7z` on PATH (`apt install p7zip-full`, or set `SEVEN_ZIP_PATH`).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Quick Start
|
|
118
|
+
|
|
119
|
+
### 1. Configure
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
cp .env.example .env # fill in real values — .env is gitignored
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Or use the guided menu (writes `.env` for you): `jira-confluence-backup` → **Configure credentials**.
|
|
126
|
+
|
|
127
|
+
### 2. Run — interactive menu
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
jira-confluence-backup # or: python main.py / python -m backup
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
=== Atlassian Full-Instance Backup ===
|
|
135
|
+
Jira https://<your-site>.atlassian.net
|
|
136
|
+
Storage s3:my-backups
|
|
137
|
+
Notify slack
|
|
138
|
+
|
|
139
|
+
1) Backup Jira 7) Validate backup
|
|
140
|
+
2) Backup Confluence 8) Cleanup backups
|
|
141
|
+
3) Backup both 9) Test connections
|
|
142
|
+
4) Full run 10) Configure credentials
|
|
143
|
+
5) Archive ./out 11) Show configuration
|
|
144
|
+
6) Upload ./archive 12) List local backups
|
|
145
|
+
0) Exit
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 3. Run — CLI (automation)
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
jira-confluence-backup --all # backup both -> archive -> upload -> notify
|
|
152
|
+
jira-confluence-backup --all --dry-run # preview only, no API calls / no cooldown burn
|
|
153
|
+
jira-confluence-backup --backup jira,confluence --archive --upload --notify
|
|
154
|
+
jira-confluence-backup --validate # check the archive against its manifest
|
|
155
|
+
jira-confluence-backup --cleanup --keep-days 28 # prune incomplete + old local backups
|
|
156
|
+
jira-confluence-backup --test-connection # exit 0 if both auth paths are OK
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
> Output is plain ASCII (`[INFO]/[OK]`) by default — safe on any console, including legacy Windows. Install the `ui` extra for colored output and progress bars.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## How It Works
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Setup -> Jira -> Confluence -> Archive -> Upload -> Notify
|
|
167
|
+
(venv) (cookies) (API token) (7z, opt. (<provider>:// (your
|
|
168
|
+
AES-256) <dest>/Y/M/D/) channels)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Stages are independent: a Jira cookie expiry does not stop the Confluence stage.
|
|
172
|
+
|
|
173
|
+
### Auth model
|
|
174
|
+
|
|
175
|
+
| Product | Endpoint | Auth | Why |
|
|
176
|
+
|---|---|---|---|
|
|
177
|
+
| Jira | `/rest/backup/1/export/runbackup` | **Session cookies + UI headers** | Atlassian gates this endpoint to UI sessions only — API tokens return 403 |
|
|
178
|
+
| Confluence | `/wiki/rest/obm/1.0/runbackup` | **Basic** (email + API token) | OBM never received the UI-only lockdown |
|
|
179
|
+
|
|
180
|
+
> **Do not replace the Jira side with an API token** — it is gated to browser
|
|
181
|
+
> sessions and returns `403 "This feature is only accessible from the UI."`.
|
|
182
|
+
> One dedicated Atlassian **admin account** supplies both: its API token (for
|
|
183
|
+
> Confluence) and its browser session cookies (for Jira).
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Storage backends
|
|
188
|
+
|
|
189
|
+
Set `STORAGE_PROVIDER` + `STORAGE_DEST` (or `--provider` / `--dest`). Only the chosen SDK is imported; a missing one prints a `pip install` hint.
|
|
190
|
+
|
|
191
|
+
| Provider | `STORAGE_DEST` | Optional SDK | Credentials |
|
|
192
|
+
|---|---|---|---|
|
|
193
|
+
| `gcs` | bucket | `requirements-gcs.txt` | `GOOGLE_APPLICATION_CREDENTIALS` (SA JSON) |
|
|
194
|
+
| `s3` | bucket | `requirements-s3.txt` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION` |
|
|
195
|
+
| `azure` | container | `requirements-azure.txt` | `AZURE_STORAGE_CONNECTION_STRING` |
|
|
196
|
+
| `local` | directory | *(none)* | *(none)* |
|
|
197
|
+
|
|
198
|
+
**S3-compatible stores** (Cloudflare R2, Backblaze B2, MinIO, DigitalOcean Spaces): use `s3` plus `S3_ENDPOINT_URL`. Objects are written to `<dest>/YYYY/MM/DD/`. Retention is the bucket's job (set a lifecycle rule); use a **write-only** identity where possible.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Notification channels
|
|
203
|
+
|
|
204
|
+
`NOTIFY_CHANNELS` is a comma list — pick any. One report is built and rendered per channel; a failed channel is logged but never blocks the rest.
|
|
205
|
+
|
|
206
|
+
| Channel | Needs | Notes |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `slack` / `discord` / `teams` / `google-chat` | `NOTIFY_WEBHOOK_URL` | platform-specific incoming webhook |
|
|
209
|
+
| `email` | `SMTP_*` | stdlib SMTP; port 465 → SSL, else STARTTLS |
|
|
210
|
+
| `webhook` | `NOTIFY_WEBHOOK_URL` | raw JSON POST (PagerDuty / Opsgenie / your API) |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Archiving: encryption, compression, names
|
|
215
|
+
|
|
216
|
+
- **Encryption** (default on): 7-Zip AES-256 with encrypted headers, password from `ARCHIVE_PASSWORD`. Turn it off with `--no-encrypt` or by leaving the password blank.
|
|
217
|
+
- **Compression**: `ARCHIVE_COMPRESSION` / `--compression` `0`–`9`.
|
|
218
|
+
- **Names**: `PRODUCT_NAME_TEMPLATE` (the per-product `.zip`) and `ARCHIVE_NAME_TEMPLATE` (the `.7z`). Tokens: `{product} {site} {date} {time} {datetime} {timestamp} {year} {month} {day}`. Defaults: `{product}-{date}` and `atlassian-backup-{date}`.
|
|
219
|
+
|
|
220
|
+
## Integrity & housekeeping
|
|
221
|
+
|
|
222
|
+
Each successful run writes a `manifest.json` (timestamp, products, per-file + archive **sha256**, `complete: true`, `encrypted`) next to the archive and uploads it too.
|
|
223
|
+
|
|
224
|
+
- `--validate` — re-checksum the local archive against the manifest.
|
|
225
|
+
- `--cleanup [--keep-days N]` — remove incomplete backups (no manifest) and, optionally, ones older than N days.
|
|
226
|
+
- `--skip-existing` — skip a product already backed up today.
|
|
227
|
+
- `--dry-run` — preview any flow without API calls, archiving, or uploads.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Jenkins
|
|
232
|
+
|
|
233
|
+
The `Jenkinsfile` runs a weekly job (cron) and is driven by environment variables:
|
|
234
|
+
|
|
235
|
+
```groovy
|
|
236
|
+
environment {
|
|
237
|
+
SITE_JIRA = 'https://<YOUR_SITE>.atlassian.net'
|
|
238
|
+
SITE_CONFLUENCE = 'https://<YOUR_SITE>.atlassian.net/wiki'
|
|
239
|
+
STORAGE_PROVIDER = 'gcs' // gcs | s3 | azure | local
|
|
240
|
+
STORAGE_DEST = '<YOUR_BUCKET>'
|
|
241
|
+
NOTIFY_CHANNELS = 'slack' // any comma list
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
It installs the matching provider SDK and binds **only** the credentials your config needs from the Jenkins Credentials store (`jira-cookies`, `atlassian-email`/`atlassian-api-token`, `archive-password`, the storage credential, and `notify-webhook-url` / `smtp-*`). No secrets live in the repo.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Cookie Refresh Procedure
|
|
250
|
+
|
|
251
|
+
The Jira `tenant.session.token` JWT expires roughly every 30 days. When it does, the Jira stage exits with code 2 (`Cookie auth rejected — cookies likely expired`). Refresh takes ~60 seconds:
|
|
252
|
+
|
|
253
|
+
1. Log into Atlassian as the backup admin account.
|
|
254
|
+
2. Open `https://<your-site>.atlassian.net/secure/admin/CloudExport.jspa`.
|
|
255
|
+
3. **F12 → Application → Cookies** and copy these five: `tenant.session.token`, `atlassian.xsrf.token`, `JSESSIONID`, `AWSALB`, `AWSALBCORS`.
|
|
256
|
+
4. Assemble as one semicolon-separated string and update it where it's stored (`JIRA_COOKIES` in `.env`, or the `jira-cookies` Jenkins credential).
|
|
257
|
+
|
|
258
|
+
`Test connections` warns you in advance when the token is within a few days of expiry.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Response Code Semantics
|
|
263
|
+
|
|
264
|
+
| Code | Meaning | Behavior |
|
|
265
|
+
|---|---|---|
|
|
266
|
+
| 200 | Backup queued / status returned | Continue polling |
|
|
267
|
+
| 403 | Auth rejected (UI-only gate) | Exit 2 — refresh Jira cookies |
|
|
268
|
+
| 412 | 48-hour cooldown active | Exit 0 + marker — stays green |
|
|
269
|
+
| 400 | Body schema rejected | Investigate body (Atlassian schema change) |
|
|
270
|
+
| 406 | Confluence cosmetic error | Ignore — backup actually started |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Configuration Reference
|
|
275
|
+
|
|
276
|
+
All values come from environment variables, optionally loaded from `.env` (see `.env.example`). In Jenkins they are bound from the Credentials store at runtime — never from a file in the repo.
|
|
277
|
+
|
|
278
|
+
| Env var | Purpose |
|
|
279
|
+
|---|---|
|
|
280
|
+
| `SITE_JIRA` / `SITE_CONFLUENCE` | Atlassian base URLs |
|
|
281
|
+
| `JIRA_COOKIES` | Browser session cookie blob for Jira |
|
|
282
|
+
| `ATL_EMAIL` / `ATL_TOKEN` | Confluence Basic auth |
|
|
283
|
+
| `ARCHIVE_PASSWORD` | 7-Zip AES-256 passphrase (blank = unencrypted) |
|
|
284
|
+
| `ARCHIVE_COMPRESSION` | 0–9 |
|
|
285
|
+
| `PRODUCT_NAME_TEMPLATE` / `ARCHIVE_NAME_TEMPLATE` | Filename templates |
|
|
286
|
+
| `STORAGE_PROVIDER` / `STORAGE_DEST` | Backend + bucket/container/dir |
|
|
287
|
+
| `S3_ENDPOINT_URL` | S3-compatible endpoint (s3 only) |
|
|
288
|
+
| `GOOGLE_APPLICATION_CREDENTIALS` / `AWS_*` / `AZURE_STORAGE_CONNECTION_STRING` | Provider credentials |
|
|
289
|
+
| `NOTIFY_CHANNELS` | Comma list of channels |
|
|
290
|
+
| `NOTIFY_WEBHOOK_URL` / `SMTP_*` | Notification delivery |
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Project Structure
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
jira-confluence-full-instance-backup/
|
|
298
|
+
├── main.py # Convenience shim (python main.py)
|
|
299
|
+
├── Jenkinsfile # Declarative pipeline (provider/channel driven)
|
|
300
|
+
├── pyproject.toml # Packaging + console script + ruff config
|
|
301
|
+
├── .env.example # Local-testing template (real .env is gitignored)
|
|
302
|
+
├── requirements.txt # Core (requests)
|
|
303
|
+
├── requirements-{gcs,s3,azure,ui}.txt # Optional extras
|
|
304
|
+
└── backup/
|
|
305
|
+
├── cli.py # Dual-mode entrypoint (menu + CLI)
|
|
306
|
+
├── jira.py # Cookie-authenticated Jira backup
|
|
307
|
+
├── confluence.py # OBM Basic-auth Confluence backup
|
|
308
|
+
├── archive.py # 7-Zip (optional AES-256, configurable level)
|
|
309
|
+
├── upload.py # Multi-provider upload (gcs/s3/azure/local)
|
|
310
|
+
├── notify.py # Multi-channel notifier
|
|
311
|
+
├── manifest.py # manifest.json: completeness + sha256 integrity
|
|
312
|
+
├── config.py # Env/.env config + Configure-menu persistence
|
|
313
|
+
├── naming.py # Filename templating
|
|
314
|
+
└── ui.py # Console UI (rich-optional, ASCII-safe)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Known Limitations
|
|
320
|
+
|
|
321
|
+
These are Atlassian platform constraints, not tool limitations:
|
|
322
|
+
|
|
323
|
+
- **48h Jira cooldown** between full-instance backups (weekly cadence is fine).
|
|
324
|
+
- **Cookie lifetime** ~30 days; monthly manual refresh required.
|
|
325
|
+
- **Confluence Filestore retention** ~14 days (the tool downloads immediately, so this affects only the source file).
|
|
326
|
+
- **No restore automation** — restoring a full-instance backup is manual via Atlassian's UI; for per-project restore use [`jira-project-backup-restore`](https://github.com/davidmalko87/jira-project-backup-restore).
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Contributing
|
|
331
|
+
|
|
332
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). In short: no secrets in the repo, keep
|
|
333
|
+
cloud SDKs optional, ASCII-only console output, and test auth/backup changes
|
|
334
|
+
against a non-prod Atlassian instance. **Do not** switch Jira to API-token auth
|
|
335
|
+
(see [Auth model](#auth-model)).
|
|
336
|
+
|
|
337
|
+
## License
|
|
338
|
+
|
|
339
|
+
MIT — see [LICENSE](LICENSE).
|
|
340
|
+
|
|
341
|
+
## Related
|
|
342
|
+
|
|
343
|
+
* [`jira-project-backup-restore`](https://github.com/davidmalko87/jira-project-backup-restore) — per-project Jira Cloud backup/restore via REST API.
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Jira & Confluence Full-Instance Backup
|
|
2
|
+
|
|
3
|
+
[](https://github.com/davidmalko87/jira-confluence-full-instance-backup/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
[](https://www.atlassian.com/software/jira)
|
|
7
|
+
[](https://www.atlassian.com/software/confluence)
|
|
8
|
+
[](#storage-backends)
|
|
9
|
+
[](#notification-channels)
|
|
10
|
+
[](https://github.com/davidmalko87/jira-confluence-full-instance-backup/commits/master)
|
|
11
|
+
|
|
12
|
+
Automated **full-instance backup** of **Jira Cloud** and **Confluence Cloud** for
|
|
13
|
+
the Atlassian **Standard plan**. Run it by hand from an interactive menu, or
|
|
14
|
+
unattended from Jenkins/cron. Backups are encrypted and shipped to **the cloud
|
|
15
|
+
of your choice** — Google Cloud Storage, AWS S3 (and S3-compatible stores),
|
|
16
|
+
Azure Blob, or a local/mounted directory — with notifications to **any channel**
|
|
17
|
+
you use: Slack, Microsoft Teams, Discord, Google Chat, email, or a generic
|
|
18
|
+
webhook.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Why?
|
|
23
|
+
|
|
24
|
+
On **March 30, 2026**, Atlassian [deprecated the Backup Manager API](https://community.atlassian.com/forums/Jira-questions/Backup-Manager-API-deprecation-is-there-going-to-be-a/qaq-p/3120079) for Jira Cloud. Direct API-token calls to the backup endpoint now return:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
HTTP 403
|
|
28
|
+
{"error":"This feature is only accessible from the UI."}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The replacement [v2 Backup & Restore API](https://developer.atlassian.com/cloud/admin/backup/) is Premium/Enterprise only, leaving Standard-plan customers with no automation path for full-instance backup — only the manual UI button. This tool restores that automation by **replaying the browser UI session** for Jira, while Confluence uses the OBM REST API (which still accepts API tokens). Both flow into one pipeline that archives, encrypts, uploads, and notifies.
|
|
32
|
+
|
|
33
|
+
For per-project Jira backup/restore, see the sibling project [`jira-project-backup-restore`](https://github.com/davidmalko87/jira-project-backup-restore).
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
| Feature | Description |
|
|
40
|
+
|---|---|
|
|
41
|
+
| **Full-instance backup** | Jira (all projects, attachments, avatars, logos) + Confluence (all spaces, attachments) in one run |
|
|
42
|
+
| **Run anywhere** | Interactive **menu** for VMs/manual use **and** **CLI flags** for Jenkins/cron — same codebase |
|
|
43
|
+
| **Pluggable storage** | **GCS · AWS S3 / S3-compatible (R2, B2, MinIO, Spaces) · Azure Blob · local** — pick one flag; only that SDK is needed |
|
|
44
|
+
| **Pluggable notifications** | **Slack · Teams · Discord · Google Chat · email (SMTP) · generic webhook** — any combination, no extra deps |
|
|
45
|
+
| **Optional encryption** | 7-Zip AES-256 with encrypted headers — on by default, switch off with `--no-encrypt` |
|
|
46
|
+
| **Configurable compression** | `0` (store) … `9` (ultra) |
|
|
47
|
+
| **Custom filenames** | Name templates: `{product} {site} {date} {time} {datetime} {timestamp}` |
|
|
48
|
+
| **Integrity & housekeeping** | `manifest.json` with sha256 + `--validate`, `--cleanup`, `--skip-existing`, `--dry-run` |
|
|
49
|
+
| **Cooldown-aware** | Atlassian's 48h throttle (HTTP 412) is detected and skipped cleanly — no false failures |
|
|
50
|
+
| **Connection test** | Validates Jira cookies + Confluence token, warns when the Jira session is near expiry |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install jira-confluence-full-instance-backup # core (requests)
|
|
58
|
+
# add the storage backend you use:
|
|
59
|
+
pip install "jira-confluence-full-instance-backup[s3]" # or [gcs] / [azure]
|
|
60
|
+
# optional nicer interactive output (progress bars, color):
|
|
61
|
+
pip install "jira-confluence-full-instance-backup[ui]"
|
|
62
|
+
# everything:
|
|
63
|
+
pip install "jira-confluence-full-instance-backup[all]"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or from source:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/davidmalko87/jira-confluence-full-instance-backup.git
|
|
70
|
+
cd jira-confluence-full-instance-backup
|
|
71
|
+
pip install -r requirements.txt # + requirements-<provider>.txt as needed
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Requirements: Python 3.10+, and `7z` on PATH (`apt install p7zip-full`, or set `SEVEN_ZIP_PATH`).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
### 1. Configure
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
cp .env.example .env # fill in real values — .env is gitignored
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Or use the guided menu (writes `.env` for you): `jira-confluence-backup` → **Configure credentials**.
|
|
87
|
+
|
|
88
|
+
### 2. Run — interactive menu
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
jira-confluence-backup # or: python main.py / python -m backup
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
=== Atlassian Full-Instance Backup ===
|
|
96
|
+
Jira https://<your-site>.atlassian.net
|
|
97
|
+
Storage s3:my-backups
|
|
98
|
+
Notify slack
|
|
99
|
+
|
|
100
|
+
1) Backup Jira 7) Validate backup
|
|
101
|
+
2) Backup Confluence 8) Cleanup backups
|
|
102
|
+
3) Backup both 9) Test connections
|
|
103
|
+
4) Full run 10) Configure credentials
|
|
104
|
+
5) Archive ./out 11) Show configuration
|
|
105
|
+
6) Upload ./archive 12) List local backups
|
|
106
|
+
0) Exit
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Run — CLI (automation)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
jira-confluence-backup --all # backup both -> archive -> upload -> notify
|
|
113
|
+
jira-confluence-backup --all --dry-run # preview only, no API calls / no cooldown burn
|
|
114
|
+
jira-confluence-backup --backup jira,confluence --archive --upload --notify
|
|
115
|
+
jira-confluence-backup --validate # check the archive against its manifest
|
|
116
|
+
jira-confluence-backup --cleanup --keep-days 28 # prune incomplete + old local backups
|
|
117
|
+
jira-confluence-backup --test-connection # exit 0 if both auth paths are OK
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
> Output is plain ASCII (`[INFO]/[OK]`) by default — safe on any console, including legacy Windows. Install the `ui` extra for colored output and progress bars.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## How It Works
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Setup -> Jira -> Confluence -> Archive -> Upload -> Notify
|
|
128
|
+
(venv) (cookies) (API token) (7z, opt. (<provider>:// (your
|
|
129
|
+
AES-256) <dest>/Y/M/D/) channels)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Stages are independent: a Jira cookie expiry does not stop the Confluence stage.
|
|
133
|
+
|
|
134
|
+
### Auth model
|
|
135
|
+
|
|
136
|
+
| Product | Endpoint | Auth | Why |
|
|
137
|
+
|---|---|---|---|
|
|
138
|
+
| Jira | `/rest/backup/1/export/runbackup` | **Session cookies + UI headers** | Atlassian gates this endpoint to UI sessions only — API tokens return 403 |
|
|
139
|
+
| Confluence | `/wiki/rest/obm/1.0/runbackup` | **Basic** (email + API token) | OBM never received the UI-only lockdown |
|
|
140
|
+
|
|
141
|
+
> **Do not replace the Jira side with an API token** — it is gated to browser
|
|
142
|
+
> sessions and returns `403 "This feature is only accessible from the UI."`.
|
|
143
|
+
> One dedicated Atlassian **admin account** supplies both: its API token (for
|
|
144
|
+
> Confluence) and its browser session cookies (for Jira).
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Storage backends
|
|
149
|
+
|
|
150
|
+
Set `STORAGE_PROVIDER` + `STORAGE_DEST` (or `--provider` / `--dest`). Only the chosen SDK is imported; a missing one prints a `pip install` hint.
|
|
151
|
+
|
|
152
|
+
| Provider | `STORAGE_DEST` | Optional SDK | Credentials |
|
|
153
|
+
|---|---|---|---|
|
|
154
|
+
| `gcs` | bucket | `requirements-gcs.txt` | `GOOGLE_APPLICATION_CREDENTIALS` (SA JSON) |
|
|
155
|
+
| `s3` | bucket | `requirements-s3.txt` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION` |
|
|
156
|
+
| `azure` | container | `requirements-azure.txt` | `AZURE_STORAGE_CONNECTION_STRING` |
|
|
157
|
+
| `local` | directory | *(none)* | *(none)* |
|
|
158
|
+
|
|
159
|
+
**S3-compatible stores** (Cloudflare R2, Backblaze B2, MinIO, DigitalOcean Spaces): use `s3` plus `S3_ENDPOINT_URL`. Objects are written to `<dest>/YYYY/MM/DD/`. Retention is the bucket's job (set a lifecycle rule); use a **write-only** identity where possible.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Notification channels
|
|
164
|
+
|
|
165
|
+
`NOTIFY_CHANNELS` is a comma list — pick any. One report is built and rendered per channel; a failed channel is logged but never blocks the rest.
|
|
166
|
+
|
|
167
|
+
| Channel | Needs | Notes |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `slack` / `discord` / `teams` / `google-chat` | `NOTIFY_WEBHOOK_URL` | platform-specific incoming webhook |
|
|
170
|
+
| `email` | `SMTP_*` | stdlib SMTP; port 465 → SSL, else STARTTLS |
|
|
171
|
+
| `webhook` | `NOTIFY_WEBHOOK_URL` | raw JSON POST (PagerDuty / Opsgenie / your API) |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Archiving: encryption, compression, names
|
|
176
|
+
|
|
177
|
+
- **Encryption** (default on): 7-Zip AES-256 with encrypted headers, password from `ARCHIVE_PASSWORD`. Turn it off with `--no-encrypt` or by leaving the password blank.
|
|
178
|
+
- **Compression**: `ARCHIVE_COMPRESSION` / `--compression` `0`–`9`.
|
|
179
|
+
- **Names**: `PRODUCT_NAME_TEMPLATE` (the per-product `.zip`) and `ARCHIVE_NAME_TEMPLATE` (the `.7z`). Tokens: `{product} {site} {date} {time} {datetime} {timestamp} {year} {month} {day}`. Defaults: `{product}-{date}` and `atlassian-backup-{date}`.
|
|
180
|
+
|
|
181
|
+
## Integrity & housekeeping
|
|
182
|
+
|
|
183
|
+
Each successful run writes a `manifest.json` (timestamp, products, per-file + archive **sha256**, `complete: true`, `encrypted`) next to the archive and uploads it too.
|
|
184
|
+
|
|
185
|
+
- `--validate` — re-checksum the local archive against the manifest.
|
|
186
|
+
- `--cleanup [--keep-days N]` — remove incomplete backups (no manifest) and, optionally, ones older than N days.
|
|
187
|
+
- `--skip-existing` — skip a product already backed up today.
|
|
188
|
+
- `--dry-run` — preview any flow without API calls, archiving, or uploads.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Jenkins
|
|
193
|
+
|
|
194
|
+
The `Jenkinsfile` runs a weekly job (cron) and is driven by environment variables:
|
|
195
|
+
|
|
196
|
+
```groovy
|
|
197
|
+
environment {
|
|
198
|
+
SITE_JIRA = 'https://<YOUR_SITE>.atlassian.net'
|
|
199
|
+
SITE_CONFLUENCE = 'https://<YOUR_SITE>.atlassian.net/wiki'
|
|
200
|
+
STORAGE_PROVIDER = 'gcs' // gcs | s3 | azure | local
|
|
201
|
+
STORAGE_DEST = '<YOUR_BUCKET>'
|
|
202
|
+
NOTIFY_CHANNELS = 'slack' // any comma list
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
It installs the matching provider SDK and binds **only** the credentials your config needs from the Jenkins Credentials store (`jira-cookies`, `atlassian-email`/`atlassian-api-token`, `archive-password`, the storage credential, and `notify-webhook-url` / `smtp-*`). No secrets live in the repo.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Cookie Refresh Procedure
|
|
211
|
+
|
|
212
|
+
The Jira `tenant.session.token` JWT expires roughly every 30 days. When it does, the Jira stage exits with code 2 (`Cookie auth rejected — cookies likely expired`). Refresh takes ~60 seconds:
|
|
213
|
+
|
|
214
|
+
1. Log into Atlassian as the backup admin account.
|
|
215
|
+
2. Open `https://<your-site>.atlassian.net/secure/admin/CloudExport.jspa`.
|
|
216
|
+
3. **F12 → Application → Cookies** and copy these five: `tenant.session.token`, `atlassian.xsrf.token`, `JSESSIONID`, `AWSALB`, `AWSALBCORS`.
|
|
217
|
+
4. Assemble as one semicolon-separated string and update it where it's stored (`JIRA_COOKIES` in `.env`, or the `jira-cookies` Jenkins credential).
|
|
218
|
+
|
|
219
|
+
`Test connections` warns you in advance when the token is within a few days of expiry.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Response Code Semantics
|
|
224
|
+
|
|
225
|
+
| Code | Meaning | Behavior |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| 200 | Backup queued / status returned | Continue polling |
|
|
228
|
+
| 403 | Auth rejected (UI-only gate) | Exit 2 — refresh Jira cookies |
|
|
229
|
+
| 412 | 48-hour cooldown active | Exit 0 + marker — stays green |
|
|
230
|
+
| 400 | Body schema rejected | Investigate body (Atlassian schema change) |
|
|
231
|
+
| 406 | Confluence cosmetic error | Ignore — backup actually started |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Configuration Reference
|
|
236
|
+
|
|
237
|
+
All values come from environment variables, optionally loaded from `.env` (see `.env.example`). In Jenkins they are bound from the Credentials store at runtime — never from a file in the repo.
|
|
238
|
+
|
|
239
|
+
| Env var | Purpose |
|
|
240
|
+
|---|---|
|
|
241
|
+
| `SITE_JIRA` / `SITE_CONFLUENCE` | Atlassian base URLs |
|
|
242
|
+
| `JIRA_COOKIES` | Browser session cookie blob for Jira |
|
|
243
|
+
| `ATL_EMAIL` / `ATL_TOKEN` | Confluence Basic auth |
|
|
244
|
+
| `ARCHIVE_PASSWORD` | 7-Zip AES-256 passphrase (blank = unencrypted) |
|
|
245
|
+
| `ARCHIVE_COMPRESSION` | 0–9 |
|
|
246
|
+
| `PRODUCT_NAME_TEMPLATE` / `ARCHIVE_NAME_TEMPLATE` | Filename templates |
|
|
247
|
+
| `STORAGE_PROVIDER` / `STORAGE_DEST` | Backend + bucket/container/dir |
|
|
248
|
+
| `S3_ENDPOINT_URL` | S3-compatible endpoint (s3 only) |
|
|
249
|
+
| `GOOGLE_APPLICATION_CREDENTIALS` / `AWS_*` / `AZURE_STORAGE_CONNECTION_STRING` | Provider credentials |
|
|
250
|
+
| `NOTIFY_CHANNELS` | Comma list of channels |
|
|
251
|
+
| `NOTIFY_WEBHOOK_URL` / `SMTP_*` | Notification delivery |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Project Structure
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
jira-confluence-full-instance-backup/
|
|
259
|
+
├── main.py # Convenience shim (python main.py)
|
|
260
|
+
├── Jenkinsfile # Declarative pipeline (provider/channel driven)
|
|
261
|
+
├── pyproject.toml # Packaging + console script + ruff config
|
|
262
|
+
├── .env.example # Local-testing template (real .env is gitignored)
|
|
263
|
+
├── requirements.txt # Core (requests)
|
|
264
|
+
├── requirements-{gcs,s3,azure,ui}.txt # Optional extras
|
|
265
|
+
└── backup/
|
|
266
|
+
├── cli.py # Dual-mode entrypoint (menu + CLI)
|
|
267
|
+
├── jira.py # Cookie-authenticated Jira backup
|
|
268
|
+
├── confluence.py # OBM Basic-auth Confluence backup
|
|
269
|
+
├── archive.py # 7-Zip (optional AES-256, configurable level)
|
|
270
|
+
├── upload.py # Multi-provider upload (gcs/s3/azure/local)
|
|
271
|
+
├── notify.py # Multi-channel notifier
|
|
272
|
+
├── manifest.py # manifest.json: completeness + sha256 integrity
|
|
273
|
+
├── config.py # Env/.env config + Configure-menu persistence
|
|
274
|
+
├── naming.py # Filename templating
|
|
275
|
+
└── ui.py # Console UI (rich-optional, ASCII-safe)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Known Limitations
|
|
281
|
+
|
|
282
|
+
These are Atlassian platform constraints, not tool limitations:
|
|
283
|
+
|
|
284
|
+
- **48h Jira cooldown** between full-instance backups (weekly cadence is fine).
|
|
285
|
+
- **Cookie lifetime** ~30 days; monthly manual refresh required.
|
|
286
|
+
- **Confluence Filestore retention** ~14 days (the tool downloads immediately, so this affects only the source file).
|
|
287
|
+
- **No restore automation** — restoring a full-instance backup is manual via Atlassian's UI; for per-project restore use [`jira-project-backup-restore`](https://github.com/davidmalko87/jira-project-backup-restore).
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Contributing
|
|
292
|
+
|
|
293
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). In short: no secrets in the repo, keep
|
|
294
|
+
cloud SDKs optional, ASCII-only console output, and test auth/backup changes
|
|
295
|
+
against a non-prod Atlassian instance. **Do not** switch Jira to API-token auth
|
|
296
|
+
(see [Auth model](#auth-model)).
|
|
297
|
+
|
|
298
|
+
## License
|
|
299
|
+
|
|
300
|
+
MIT — see [LICENSE](LICENSE).
|
|
301
|
+
|
|
302
|
+
## Related
|
|
303
|
+
|
|
304
|
+
* [`jira-project-backup-restore`](https://github.com/davidmalko87/jira-project-backup-restore) — per-project Jira Cloud backup/restore via REST API.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Full-instance backup of Atlassian Cloud (Jira + Confluence).
|
|
2
|
+
|
|
3
|
+
Backs up to pluggable cloud storage (GCS / S3 / Azure / local). Modules run as
|
|
4
|
+
``python -m backup.<name>`` from the Jenkins pipeline (jira, confluence,
|
|
5
|
+
archive, upload, notify); the dual-mode CLI/menu is ``backup.cli`` (also the
|
|
6
|
+
``jira-confluence-backup`` console script and ``python -m backup``).
|
|
7
|
+
"""
|
|
8
|
+
__version__ = "0.1.0"
|