# Obnam - backup software

Obnam is an exploration of ideas for implmenting backup software. The long
term goal is to have encrypted, de-duplicated backups packaged in a command
line program that is both efficient and straighforward to use. The current
state is that some of the fundamentals for encrypting and storing chunks of
data have been implemented.

To be clear: Obnam is not currently usable for making backups.

The describe the approach for backups this crate is implementing.

* [`arch.md`](doc/arch.md)
* <https://blog.liw.fi/posts/2025/obnam3/>
* <https://obnam.org/blog/>

## Status

This generation of Obnam is under active development. It is ready to be used.

The first two generations of Obnam are discontinued.

## Example

From the source tree, using the Rust `cargo` tool to build and run the program:

~~~
cargo run -q -- help
~~~

(This section needs to be updated to be useful, sorry. Meanwhile, there are
tested examples in the subplot in [`obnam.md`](obnam.md).)

## Communication

For now, the way to discuss Obnam is to do so on the
[fediverse](https://en.wikipedia.org/wiki/Fediverse). Use the hashtab `#obnam`
and mention `@liw@toot.liw.fi`. You can also use issues in the
[Radicle repository](https://app.radicle.xyz/nodes/radicle.liw.fi/rad%3AzbWNQYkQ4QKgdSQcd1tjaemv6d6x).

Later, if the community around 

## Contributing

Obnam is open source software. Contributions would very much be welcome:

* You could become a stakeholder: what do you need and want from a backup
  program? Actively participating in defining the acceptance criteria for
  Obnam, and how to verify Obnam meets them, helps make the program better
  for your needs. A diverse set of stakeholders makes the program better
  people in general.
* Use the software and give feedback. This helps everyone build confidence
  the software actually works. (Although, bear in mind, that Obnam is still
  far from being mature.)
* Help produce documentation that people can understand. Good documentation
  is in a form the recipient can best understand. It might be a short, written
  tutorial for some, a detailed book for others, or a video, or podcast, or
  something else. Also help maintain existing documentation asi it inevitably
  goes out of date.
* If you can program, help fixing bugs or improve functionality. Code
  contributions are often the most obvious one for open source software, but
  by far not the only important one.
  
There's more ways to contribute: this is not an exhautive list.

You can submit contributions in the form of patches to Lars via several methods:

* A Radicle patch (easiset for Lars).
* A URL to a public Git repository with changes in some branch, via email or
  the fediverse.
* `git format-patch` patches via email.

If some other method would be easier for you, don't hesitate to ask.

## Understanding and navigating the code base

Obnam is written in Rust.

The code is both a library and an an application. It's a library first: all
functionality goes into the library and the application (`src/bin` tree)
merely calls the library.

The main function of the program is `src/bin/obnam.rs`, and leaf-level
subcommands are in `src/bin/cmd/*.rs`. The `Leaf` trait defines the
interface to those types. Non-leaf subcommands are in `obnam.rs`
directly.

See the library documentation for what's in the library. It's not documented
here to avoid being out of date. Use `cargo doc --open` to format and read the
library documentation.

Obnam uses [Ambient](https://ambient.liw.fi/) for its Continuous
Integration system and [Radicle](https://radicle.xyz/) for Git hosting.
See [ci0](https://ci0.liw.fi/zbWNQYkQ4QKgdSQcd1tjaemv6d6x.html) or
[callisto](https://callisto.liw.fi/zbWNQYkQ4QKgdSQcd1tjaemv6d6x.html) for CI
results and logs.

## Error types

Each module defines its own error type, and only return errors of that
type. This makes it easier for callers to know what errors they may
need to handle.

All error types are defined using the
[`thiserror`](https://crates.io/crates/thiserror) crate. The main program
prints out error messages from error values itself, without using the `anyhow`
crate.

## Encryption

Obnam uses the `aes-gcm-siv` for AEAD encryption of chunks, and the `rsop` and
`rsoct` programs to encrypt credentials using OpenPGP. Other credential encryption
methods can and should be added, for example using a passphrase provided by the
user. The SOP implementation needs to be made configurable at some point.

## Building code and documentation, and running tests

To build the code and to run tests, see `Makefile`. It's mean to be simple and
easy to follow.

* `make` -- build all code, all docs, and run all tests
* `make test` -- build all code, run tests
* `make subplot_built` -- build test program with Subplot
* `make subplot` -- build test program with Subplot, run it
* `make mutants` -- use `cargo mutatnts` to ensure tests cover buggy
  code mutations

## Test suite

The code uses standard Rust unit tests and the
[Subplot](https://subplot.tech/) tool for testing.

Most code modules have unit tests, using the `#[cfg(test)]` decorator,
as usual in Rust.

Subplot is a tool for documenting acceptance criteria and how to
verify they are met. See its documentation for details. Obnam uses
Subplot to generate a Python test program, `test.py`, and runs that to
verify Obnam meets its acceptance criteria.

Acceptance criteria are expressed as prose and as a test scenario. The
prose is structured as:

* "Want" -- the acceptance criterion, expressed as a "want" from the
  software. For example, "Want: The command `obnam chunk encrypt`
  encrypts a message, and `obnam chunk decrypts` decrypts the message,
  giving the original message."
* "Why" -- a justification for the want. For example, "Why: This
  ensures the encryption can be undone."
* "Who" -- who wants or needs this?

The scenario is expressed using stilted English-like prose, structured
as steps that start with a keyword:

* "given" a pre-condition, or set up for the later steps
* "when" some action is taken
" *then" some post-condition is true

For example:

> given an installed obnam  
> given file greeting.txt  
> when I run obnam chunk encrypt --key secret --label sticky.tape greeting.txt --output chunk.file  
> when I run obnam chunk decrypt --key secret chunk.file  
> then stdout is exactly "Hello, world.\n"

Subplot generates Python code from these, by emitting code that calls
a function that implements each step. See `obnam.py` for Obnam
specific step functions.

The test program executes all the scenarios and checks each step
succeeds. If they do, Obnam meets the acceptance criteria as expressed
as scenarios.

## Legalese

Radicle is distributed under the terms of both the MIT license and the Apache
License (Version 2.0).

See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details.
