Recover
Open an artifact with no account, no CLI, and no saved.sh.
View as MarkdownA backup you can only open through a vendor is a dependency, not a backup. This page exists so that sentence is testable.
Everything below uses tools already on your machine. None of it involves us.
What an artifact is
An artifact is an ordinary file, produced by a pipeline with no proprietary step:
dump → compress → encrypt → uploadReversing it is the same steps backwards, with gpg, gunzip and whatever tool made the
dump. There is no saved.sh container format, no custom codec, and no index we hold that you
need.
1. Get the bytes
While you have an account, the fastest route is the CLI or the dashboard:
sctl artifact get <artifact-id>
sctl artifact download <artifact-id> --output ./artifactsctl artifact get prints what you need to open it: the filename, the size, the checksum,
whether it is compressed and encrypted, and which key it was encrypted to.
Downloads are never gated on billing state. A workspace that is behind on payment can still read and download every artifact it has. Your backups are not leverage.
Without our API
Where the bytes are depends on how the backup was configured to deliver them.
| Where the artifact lives | How you get it without us |
|---|---|
| Your own bucket (delivery) | Directly, with any S3 client and your own credentials |
| Our storage | Through a presigned URL from our API |
If keeping a copy you can reach without us matters, that is what a destination is for.
Point a backup at a bucket you own, and the artifact lands there under
<workspace-id>/<backup-id>/<run-id>/artifact, readable with aws s3 cp and no involvement
from us at all.
Artifacts in our storage are not directly listable by you: we hand out a presigned URL rather than credentials to the bucket. That is the correct security posture, and it is also a dependency. If your recovery plan must survive us being unreachable, deliver to your own bucket as well.
2. Decrypt
With the private key you generated, the half we never had. The command is identical on
Linux, macOS and Windows once gpg is installed; see
installing gpg.
gpg --decrypt app.dump.gz.gpg > app.dump.gz# Windows PowerShell: redirect as raw bytes, not text
gpg --output app.dump.gz --decrypt app.dump.gz.gpgOn Windows, use gpg --output <file> rather than >. PowerShell's redirection re-encodes
the stream as text and will corrupt a binary dump.
If this key is gone, stop. There is no recovery path, no support request and no override. We store ciphertext and we do not have your key. Verify you still hold it before you need it.
This does not decompress. Compression is applied before encryption, so decrypting a
compressed artifact gives you a gzip file and step 3 is not optional. gpg does undo the
PGP message's own internal compression, which is a different layer and not the one named in
the filename.
3. Decompress, if it was compressed
Whether or not it was also encrypted. A compressed artifact is a plain gzip file once any PGP wrapper is off:
gunzip restored.gzThe filename records the layers in the order they were applied, so app.dump.gz.gpg peels
right to left: gpg first, then gunzip. Check sctl artifact get if the name has been
lost, or just look at the
magic bytes: 1F 8B
is gzip.
4. Restore
Now it is a plain dump, and the tool that made it is the tool that reads it:
| Source | Command |
|---|---|
postgres | pg_restore -d mydb app.dump |
mysql | mysql -u root -p app < app.sql |
redis | Stop Redis, copy the RDB into place, start it |
s3 | tar -xf archive.tar |
folder | unzip folder.zip |
file, script, web | It is already the file |
Doing it with the CLI instead
sctl restore does all four steps in one command, on your machine.
The target type is the subcommand, and each takes only the flags that type needs.
# Replayed into a database
sctl restore postgres <artifact-id> --host localhost --database scratch --user postgres
sctl restore mysql <artifact-id> --database scratch --user root
# Written to a path
sctl restore file <artifact-id> --path ./restored.tar
sctl restore folder <artifact-id> --path ./restored.zip| Subcommand | Flags |
|---|---|
postgres, mysql | --database (required), --host, --port, --user, --password, --ssl-mode |
file, folder | --path (required) |
--key applies to all four: a private key file, defaulting to your gpg keyring or agent. If
you pass it, the key is imported into a temporary keyring that is deleted when the command
exits.
Restore is entirely client-side: download, decrypt with your key, decompress, reconstruct. Neither the target nor its credentials are ever sent to us.
You name the target yourself, so nothing is read from the backup definition. A restore works when the definition has been deleted but the artifact has not: you need the artifact and your key, and nothing else.
Do this on a normal day
The procedure above is worth performing once, deliberately, while nothing is wrong, against a scratch database, on a laptop, with the CLI logged out.
That rehearsal is what turns a backup into a recovery plan. It also catches the two failures that only ever surface under pressure: a private key nobody actually kept, and a dump that restores into a schema that has since moved on.