# Ambient - a CI engine

See <https://ambient.liw.fi/> for more information.

## Feedback and contributions

The Radicle repository (`rad:zwPaQSTBX8hktn22F6tHAZSFH2Fh`) is my
preferred way to get feedback in the form of issue tickets or patches.
However, the codeberg.org repository
(<https://codeberg.org/ambient/ambient-ci>) is also OK. Or mention me
on the fediverse (`@liw@toot.liw.fi`) or send me email.


## Build and run tests

To build the code and to run the test suite:

~~~
make
~~~

The `Makefile` targets `build` and `test` can be used to do only part
of that.


## Dependencies

You'll need, at least, with package names as they're in Debian:

* [Subplot](https://subplot.tech/) (not packaged in Debian)
* `python`
* `python3-yaml`
* `qemu-utils` (specifically `qemu-img`)
* `ovmf` (UEFI implementation for virtual machines)
* `qemu-system-x86` (specifically `kvm`)
* `rsync`


## On logging

Logging is communication and has audiences. Communication needs to be suitable
for what it tries to convey and what each audience needs. For Ambient, the
audiences are, roughly:

* the software developer whose project is being built and tested in CI
  - they mostly want to know if something failed under CI that was caused by their code
  - for example, if their code has a syntax error or a test failed
* the sysadmin who runs Ambient
  - they mostly want to know if Ambient is misbehaving, such as a disk being
    full
* the Ambient developers
  - they mostly want to know Ambient works as intended, e.g., in Ambient's own test suite

These are served by different kinds of logging.

* the developer needs the run log, with everything that Ambient did during the
  CI run for their project, and what the result was, with enough detail that
  they can usually figure out what the problem is, if an action fails
  - they also don't want to be overwhelmed by a lot of uninteresting detail
* the sysadmin can also be served by the run log, although they may care about
  other parts and details than the developer
* the Ambient developer needs some kind of log that the test suite can analyze

Status quo for logging:

* Ambient itself (`ambient`) produces a JSON Lines format run log (`run.log`
  in the project state directory). In the VM, the `ambient-execute-plan` does
  as well, but that output can be surrounded by non-JSON junk produced by,
  for example, the VM BIOS at boot. When the VM is shut down, `ambient` parses
  the output from the VM (captured via a serial port), and extracts the JSON
  parts, and outputs those to its own JSON log.

* The JSON Lines log is postprocessed (`ambient log --html`) into an HTML
  page. This is what developers and sysadmins are meant to actually read. The
  HTML log will probably need to be customized for some audiences, but having
  the JSON Lines format available makes that tolerably easy.

* The output captured from the VM serial port is stored in raw format
  (`raw.log` in the project state directory). This may be helpful in special
  cases.

These should cover everything except the needs of the test suite.

The test suite primarily needs to know what actions are run, including in pre-
and post-plan. In principle that is captured in the JSON Lines log. There's
also a need to see that `--dry-run` works. That doesn't end up in a run log:
the log isn't created for a dry run. For that specific case, `ambient` will
output a line to stderr.


## Testing HTML log generation

To test chanes to HTML run log generation, set up a test project, run CI on
the test project, then generate HTML log.

* [`projects.yaml`](projects.yaml) has a sample project.
* Run `cargo run -- run --projects projects.yaml --force`
* Run `cargo run -- log pwd --format=html --output /tmp/log.html`
* Open `/tmp/log.html` in a web browser.

## Implementing a pre-plan action to download dependencies

A core aspect of the Ambient security design is that all dependencies must
be downloaded in a pre-plan action, as the virtual machine for the actual
plan doesn't have network access. Although pre- and post-plan are executed
in their own dedicated VMs, with network access, the should still take care
to avoid executing any code from the project under test, or any dependencies
they download.

The pre- and post-plan VMs provide all the isolation as the plan VM, except
for attacks that use the network.

Note that this code can also be embedded in the package manager manifest (e.g.
`package.json` scripts for NPM, arbitrary ruby code in `Gemfile` for Bundler,
and so on). That is, while we can probably trust the package manager itself,
we must avoid any project code invoked by the package manager.

(Ideally the Ambient implementation would at least allow constraining network
access by target and volume, and this will hopefully be implemented later.)

In practice this means that Ambient needs a pre-plan action for every type of
dependency. For example, there is a generic HTTP download action, `http_get`.
Using it as an example:

* The actual action is implemented in `src/action_impl/http_get.rs`.
* This is a submodule of the `action_impl` module, and so `src/action_impl/mod.rs`
  needs lines `mod http_get;` and `pub use http_get::*;` added. This makes the
  `http_get` module part of the `action_impl` module and its symbols exported.
* The `HttpGet(HttpGet)` variant is added to the `PrePlanAction` and the
  `RunnableAction` types.
* The `RunnableAction::from_pre_plan_action` function needs to handle the new
  variant.
* Likewise, the `RunnableAction::name` method.

There may be some other details, but the overall process is the above.

See also the `DebGet` action for downloading Debian packages, in
`src/action_impl/debian.rs`. It is a fuller example than `HttpGet`.

Adding these pre-plan actions is meant to be simple, but there's many details
to get right. Luckily, the Rust compiler will complain if you miss something.


## Legalese

(See [`COPYING.md`](COPYING.md) for a copy of the license.)

Any changes made in September, 2025, or later, by Lars Wirzenius, are
copyright Better Internet Foundation.

Copyright 2023  Lars Wirzenius, Better Internet Foundation, and others

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
