Developer HOWTO
This document is intended for people who want to add support for new framework.
How it works
There’s a class called Builder
(see graminescaffolding/builder.py
)
which directs the whole process of building the container. The build is composed
of steps:
Templates are rendered. Templates are found in
graminescaffolding/templates/framework/<framework>
directory or directly ingraminescaffolding/templates
. They are rendered into files in subdirectory.scag
placed next toscag.toml
in root directory of the project. There are a few common templates that are rendered for every build (likeapp.manifest.template
andDockerfile
), and frameworks may render additional templates as required.Most of the documentation about templates is in Templates. That document is aimed mostly at people who customise existing templates through application-specific overrides, but if you’re developing new framework, you’ll probably ship your templates in graminescaffolding/templates.
Base system image is installed into temporary chroot directory and is archived into temporary tarball
.scag/rootfs.tar
. “Base system” consists of vanilla Debian image, on top of which Gramine package is installed. Gramine installed inside this chroot is required to be exactly the same version as the one installed. Seecreate_chroot()
method inbuilder.py
file.A base system Docker image is created from
rootfs.tar
(seeDockerfile-rootfs
template, rendered to.scag/Dockerfile-rootfs
).Main docker image is built (with
framework/<framework>/Dockerfile
template, rendered to.scag/Dockerfile
). It’s derivedFROM
the base system image created in step 3.This is the step that varies the most according to specific framework.
gramine-manifest
is run at the end of this stage.Contents of this customised docker image are extracted into temporary directory and
gramine-sgx-sign
is ran outside of the docker build process. (This is because if user has signing plugins configured on the workstation, they can’t easily be executed inside Docker).Artifacts from
gramine-sgx-sign
(app.manifest.sgx
andapp.sig
) are used to build third Docker image, based on the second (customised) one. The manifest and SIGSTRUCT are added to this image. This is the final image that can be shipped.
Step 2 is executed via mmdebstrap
. mmdebstrap
is a tool for creating
Debian-based system images. The process is customisable with hooks. There are
two hooks used by scaffolding:
setup
(rendered as.scag/mmdebstrap-hooks/setup.sh
): Runs very early in the bootstrap process and prepares installation environment. Probably should not be touched unless you need to pin some packages for reproducible builds.customize
(rendered as.scag/mmdebstrap-hooks/customize.sh
): Runs after all deb packages have been installed. Normally not needed, all customisation happens inDockerfile
, but might be used for exotic setups which need to be cached inrootfs.tar
instead of Docker layers.
All hooks are executed with the first argument being the path to temporary
chroot directory, so if you need to run something inside chroot, you should
prefix your command with chroot "$1"
, like chroot "$1" gramine-manifest
...
. If you don’t want to do that (for example, to copy files from outside),
you obviously shouldn’t (cp /path/to/source "$1"/path/inside/chroot
). Please
use absolute paths.
Expected filesystem layout
path |
contents |
---|---|
|
Base system (Debian 12) with gramine installed from packages. |
|
Full contents of the app repository. Also
Docker’s |
|
Gramine Manifest files
( |
|
Templates rendered and files copied to
|
Builders
To create a new framework, inherit from Builder class, then override:
framework (str)
extra_files (dict of str: iterable, str is file path relative to
.scag/
magic directory, and iterable of template names, which are sequentially tried, until one is found)
After defining this class, you should add it to entrypoints in
pyproject.toml
.