Design: trust, for a build of files on this machine#
Note
Decided with the maintainer on 2026-10-18, after the review before 0.2.0 asked where a local
build’s trust comes from. It says what a build of a pipeline’s folder may do before you have said
you trust that pipeline, how you say so, and what a record of it looks like. Built with this page,
2026-10-18: chartbook trust, the record, and the gates.
The problem#
A build of a folder trusted its chartbook.toml completely. Three things followed. chartbook docs ran a dataframe’s SQL query to show its first rows, and DuckDB’s SQL reads any file on the
machine (read_csv('~/.aws/credentials')), so the manifest decided what landed on a page. The
manifest’s logo, favicon, site_dir, a note’s path and a write-up’s docs_path could name
any file on the disk, and the build copied it into the site. And chartbook build and chartbook run ran the pipeline’s build script, which is code. None of this matters for your own work. It
matters the day you clone a stranger’s pipeline to look at it, and publish what the build made.
A build of files from a store already runs as a build of files that are not your own
(chartbook.config.untrusted_source, Design: the versioned catalog): no template from the folder, every
template in Jinja’s sandbox, only pages and pictures from the site folder, no table or query run, no
path outside the folder, no notebook run. This page brings a local folder under the same rule until
you say otherwise.
What you say, and what it allows#
You trust a pipeline (a folder) or a repository (any clone whose origin is it), at one of
two levels:
Level |
|
|
|---|---|---|
none (the default for a folder you did not make) |
As a build of files from a store: no query run (the glimpse says the query was not read, and why), no template or file from outside the folder, Jinja’s sandbox. The site is still built, with a warning that says how to trust the folder; a manifest that names a file outside the folder stops the render, naming the entry, as it stops a version’s build. |
Refused, naming the folder, its ID and the command that trusts it. |
|
As your own: queries run for glimpses and the index, files the manifest names are read wherever they are. |
Refused: trusted to render, not to run. |
|
As your own. |
The build script runs. |
run includes render. A third level later is a new word in the same file; nothing here depends
on there being two.
How you say it#
chartbook trust # this folder, at "run"
chartbook trust --render # this folder, to render only
chartbook trust ../rates # another folder
chartbook trust --repository # this folder's origin repository: every clone of it
chartbook trust --members # in a catalog: the catalog's folder and each member folder here
chartbook trust --members --render # the same, to render only
chartbook trust --list # what is trusted, and how
chartbook trust --forget [PATH] # no longer
chartbook trust --forget --repository # no longer, for this folder's repository
A folder’s trust covers the folders inside it, so chartbook trust ~/GitRepositories/ftsfr trusts
every pipeline under it, and chartbook trust ~ would trust them all; the command says so when the
folder has no chartbook.toml. A repository’s trust covers any folder whose origin remote names it
(chartbook.identity.repository_key), wherever it is cloned.
Three commands record trust without being asked to. A project chartbook init makes is recorded
at run as it is made: you made it. A catalog chartbook catalog init makes has its folder
recorded at run, for the same reason. A folder chartbook catalog add adds is recorded at
render, unless it is trusted already: adding a folder to your own catalog is asking for it to be
rendered there, and run stays yours to say, since chartbook build in a catalog runs every
member’s script. Each says so in one line.
Two things are trusted without a record. Under CI (the environment variable, as the store’s notes
already use it), the checkout is trusted at run: the top of the git repository the working
directory is in, or the working directory itself. A runner builds its own checkout, and a pull
request from a fork runs its code in CI whatever ChartBook does. CHARTBOOK_TRUST=all trusts every
folder at run (the test suite runs so; a container that is nothing but your own code may); it is
the one value the variable takes, and another is said once, and ignored. A build of files from a
store (CHARTBOOK_UNTRUSTED_SOURCE=1) is never trusted, whatever the record says.
A git dependency is built in ChartBook’s own copy of its commit, by its own build script: naming
it in [dependencies] is the trust for that, as installing a package is for its code, and the
pipeline that names it must itself be trusted at run for chartbook build to run at all.
The record#
~/.chartbook/trust.toml, this user’s, beside chartbook.toml, sources.toml and machine-id.
Written by chartbook trust and by chartbook init, whole or not at all; read by every build on
this machine.
# Pipelines you have trusted (chartbook trust): their queries and build scripts run here, and the
# files their manifests name are read wherever they are.
[[pipeline]]
path = "/Users/me/GitRepositories/ftsfr/rates" # resolved; the folders inside it too
level = "run" # "render" or "run"
id = "ftsfr/rates" # for you to read; nothing goes by it
repository = "https://github.com/ftsfr/rates"
since = "2026-10-18T22:14:05Z"
[[repository]]
url = "https://github.com/ftsfr/rates" # any clone whose origin remote is this
level = "run"
since = "2026-10-18T22:14:05Z"
A folder’s level is the highest of every entry that covers it. The file is read as settings are:
one that cannot be read stops the command, naming the file; an entry of another shape (a relative
path among them, which would name another folder from each folder a command is run in) is passed
over with a warning naming the file and the entry (TOML gives no line for a table), and a write
keeps it as it was. A pipeline or repository key that is a table rather than an array is passed
over the same way, and a write refuses to rewrite the file rather than drop it. since is written
as a string, ISO 8601 with Z; one written as a TOML date-time is read. The id and repository
of a [[pipeline]] entry are notes for you; a stranger’s manifest claiming your [project] id
gains nothing, since the entry is matched by path. A [[repository]] entry is matched by the
folder’s origin remote, which you set when you cloned; a folder you did not clone yourself (an
archive unpacked with its .git/ inside) may name any repository in its .git/config, so trust a
repository only for clones you made, and trust such a folder by its path.
Where the gate is#
chartbook.config:trust_of(folder)gives"run","render"or None, from the record,CI,CHARTBOOK_TRUST;record_trust,record_repository_trust,forget_trust,read_trust.untrusted_source()is unchanged: the environment variable, for a build of files from a store.chartbook docs(cli._render_site): a pipeline folder with no trust renders as a store build renders (CHARTBOOK_UNTRUSTED_SOURCE=1is set for the render, before anything is read, and put back after), with a warning that says why and how to trust it. A catalog: the catalog’s own folder and every member folder on this machine must be trusted atrender; one that is not is an error that lists them and sayschartbook trust --members. The member folders are read from the catalog’s manifest alone (manifest.catalog_member_dirs), before any member’s is loaded. Mixing trusted and untrusted members in one build is not built: the untrusted mode is the process’s. A member that is store-only has no folder and is unaffected.chartbook buildandchartbook run(run.run, so that the library is gated as the command is): every folder whose script would run must be trusted atrun, elseRunErrorwith the list and the command. The check is made once the order of the run is known, so agitdependency may be fetched into ChartBook’s own cache before an untrusted pipeline is refused; nothing of either runs.chartbook buildin a catalog applies the render’s gate first, before any member’s script runs.catalog buildasdocs, before--clean, so that a refused build leaves the kept tree.chartbook create-data-glimpsesandchartbook publishread and copy the files the manifest names, so they take the render’s gate and run their work in the same untrusted mode: in a folder with no trust, a path outside the folder is refused as the manifest loads, and no query is run.chartbook checkreads and executes nothing, and is not gated; it says the folder’s level in its last line when the level is notrun(for a catalog, the lowest among its own folder and its member folders here).chartbook initrecords the new project atrunand says so in one line;catalog initrecords the catalog’s folder atrun, andcatalog addeach folder added atrenderunless it is trusted already. When the record cannot be written (no home folder), each says so and goes on.A catalog’s member folder with no
chartbook.tomlis passed over by the gate (the build says the entry names no pipeline, as before), andchartbook trust --membersrecords nothing while there is one, naming it: a folder trusted before anything is there would trust whatever is put there.
Asked at a terminal#
Changed 2026-10-19, at the maintainer’s word: refusing a build until chartbook trust was typed
was annoying, and the first build of a folder now asks, once, when a person is there to answer.
ChartBook has not run the code in this folder before:
~/GitRepositories/rates (acme/rates, github.com/acme/rates)
Its build command runs on this machine:
doit
y it's mine: trust this folder and the folders inside it, and don't ask again
r render its site only, without running its code
n stop
Trust this folder? [y/r/N]:
Who is asked. A person: stdin and stderr are terminals (a closed one is none),
CIis not set, and this is not a build ChartBook is running (CHARTBOOK_BATCHon,CHARTBOOK_RUN_DIR), nor a build of files from a store (CHARTBOOK_UNTRUSTED_SOURCE). Everyone else behaves as this page says above: a script’s behaviour does not depend on the prompt, and CI never hangs on one.When. At the first gate a folder meets:
chartbook buildandchartbook runbefore the build script (cli._ask_before_running),chartbook docs generate,catalog generate,publishandcreate-data-glimpsesat the render’s gate (cli._require_trust_to_render). One command asks once (cli._trust_answers);chartbook build’s render does not ask again.The answers.
yrecords the folder atrun, aschartbook trustthere would; one level, so a person need not learn two. Because a yes then lets a laterchartbook buildrun without asking, a question asked while only rendering shows the build command too, and says the trust covers the folders inside.rrenders without running the build command: a folder not trusted at all as a build of files from a store, one trusted to render as before. It is offered where there is a site to render (not byrun), and is called “render its site only”, not “safe mode”: notebooks and pages still render, and what is held back is code, queries and outside files. Enter,n, end of input and Ctrl-C stop at once; any other answer is asked again. Enter means stop because the default answer should do nothing surprising. The answer is read in short waits, so that Ctrl-C stops even when the system hands the interrupt to another of the process’s threads (polars runs its own).What is shown of a folder is someone else’s text: folded (blank lines, runs of space), with any control or format character written as
<U+…>, ten lines at most, so a manifest cannot pad the build command off the screen or reorder it with a right-to-left mark.A catalog asks once,
[y/N], listing the catalog’s own folder and each member folder the command needs (forchartbook build, a member trusted to render only too), each with its build command; the question says whether their scripts run now.yrecords them all, the catalog’s own folder with no ID, aschartbook trust --membersrecords it.Not asked about: a
gitdependency (naming it is the trust, above), a folder trusted already, and a build of files from a store.
Not doing, and later#
A prompt that chooses the level (
renderorrun) or a parent folder:chartbook trust --render,chartbook trust <parent>and--repositorysay those.No trust by
[project] id, since a manifest can say any ID.Telling a clone you made from a folder that arrived with a
.git/confignaming a repository you trust:originis taken at its word. The record says to trust a repository only for clones you made.Rendering untrusted members of a catalog the store way, beside trusted ones, when the untrusted mode is no longer the process’s.
Trust carried in a shared store’s notes, or by an organization’s settings file. A machine’s trust is its user’s.