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

chartbook docs, catalog build

chartbook build, chartbook run

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.

render

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.

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=1 is 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 at render; one that is not is an error that lists them and says chartbook 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 build and chartbook run (run.run, so that the library is gated as the command is): every folder whose script would run must be trusted at run, else RunError with the list and the command. The check is made once the order of the run is known, so a git dependency may be fetched into ChartBook’s own cache before an untrusted pipeline is refused; nothing of either runs. chartbook build in a catalog applies the render’s gate first, before any member’s script runs. catalog build as docs, before --clean, so that a refused build leaves the kept tree.

  • chartbook create-data-glimpses and chartbook publish read 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 check reads and executes nothing, and is not gated; it says the folder’s level in its last line when the level is not run (for a catalog, the lowest among its own folder and its member folders here).

  • chartbook init records the new project at run and says so in one line; catalog init records the catalog’s folder at run, and catalog add each folder added at render unless 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.toml is passed over by the gate (the build says the entry names no pipeline, as before), and chartbook trust --members records 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), CI is not set, and this is not a build ChartBook is running (CHARTBOOK_BATCH on, 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 build and chartbook run before the build script (cli._ask_before_running), chartbook docs generate, catalog generate, publish and create-data-glimpses at 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. y records the folder at run, as chartbook trust there would; one level, so a person need not learn two. Because a yes then lets a later chartbook build run without asking, a question asked while only rendering shows the build command too, and says the trust covers the folders inside. r renders 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 by run), 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 (for chartbook build, a member trusted to render only too), each with its build command; the question says whether their scripts run now. y records them all, the catalog’s own folder with no ID, as chartbook trust --members records it.

  • Not asked about: a git dependency (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 (render or run) or a parent folder: chartbook trust --render, chartbook trust <parent> and --repository say 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/config naming a repository you trust: origin is 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.