Repository navigation
docs(cache): document the cache signing trust model - #10526
dmadisetti wants to merge 3 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
No issues found across 2 files
Architecture diagram
sequenceDiagram
participant User as User Config
participant Env as Environment
participant Proj as Project Config
participant NB as Notebook Metadata
participant Marimo as marimo Runtime
participant Cache as Cache Store
participant Crypto as Signing/Verification
Note over User,Crypto: Cache Signing Trust Model Architecture
Note over User,Env: Trusted Configuration Sources
User->>Marimo: signing.private_key_path
User->>Marimo: signing.trusted_signers
User->>Marimo: cache.verification (off|on|strict)
Env->>Marimo: cache.verification override
Note over Proj,NB: Untrusted Configuration Sources
Proj->>Marimo: cache.store (allowed)
Proj--xMarimo: signing (ignored)
Proj--xMarimo: cache.verification (ignored)
NB--xMarimo: signing (ignored)
NB--xMarimo: cache.verification (ignored)
Note over Marimo: Cache Read Flow
Marimo->>Cache: Request cached entry
Cache-->>Marimo: Return serialized data
alt verification = "on" (default)
Marimo->>Crypto: Verify signature with trusted key
Crypto->>Crypto: Check fingerprint whitelist
alt Trusted & valid signature
Crypto-->>Marimo: Signature valid
Marimo->>Marimo: Deserialize with pickle.loads
else Foreign key or invalid
Crypto-->>Marimo: Verification failed
Marimo->>Marimo: Treat as cache miss (recompute)
end
else verification = "strict"
Marimo->>Crypto: Verify signature with trusted key
Crypto->>Crypto: Check fingerprint whitelist
alt Trusted & valid signature
Crypto-->>Marimo: Signature valid
Marimo->>Marimo: Deserialize with pickle.loads
else Foreign key or invalid
Crypto-->>Marimo: Verification failed
Marimo->>Marimo: Raise exception (fail closed)
end
else verification = "off"
Marimo->>Marimo: Deserialize without verification
Note over Marimo: Unverified pickle.loads - code execution risk
end
Note over Marimo: Cache Write Flow
alt verification = "off"
Marimo->>Cache: Write unsigned entry
else verification = "on" or "strict"
Marimo->>Crypto: Sign entry with local Ed25519 key
Crypto-->>Marimo: Signature attached
Marimo->>Cache: Write signed entry
end
Note over Crypto: Missing cryptography package
alt cryptography not installed
Note over Marimo,Crypto: verification="on": all reads miss, writes skipped
Note over Marimo,Crypto: verification="strict": raises
end
1e50702 to
6d70e13
Compare
295ce43 to
eab9543
Compare
There was a problem hiding this comment.
Pull request overview
Adds documentation describing marimo’s cache-signing trust model, including how signing keys are trusted across machines, how cache verification postures behave, and where security-sensitive settings can (and cannot) be configured.
Changes:
- Add a new “Cache signing and trust” section to the caching API docs, covering trust, sharing workflows, and
verificationpostures. - Update configuration docs to clarify that some security-sensitive settings cannot be overridden by repository-traveling config layers (e.g.,
pyproject.toml, script metadata, project.marimo.toml).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| docs/guides/configuration/index.md | Clarifies override limits and warns that repository-traveling layers can’t set signing / cache.verification. |
| docs/api/caching.md | Documents cache signing, key trust, verification modes, and where trust configuration is honored. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
6d70e13 to
1705282
Compare
eab9543 to
091e2bb
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
docs/api/caching.md:334
- The verification table implies entries are always signed on write for
verification="on"/"strict", but LazyLoader skips writes when no private signing key is available (e.g. a public-key-only verifier). This row should be qualified to avoid suggesting unsigned entries will be written under verifying modes.
| Foreign key, bad signature, or unsigned | served **unchecked** | **miss** — recomputed | **raises** |
| On write | not signed | signed | signed |
docs/api/caching.md:354
- This section says
[signing]and[cache].verificationare read from user config files only, but earlier in the same doc you describeMARIMO_CACHE_SIGNING_PRIVATE_KEY/MARIMO_CACHE_SIGNING_PUBLIC_KEYas additional (trusted, operator-controlled) ways to configure signing identity/trust. Consider clarifying that the restriction is about repository-controlled config layers, and that environment variables are still honored.
`[signing]` and `[cache].verification` are read from your own user configuration
only — the file at `~/.config/marimo/marimo.toml` or `~/.marimo.toml`. marimo
ignores them in `pyproject.toml`, in notebook script metadata, and in a
`.marimo.toml` that sits inside a project directory.
1705282 to
23c4901
Compare
091e2bb to
bf80d22
Compare
23c4901 to
1b50609
Compare
bf80d22 to
a3982d4
Compare
1b50609 to
07ef828
Compare
a3982d4 to
a732d38
Compare
07ef828 to
88d3503
Compare
a732d38 to
84abef3
Compare
32d2111 to
45b1cf7
Compare
3963cc2 to
63cc6a4
Compare
45b1cf7 to
02e01cc
Compare
63cc6a4 to
d574a97
Compare
02e01cc to
1dcbe8d
Compare
d574a97 to
c841dac
Compare
1dcbe8d to
78088ea
Compare
78088ea to
8be95ab
Compare
| whatever code the entry tells it to. Reading a cache someone else wrote therefore | ||
| means running code they chose. | ||
|
|
||
| The lazy loader defends against that. It signs each entry it writes with an |
There was a problem hiding this comment.
Has lazy loader been introduced before in the documentation? You should define it when it is first mentioned. When I read this paragraph, I think "What lazy loader? What is a lazy loader?"
| Two environment variables set the same thing without a config file: | ||
| `MARIMO_CACHE_SIGNING_PRIVATE_KEY` holds a signing identity, and | ||
| `MARIMO_CACHE_SIGNING_PUBLIC_KEY` adds one trusted key. Both take the key itself | ||
| in Privacy-Enhanced Mail (PEM) form, not a path. |
There was a problem hiding this comment.
This is difficult for a user to understand. Instead of saying "Two environment variables set the same thing without …" you should frame this as instructive for a user, based on what they are trying to do.
For example, something like: "You can also using environment variables. Store XXX in the XXX environment variable, and XXX in the XXX environment variable. The environment variables expect keys in XXX form."
| Restoring a cache entry deserializes it with `pickle`, so trusting a | ||
| fingerprint lets whoever holds that key run arbitrary code on your machine. |
There was a problem hiding this comment.
"Restoring a cache entry can involve arbitrary code execution. For this reason, only add a fingerprint if you would run any script that person handed you"
…team#10523) ## 📝 Summary Formalizes the caching config entrypoints, and adds "signing" fields for cache verification. This PR introduces the bones for signature verification that will come in a subsequent change. Cache configuration moves out of `experimental` into a top-level `[cache]` table, and a `[signing]` table is added for trust and identity: ```toml [cache] verification = "on" # off | on | strict [cache.store] type = "file" args = { save_path = "~/.cache/marimo" } # Or a tiered store: # [[cache.store]] # type = "file" # [[cache.store]] # type = "redis" [signing] private_key_path = "~/.marimo/key.pem" [signing.trusted_signers] "SHA256:kV9x2c...q8" = "CI cache key" "SHA256:abc9f1...4d" = "Alice" ``` `[cache].verification` and `[signing]` are declared and merged here, with followup providing implementation. ### Breaking `experimental.cache` is removed for the explicit cache path. ### Notes - `signing.trusted_signers` is a **replace** path in `merge_config`, not a deep merge. Deep-merging unions the fingerprints from every layer, and then no layer can remove a signer that a lower-priority one anchored. - `signing.private_key_path` joins the secrets mask, so this machine's signing identity is never serialized to the frontend. ### Stack 1. **this PR** — config entrypoints + signing fields 2. marimo-team#10524 — `SigningPolicy`, `mode` -> `verification` 3. marimo-team#10525 — config sanitization 4. marimo-team#10526 — docs
8be95ab to
724244f
Compare
Covers the config surface, the verification settings, and the framing that matters: trusting a fingerprint grants arbitrary code execution to whoever holds that key, because a cache restore is `pickle.loads`. There is no narrower cache-only version of the grant, so the docs say so plainly rather than leaving users to infer it. The section states its scope up front. Signing applies to `method="lazy"`; the default `method="pickle"` neither signs nor verifies, so a cache it wrote carries no provenance. Also documents which layers may set these settings and why the repository-controlled ones cannot, and corrects the `pythonpath` and `dotenv` sections: both are now read only from user configuration, and the `.env` beside a `pyproject.toml` is no longer loaded implicitly.
724244f to
9746916
Compare
📝 Summary
Docs for the cache signing trust model.
Adds a "Cache signing and trust" section to
docs/api/caching.mdcovering the config surface, theverification postures, and the sharing-between-machines workflow.
Stack
SigningPolicy,mode→verification