From eaffe6f7f1cf0ad37a6987a17d7ed08526a697a4 Mon Sep 17 00:00:00 2001 From: Lorenzo S <46894435+Suffro@users.noreply.github.com> Date: Sat, 1 Aug 2026 21:09:05 +0200 Subject: [PATCH] Show the demo box driven from an application, and give it a folder shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page taught the CLI path only, while an application uses the consumer libraries — the question the demo exists to answer stops one step short otherwise. Both consumers now appear, driving the same downloaded files through the same key. The steps also unpacked everything into one flat directory, which turns into a pile as soon as a script joins it. The box keeps its own folder and is left exactly as downloaded, the key gets another, and the application file sits above both. That separation is not only tidiness: a key that travels with the artefact proves nothing, and the layout is the first place to show it. --- docs/guides/demo-box.md | 129 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 13 deletions(-) diff --git a/docs/guides/demo-box.md b/docs/guides/demo-box.md index 048d3b0..c62f4b7 100644 --- a/docs/guides/demo-box.md +++ b/docs/guides/demo-box.md @@ -32,26 +32,34 @@ The demo box is the .zip you find inside it, next to the .rel Once you have downloaded the demo, follow these steps: -1. **Install scrollcase and unzip the demo:** +1. **Install scrollcase and unpack the demo into a folder of its own:** ```sh npm install -g scrollcase # this will install it globally -unzip hello-box-1.0.0-.zip -d hello-box -cd hello-box +mkdir scrollcase-demo && cd scrollcase-demo +unzip ../hello-box-1.0.0-.zip -d box ``` -> **hello-box** contains 2 files: the **demo box** `.zip` to run, and its matching `.release.json`.
+> **box/** now holds 2 files: the **demo box** `.zip` to run, and its matching `.release.json`.
--- -2. **Download the demo public key into the same folder:** +2. **Download the demo public key, next to the box rather than inside it:** ```sh -curl -O https://raw.githubusercontent.com/suffro/scrollcase/main/examples/keys/example-signing-public.json +mkdir keys +curl -o keys/example-signing-public.json \ + https://raw.githubusercontent.com/suffro/scrollcase/main/examples/keys/example-signing-public.json ``` or alternatively here's its GitHub link: [`example-signing-public.json`](https://github.com/suffro/scrollcase/blob/main/examples/keys/example-signing-public.json) +::: tip Why the key lives outside the box +A signature only proves where something came from if the key does not travel with it. Keeping the +key in its own folder — and downloading it from the repository rather than the release — is the +habit to carry into a real project, where the key will not be a demo key. +::: + --- 3. **Verify and run the box:** @@ -60,25 +68,26 @@ or alternatively here's its GitHub link: [`example-signing-public.json`](https:/ ```sh -scrollcase verify *.release.json --public-key example-signing-public.json -scrollcase run *.release.json --public-key example-signing-public.json +scrollcase verify box/*.release.json --public-key keys/example-signing-public.json +scrollcase run box/*.release.json --public-key keys/example-signing-public.json ``` ```powershell -scrollcase verify (Get-ChildItem *.release.json).Name --public-key example-signing-public.json -scrollcase run (Get-ChildItem *.release.json).Name --public-key example-signing-public.json +scrollcase verify (Get-ChildItem box\*.release.json).FullName --public-key keys\example-signing-public.json +scrollcase run (Get-ChildItem box\*.release.json).FullName --public-key keys\example-signing-public.json ``` -> The `*.release.json` above is a real shell glob, not a placeholder — your shell replaces it -> with the one release document in the folder. PowerShell does not expand globs for a command like +> The `box/*.release.json` above is a real shell glob, not a placeholder — your shell replaces +> it with the one release document in the folder. PowerShell does not expand globs for a command like > this, which is why it needs `Get-ChildItem`. Either way you can always type the file name you see -> after unzipping. +> after unzipping. You never name the box archive: `verify` finds it beside the release document, +> under the hash that document commits to. @@ -86,6 +95,100 @@ scrollcase run (Get-ChildItem *.release.json).Name --public-key example-signing- 4. **Check out the results, that's it.** +At this point the folder looks like this — the box untouched in its own directory, the key beside +it, nothing loose: + +```text +scrollcase-demo/ +├── box/ +│ ├── .zip # the demo box, left exactly as downloaded +│ └── .release.json +└── keys/ + └── example-signing-public.json +``` + +## Run it from your own app + +The CLI is the quickest way to see a box work, but an application does not shell out to it: both +consumers expose the same verify-then-run semantics as a library, and they take the very files you +just downloaded. Same folder, same key, nothing rebuilt. + + + + +```sh +npm install scrollcase +npm install --save-dev tsx typescript +``` + +```ts +// run-box.ts +import { readdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { runBox } from 'scrollcase/consumer'; + +const release = readdirSync('box').find((name) => name.endsWith('.release.json'))!; + +runBox(join('box', release), { + publicPath: 'keys/example-signing-public.json', + stdout: 'inherit', + stderr: 'inherit', + onPrepared: ({ boxId, version, targetId }) => { + console.log(`Running ${boxId} ${version} (${targetId})`); + }, +}).then((result) => { + process.exitCode = result.exitCode ?? 1; +}); +``` + +```sh +npx tsx run-box.ts +``` + + + + +```sh +python -m pip install scrollcase-consumer +``` + +```python +# run_box.py +from pathlib import Path + +from scrollcase_consumer import PreparedBox, run_box + +release = next(Path("box").glob("*.release.json")) + + +def report(prepared: PreparedBox) -> None: + print(f"Running {prepared.box_id} {prepared.version} ({prepared.target_id})", flush=True) + + +result = run_box( + release, + public_key_path="keys/example-signing-public.json", + on_prepared=report, +) +raise SystemExit(result.exit_code or 0) +``` + +```sh +python run_box.py +``` + + + + +Drop either file at the top of `scrollcase-demo/` and run it from there. `runBox` verifies the +signature, extracts to a private temporary directory, executes, and cleans up after itself — the +same chain `scrollcase run` performs, minus the terminal. `onPrepared` fires after verification and +before execution, which is how an application shows what it is about to run without repeating the +trust chain itself. + +The Python package is published separately: `npm install scrollcase` does not install it, and +`pip install scrollcase-consumer` needs no Node at all. Full surface in the +[Library APIs reference](/reference/api). ## What just happened