Repository navigation
feat(cache): formalize caching config and add signing fields - #10523
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
7bf7e55 to
2656fea
Compare
There was a problem hiding this comment.
Review completed against the latest diff
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
Pull request overview
Formalizes marimo’s caching configuration by promoting cache settings to a top-level [cache] table, adding a new [signing] table for future cache signature verification, and preserving backward compatibility with legacy experimental.cache configs.
Changes:
- Add top-level
cacheandsigningconfig schemas, includingcache.verificationandsigning.{private_key_path,trusted_signers}. - Update cache store resolution to prefer
[cache].storewhile falling back toexperimental.cache, and accept legacystorevstypekeys for store selection. - Extend config merge and secrets-masking behavior to support trust revocation (
trusted_signersreplace semantics) and prevent signing identity leakage (private_key_pathmasking), with accompanying tests.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/_save/stores/test_store_config.py | Adds regression coverage for legacy store key parsing and top-level cache store resolution precedence. |
| tests/_config/test_secrets_config.py | Verifies signing.private_key_path is masked and placeholder round-trips don’t overwrite real secrets. |
| tests/_config/test_config.py | Ensures signing.trusted_signers uses replace semantics to allow narrowing/revoking trust. |
| marimo/_save/stores/init.py | Switches store lookup to [cache].store with fallback to experimental.cache and supports legacy store key. |
| marimo/_config/secrets.py | Adds signing.private_key_path to the secrets mask list. |
| marimo/_config/config.py | Introduces new CacheConfig/SigningConfig types and updates merge behavior for signing.trusted_signers. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
2656fea to
918b703
Compare
Promotes cache configuration out of `experimental` into a top-level `[cache]`
table, and introduces the `[signing]` table that a later change uses to verify
cache signatures.
[cache]
verification = "on" # off | on | strict
[cache.store]
type = "file"
[signing]
private_key_path = "~/.marimo/key.pem"
[signing.trusted_signers]
"SHA256:kV9x2c...q8" = "CI cache key"
`[cache].verification` and `[signing]` are declared and merged here but nothing
reads them yet; the `SigningPolicy` that consumes them lands next.
BREAKING: `experimental.cache` is gone, not aliased. Move the store to
`[cache].store` and spell its key `type`, which is what `StoreConfig` has always
declared. The old reader looked up `store` instead, so that spelling worked by
accident.
`signing.trusted_signers` is a replace path in `merge_config` rather than a deep
merge. Deep-merging would union the fingerprints from every layer, leaving no way
for a higher-priority layer to narrow or revoke trust.
`signing.private_key_path` joins the secrets mask, so this machine's signing
identity is never serialized to the frontend.
918b703 to
c814b4b
Compare
Bundle ReportChanges will increase total bundle size by 90.71kB (0.35%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: marimo-esmAssets Changed:
|
Coverage Report for ./frontend
File CoverageNo changed files found. |
| ("ai", "bedrock", "aws_secret_access_key"), | ||
| ("runtime", "dotenv"), | ||
| # This machine's signing identity — never serialized to the frontend. | ||
| ("signing", "private_key_path"), |
There was a problem hiding this comment.
should we include cache here as well? in case there is anything sensitive in it?
There was a problem hiding this comment.
Cache itself is not sensitive, but the private key is. That's in the stack, so just getting this in
…ion (#10524) ## 📝 Summary Builds on #10523, which added the config fields. Introduces `SigningPolicy` and refactors the signing logic to use the term "verification" over `mode`. `marimo/_save/signing_policy.py` resolves the config into a frozen policy at context creation (before untrusted code can run). `LazyLoader` reads the frozen policy as its default trust and identity source; (with explicit kwargs still allowed). Recap of `verification` types: | Entry at load | `off` | `on` (default) | `strict` | |---|---|---|---| | trusted fingerprint + valid signature | serve (unchecked) | serve | serve | | foreign / bad signature / unsigned | serve (unchecked) | **miss** (recompute) | **raise** | | on write (private key available) | not signed | signed | signed | `off` is the only posture that serves unverified bytes. `on` is fail-safe, `strict` is fail-closed. ### Stack 1. #10523 — config entrypoints + signing fields 2. **this PR** — `SigningPolicy`, `mode` → `verification` 3. — config sanitization (untrusted layers) 4. — docs
## 📝 Summary
Adds config sanitization.
marimo merges configuration from several layers, and two of them travel
with the code.
Trusting a signing key is a grant of arbitrary code execution, because a
cache restore is
`pickle.loads`. So a layer that could name its own key as trusted, or
turn verification off, could
ship a poisoned cache entry that runs on `git clone`.
```
user config ─┐
environment ─┼─→ merged effective config → SigningPolicy (frozen)
│
pyproject ───┤
PEP 723 ─────┼─→ strip [signing] + [cache].verification
workspace ───┘ .marimo.toml
```
### Stack
1. #10523 — config entrypoints + signing fields
2. #10524 — `SigningPolicy`, `mode` → `verification`
3. **this PR** — config sanitization (untrusted layers)
4. — docs
---------
Signed-off-by: Dylan Madisetti <dylan@madisetti.me>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…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
…ion (marimo-team#10524) ## 📝 Summary Builds on marimo-team#10523, which added the config fields. Introduces `SigningPolicy` and refactors the signing logic to use the term "verification" over `mode`. `marimo/_save/signing_policy.py` resolves the config into a frozen policy at context creation (before untrusted code can run). `LazyLoader` reads the frozen policy as its default trust and identity source; (with explicit kwargs still allowed). Recap of `verification` types: | Entry at load | `off` | `on` (default) | `strict` | |---|---|---|---| | trusted fingerprint + valid signature | serve (unchecked) | serve | serve | | foreign / bad signature / unsigned | serve (unchecked) | **miss** (recompute) | **raise** | | on write (private key available) | not signed | signed | signed | `off` is the only posture that serves unverified bytes. `on` is fail-safe, `strict` is fail-closed. ### Stack 1. marimo-team#10523 — config entrypoints + signing fields 2. **this PR** — `SigningPolicy`, `mode` → `verification` 3. — config sanitization (untrusted layers) 4. — docs
…am#10525) ## 📝 Summary Adds config sanitization. marimo merges configuration from several layers, and two of them travel with the code. Trusting a signing key is a grant of arbitrary code execution, because a cache restore is `pickle.loads`. So a layer that could name its own key as trusted, or turn verification off, could ship a poisoned cache entry that runs on `git clone`. ``` user config ─┐ environment ─┼─→ merged effective config → SigningPolicy (frozen) │ pyproject ───┤ PEP 723 ─────┼─→ strip [signing] + [cache].verification workspace ───┘ .marimo.toml ``` ### Stack 1. marimo-team#10523 — config entrypoints + signing fields 2. marimo-team#10524 — `SigningPolicy`, `mode` → `verification` 3. **this PR** — config sanitization (untrusted layers) 4. — docs --------- Signed-off-by: Dylan Madisetti <dylan@madisetti.me> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
📝 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
experimentalinto a top-level[cache]table, and a[signing]table is added for trust and identity:[cache].verificationand[signing]are declared and merged here, with followup providing implementation.Breaking
experimental.cacheis removed for the explicit cache path.Notes
signing.trusted_signersis a replace path inmerge_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_pathjoins the secrets mask, so this machine's signing identity is never serialized to the frontend.Stack
SigningPolicy,mode->verification