From 727e8b17dbdb80437c034569ee8fa6d135ddcb86 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:03:57 -0700 Subject: [PATCH 1/5] docs: make issue-led GitHub publishing the default app flow --- AGENTS.md | 41 +++--- README.md | 85 ++++++------ README.zh-CN.md | 42 +++--- docs/CODE-WALKTHROUGH.md | 49 +++++-- docs/GLOSSARY.md | 11 +- docs/HOST-API-V1.md | 14 +- docs/HOST-API-V1.zh-CN.md | 4 +- docs/PUBLISHING.md | 191 ++++++++++++++++----------- docs/PUBLISHING.zh-CN.md | 104 +++++++++++---- docs/QUICKSTART.md | 43 ++++-- docs/QUICKSTART.zh-CN.md | 34 +++-- flows/README.md | 24 ++-- flows/README.zh-CN.md | 10 +- flows/script-app/FLOW.md | 16 ++- templates/script-app/AGENTS.md | 24 +++- templates/script-app/README.md | 19 +++ templates/script-app/README.zh-CN.md | 15 +++ 17 files changed, 477 insertions(+), 249 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b19e1c74..793dad0e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,11 +42,12 @@ needs no AI service or API key. ends with [docs/PUBLISHING.md](docs/PUBLISHING.md) (final bundle, screenshots, human checkpoints), then App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) - (signing, tag and issue, done by a person). + (the submission issue, release provenance and Hub review). Opening the + issue is the request to publish; a tag/release is not automatic submission. 3. Follow the flow's steps **in order and exactly**. Each step has a pass condition; do not start the next step until it holds. 4. **Stop at every human checkpoint** (steps marked **HUMAN**, or rows whose - "Human?" column says yes): publisher keys and signing, publisher identity + "Human?" column says yes): GitHub release workflow, publisher identity and privacy text, platform claims, paid image generation, visual approval, the release tag, submission. Report and wait. Never fabricate an approval, a review result, a submission or a person's answer. @@ -132,8 +133,9 @@ needs no AI service or API key. `tools/octo shot`, then open each PNG and look at it. Never draw, generate, redraw from `/snap`, crop from another app, or copy a screenshot to make the gate pass. -- **Restamp after every edit.** `tools/octo check` and `tools/octo run` stamp - for you. +- **Restamp editable source after every edit.** `tools/octo check` and + `tools/octo run` stamp unsigned source for you. Never restamp or strip the + proof from a sealed GitHub-attested or legacy signed release. - **Keep the bundle clean.** Only `manifest.json`, `listing.json`, the entry file (`main.splash`, or `page.card` with `kit/`), artwork and screenshots go in `bundle/`. An app with its own agent adds `tools.json`, `AGENT.md`, @@ -198,18 +200,25 @@ The gate checks some of these; reviewers and the shells hold you to the rest. Confirm it with `git check-attr text -- /manifest.json`, which prints a line ending in `text: unset` ([QUICKSTART §3](docs/QUICKSTART.md#3-create-an-app)). -- **Sign last, and never edit after signing.** Capture screenshots and run - `card-host` on the unsigned bundle; `card-host` refuses a signed one. Only - a person signs. Any edit after signing needs a new stamp and a new - signature. -- **Never move a tag.** Tag the commit that holds the final signed bundle, - `v` plus the manifest's `version` (`v0.1.0`). To change anything after - that, release a new version under a new tag. -- **Run the final check from a fresh clone.** `tools/octo check` restamps an - unsigned bundle, so it passes a working copy whose committed digest is - stale. Clone the tag into a new directory and run `hub check` there without - restamping, as a reviewer does - ([SUBMITTING §6](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#6-freeze-and-verify-the-release)). +- **Use GitHub publishing for a new app.** `tools/octo publish-github ` + installs the tag workflow; `new` also copies it. No developer signing key + or signing secret is required. Review the workflow and test unsigned source + before release. Manual Ed25519 signing is optional compatibility only. +- **Never move a tag.** Commit tested editable source and the workflow, then + use `v` plus the manifest's version (`v0.1.0`). The workflow prepares, + attests, verifies and packs the release; do not commit its sealed output + back over the editable source. Every later release needs a new version/tag. +- **Verify the release artifact separately.** A source gate pass is not + publisher-proof verification. The workflow must pass `publisher-verify` + and `publisher-pack`; no restamping after attestation. `card-host` refuses + sealed releases. Contract 1.8.0 / `publisher-github-v1` support and a + compatible host are required; live publishing and installation remain + unverified until separately exercised. See [PUBLISHING §3.6](docs/PUBLISHING.md#36-publisher-key--human). +- **An issue requests publication.** Include repository, version/commit, + screenshots and permissions; it may precede the release. Attach the + successful workflow and exact release pack when ready. The Hub checks it, + an administrator approves, and the authenticated catalog publishes it. + Never claim that pushing a tag automatically submits or approves an app. - **No `script` in a Glance tool.** An agent tool that publishes Glance cards accepts `template` with `initial`, or L0 `source` with `data`, and never `script`. OctoSense runs a script card under the app's own policy. diff --git a/README.md b/README.md index a322be0a..353a82ae 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ The development harness for [OctoSense](https://github.com/OctoSense-org) apps. It takes you, or a coding agent, from an idea (a text brief, a generated UX image) to a contained app bundle that passes the [OctoSense App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub) gate -and is ready for a person to sign and submit. +and is ready for a GitHub-attested release and App Hub review, without a +separate developer signing key. It holds the rules for agents ([AGENTS.md](AGENTS.md)), step-by-step design flows ([flows/](flows/README.md)), the developer docs ([docs/](docs/)), a @@ -57,7 +58,7 @@ organizers. What a contestant needs from here: | **AI in the app** | Building an app needs no AI service, and `card-host` serves none, so make the app complete without one. See [AI in your app](#ai-in-your-app). | | **Reference apps** | The three published [connected apps](#connected-apps-github-gmail-and-google-calendar). | | **Demo** | The app in `card-host` (`tools/octo run`, driven over the remote bridge) and real screenshots from `tools/octo shot`. To show it inside OctoSense, with its host services, run the OctoSense desktop shell against a local catalog ([PUBLISHING §4](docs/PUBLISHING.md#4-rehearse-the-store-path-locally)). | -| **Submit to the App Hub** | Prepare the bundle with [docs/PUBLISHING.md](docs/PUBLISHING.md); then a person signs, tags and opens the issue as App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) describes. A contest entry is not automatically an App Hub submission; the hackathon page says what the event needs. | +| **Submit to the App Hub** | Prepare the bundle with [docs/PUBLISHING.md](docs/PUBLISHING.md); then open the submission issue to request publication and attach a GitHub-attested release, as App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) describes. A contest entry is not automatically an App Hub submission; the hackathon page says what the event needs. | | **Test headless** | `tools/octo run … --hidden`: the window never appears, so an agent can test your app (and several apps at once, one `--port` each) without taking over your screen. See [Headless testing](#headless-testing-many-apps-no-screen). | | **Check what your agent built** | [docs/MODEL-VALIDATION.md](docs/MODEL-VALIDATION.md): drive and capture the app natively, repair failures, and tie the evidence to the final source. | | **Agentic app references** | [Email Action and Meeting Planner](examples/agentic-hackathon/README.md): fake email/calendar data, real app-agent entry points, a labeled offline fallback, review-before-action and native interaction tests. | @@ -121,10 +122,11 @@ Read these in order: `tools/octo`; use only documented APIs (or ones you can cite from the runtime source or a system app). 4. [docs/PUBLISHING.md](docs/PUBLISHING.md): finalize the bundle, capture - screenshots and pass the gate. A person then signs and submits it with + screenshots and pass the gate. Request publication with an issue and attach + the verified GitHub release, following App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md). -The human checkpoints (publisher keys and signing, publisher identity and +The human checkpoints (release workflow, publisher identity and privacy text, platform claims, paid image generation, visual approval, the release tag, submission) are listed in [AGENTS.md](AGENTS.md#how-to-work); [flows/README.md](flows/README.md#every-flow-follows-the-same-contract) @@ -158,6 +160,7 @@ Use `main` of each repository. | The gate (`hub`) | App Hub `main`, app contract 1.7 (the manifest rules `hub` enforces), which admits the connected-account capabilities `auth`, `github`, `gmail` and `gcalendar`, the [Host API v1](docs/HOST-API-V1.md) declarations and the `wasm` capability. | | `card-host` | App Hub `main`. It runs one bundle and serves no host services except `runtime` discovery. Build it as the [Quick path](#quick-path) shows. | | The shells | OctoSense `main`; its latest desktop release is `desktop-v0.1.0-beta.2`. The desktop shell and the phone's Home run system and store apps; the desktop also serves connected accounts and app agents' host-service tools. | +| GitHub publishing | Working-branch implementation: contract 1.8.0 / `publisher-github-v1`, no developer key. Live attestation and compatible-host installation remain unverified; compatible release pending. | | Submission | An issue on OctoSense-App-Hub, as App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) describes. | | Installing your own bundle on a phone | Not supported. See [Running an app](#running-an-app). | @@ -257,11 +260,12 @@ Run `tools/octo -h` for flags. | Command | Does | | --- | --- | +| `publish-github [--replace]` | Install the reviewed `.github/workflows/publish-app.yml`; no push, release or submission. `new` also copies it. A new matching version tag triggers GitHub attestation and release assets; no developer signing secret. | | `doctor` | Checks Python, looks for the App Hub checkout and cargo, finds `hub` and `card-host` (rejecting GitHub's unrelated `hub` CLI), checks the template, and prints how to fix what is missing. | | `new --platform PLATFORM [--id ID] [--name NAME] [--system]` | Copies `templates/script-app` (`bundle/`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.gitignore`), sets id, name and version `0.1.0`, writes the `--platform` values into the listing, and stamps the bundle. `--platform` is required; repeat it for each platform you will test on. Ids are `[a-z0-9.-]{1,64}`; `os.*` needs `--system`. It refuses a reserved id, or one whose last segment is reserved, before it creates any file ([What an app is](#what-an-app-is)). | | `run [--port N] [--hidden] [--detach] [--system] [--no-stamp] [--app-data DIR] [--static PREFIX=DIR]` | Runs `card-host --bundle … --app-data … --allow-unsigned --stamp` with `MAKEPAD_REMOTE=` (default 8141). Refuses a port that is already taken. `--detach` returns once the app is admitted, its bridge listens and the first frame is drawn. The app's jail (its private data directory) is `/.local-state//`. | | `shot [--settle S]` | Saves a PNG of the running window (`GET /g?raw=1`) once the app's widgets exist and two frames in a row match (at most `--settle`, 2 s by default). | -| `check [hub check flags]` | `hub stamp`, then `hub check --allow-unsigned`; exits nonzero on a refusal. Passes other flags, such as `--catalog` or `--publisher-key`, to `hub check`. Does not restamp a signed manifest. A failed stamp returns its status at once and skips the gate. | +| `check [hub check flags]` | `hub stamp`, then `hub check --allow-unsigned`; exits nonzero on a refusal. Passes other flags, such as `--catalog` or `--publisher-key`, to `hub check`. Does not restamp a manifest with a legacy signature or `integrity.github`. A failed stamp returns its status at once and skips the gate. | | `package-help` | Prints the publish checklist. | `doctor` prints every place it looks for `hub` and `card-host`; @@ -315,7 +319,8 @@ my-app/ the app's own Git repository | `capabilities` | The permissions the app asks for. | | `network.hosts` | Bare host names; needs `net`. | | `storage`, `compute`, `agent` | Optional requests, clamped to the host's ceilings; `hub check` prints the result as its `grants:` line. `storage.accounts: true` gives each account its own data folder and agent, instead of one shared `device` folder; `storage.agent_workspace` sets what the agent may read: its account's folder (the default) or nothing. | -| `integrity.bundle_blake3` | Written by `hub stamp`; `hub sign-manifest` adds the signature. | +| `integrity.github` | The repository/owner/workflow/tag/commit identity and GitHub attestation, added by the new publisher workflow (`publisher-github-v1`, compatible host pending). | +| `integrity.bundle_blake3` | Written by `hub stamp` during development; the GitHub workflow prepares the final digest and attestation. Legacy Ed25519 signing remains optional. | For every field, see App Hub's [The manifest](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.md#the-manifest). @@ -449,18 +454,18 @@ Widgets built by `on_render` are listed in `/snap` and `/d` like any other; content an app adds later, from a timer or a reply, appears once it is drawn, so poll `/snap?q=` for it. `card-host` registers **no** host services, so a Mail-style app gets `no service answers "mail" on this device` -there. `card-host` also refuses signed manifests: take screenshots before -signing. +there. `card-host` also refuses sealed attested/signed releases: test and +capture editable source before release. **In the shells.** The OctoSense desktop shell and the phone's Home run apps with App Hub's Card runner (the `card` module in App Hub's `crates/appstore`), not with `card-host`; the Card runner applies the same manifest policy. System apps are packed into the shell build from OctoSense's `apps/`; store apps are installed from the App Hub store out of -the signed catalog. To try your own app in the desktop shell before it is -published, publish it into a local catalog with a throwaway trust anchor (a -test root key) and point the desktop shell's `OCTOSENSE_HUB` / -`OCTOSENSE_HUB_ANCHOR` at it; the shell's store installs and opens the app +the authenticated catalog. For an optional legacy rehearsal before submission, +publish a test bundle into a local catalog with a throwaway trust anchor, +then point `OCTOSENSE_HUB` / `OCTOSENSE_HUB_ANCHOR` at that mirror. The +shell's store installs and opens the test app ([PUBLISHING §4](docs/PUBLISHING.md#4-rehearse-the-store-path-locally)). **On a phone, today** ([QUICKSTART §9](docs/QUICKSTART.md#9-run-it-on-an-octosense-phone)): @@ -473,9 +478,9 @@ test root key) and point the desktop shell's `OCTOSENSE_HUB` / - The closest verified path is the desktop rehearsal above. - `card-host`'s remote bridge is compiled out on Android, so phone testing does not use `tools/octo`. -- After publication, the app appears in every phone's store from the signed - catalog, unless it declares `auth`: no released phone build accepts that - capability. +- After Hub admission, only a compatible host can install the app. Released + phone builds lack both `auth` and `publisher-github-v1`; catalog visibility + does not establish runtime compatibility. ## Headless testing: many apps, no screen @@ -514,31 +519,29 @@ an earlier App Hub and Makepad. ## Publishing -Publishing has two halves, owned by two repositories: - -1. **Here.** [docs/PUBLISHING.md](docs/PUBLISHING.md) takes a working app to - a bundle that is ready to sign: the final manifest and listing (no - placeholders; the publisher fields are the publisher's to write), real - screenshots from `tools/octo shot`, `tools/octo check` passing with only - the unsigned warning, and the `hub scan` questions answered in writing. - There are seven questions, or eight when the bundle ships `tools.json`, - `AGENT.md` or skills. `tools/octo package-help` prints the checklist. -2. **App Hub.** [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) - is the step-by-step submission a person follows: sign last, commit and - tag, run `hub check` on a fresh clone of the tag without restamping, and - open a `Submit ` issue. - [PUBLISHING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.md) - is the reference for every gate rule and field. - -A maintainer re-runs the gate and the scan on the exact bytes of your tag -and runs `hub publish`, which copies the bundle into App Hub and signs a new -catalog. - -- Never open a pull request that edits App Hub's `catalog.json`, `index/` or - `artifacts/`: only `hub publish` with App Hub's catalog key writes them. -- Never move a release tag. To change a published app, release a new version. -- The gate does not judge screenshots, listing text or the privacy policy; a - reviewer does. +**Open a submission issue to ask the App Hub to publish your app.** Include +its repository, version/commit, screenshots and requested permissions. The +issue can precede the release: Hub checks report missing items or refusals, +and an administrator approves the exact candidate before catalog publication. + +[docs/PUBLISHING.md](docs/PUBLISHING.md) covers the local gate, screenshots and +review answers. `tools/octo publish-github ` installs the +publishing workflow (`new` also copies it). After review, commit tested source +and push a new `v` tag. GitHub Actions prepares, attests, +verifies and packs the release using its native identity; developers do not +create `publisher.key` or store a signing secret. + +Attach the successful workflow and exact release pack to the submission issue. +A GitHub release supplies verifiable bytes; it is not a new App Hub submission +channel or automatic approval. See App Hub's +[SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md). +Routine updates use new versions/tags from the same repository/owner/workflow. +Never move a released tag or hand-edit the Hub's admitted catalog/artifacts. + +This working-branch path requires contract 1.8.0 / `publisher-github-v1`. +Live publisher attestation and compatible-host installation remain unverified; +a compatible host release is pending. Manual Ed25519 signing is optional +compatibility, and old reference releases remain unchanged. ## Repository layout @@ -552,7 +555,7 @@ catalog. | [docs/HOST-SERVICES.md](docs/HOST-SERVICES.md) | `host.request`, sheets, "secrets are the host's", adding a service | | [docs/AI-SERVICES.md](docs/AI-SERVICES.md) ([简体中文](docs/AI-SERVICES.zh-CN.md)) | OctoSense's assistant (octos): what an app can use today, app agents and their tools, Glance cards and in-card chat (`sys.chat`) | | [docs/MODEL-VALIDATION.md](docs/MODEL-VALIDATION.md) ([简体中文](docs/MODEL-VALIDATION.zh-CN.md)) | Checking what a coding agent built: native input and capture, review loops, repair | -| [docs/PUBLISHING.md](docs/PUBLISHING.md) | From a working app to a bundle ready to sign: final manifest and listing, screenshots, the gate, the local store rehearsal and the human checkpoints | +| [docs/PUBLISHING.md](docs/PUBLISHING.md) | From a working app to a publication issue and GitHub-attested release: final listing, screenshots, gate/review, workflow and Hub approval | | [docs/CODE-WALKTHROUGH.md](docs/CODE-WALKTHROUGH.md) | How `tools/octo`, App Hub and the OctoSense shell connect, traced through one request | | [docs/GLOSSARY.md](docs/GLOSSARY.md) | One meaning per term | | [docs/NATIVE-WORKSPACE.md](docs/NATIVE-WORKSPACE.md), [docs/l0/](docs/l0/) | Sibling-source setup for the native runtime; L0 card examples | diff --git a/README.zh-CN.md b/README.zh-CN.md index e01b4505..80dff55c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@ 未注明中文版的链接指向英文文档。 -[OctoSense](https://github.com/OctoSense-org) 应用的开发工具集。它带着你(或编码 Agent)从一个想法(一段文字需求、一张生成的 UX 图)走到一个隔离运行的应用包:通过 [OctoSense App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub) 的准入检查,只待人工签名并提交。 +[OctoSense](https://github.com/OctoSense-org) 应用的开发工具集。它带着你(或编码 Agent)从一个想法(一段文字需求、一张生成的 UX 图)走到一个隔离运行的应用包:通过 [OctoSense App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub) 的准入检查,准备生成 GitHub 发布证明并接受 App Hub 审核,无需单独的开发者签名密钥。 仓库包含:给 Agent 的规则([AGENTS.md](AGENTS.md))、分步骤的设计流程([flows/](flows/README.zh-CN.md))、开发者文档([docs/](docs/))、可直接运行的应用模板([templates/script-app](templates/script-app/README.zh-CN.md))、完整示例([examples/](examples/README.zh-CN.md)),以及 `tools/octo`:一个小型命令行工具,封装 App Hub 的 `card-host` 和 `hub` 程序。`tools/octo` 从不决定准入:`check` 先为未签名的应用包写入摘要(stamp),再原样转交 `hub check` 的输出和退出码。 @@ -44,7 +44,7 @@ | **应用中的 AI** | 开发应用不需要任何 AI 服务,`card-host` 也不提供 AI 服务,所以应用不依赖 AI 也要完整可用。见[应用中的 AI](#应用中的-ai)。 | | **参考应用** | 三个已发布的[连接账户的应用](#连接账户的应用githubgmail-和-google-calendar)。 | | **演示** | 在 `card-host` 中运行应用(`tools/octo run`,通过远程控制桥操作),并用 `tools/octo shot` 截取真实截图。要在 OctoSense 内连同宿主服务一起展示,让 OctoSense 桌面端 Shell 读取本地签名目录([PUBLISHING §4](docs/PUBLISHING.zh-CN.md#4-在本地演练商店流程))。 | -| **提交到 App Hub** | 先按 [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md) 准备好应用包,再由人工按 App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 签名、打 tag 并开 issue。参赛作品不等于自动提交到 App Hub;比赛需要什么,以黑客松页面为准。 | +| **提交到 App Hub** | 先按 [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md) 准备好应用包,再由人工按 App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 开 issue 表达发布意图,并附上 GitHub 证明的发布包。参赛作品不等于自动提交到 App Hub;比赛需要什么,以黑客松页面为准。 | | **无头测试** | `tools/octo run … --hidden`:窗口不会出现,Agent 测试应用时不会占用你的屏幕(也可同时测多个应用,每个用自己的 `--port`)。见[无头测试](#无头测试同时测多个应用不占屏幕)。 | | **检查 Agent 做出的应用** | [docs/MODEL-VALIDATION.zh-CN.md](docs/MODEL-VALIDATION.zh-CN.md):以原生方式操作应用并截图,修复失败之处,并把证据与最终源码对应起来。 | | **Agent 应用参考** | [Email Action 与 Meeting Planner](examples/agentic-hackathon/README.zh-CN.md):虚构邮件/日历、真实应用 Agent 入口、明确标注的离线路径、操作前确认及原生交互测试。 | @@ -79,9 +79,9 @@ App Hub 签名目录中有三个应用通过宿主使用用户的 GitHub 或 Goo 1. [AGENTS.md](AGENTS.md):规则、完成标准,以及每个必须停下来交给人决定的节点。 2. [flows/README.zh-CN.md](flows/README.zh-CN.md):按起点选择设计流程,然后逐步执行该流程的 `FLOW.md`。 3. [docs/QUICKSTART.zh-CN.md](docs/QUICKSTART.zh-CN.md) 与 [docs/SCRIPT-API.md](docs/SCRIPT-API.md):用 `tools/octo` 构建并运行应用;只使用有文档的 API(或能在运行时源码、某个系统应用中找到出处的 API)。 -4. [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md):定稿应用包、截图、通过准入检查。之后由人工按 App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 签名并提交。 +4. [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md):定稿应用包、截图、通过准入检查。之后由人工按 App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 开提交 issue,并补充经过验证的 GitHub 发布包。 -需要人来把关的节点(发布者密钥与签名、发布者身份与隐私文本、平台声明、付费图像生成、视觉确认、发布 tag、提交)都列在 [AGENTS.md](AGENTS.md#how-to-work) 中;[flows/README.zh-CN.md](flows/README.zh-CN.md#每个流程都遵循同一份约定) 说明所有流程共有的那些节点。Agent 绝不伪造人的确认、评审结果或提交记录。 +需要人来把关的节点(发布工作流、发布者身份与隐私文本、平台声明、付费图像生成、视觉确认、发布 tag、提交)都列在 [AGENTS.md](AGENTS.md#how-to-work) 中;[flows/README.zh-CN.md](flows/README.zh-CN.md#每个流程都遵循同一份约定) 说明所有流程共有的那些节点。Agent 绝不伪造人的确认、评审结果或提交记录。 ### AppCard UX 技能 @@ -98,6 +98,7 @@ App Hub 签名目录中有三个应用通过宿主使用用户的 GitHub 或 Goo | 准入检查(`hub`) | App Hub `main`,应用契约 1.7(即 `hub` 执行的清单规则),准入连接账户所需的 `auth`、`github`、`gmail` 和 `gcalendar` 能力、[Host API v1](docs/HOST-API-V1.zh-CN.md) 的各项声明,以及 `wasm` 能力。 | | `card-host` | App Hub `main`。它运行单个应用包,除了用于发现宿主 API 的 `runtime`,不提供任何宿主服务。构建方法见[快速上手](#快速上手)。 | | Shell | OctoSense `main`;桌面端最新的发布版本是 `desktop-v0.1.0-beta.2`。桌面端 Shell 和手机 Home 运行系统应用与商店应用;桌面端还支持已连接账户,并为应用 Agent 提供宿主服务工具。 | +| GitHub 发布 | 工作分支中的实现:应用契约 1.8.0 / `publisher-github-v1`,无需开发者密钥。真实证明和兼容宿主安装尚未验证,兼容版本尚待发布。 | | 提交途径 | 在 OctoSense-App-Hub 开 issue,见 App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md)。 | | 在手机上安装自己的应用包 | 不支持。见[运行应用](#运行应用)。 | @@ -175,11 +176,12 @@ tools/octo package-help | 命令 | 作用 | | --- | --- | +| `publish-github [--replace]` | 安装经过评审的 `.github/workflows/publish-app.yml`,不推送、不发布、不提交。`new` 也会复制它。新的匹配版本 tag 触发 GitHub 证明和 release 产物,无需开发者签名 secret。 | | `doctor` | 检查 Python,查找 App Hub 仓库和 cargo,查找 `hub` 与 `card-host`(排除 GitHub 那个同名的 `hub` CLI),检查模板,并输出缺失项的修复方法。 | | `new --platform PLATFORM [--id ID] [--name NAME] [--system]` | 复制 `templates/script-app`(`bundle/`、`AGENTS.md`、`CLAUDE.md`、`GEMINI.md`、`.gitignore`),设置 id、名称和版本 `0.1.0`,把 `--platform` 的值写入商店信息,并为应用包写入摘要。`--platform` 必填,每个要测试的平台写一次。id 格式为 `[a-z0-9.-]{1,64}`;`os.*` 需要 `--system`。id 本身是保留名,或最后一段是保留名时,它在创建任何文件之前就会拒绝(见[应用是什么](#应用是什么))。 | | `run [--port N] [--hidden] [--detach] [--system] [--no-stamp] [--app-data DIR] [--static PREFIX=DIR]` | 以 `MAKEPAD_REMOTE=`(默认 8141)运行 `card-host --bundle … --app-data … --allow-unsigned --stamp`。端口已有程序占用时拒绝运行。`--detach` 在应用已准入、远程控制桥开始监听并画出第一帧后返回。应用的 jail(它的私有数据目录)在 `/.local-state//`。 | | `shot [--settle S]` | 等应用的控件出现、且连续两帧相同(最多 `--settle`,默认 2 秒)后,保存运行中窗口的 PNG(`GET /g?raw=1`)。 | -| `check [hub check flags]` | 先 `hub stamp`,再 `hub check --allow-unsigned`;检查不通过时以非零退出码退出。其他参数(如 `--catalog`、`--publisher-key`)原样传给 `hub check`。不会为已签名的清单重新写入摘要。写入摘要失败时,立即返回其退出码,不运行准入检查。 | +| `check [hub check flags]` | 先 `hub stamp`,再 `hub check --allow-unsigned`;检查不通过时以非零退出码退出。其他参数(如 `--catalog`、`--publisher-key`)原样传给 `hub check`。不会为含旧版签名或 `integrity.github` 的清单重新写入摘要。写入摘要失败时,立即返回其退出码,不运行准入检查。 | | `package-help` | 输出发布检查表。 | `doctor` 会列出它查找 `hub` 和 `card-host` 的每个位置;查找顺序(包括 Windows 上的 `.exe` 文件名)见 [QUICKSTART §2](docs/QUICKSTART.zh-CN.md#2-构建-hub-和-card-host)。 @@ -223,7 +225,8 @@ my-app/ 应用自己的 Git 仓库 | `capabilities` | 应用申请的能力。 | | `network.hosts` | 纯主机名;需要 `net`。 | | `storage`、`compute`、`agent` | 可选的申请项,宿主会把它们限制在上限以内;`hub check` 把结果输出为 `grants:` 行。`storage.accounts: true` 为每个账户分别提供数据文件夹和 Agent,而不是共用一个 `device` 文件夹;`storage.agent_workspace` 决定 Agent 能读什么:它所属账户的文件夹(默认)或者什么都不读。 | -| `integrity.bundle_blake3` | 由 `hub stamp` 写入;`hub sign-manifest` 再加上签名。 | +| `integrity.github` | 新发布工作流加入的仓库/所有者/工作流/tag/commit 身份和 GitHub 证明(`publisher-github-v1`,兼容宿主待发布)。 | +| `integrity.bundle_blake3` | 开发时由 `hub stamp` 写入;GitHub 工作流准备最终摘要和证明。旧版 Ed25519 签名仍是可选路径。 | 全部字段见 App Hub 的 [清单](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.zh-CN.md#清单)。 @@ -274,7 +277,7 @@ OctoSense 每个 Shell 运行一个 octos Agent 内核,由用户在系统应 | `/g?raw=1` | 返回窗口的 PNG(即 `tools/octo shot` 保存的内容) | | `/quit`(或 `/gq`:截下所有窗口后退出) | 退出;最后一定要调用 | -`on_render` 生成的控件与其他控件一样出现在 `/snap` 和 `/d` 中;应用稍后才添加的内容(来自定时器或响应)在绘制后才出现,请轮询 `/snap?q=` 等待它。`card-host` **不**注册任何宿主服务,所以类似 Mail 的应用在其中会得到 `no service answers "mail" on this device`。`card-host` 还会拒绝已签名的清单:请在签名之前截图。 +`on_render` 生成的控件与其他控件一样出现在 `/snap` 和 `/d` 中;应用稍后才添加的内容(来自定时器或响应)在绘制后才出现,请轮询 `/snap?q=` 等待它。`card-host` **不**注册任何宿主服务,所以类似 Mail 的应用在其中会得到 `no service answers "mail" on this device`。`card-host` 还会拒绝封存的证明/签名发布包:请在发布前测试可编辑源码并截图。 **在 Shell 中。** OctoSense 桌面端 Shell 和手机 Home 通过 App Hub 的 Card runner(App Hub `crates/appstore` 中的 `card` 模块)运行应用,而不是 `card-host`;Card runner 执行同一套清单策略。系统应用从 OctoSense 的 `apps/` 打包进 Shell 构建;商店应用从 App Hub 商店根据签名目录安装。想在发布前在桌面端 Shell 中试用自己的应用:用一次性信任锚(一把测试用根密钥)把它发布到本地签名目录,再把桌面端 Shell 的 `OCTOSENSE_HUB` / `OCTOSENSE_HUB_ANCHOR` 指向该目录;Shell 的商店即可安装并打开该应用([PUBLISHING §4](docs/PUBLISHING.zh-CN.md#4-在本地演练商店流程))。 @@ -283,7 +286,7 @@ OctoSense 每个 Shell 运行一个 octos Agent 内核,由用户在系统应 - 无法把任意应用包侧载到普通 OctoSense 手机上。手机商店读取 App Hub 内置地址上的签名目录,只信任编译进构建的信任锚;`OCTOSENSE_HUB` / `OCTOSENSE_HUB_ANCHOR` 是环境变量,Android 启动器不会设置。在设备上从本地签名目录安装不受支持,也未验证。 - 最接近的已验证路径是上面的桌面端演练。 - Android 版 `card-host` 不编译远程控制桥,所以手机测试不使用 `tools/octo`。 -- 发布之后,应用会通过签名目录出现在每台手机的商店中;声明了 `auth` 的应用除外,因为目前没有任何已发布的手机版本接受这个能力。 +- Hub 准入后,只有兼容宿主才能安装应用。已发布手机版本缺少 `auth` 和 `publisher-github-v1`;目录可见不代表运行时兼容。 ## 无头测试:同时测多个应用,不占屏幕 @@ -306,16 +309,23 @@ curl -s 127.0.0.1:8161/quit; curl -s 127.0.0.1:8162/quit ## 发布 -发布分两个阶段,分别由两个仓库负责: +**开提交 issue,向 App Hub 表达发布应用的意图。** 提供仓库、版本/commit、截图 +和请求的权限。可以先开 issue 再准备 release:Hub 检查报告缺项或拒绝原因, +管理员批准确切的候选版本后,才发布目录条目。 -1. **本仓库。** [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md) 把能运行的应用变成待签名的应用包:定稿清单和商店信息(没有占位文本;发布者字段由发布者本人填写),用 `tools/octo shot` 截取真实截图,`tools/octo check` 通过且只剩未签名警告,并书面回答 `hub scan` 的问题。问题有七个;应用包附带 `tools.json`、`AGENT.md` 或 skills 时有八个。`tools/octo package-help` 会输出检查表。 -2. **App Hub。** [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 是由人工执行的分步提交流程:所有改动完成后再签名,然后 commit 并打 tag,在 tag 的全新克隆上运行 `hub check`(不重新写入摘要),最后开 `Submit ` issue。[PUBLISHING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.zh-CN.md) 是每条准入规则和每个字段的参考。 +[docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md) 讲解本地准入检查、截图和审核答案。 +`tools/octo publish-github ` 安装发布工作流(`new` 也会复制它)。 +审阅后 commit 已测试源码,再推送新的 `v` tag。GitHub Actions +使用原生身份依次准备、证明、验证和打包,无需开发者创建 `publisher.key` 或保管签名 secret。 -维护者会对你的 tag 中的确切字节重新运行准入检查和扫描,再执行 `hub publish`:把应用包复制进 App Hub 并签署新的签名目录。 +把成功的工作流和确切的 release pack 附到同一提交 issue。GitHub release 提供 +可验证的字节,不是新的 App Hub 提交渠道,也不会自动获批。见 App Hub 的 +[SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md)。 +日常更新使用同一仓库、所有者和工作流下的新版本/新 tag。不要移动已发布 tag, +也不要手改 Hub 已准入的目录和产物。 -- 绝不要开 pull request 修改 App Hub 的 `catalog.json`、`index/` 或 `artifacts/`:只有用 App Hub 签名目录密钥运行的 `hub publish` 才能写入它们。 -- 绝不要移动发布 tag。要修改已发布的应用,请发布新版本。 -- 准入检查不评判截图、商店信息文本或隐私政策;这些由审核人负责。 +此工作分支路径需要契约 1.8.0 / `publisher-github-v1`。真实发布证明和兼容宿主安装 +尚未验证,兼容宿主版本尚待发布。手动 Ed25519 签名仅是可选兼容路径,旧参考版本保持原样。 ## 仓库结构 @@ -329,7 +339,7 @@ curl -s 127.0.0.1:8161/quit; curl -s 127.0.0.1:8162/quit | [docs/HOST-SERVICES.zh-CN.md](docs/HOST-SERVICES.zh-CN.md)([English](docs/HOST-SERVICES.md)) | `host.request`、面板、“密钥归宿主所有”、新增宿主服务 | | [docs/AI-SERVICES.zh-CN.md](docs/AI-SERVICES.zh-CN.md)([English](docs/AI-SERVICES.md)) | OctoSense 的助手(octos):应用目前能用什么、应用 Agent 及其工具、速览卡片和卡片内对话(`sys.chat`) | | [docs/MODEL-VALIDATION.zh-CN.md](docs/MODEL-VALIDATION.zh-CN.md)([English](docs/MODEL-VALIDATION.md)) | 检查编码 Agent 做出的应用:原生输入与截图、评审循环、修复 | -| [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md)([English](docs/PUBLISHING.md)) | 从能运行的应用到待签名的应用包:定稿清单和商店信息、截图、准入检查、本地商店演练和人工把关节点 | +| [docs/PUBLISHING.zh-CN.md](docs/PUBLISHING.zh-CN.md)([English](docs/PUBLISHING.md)) | 从能运行的应用到提交 issue 和 GitHub 发布证明:定稿商店信息、截图、准入/审核、工作流与 Hub 批准 | | [docs/CODE-WALKTHROUGH.md](docs/CODE-WALKTHROUGH.md) | `tools/octo`、App Hub 与 OctoSense Shell 如何衔接,沿一个请求逐层追踪 | | [docs/GLOSSARY.md](docs/GLOSSARY.md) | 每个术语只有一个含义 | | [docs/NATIVE-WORKSPACE.md](docs/NATIVE-WORKSPACE.md)、[docs/l0/](docs/l0/) | 原生运行时所需同级仓库的配置;L0 卡片示例 | diff --git a/docs/CODE-WALKTHROUGH.md b/docs/CODE-WALKTHROUGH.md index 89ac0901..48b06cba 100644 --- a/docs/CODE-WALKTHROUGH.md +++ b/docs/CODE-WALKTHROUGH.md @@ -63,7 +63,7 @@ responsibility. that is, or ends in, a name in `RESERVED_NAMES` (kept in step with App Hub's contract, which stays the authority), and an `os.*` id without `--system`. Its argument parser requires at least one `--platform`. `cmd_new` then -copies the template and contributor instructions, writes the id, name and +copies the template, contributor instructions and publishing workflow, writes the id, name and version into the manifest and the deduplicated platforms into the listing, and stamps when `hub` is available. The platforms are a claim to test, not evidence. Complete the listing, artwork and screenshots before submitting @@ -98,13 +98,37 @@ frame. Open the PNG and look at it. `cmd_check` calls `hub stamp` for unsigned bundles. If stamping fails, it prints that command's output, returns its failure status and skips the gate. Otherwise it runs `hub check`, forwards extra gate flags and returns the -gate's exit status. A signed manifest skips stamping. The command also +gate's exit status. A manifest with a legacy signature or `integrity.github` +skips stamping. The command also prints progress lines and listing-placeholder notes. App Hub owns admission policy; this Python command handles the development sequence. -Because `check` restamps first, a pass does not prove that the digest -committed in your repository is current. Before you submit, run `hub check` -on a fresh clone of the tag. +Because `check` restamps editable source first, a pass does not prove that its +committed digest is current. Check before each source commit. The GitHub release +pack is sealed separately; a source check does not verify that publisher proof. + +### Trace `tools/octo publish-github` + +`cmd_publish_github` requires an editable app directory with `bundle/manifest.json`. +`publisher_workflow` reads `tools/publisher-toolchain.json` and requires an exact +reviewed App Hub commit; no pin means refusal, not a fallback to moving `main`. +`install_publisher_workflow` writes `.github/workflows/publish-app.yml` atomically, +refuses symlink paths and requires `--replace` for different existing content. +`cmd_new` uses the same installer. Neither command pushes or submits anything. + +The template in `tools/publish-app.template.yml` runs on a new `v*` tag in a +public GitHub repository. Its prepare job builds the pinned native `hub` and +runs `publisher-prepare` to check/bind source and emit the canonical manifest +outside `bundle/`. The publishing job uses `actions/attest`, attaches the proof, +then runs `publisher-verify` and `publisher-pack` without restamping. Its release +contains the sealed pack, canonical manifest and release receipt. The developer +supplies no private signing key; GitHub supplies the job/OIDC identity. + +`publisher-github-v1` needs contract 1.8.0 and a compatible Store verifier. +Live proof and installation remain unverified; a compatible release is pending. +Opening an App Hub issue expresses publication intent and can happen first; +the workflow provides verifiable bytes for that issue. Hub checks, administrator +approval and authenticated catalog publication remain separate steps. ## 4. Run a contained script app @@ -163,7 +187,7 @@ tools/octo check ~/apps/walkthrough/bundle ``` `run` stamps the manifest by default. Test with `card-host` on an unsigned -copy; test signing and installation through +copy; the optional legacy signing/install compatibility path is [the store rehearsal](PUBLISHING.md#4-rehearse-the-store-path-locally). The same host accepts an L0 `page.card` bundle with its data and kit. The @@ -210,7 +234,7 @@ service for a single model request. `llm` manages provider configuration for system apps. To test your app in the desktop shell before public submission, follow -[the local signed-catalog rehearsal](PUBLISHING.md#4-rehearse-the-store-path-locally). +[the optional legacy signed-catalog rehearsal](PUBLISHING.md#4-rehearse-the-store-path-locally). The standalone store installs bundles; the full shell launches their app clients. Phone catalog configuration belongs to the Home build; see [the phone limitations](QUICKSTART.md#9-run-it-on-an-octosense-phone). @@ -408,10 +432,13 @@ All app flows converge on the same delivery sequence in 3. Restamp and check the completed bundle; only the unsigned warning may remain. Complete the `hub scan` review packet in [PUBLISHING](PUBLISHING.md). -4. **HUMAN:** the key holder signs using a private key stored outside the - repository, then checks the signature with the publisher's public key. -5. **HUMAN:** approve submission of the exact version and open the App Hub - issue. A maintainer repeats the gate and review before publishing. +4. **HUMAN:** open the App Hub issue to request publication (it may happen + earlier), with repo/version/commit, screenshots and permissions. +5. Install/review the GitHub publishing workflow, commit tested source and + push a new matching version tag with the person's authorization. The + workflow attests and verifies the release without a developer key. Add + that exact pack and workflow result to the issue; Hub checks and + administrator approval still precede catalog publication. The image and kit flows also have human checkpoints for paid generation or licensed assets and semantic/visual approval. Preserve the source inputs diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md index 2b0a09b0..95edfed5 100644 --- a/docs/GLOSSARY.md +++ b/docs/GLOSSARY.md @@ -14,33 +14,34 @@ Each term below has one meaning across these docs. | **Card app** | An app whose bundle holds `page.card` (L0), optional `page.data.json` and a `kit/`. The host lowers the card to widgets; the card holds no program. Produced by the [image-to-card flow](../flows/image-to-card/FLOW.md). | | **Card runner** | The part of an OctoSense shell (App Hub's `appstore` crate, `card` module) that runs one installed or system app: it admits the app, resolves its policy, sets up its jail, evaluates it and pumps its host services. | | **`card-host`** | App Hub's reference contained host for one bundle on the desktop (`crates/card-host`). Run it during development with `card-host --bundle --allow-unsigned`. It applies the same policy code as the Card runner but serves no host services except `runtime` discovery. | -| **Catalog** | `catalog.json`: the signed list of admitted app versions a store reads, with a copy of each bundle under `artifacts/`. A store verifies it against a trust anchor before it shows anything. | +| **Catalog** | The authenticated list of admitted app versions a Store reads. GitHub-attested v2 and legacy Ed25519 `catalog.json` have distinct verifier paths; catalog publication requires Hub approval, not just an app release. | | **Contained app** | A script or card app that runs in a policed isolate, under the policy its manifest resolves to. Store apps and system apps are both contained. | | **Flow** | A documented, step-by-step procedure in [flows/](../flows/README.md) (`FLOW.md`) that a person or agent follows from an input to a checked bundle. | | **Gate** | `hub check`: the deterministic admission rules (file types, digest, assets, secrets, listing, policy, version and publisher continuity). The same code runs on the developer's machine and in App Hub's admission. | | **Glance** | The screen of cards that apps publish with `glance.publish`: a panel on the desktop and a feed on the phone. A Glance card opens only the app that published it. See [AI-SERVICES](AI-SERVICES.md#publishing-to-the-glance-screen). | | **Host service** | Work the shell does for an app, in Rust, with things the app must never hold (a socket, a credential, a device). The app calls `host.request(".", args, fn(r){…})`; the capability `` must be granted. See [HOST-SERVICES](HOST-SERVICES.md). | -| **`hub`** | App Hub's command-line tool (`crates/app-hub/src/bin/hub.rs`): `keygen`, `pubkey`, `certify`, `stamp`, `sign-manifest`, `check`, `scan`, `publish`, `withdraw`, `remove`, `verify`. Not GitHub's `hub` CLI. | +| **`hub`** | App Hub's command-line tool (`crates/app-hub/src/bin/hub.rs`), with commands including `stamp`, `check`, `scan` and the new `publisher-prepare`, `publisher-attach`, `publisher-verify`, `publisher-pack`; legacy signing/catalog commands remain for compatibility. Not GitHub's `hub` CLI. | | **Isolate** | One Splash VM with its own heap, jail, storage quota, capability list, host allowlist, instruction budget and heap ceiling. Every app runs in its own. | | **Jail** | An app's private storage directory, `//`. Only an app granted `storage` has one. | | **Kit** | A named set of widgets and styles a card is lowered with (`kit/` in a card bundle); the [sketch kit flow](../flows/kits/sketch/FLOW.md) builds one. | | **L0** | The declarative card language a card app's `page.card` is written in: data, state, events and views, lowered to widgets by a kit. Examples in [docs/l0/](l0/). | | **Listing** | `bundle/listing.json`: what the store shows before install (subtitle, description, category, keywords, screenshots, icon, platforms, publisher, release notes, age rating, license). Reviewed with the bundle. Schema: `crates/app-policy/src/listing.rs`. | -| **Manifest** | `bundle/manifest.json`: id, version, name, integrity digest (and signature), capabilities, network hosts, storage and compute requests, optional agent. It is the only place an app states its own limits, and the gate refuses unknown fields. Schema: `crates/app-contract/src/manifest.rs` in OctoSense-App-Hub, the app contract crate `octosense-app-contract`. | +| **Manifest** | `bundle/manifest.json`: id, version, name, integrity digest and publisher proof (GitHub attestation or legacy signature), capabilities, network hosts, storage and compute requests, optional agent. It is the only place an app states its own limits, and the gate refuses unknown fields. Schema: `crates/app-contract/src/manifest.rs` in OctoSense-App-Hub, the app contract crate `octosense-app-contract`. | | **Model text** | Words a model wrote (`model-copy`, a digest's summary, a `sys.chat` reply). An L0 card may show it only in a text slot, where the kit marks it AI-written, and never acts on it (OctoScript [`docs/ui-profile-l0.md`](https://github.com/OctoSense-org/OctoScript/blob/main/docs/ui-profile-l0.md) §4.2). | | **Native app** | A compiled Rust app the shell links from OctoSense's `native-apps.json`, such as Rinx. Most run inside the shell's process as native modules; on the desktop, Terminal and Task run as separate process apps. | | **octos** | The agent kernel inside OctoSense ([octos-org/octos](https://github.com/octos-org/octos)): one per shell, configured by AI providers. Not `tools/octo`, which is this repository's CLI. See [AI-SERVICES](AI-SERVICES.md). | | **OctoScript** | The layer above Makepad that gives this repository its name: the OctoScript VM and OctoScript-Makepad (the UI framework, kits and L0 lowering). Not a language app authors write. | | **OctoSense app** | Anything a person installs or opens on an OctoSense device as an app. Two kinds ship through App Hub: a script app and a card app. | | **Palpo** | A Matrix server. Its operations are the 29 `palpo.*` capabilities; no OctoSense shell serves them. | -| **Publisher key** | The Ed25519 key a publisher signs manifests with (`hub keygen`, `hub sign-manifest`). Keep it outside every repository. Once the key is on record, every later version must be signed with it. | +| **GitHub publisher proof** | A GitHub Actions attestation over the canonical app manifest, bound to the repository/owner IDs, workflow, version tag and source commit. Fresh apps and routine updates need no developer signing key. Requires `publisher-github-v1` / contract 1.8.0 and a compatible host; live acceptance remains pending. | +| **Publisher key** | An Ed25519 signing key used only in the optional legacy compatibility path (`hub keygen`, `hub sign-manifest`). Keep it outside repositories. New GitHub publishing does not require one. | | **Rinx** | A Matrix client that OctoSense links as a native app. Its mini-app host serves `octos.*` to bundles a person imports into it. **Unverified:** it serves `matrix.*` to them too. No OctoSense shell serves `matrix.*` to an installed app. | | **Scan** | `hub scan`: the review packet a human or model reviewer answers after the gate passes. It holds the app's source, listing and grants, and seven questions (eight when the bundle ships agent files), but no screenshots. | | **Script app** | An app whose bundle holds `main.splash`, a Splash program with its own state, handlers, storage and requests. The host runs it unchanged in a policed isolate. It is the default kind, and the one this repository's [QUICKSTART](QUICKSTART.md) builds. | | **Sheet** | A host-owned surface a host service draws over an app, in its own isolate under no app's policy, for things only the person may type (a password). Only the sheet may call `.sheet.*` methods. | | **Shell** | The OctoSense host that installs and runs apps: the desktop, or Home on the phone. | | **Splash** | Makepad's runtime script and widget language (`Splash` widget, `widgets/src/splash*.rs` in OctoSense-org/makepad). A script app's `main.splash` is Splash source. | -| **Stamp** | Writing the bundle's BLAKE3 digest into `manifest.json` (`hub stamp `). Every byte change needs a restamp; a signature covers the stamped digest. | +| **Stamp** | Writing the bundle's BLAKE3 digest into `manifest.json` (`hub stamp `). Editable source needs a restamp after byte changes; never restamp a sealed attested/signed release. | | **Store app** | An app installed from the App Hub store. Its id never starts with `os.`. | | **`sys.chat`** | An L0 source for a chat with the publishing app's agent inside a card; the host keeps the transcript and writes the agent's replies (OctoScript [`docs/ui-profile-l0.md`](https://github.com/OctoSense-org/OctoScript/blob/main/docs/ui-profile-l0.md) §5.15). See [AI-SERVICES](AI-SERVICES.md#ai-written-text-and-in-card-chat-model-copy-syschat). | | **System agent** | The shell's own assistant session (`_main:api:octosense#system`), owner of every app peer, which the person talks to in the system chat (the assistant pane). It lists app agents and hands them work (`peer_list`, `peer_send_input`), holds no app's tools, cannot approve for an app and cannot close an app's peer. | diff --git a/docs/HOST-API-V1.md b/docs/HOST-API-V1.md index a985cdff..7cb44e4f 100644 --- a/docs/HOST-API-V1.md +++ b/docs/HOST-API-V1.md @@ -287,12 +287,14 @@ lacks, the reason is `this host does not implement required APIs: @` instead. Test such an app this way: -1. Check the final signed bundle with `hub` built from App Hub `main`: - `hub check --publisher-key =` - prints a line that ends in `— PASSED`. -2. Install it from a local mirror in an OctoSense desktop shell built from - `main`, as [PUBLISHING §4](PUBLISHING.md#4-rehearse-the-store-path-locally) - shows. +1. Check editable source with `hub check --allow-unsigned` after + stamping. Use the GitHub publishing workflow for the final release proof + ([PUBLISHING §3.6](PUBLISHING.md#36-publisher-key--human)); it needs no developer key. +2. Test host services in a compatible OctoSense shell. The + [local mirror rehearsal](PUBLISHING.md#4-rehearse-the-store-path-locally) + is an optional legacy compatibility route for pre-publication tests, not + verification of GitHub-attested releases. `publisher-github-v1` needs a + compatible Store verifier; its released-host installation is still pending. 3. Exercise discovery and the fallback for a missing API, account changes, permission denial and revocation, a tool call while the app is closed, and the native review of a backend write. diff --git a/docs/HOST-API-V1.zh-CN.md b/docs/HOST-API-V1.zh-CN.md index 853daad4..69d3c918 100644 --- a/docs/HOST-API-V1.zh-CN.md +++ b/docs/HOST-API-V1.zh-CN.md @@ -185,8 +185,8 @@ app_tools.dispatch@1 拒绝原因会写出宿主缺少的 API;对 `host-api-v1` 来说是 `app_policy.device_consent@1`。如果 `host_api.required` 列出了宿主缺少的方法,原因则是 `this host does not implement required APIs: @`。请改用以下方式测试这类应用: -1. 用 App Hub `main` 构建的 `hub` 检查最终签名的应用包:`hub check --publisher-key =` 应输出一行以 `— PASSED` 结尾的结果。 -2. 按 [PUBLISHING §4](PUBLISHING.zh-CN.md#4-在本地演练商店流程) 的步骤,从本地镜像把它安装到用 `main` 构建的 OctoSense 桌面端 Shell 中。 +1. 写入摘要后,用 `hub check --allow-unsigned` 检查可编辑源码。最终发布证明使用 GitHub 工作流([PUBLISHING §3.6](PUBLISHING.zh-CN.md#36-发布者密钥human)),无需开发者密钥。 +2. 在兼容的 OctoSense Shell 中测试宿主服务。[本地镜像演练](PUBLISHING.zh-CN.md#4-在本地演练商店流程) 是发布前测试的可选旧格式兼容路径,不能验证 GitHub 证明的发布包。`publisher-github-v1` 需要兼容 Store 验证器,其已发布宿主上的安装仍待验证。 3. 逐项测试:API 发现与缺少 API 时的降级、账户切换、拒绝和撤销权限、应用关闭时调用工具,以及后端写操作的原生审阅。 4. 在 `listing.json` 中只列出实际测试过的平台。 diff --git a/docs/PUBLISHING.md b/docs/PUBLISHING.md index 189e94a8..16df39a9 100644 --- a/docs/PUBLISHING.md +++ b/docs/PUBLISHING.md @@ -2,11 +2,17 @@ English | [简体中文](PUBLISHING.zh-CN.md) -Take a working script app to a bundle that is ready to sign: the final -manifest and listing, real screenshots, a passing gate with the review -questions answered, and a rehearsal of the store path on your own machine. A -coding agent can run these steps top to bottom and stop exactly where a -person must act. +Take a working script app through local checks to a GitHub-attested release +and App Hub review. Finish the manifest, listing, real screenshots and review +answers first; the tag workflow then prepares and verifies the sealed release +without a developer signing key. See §3.6 for the current implementation limits. + +**Opening an App Hub submission issue is the request to publish.** Include the +repository, version/commit, screenshots and requested permissions. You can open +it before the release is ready; add the tag, workflow result and release pack +when available. Hub checks report missing items or refusals, an administrator +approves the exact candidate, and the Hub publishes the catalog entry. Creating +a GitHub release alone does not submit or approve an app. Two App Hub documents own the rest: @@ -17,8 +23,8 @@ Two App Hub documents own the rest: - Start here when [QUICKSTART](QUICKSTART.md) §1–6 pass: the app runs in `card-host`, and you have tested its interactions. -- **HUMAN** marks a checkpoint an agent must not pass on its own: private - keys, the publisher identity and privacy text, the platforms claimed, the +- **HUMAN** marks a checkpoint requiring the person’s authorization: the + publisher identity and privacy text, the platforms claimed, the release tag and the submission. An agent stops, reports and waits. ## 1. What gets published @@ -29,6 +35,7 @@ tools, keys, logs, `.local-state/`, `build/review.json`) stays outside it. ```text my-app/ AGENTS.md README.md .gitignore not submitted + .github/workflows/publish-app.yml release workflow; outside the bundle .gitattributes copied by tools/octo new: bundle/** -text, so Git never rewrites the bundle build/review.json not submitted (hub scan output) .local-state/ not submitted (card-host jail) @@ -175,8 +182,8 @@ is already published is refused: `tools/octo check` restamps an unsigned bundle before it checks, so it passes even when the digest you committed is stale. Run it as the last step before -every commit. The final check runs from a fresh clone of the release tag -(§3.8). +every source commit. The tag workflow prepares and verifies the sealed release +pack separately (§3.7); a source check alone is not publisher-proof verification. ### 3.5 Answer the review questions @@ -196,82 +203,107 @@ issue yourself. There are seven questions, and an eighth about the agent files when the bundle ships `tools.json`, `AGENT.md` or skills. Answer each one in writing, for example in `$APP/review/ANSWERS.md`; the reviewer asks the same ones ([SUBMITTING §8](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#8-what-reviewers-check)). -On a signed bundle, `hub scan` needs `--publisher-key =`. +Answer the questions on the editable source. For the optional legacy Ed25519 +path, scanning a signed bundle needs `--publisher-key =`. -### 3.6 Publisher key — HUMAN + -A publisher key is an Ed25519 key that identifies the publisher across every -version: App Hub refuses an update signed by a different key. The person who -owns the app creates and keeps it. An agent never creates, copies, uploads or -prints a private key unless that person asked for exactly that, in this -session. +### 3.6 GitHub publisher identity — HUMAN -`hub keygen ` writes the private key as hex and prints the public -half; `hub pubkey ` prints the public half again. Keep the key -outside every repository: +The default path for a new app uses its public GitHub repository and a GitHub +Actions attestation. You do not generate `publisher.key` or add a signing +secret to the repository. Review the publisher details and the workflow before +releasing under your account. -```sh -"$HUB" keygen -``` - -`keygen` never overwrites. If a file or a symlink already exists at that -path, it stops with -`hub: cannot create new signing key "": File exists (os error 17)`; -choose a new path, and never delete a key you have published with. On macOS -and Linux, it creates the file with mode 0600, readable only by you. On -Windows, keep the key in a folder that only you can read. A `hub` built -before App Hub's current `main` overwrites without asking and uses your -default permissions; rebuild it first. - -[SUBMITTING §5](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#5-produce-the-final-bytes) -gives the publisher id and the signing commands, and -[SUBMITTING §1](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#1-lay-out-the-repository) -shows what `publisher.json` holds; App Hub's -[Signing](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.md#signing) -is the reference. +**Availability:** this path is being implemented with app contract 1.8.0 and +`publisher-github-v1`. Live publisher attestation and installation of such a +release remain unverified; a compatible OctoSense host release is pending. +Older hosts refuse this requirement. The installer fails closed until its +`publisher-toolchain.json` names a reviewed, immutable App Hub revision. -### 3.7 Sign the final bytes — HUMAN +For an existing editable app directory, install the workflow from Design Flow: -Sign last. The signature covers the manifest, and the manifest carries the -digest of every other file. Once the bundle is signed: - -- any edit breaks the digest, and restamping alone then breaks the signature, - so a person stamps and signs again; -- `card-host` refuses the bundle, so capture screenshots and test before - signing; -- `tools/octo check` no longer restamps it, and refuses it unless you pass - `--publisher-key =`. +```sh +tools/octo publish-github "$APP" +``` -[SUBMITTING §5](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#5-produce-the-final-bytes) -gives the commands and their output. +`tools/octo new` also installs `.github/workflows/publish-app.yml`. The command +only writes that file: it does not push, release, submit or approve the app. +It refuses to overwrite a different workflow unless you explicitly use +`--replace`. No developer signing secret is required; the workflow uses GitHub's +short-lived job token and OIDC permissions for attestation and release creation. + +Keep the tested, unsigned `bundle/` as source. Review and commit the workflow, +source, real screenshots and `.gitattributes` in the public app repository. +Create and push a **new** `v` tag for that commit, for example +`v0.1.0` when the manifest says `0.1.0`. Do not move or recreate a released tag. + + + +### 3.7 Attest the final bytes in GitHub Actions + +The tag-push workflow performs this sequence with a pinned App Hub toolchain: + +1. `hub publisher-prepare` checks the bundle, binds the repository name and + immutable repository/owner IDs, workflow path, tag and commit, and writes + the canonical manifest outside `bundle/`. +2. GitHub's `actions/attest` attests that canonical manifest. The native + verifier checks the GitHub-hosted tag-push identity and source commit. +3. `hub publisher-attach` embeds the proof at `integrity.github.attestation`; + `hub publisher-verify` validates it. +4. `hub publisher-pack` verifies again and produces `app.bundle.pack.json` + without restamping. The release also contains `octosense-app-manifest.json` + and `release-receipt.json`. + +These are workflow stages, not local key-generation commands. An attested +bundle is sealed: do not edit, restamp or strip its proof. `card-host` cannot +run it because it has no publisher-proof verifier. Test the editable source +before release, then test the admitted release in a compatible Store host. +A tag's source archive and its sealed release pack are different artifacts; +checking the source alone does not verify the published proof. + +For a routine update, edit and test the source, increment `manifest.version`, +and push a new matching tag from the same repository/owner/workflow identity. +The gate checks continuity. A release receipt records the release inputs and +pack digest; it is not App Hub approval. ### 3.8 Submit — HUMAN -A person commits the signed bundle, tags that commit, runs `hub check` on a -fresh clone of the tag (without restamping), and opens a `Submit ` -issue on OctoSense-App-Hub. App Hub's SUBMITTING describes each step: -[§6 Freeze and verify the release](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#6-freeze-and-verify-the-release) -and -[§7 Open the submission issue](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#7-open-the-submission-issue), -with every field the issue needs. - -- Never move or recreate a tag. To change anything, release a new version. -- Never open a pull request that edits App Hub's `catalog.json`, `index/` or - `artifacts/`. Only `hub publish` with App Hub's catalog key writes them, - and every store refuses a catalog that key did not sign. -- An agent may draft the issue text, for example into `build/SUBMISSION.md`. - It never claims a submission was made, reviewed or approved unless a person - did it and says so. - -### 3.9 What App Hub does next - -A maintainer runs the gate and the scan on the exact bytes of your tag, then -publishes the bundle into a new signed catalog or answers with findings to -fix. [SUBMITTING §9](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#9-after-you-submit) -covers what follows and how to ship a fix. +Open a `Submit ` issue on OctoSense-App-Hub to request +publication. Include the repository, version/commit, screenshots, requested +permissions and review answers. The issue can be opened before the release is +ready. Add the release URL, tag, successful workflow run and exact pack/digest +when the workflow succeeds; the Hub needs these verified bytes before admission. Follow App Hub's +[SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) +for the current issue fields. + +- A GitHub release is not automatic admission to App Hub. +- Do not hand-edit the Hub's catalog, index or admitted artifacts in a pull + request. Its protected review/publishing workflow admits the exact bundle. +- An agent may prepare the workflow and draft the issue in + `build/SUBMISSION.md`. It must not claim a release, review or approval it + did not observe. Respect the person's authorization for external actions. + +### 3.9 What the App Hub does next + +The Hub verifies the publisher proof and bundle, runs admission and review, +and either admits the exact release through its authenticated catalog or +returns concrete refusals. Only after that does a compatible Store offer it. +If changes are needed, publish a new version/tag; do not replace old bytes. + +Manual Ed25519 signing remains an **optional compatibility path** for older +workflows. It is not a step in new GitHub publishing. The older local rehearsal +below preserves its original commands and evidence; existing reference releases +and their signatures are unchanged. ## 4. Rehearse the store path locally +**Optional legacy compatibility rehearsal.** The commands and recorded results +in this section use Ed25519 publisher/catalog keys. They are not required by +the GitHub publishing path and do not validate `publisher-github-v1`. Use an +explicitly prepared legacy test bundle for this rehearsal, never restamp a +GitHub-attested release. + Run the whole publish-and-install path on your own machine, signed with your own trust anchor (a throwaway root key in place of App Hub's), to see what a device does. The rehearsal also runs the app's host services, which @@ -408,7 +440,7 @@ under `store-data/my-test-notes/bundle`; **OPEN** does not show the app. | Checkpoint | Why an agent stops | | --- | --- | -| Creating, storing or using the publisher key (3.6, 3.7) | It is the publisher's identity; losing it blocks every update. | +| GitHub publisher identity and release workflow (3.6, 3.7) | The release binds the public repository, owner, workflow, tag and commit; the person authorizes publication under that identity. | | Publisher name, support contact, privacy policy text (3.2) | Legal and personal statements only the publisher can make. | | Platforms claimed (3.2) | A platform claim must match a run that a person did or recorded; an agent cannot vouch for one. | | Tagging the release (3.8) | The tag names the exact bytes reviewers check; it never moves. | @@ -418,7 +450,7 @@ under `store-data/my-test-notes/bundle`; **OPEN** does not show the app. ## 6. Checklist (copy, then run top to bottom) `tools/octo package-help` prints a shorter version; this one adds the -`--hidden`, `.DS_Store` and fresh-clone steps. +`--hidden`, `.DS_Store` and release-proof checks. ```text [ ] tools/octo doctor -> hub and card-host [ok] @@ -434,9 +466,12 @@ under `store-data/my-test-notes/bundle`; **OPEN** does not show the app. [ ] tools/octo check "$B" --catalog -> no version or continuity refusal [ ] mkdir -p "$APP/build"; hub scan "$B" --packet "$APP/build/review.json" -> 7 questions answered in writing (8 with tools.json, AGENT.md or skills) [ ] git -C "$APP" check-attr text -- "$B/manifest.json" -> "text: unset" (QUICKSTART §3) -[ ] git status: only bundle/ and app sources; no keys, .local-state or build/ -[ ] HUMAN: sign last; hub check --publisher-key = -> PASSED (App Hub SUBMITTING §5) -[ ] HUMAN: commit, tag v, plain hub check on a fresh clone of the tag (SUBMITTING §6) -[ ] HUMAN: open the issue "Submit " on OctoSense-App-Hub (SUBMITTING §7) +[ ] git status: only app sources and reviewed workflow; no secrets, .local-state or build/ +[ ] tools/octo publish-github "$APP" -> reviewed .github/workflows/publish-app.yml; no developer key +[ ] HUMAN: commit tested source/workflow, then push a NEW tag v +[ ] GitHub workflow succeeds; publisher-verify and publisher-pack pass on the attested release +[ ] release pack, canonical manifest and receipt exist; compatible-host installation separately verified or marked pending +[ ] HUMAN: submission issue requests publication; attach repo/version/commit, screenshots and permissions (may open earlier) +[ ] Add the successful workflow and exact release pack to that issue; Hub checks/admin approval/catalog publication are separate [ ] report: what was verified, on which platform, and what was not ``` diff --git a/docs/PUBLISHING.zh-CN.md b/docs/PUBLISHING.zh-CN.md index 01ecdb51..955afead 100644 --- a/docs/PUBLISHING.zh-CN.md +++ b/docs/PUBLISHING.zh-CN.md @@ -4,7 +4,9 @@ 未注明中文版的链接指向英文文档。 -把能运行的脚本应用做成待签名的应用包:清单和商店信息已定稿,截图都是实际截取的,准入检查已通过、审核问题已作答,商店流程也已在你自己的机器上演练过。编码 Agent 可以从头到尾执行这些步骤,并正好停在必须由人操作的地方。 +让能运行的脚本应用通过本地检查,进入 GitHub 证明和 App Hub 审核流程。先完成清单、商店信息、真实截图和审核答案;tag 工作流再生成并验证封存的发布包,无需开发者签名密钥。当前实现限制见 §3.6。 + +**开 App Hub 提交 issue,才是请求发布。** 填写仓库、版本/commit、截图和请求的权限;可以在 release 准备好之前开 issue,之后补充 tag、工作流结果和 release pack。Hub 检查报告缺项或拒绝原因,管理员批准确切的候选版本后,Hub 才发布目录条目。创建 GitHub release 本身不会提交或批准应用。 其余内容由 App Hub 的两份文档负责: @@ -14,7 +16,7 @@ | 签名、打 tag、提交 issue、审核人员检查什么、常见拒绝原因 | App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) | - 在 [QUICKSTART](QUICKSTART.zh-CN.md) 的 §1–6 都走通之后,从这里开始:应用已能在 `card-host` 中运行,你也测试过它的交互。 -- **HUMAN** 标出 Agent 不能自行越过的把关节点:私钥、发布者身份与隐私文本、声明的平台、发布 tag 和提交。到了这些节点,Agent 停下、汇报,然后等待。 +- **HUMAN** 标出需要用户授权的把关节点:发布者身份与隐私文本、声明的平台、发布 tag 和提交。到了这些节点,Agent 停下、汇报,然后等待。 ## 1. 发布的是什么 @@ -23,6 +25,7 @@ ```text my-app/ AGENTS.md README.md .gitignore 不提交 + .github/workflows/publish-app.yml 发布工作流;不放进应用包 .gitattributes 由 tools/octo new 复制:bundle/** -text,让 Git 永不改写应用包 build/review.json 不提交(hub scan 的输出) .local-state/ 不提交(card-host 的 jail) @@ -129,7 +132,7 @@ hub: the bundle was refused [refused] version: version 0.1.0 of org.octosense.samples.githubnotes is already published; publish a new version ``` -`tools/octo check` 会在检查之前为未签名的应用包重新写入摘要,所以即使你 commit 的摘要已经过时,它也会通过。每次 commit 之前,把它作为最后一步运行。最终检查在发布 tag 的全新克隆上进行(§3.8)。 +`tools/octo check` 会在检查之前为未签名的应用包重新写入摘要,所以即使你 commit 的摘要已经过时,它也会通过。每次 commit 之前,把它作为最后一步运行。tag 工作流另行生成并验证封存的发布 pack(§3.7);源码检查不能代替发布者证明验证。 ### 3.5 回答审核问题 @@ -143,46 +146,90 @@ wrote the review packet to …/build/review.json no --reviewer given; the packet holds 7 questions for one ``` -审核包中有清单、商店信息、授权、程序、Agent 文件(如有)和问题。审核包不含截图,请自己把截图附到 issue 中。问题共 7 个;应用包附带 `tools.json`、`AGENT.md` 或 skills 时,还有关于 Agent 文件的第 8 个问题。逐题书面作答,例如写在 `$APP/review/ANSWERS.md` 中;审核人员问的也是这些问题([SUBMITTING §8](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#8-审核检查什么))。扫描已签名的应用包时,`hub scan` 需要 `--publisher-key =`。 +审核包中有清单、商店信息、授权、程序、Agent 文件(如有)和问题。审核包不含截图,请自己把截图附到 issue 中。问题共 7 个;应用包附带 `tools.json`、`AGENT.md` 或 skills 时,还有关于 Agent 文件的第 8 个问题。逐题书面作答,例如写在 `$APP/review/ANSWERS.md` 中;审核人员问的也是这些问题([SUBMITTING §8](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#8-审核检查什么))。对可编辑源码回答审核问题。仅在可选的旧版 Ed25519 路径中,扫描已签名应用包的 `hub scan` 需要 `--publisher-key =`。 + + -### 3.6 发布者密钥(HUMAN) +### 3.6 GitHub 发布者身份(HUMAN) -发布者密钥是一把 Ed25519 密钥,在所有版本中标识同一个发布者:用另一把密钥签名的更新,App Hub 会拒绝。密钥由应用的所有者创建并保管。除非所有者在本次会话中明确要求这样做,否则 Agent 绝不创建、复制、上传或输出私钥。 +新应用默认使用自己的公开 GitHub 仓库和 GitHub Actions 证明。开发者无需生成 +`publisher.key`,也无需添加仓库签名 secret。用自己的账户发布前,请审阅发布者 +信息和工作流。 -`hub keygen ` 以十六进制写入私钥,并输出公钥;`hub pubkey ` 可以再次输出公钥。把密钥放在所有仓库之外: +**可用状态:** 此路径正在实现,使用应用契约 1.8.0 和 `publisher-github-v1`。 +真实 GitHub 发布者证明及其安装尚未验证,兼容的 OctoSense 宿主版本尚待发布。 +旧宿主会拒绝这个要求。`publisher-toolchain.json` 尚未指定经过评审的不可变 +App Hub commit 时,安装命令会拒绝继续,不会改用浮动版本。 + +对已有的可编辑应用目录,在 Design Flow 中安装工作流: ```sh -"$HUB" keygen +tools/octo publish-github "$APP" ``` -`keygen` 从不覆盖已有文件。如果该路径上已经有文件或符号链接,它会停下并报错 `hub: cannot create new signing key "": File exists (os error 17)`;请换一个路径,并且绝不要删除已经用来发布过的密钥。在 macOS 和 Linux 上,它以 0600 权限创建文件,只有你能读取。在 Windows 上,请把密钥放在只有你能读取的文件夹中。比 App Hub 当前 `main` 旧的 `hub` 会不加询问地直接覆盖,并沿用你的默认权限;请先重新构建 `hub`。 +`tools/octo new` 也会安装 `.github/workflows/publish-app.yml`。命令只写入这个文件, +不会推送、发布、提交或批准应用。除非显式加上 `--replace`,否则不会覆盖不同的 +已有工作流。无需开发者签名 secret;工作流使用 GitHub 的短期任务令牌和 OIDC +权限生成证明并创建 release。 + +仓库保留已测试、未签名的 `bundle/` 源码。审阅并 commit 工作流、源码、真实截图 +和 `.gitattributes`,存放在公开应用仓库。为该 commit 创建并推送一个**新**的 +`v` tag,例如清单版本为 `0.1.0` 时使用 `v0.1.0`。 +绝不要移动或重建已发布的 tag。 -发布者 id 和签名命令见 [SUBMITTING §5](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#5-生成最终字节),`publisher.json` 包含哪些内容见 [SUBMITTING §1](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#1-安排仓库结构);完整参考见 App Hub 的 [签名](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.zh-CN.md#签名) 一节。 + -### 3.7 为最终字节签名(HUMAN) +### 3.7 在 GitHub Actions 中证明最终字节 -签名放在最后。签名覆盖清单,而清单中的摘要覆盖其他所有文件。应用包签名之后: +推送 tag 后,工作流用固定版本的 App Hub 工具依次执行: -- 任何改动都会让摘要对不上,而只重新写入摘要又会让签名失效,所以要由人重新写入摘要并重新签名; -- `card-host` 会拒绝这个应用包,所以截图和测试都要在签名之前完成; -- `tools/octo check` 不再为它重新写入摘要;除非你传入 `--publisher-key =`,否则它会拒绝这个应用包。 +1. `hub publisher-prepare` 检查应用包,绑定仓库名称、不可变的仓库/所有者 ID、 + 工作流路径、tag 和 commit,并在 `bundle/` 之外写入规范化清单。 +2. GitHub 的 `actions/attest` 为该清单生成证明。原生验证器检查 GitHub 托管的 + tag-push 工作流身份及源码 commit。 +3. `hub publisher-attach` 把证明嵌入 `integrity.github.attestation`,随后 + `hub publisher-verify` 验证它。 +4. `hub publisher-pack` 再次验证,不重新写入摘要,产出 `app.bundle.pack.json`。 + release 还包含 `octosense-app-manifest.json` 和 `release-receipt.json`。 -命令及其输出见 [SUBMITTING §5](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#5-生成最终字节)。 +这些是工作流阶段,不是本地生成密钥的步骤。附有证明的应用包已经封存,不能再 +修改、重新写入摘要或删除证明。`card-host` 没有发布者证明验证器,不能运行它。 +发布前测试可编辑源码,准入后在兼容的 Store 宿主中测试发布包。tag 的源码归档 +和附有证明的 release pack 是不同产物;仅检查源码不能验证已发布的证明。 + +日常更新时,修改并测试源码、递增 `manifest.version`,再从同一个仓库、所有者和 +工作流身份推送匹配的新 tag。准入检查会验证身份连续性。release receipt 记录 +发布输入和 pack 摘要,不代表 App Hub 已批准应用。 ### 3.8 提交(HUMAN) -由人 commit 已签名的应用包,为这个 commit 打 tag,在 tag 的全新克隆上运行 `hub check`(不重新写入摘要),然后在 OctoSense-App-Hub 开一个 `Submit ` issue。App Hub 的 SUBMITTING 逐一说明了这些步骤:[§6 冻结并验证发布](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#6-冻结并验证发布)和 [§7 开提交 issue](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#7-开提交-issue),包括 issue 需要填写的每个字段。 +向 OctoSense-App-Hub 开 `Submit ` issue,表达发布意图。 +提供仓库、版本/commit、截图、请求的权限和审核答案。可以先开 issue,再准备 release。 +工作流成功后,在同一 issue 补充 release URL、tag、工作流运行和确切的 pack/摘要; +Hub 准入之前需要这些经过验证的字节。当前 issue 字段见 App Hub 的 +[SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md)。 -- 绝不要移动或重建 tag。要修改任何内容,请发布新版本。 -- 绝不要开 pull request 修改 App Hub 的 `catalog.json`、`index/` 或 `artifacts/`。只有用 App Hub 签名目录密钥运行的 `hub publish` 才能写入它们,而且签名目录只要不是这把密钥签的,所有商店都会拒绝。 -- Agent 可以起草 issue 正文,例如写到 `build/SUBMISSION.md` 中。除非确实有人做了并明确告知,否则 Agent 绝不声称已经提交、已经审核或已经批准。 +- 创建 GitHub release 不会自动获得 App Hub 准入。 +- 不要在 pull request 中手改 Hub 的目录、索引或已准入产物。受保护的审核和发布 + 工作流会准入确切的应用包。 +- Agent 可以准备工作流,并在 `build/SUBMISSION.md` 起草 issue;不能声称尚未 + 观察到的发布、审核或批准已经发生。对外部操作遵循用户的授权。 ### 3.9 App Hub 接下来做什么 -维护者会对你的 tag 中的确切字节运行准入检查和扫描,然后把应用包发布到新的签名目录,或者回复需要修复的问题。之后的流程以及如何发布修复,见 [SUBMITTING §9](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#9-提交之后)。 +Hub 验证发布者证明和应用包,执行准入检查与审核,通过其经过身份验证的目录 +准入确切版本,或者返回具体拒绝原因。之后兼容的 Store 才会提供该应用。 +需要修改时发布新版本和新 tag,不要替换旧字节。 + +手动 Ed25519 签名仍是旧工作流的**可选兼容路径**,不是新 GitHub 发布流程的一步。 +下节保留旧本地演练的命令和记录;已有参考版本及其签名保持原样。 ## 4. 在本地演练商店流程 +**可选的旧格式兼容演练。** 本节命令和历史结果使用 Ed25519 发布者/目录密钥, +不是 GitHub 发布的必需步骤,也不能验证 `publisher-github-v1`。请使用专门准备的 +旧格式测试包,绝不要为附有 GitHub 证明的发布包重新写入摘要。 + 在自己的机器上走一遍完整的发布和安装流程,用你自己的信任锚签名(以一把一次性根密钥代替 App Hub 的根密钥),看看设备上会发生什么。演练还会运行应用的宿主服务,这是 `card-host` 做不到的。镜像及其密钥放在 `build/` 下,绝不要放进 `bundle/`。 ### 4.1 发布到本地镜像 @@ -272,7 +319,7 @@ App Hub 的独立商店 `appstore` 不需要 Shell 也能从同一个镜像安 | 把关节点 | Agent 为什么停下 | | --- | --- | -| 创建、保管或使用发布者密钥(3.6、3.7) | 它代表发布者的身份;丢失之后,任何更新都无法发布。 | +| GitHub 发布者身份与发布工作流(3.6、3.7) | 发布绑定公开仓库、所有者、工作流、tag 和 commit;由人授权以这个身份发布。 | | 发布者名称、支持联系方式、隐私政策文本(3.2) | 这些法律声明和个人声明只有发布者本人才能作出。 | | 声明的平台(3.2) | 每个平台声明都要对应一次由人执行或记录的实际运行;Agent 无法为此担保。 | | 为发布打 tag(3.8) | tag 标识审核人员检查的确切字节,永不移动。 | @@ -281,7 +328,7 @@ App Hub 的独立商店 `appstore` 不需要 Shell 也能从同一个镜像安 ## 6. 检查表(复制后从上到下执行) -`tools/octo package-help` 会输出一个简短版本;这里的版本多了 `--hidden`、`.DS_Store` 和全新克隆这几步。 +`tools/octo package-help` 会输出一个简短版本;这里的版本多了 `--hidden`、`.DS_Store` 和发布证明检查。 ```text [ ] tools/octo doctor -> hub 和 card-host 均为 [ok] @@ -297,9 +344,12 @@ App Hub 的独立商店 `appstore` 不需要 Shell 也能从同一个镜像安 [ ] tools/octo check "$B" --catalog -> 没有 version 或 continuity 拒绝 [ ] mkdir -p "$APP/build"; hub scan "$B" --packet "$APP/build/review.json" -> 7 个问题都已书面作答(附带 tools.json、AGENT.md 或 skills 时为 8 个) [ ] git -C "$APP" check-attr text -- "$B/manifest.json" -> "text: unset"(QUICKSTART §3) -[ ] git status 中只有 bundle/ 和应用源码,没有密钥、.local-state 或 build/ -[ ] HUMAN:最后签名;hub check --publisher-key = -> PASSED(App Hub SUBMITTING §5) -[ ] HUMAN:commit,打 tag v,在 tag 的全新克隆上直接运行 hub check(SUBMITTING §6) -[ ] HUMAN:在 OctoSense-App-Hub 开 issue "Submit "(SUBMITTING §7) +[ ] git status 中只有应用源码和已审阅的工作流,没有 secret、.local-state 或 build/ +[ ] tools/octo publish-github "$APP" -> 已审阅 .github/workflows/publish-app.yml;无需开发者密钥 +[ ] HUMAN:commit 已测试源码和工作流,再推送新的 v tag +[ ] GitHub 工作流成功;publisher-verify 和 publisher-pack 验证带证明的发布包通过 +[ ] release pack、规范化清单和 receipt 齐全;兼容宿主安装单独验证,或明确标记待验证 +[ ] HUMAN:提交 issue 表达发布意图,附仓库/版本/commit、截图和权限(可提前开) +[ ] 在同一 issue 补充成功工作流和确切 release pack;Hub 检查、管理员批准、目录发布另行执行 [ ] 汇报:验证了什么、在哪个平台上验证、哪些没有验证 ``` diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 97989ab8..de11b2ed 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -523,7 +523,7 @@ my-notes 0.1.0 — PASSED grants: capabilities {"storage"}, hosts {}, storage 16777216 bytes, agent none ``` -The unsigned warning is expected until a person signs the bundle. The +The unsigned warning is expected while developing editable source. The placeholder note stays until a person writes the publisher fields. To catch a version that is already published, add App Hub's catalog: @@ -534,9 +534,9 @@ A reused version is refused with `check` restamps an unsigned bundle first. If you edit the bundle after your last `check` and commit without running it again, the committed digest is stale, and a reviewer's plain `hub check` refuses it with `[refused] digest`. -Run `tools/octo check` as the last step before every commit; before you -submit, run plain `hub check` on a fresh clone of your release tag -([SUBMITTING §6](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#6-freeze-and-verify-the-release)). +Run `tools/octo check` as the last step before each source commit. The GitHub +workflow separately prepares and verifies the sealed release pack (§10); its +proof is not present in the editable tag source. ## 9. Run it on an OctoSense phone @@ -550,7 +550,7 @@ What exists today: `OCTOSENSE_HUB_ANCHOR` (a mirror directory or URL, and its anchor) are environment variables, which the Android launcher does not set; no on-device setting for them was found. **Unverified on a device.** -- **The closest real path is on the desktop:** publish into a local catalog +- **An optional legacy test path is on the desktop:** publish into a local catalog with your own throwaway anchor and install it with App Hub's store, which runs the same install code as a phone ([PUBLISHING §4](PUBLISHING.md#4-rehearse-the-store-path-locally)). The @@ -575,12 +575,29 @@ app with the App Studio tools of an OctoSense test build ## 10. Publish -[PUBLISHING](PUBLISHING.md) takes the bundle from here to ready-to-sign: -final manifest and listing, real screenshots, a passing gate, the review -questions, and a local rehearsal of the store path. A person then signs, -tags and submits it, following App Hub's -[Submit an app to the App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md). -`tools/octo package-help` prints the checklist. +**Open an App Hub submission issue to request publication.** Include the app +repository, version/commit, screenshots and permissions. It can precede the +release; add verified release artifacts when ready. Hub checks and administrator +approval are required before the catalog offers the app. + +[PUBLISHING](PUBLISHING.md) covers the full process. After testing source: + +```sh +tools/octo publish-github ~/apps/my-app +tools/octo package-help +``` + +Review and commit `.github/workflows/publish-app.yml` with the tested app, then +push a new `v` tag. GitHub Actions prepares, attests, verifies +and packs it; no `publisher.key` or developer signing secret is required. +Attach the successful workflow and exact release pack to the submission issue. +Neither installing the workflow nor creating a GitHub release submits or +approves the app. Routine updates use new versions/tags from the same identity. + +This working-branch path needs contract 1.8.0 / `publisher-github-v1`; a compatible +host release is pending, and live publishing/installation remain unverified. +Older hosts and `card-host` refuse the sealed release. The local Ed25519 store +rehearsal is optional compatibility, not a required publishing step. ## Troubleshooting @@ -615,8 +632,8 @@ tags and submits it, following App Hub's | `check`: `[refused] assets: … contains https://…` in an ordinary license `.txt` or `.md` file | Rebuild `hub` from App Hub #146 or later. Plain documentation URLs are accepted; retain required license notices. Agent guidance and structured resource references still have separate checks. | | `check`: `[refused] resource-invalid (…/font_src): not a portable bundle path: "makepad_widgets:resources/…"` | Current `hub` accepts the exact built-in `Inter.ttf`, `LXGWWenKaiRegular.ttf` and `LXGWWenKaiBold.ttf` paths (§7). Rebuild an older gate. For other fonts, bundle a font file and use a relative path such as `assets/Body.ttf`. `desktop-v0.1.0-beta.2` still predates bundled-font loading; use the plain L0 role kit without `font_src` on that release. | | `hub: the bundle exceeds the size limit`, with no report | The bundle is over 8 MiB. Shrink or drop images and fonts. | -| `check` or `hub scan` on a signed bundle: `publisher key "…" is not registered with this hub` | Pass the publisher's public key: `tools/octo check --publisher-key =` (the same flag works for `hub scan`). | -| `card-host: refused: no signature verifier is installed` | `card-host` does not run signed bundles; test the unsigned copy and sign last. | +| Optional legacy Ed25519 `check` or `hub scan` on a signed bundle: `publisher key "…" is not registered with this hub` | Pass the publisher's public key: `tools/octo check --publisher-key =` (the same flag works for `hub scan`). | +| `card-host: refused: no signature verifier is installed` | `card-host` does not run sealed attested/signed releases; test editable unsigned source, then use a compatible Store host for the admitted release. | | `hub scan … --packet build/review.json` prints `hub: build/review.json: No such file or directory (os error 2)` | `hub` does not create the packet's directory. Run `mkdir -p build` first. | | `hub check --help` prints `hub: No such file or directory (os error 2)` | Your `hub` predates App Hub's current `main`, where `--help` prints the usage. Rebuild it (§2), or run `hub` with no arguments. | | Any other gate refusal | App Hub's [Common refusals and how to fix them](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#common-refusals-and-how-to-fix-them). | diff --git a/docs/QUICKSTART.zh-CN.md b/docs/QUICKSTART.zh-CN.md index a3630468..d597fda7 100644 --- a/docs/QUICKSTART.zh-CN.md +++ b/docs/QUICKSTART.zh-CN.md @@ -314,27 +314,45 @@ my-notes 0.1.0 — PASSED grants: capabilities {"storage"}, hosts {}, storage 16777216 bytes, agent none ``` -在人工为应用包签名之前,出现未签名警告是正常的。在人工填写发布者字段之前,占位提示会一直存在。 +开发可编辑源码期间,出现未签名警告是正常的。在人工填写发布者字段之前,占位提示会一直存在。 要检查版本是否已经发布过,加上 App Hub 的签名目录:`tools/octo check --catalog /OctoSense-App-Hub/catalog.json`。如果版本号已经用过,准入检查会拒绝并输出 `[refused] version: version 0.1.0 of is already published; publish a new version`。 -`check` 会先为未签名的应用包重新写入摘要。如果你在最后一次 `check` 之后又修改了应用包,却没有重新运行就 commit,commit 中的摘要就是过期的:审核人员直接运行 `hub check` 时,会以 `[refused] digest` 拒绝它。每次 commit 之前,都把 `tools/octo check` 作为最后一步;提交之前,在发布 tag 的全新克隆上直接运行 `hub check`([SUBMITTING §6](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#6-冻结并验证发布))。 +`check` 会先为未签名的应用包重新写入摘要。如果你在最后一次 `check` 之后又修改了应用包,却没有重新运行就 commit,commit 中的摘要就是过期的:审核人员直接运行 `hub check` 时,会以 `[refused] digest` 拒绝它。每次源码 commit 之前,都把 `tools/octo check` 作为最后一步。GitHub 工作流会另行生成并验证封存的 release pack(§10);可编辑的 tag 源码不包含这个证明。 ## 9. 在 OctoSense 手机上运行 目前的情况: - **无法把任意应用包侧载到普通 OctoSense 手机上。** 手机商店读取内置的 Hub 地址(`DEFAULT_HUB`,即 `raw.githubusercontent.com/OctoSense-org/OctoSense-App-Hub/main/`),并且只信任编译进构建的信任锚(App Hub 的根公钥)。`OCTOSENSE_HUB` 和 `OCTOSENSE_HUB_ANCHOR`(镜像目录或 URL,及其信任锚)是环境变量,Android 启动器不会设置它们;也没有找到在设备上设置它们的选项。**在设备上未验证。** -- **最接近真实情况的路径在桌面端:** 用你自己的一次性信任锚把应用发布到本地签名目录,再用 App Hub 的商店安装;这个商店运行的安装代码与手机上的相同([PUBLISHING §4](PUBLISHING.zh-CN.md#4-在本地演练商店流程))。OctoSense 桌面端 Shell 同样读取 `OCTOSENSE_HUB` 和 `OCTOSENSE_HUB_ANCHOR`;它的商店会从这个签名目录安装你的应用,并在 Shell 的 Card runner 中打开。 +- **桌面端的可选旧格式测试路径:** 用你自己的一次性信任锚把应用发布到本地签名目录,再用 App Hub 的商店安装;这个商店运行的安装代码与手机上的相同([PUBLISHING §4](PUBLISHING.zh-CN.md#4-在本地演练商店流程))。OctoSense 桌面端 Shell 同样读取 `OCTOSENSE_HUB` 和 `OCTOSENSE_HUB_ANCHOR`;它的商店会从这个签名目录安装你的应用,并在 Shell 的 Card runner 中打开。 - **第一方应用**作为系统应用进入手机:应用包位于 [OctoSense `apps/`](https://github.com/OctoSense-org/OctoSense/tree/main/apps),列在 Shell 的 `system-apps.json` 中(手机上是 OctoSense 的 `phone/system-apps.json`),由 App Hub 的 `crates/app-hub-app/build.rs` 打包,再经过 Home 或 ROM 构建。这条路径用于 OctoSense 维护的 `os.*` 应用,不用于商店应用。 - **连接账户的应用**(`auth`)无法安装到手机上:目前没有任何已发布的手机版本接受 `auth` 能力。 -- **发布之后**,你的应用会通过签名目录出现在每台手机的商店中。 +- **Hub 准入之后**,只有兼容宿主才能安装应用。已发布手机版本不支持 `auth` 和 `publisher-github-v1`;目录可见不等于运行时兼容。 Android 版 `card-host` 不编译远程控制桥。在手机上,请用 OctoSense 测试构建中的 App Studio 工具操作应用([MODEL-VALIDATION](MODEL-VALIDATION.zh-CN.md#选择测试方式)),而不是 `tools/octo`。 ## 10. 发布 -[PUBLISHING](PUBLISHING.zh-CN.md) 介绍如何把应用包从这里推进到待签名状态:定稿清单和商店信息、截取真实截图、通过准入检查、回答审核问题,以及本地商店演练。之后由人工按照[向 App Hub 提交应用](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md)签名、打 tag 并提交。`tools/octo package-help` 会输出检查表。 +**开 App Hub 提交 issue 来请求发布。** 填写应用仓库、版本/commit、截图和权限。 +可以先开 issue,再补充经过验证的 release 产物。Hub 检查和管理员批准之后,目录才会提供应用。 + +完整流程见 [PUBLISHING](PUBLISHING.zh-CN.md)。测试源码后执行: + +```sh +tools/octo publish-github ~/apps/my-app +tools/octo package-help +``` + +审阅 `.github/workflows/publish-app.yml`,与已测试应用一起 commit,再推送新的 +`v` tag。GitHub Actions 会准备、证明、验证和打包,无需 +`publisher.key` 或开发者签名 secret。把成功工作流和确切的 release pack 附到 +提交 issue。安装工作流、创建 GitHub release 都不会自动提交或批准应用。 +日常更新使用同一身份下的新版本/新 tag。 + +此工作分支路径需要契约 1.8.0 / `publisher-github-v1`;兼容宿主版本尚待发布, +真实发布与安装尚未验证。旧宿主和 `card-host` 会拒绝封存的发布包。 +本地 Ed25519 商店演练是可选兼容路径,不是发布的必需步骤。 ## 故障排查 @@ -365,12 +383,12 @@ Android 版 `card-host` 不编译远程控制桥。在手机上,请用 OctoSen | `check`:`[refused] listing: listing names no platforms` | 商店信息的 `platforms` 为空,原始模板就是这样。在 `listing.json` 中列出你测试过的平台,或用 `tools/octo new … --platform …` 创建应用(§3)。 | | `check`:`[refused] identity: app id "…" ends in "…", which is reserved: …` | 修改 id 的最后一段(§3)。同样的检查结果还会在 `policy` 下再出现一次。 | | `check`:`[refused] contents: .DS_Store has extension "", which a bundle may not hold` | 删除这个文件:`find -name .DS_Store -delete`。其他扩展名未知的文件也必须移出 `bundle/`。 | -| `check`:`[refused] digest: the bundle hashes to …, the manifest claims …` | 上次写入摘要之后,字节发生了变化。未签名的应用包:再运行一次 `tools/octo check`。已签名的应用包:由人工重新写入摘要并签名。只在全新克隆上出现时:检出时转换了换行符(commit `new` 写入的 `.gitattributes`,见 §3),或者 commit 中的摘要已过期(§8)。 | +| `check`:`[refused] digest: the bundle hashes to …, the manifest claims …` | 上次写入摘要之后,字节发生了变化。未签名的应用包:再运行一次 `tools/octo check`。已封存的发布包:修复可编辑源码并生成新版本/新 tag,不要重新写入发布包的摘要。只在全新克隆上出现时:检出时转换了换行符(commit `new` 写入的 `.gitattributes`,见 §3),或者 commit 中的摘要已过期(§8)。 | | `check`:`[refused] assets: … contains https://…`(普通许可 `.txt` 或 `.md` 文件) | 从 App Hub #146 或更新版本重新构建 `hub`。普通文档 URL 可以通过检查;保留要求提供的许可声明。Agent 指引与结构化资源引用仍须单独检查。 | | `check`:`[refused] resource-invalid (…/font_src): not a portable bundle path: "makepad_widgets:resources/…"` | 当前 `hub` 接受内置 `Inter.ttf`、`LXGWWenKaiRegular.ttf`、`LXGWWenKaiBold.ttf` 的确切路径(§7);请重建旧版准入工具。其他字体要随应用打包并使用相对路径,例如 `assets/Body.ttf`。`desktop-v0.1.0-beta.2` 仍早于打包字体加载功能;这个版本请使用不设 `font_src` 的纯 L0 角色套件。 | | `hub: the bundle exceeds the size limit`,没有报告 | 应用包超过了 8 MiB。压缩或删除图片和字体。 | -| 对已签名的应用包运行 `check` 或 `hub scan`:`publisher key "…" is not registered with this hub` | 传入发布者公钥:`tools/octo check --publisher-key =`(`hub scan` 也可以用同一个参数)。 | -| `card-host: refused: no signature verifier is installed` | `card-host` 不运行已签名的应用包;请用未签名的副本测试,最后再签名。 | +| 可选旧版 Ed25519 路径,对已签名应用包运行 `check` 或 `hub scan`:`publisher key "…" is not registered with this hub` | 传入发布者公钥:`tools/octo check --publisher-key =`(`hub scan` 也可以用同一个参数)。 | +| `card-host: refused: no signature verifier is installed` | `card-host` 不运行封存的证明/签名发布包;先测试未签名的可编辑源码,准入后再用兼容 Store 宿主运行发布包。 | | `hub scan … --packet build/review.json` 输出 `hub: build/review.json: No such file or directory (os error 2)` | `hub` 不会创建审核包所在的目录。先运行 `mkdir -p build`。 | | `hub check --help` 输出 `hub: No such file or directory (os error 2)` | 你的 `hub` 比 App Hub 当前的 `main` 旧;在当前 `main` 中,`--help` 会输出用法。重新构建(§2),或不带参数运行 `hub`。 | | 准入检查的其他拒绝 | 见 App Hub 的[常见拒绝原因及修复](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#常见拒绝原因及修复)。 | diff --git a/flows/README.md b/flows/README.md index 475c7495..a2ef6711 100644 --- a/flows/README.md +++ b/flows/README.md @@ -47,9 +47,10 @@ Supporting code, not flows: - **Semantic and visual review.** A person (or a reviewer they name) checks the mapping against the source image and approves screenshots. A passing script is not a visual approval. - - **Signing with private keys.** Only the key holder runs `hub keygen` or - `hub sign-manifest`. Keys never enter the repository, the bundle, a - prompt or a log. + - **Publisher identity and release workflow.** Review the GitHub repository, + workflow and release tag before publication. New GitHub apps and routine + updates need no developer signing key. Manual Ed25519 signing is optional + compatibility; its private keys never enter a repo, bundle, prompt or log. - **Release and submission.** Tagging the release and opening the `Submit ` issue on OctoSense-App-Hub ([SUBMITTING §7](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#7-open-the-submission-issue)) @@ -64,8 +65,6 @@ Supporting code, not flows: ([QUICKSTART §2](../docs/QUICKSTART.md#2-build-hub-and-card-host)). - `APP_REPO`: the absolute path of the app's repository, which holds `bundle/`. - - `APP_SIGNING_KEY` and `APP_PUBLISHER_ID`: the publisher's key file and - publisher id. Only the publisher sets them. If the build fails with `no variant … TextInputStateQuery`, see [The `card-host` build fails on `TextInputStateQuery`](../docs/QUICKSTART.md#the-card-host-build-fails-on-textinputstatequery). @@ -78,14 +77,17 @@ Supporting code, not flows: | 5 | Screenshot | in a second terminal, from this repository: `tools/octo shot 8141 "$APP_REPO/bundle/screenshots/01-main.png"`, then `curl -sS 127.0.0.1:8141/quit`. `shot` waits for the app's widgets and a settled frame. | the PNG shows the app, not an error frame (**HUMAN** review) | | 6 | Restamp and check | `"$HUB_BIN" stamp "$APP_REPO/bundle" && "$HUB_BIN" check "$APP_REPO/bundle" --allow-unsigned` | only the unsigned warning remains | | 7 | Review questions | `mkdir -p "$APP_REPO/build" && "$HUB_BIN" scan "$APP_REPO/bundle" --packet "$APP_REPO/build/review.json"` | the packet is written and its questions are answered in writing: seven, or eight when the bundle ships `tools.json`, `AGENT.md` or skills | - | 8 | Sign (**HUMAN**) | `"$HUB_BIN" sign-manifest "$APP_REPO/bundle" --key "$APP_SIGNING_KEY" --key-id "$APP_PUBLISHER_ID"`, last, after every other change | `"$HUB_BIN" check "$APP_REPO/bundle" --publisher-key "$APP_PUBLISHER_ID=$("$HUB_BIN" pubkey "$APP_SIGNING_KEY")"` passes | - | 9 | Release and submit (**HUMAN**) | commit, tag, run `hub check` on a fresh clone of the tag, then open a `Submit ` issue ([SUBMITTING §6–7](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#6-freeze-and-verify-the-release)) | `hub check` passes on the fresh clone, and the issue is open | + | 8 | Request publication (**HUMAN**, may happen earlier) | Open `Submit ` on App Hub with repo/version/commit, screenshots and permissions | The issue records the request; missing release artifacts can be added later | + | 9 | Prepare release (**HUMAN** for public actions) | `tools/octo publish-github "$APP_REPO"`; review/commit tested source and workflow, then push a new `v` tag | GitHub `publisher-verify` and `publisher-pack` succeed; attach release/pack/digest to the issue | + | 10 | Hub review | Hub checks the exact candidate; administrator reviews and approves it | Authenticated catalog publication completes; a GitHub release alone is not approval | - `card-host` refuses signed manifests, so take screenshots before signing. - This repository's [docs/PUBLISHING.md](../docs/PUBLISHING.md) walks steps - 1–7 for script apps. App Hub's + `card-host` refuses sealed releases, so test/capture editable source first. + The new workflow needs contract 1.8.0 / `publisher-github-v1`; live publishing + and compatible-host installation remain unverified, with a compatible + release pending. These are pass conditions, not claimed test results. + This repository's [docs/PUBLISHING.md](../docs/PUBLISHING.md) covers the flow. App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) - covers signing and submission, and its + covers the submission issue and review, and its [PUBLISHING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.md) is the reference for every gate rule. 5. **Purchased assets stay private.** Never share purchased design assets or diff --git a/flows/README.zh-CN.md b/flows/README.zh-CN.md index 664482ad..c6f31aa9 100644 --- a/flows/README.zh-CN.md +++ b/flows/README.zh-CN.md @@ -29,14 +29,13 @@ 3. **人工检查点。** 标记为 **HUMAN** 的步骤是 Agent 必须停下的地方:报告已准备好的内容,然后等待人来处理。检查点包括: - **使用付费生成器生成图像。** 由人运行生成器(或明确授权这笔花费),并提供原始输出和确切的提示词。 - **语义与视觉评审。** 由人(或其指定的评审人)对照源图检查映射,并批准截图。脚本通过不等于视觉批准。 - - **用私钥签名。** 只有密钥持有人才能运行 `hub keygen` 或 `hub sign-manifest`。密钥永远不进入仓库、应用包、提示词或日志。 + - **发布者身份与发布工作流。** 发布前审阅 GitHub 仓库、工作流和 tag。新 GitHub 应用及日常更新无需开发者签名密钥。手动 Ed25519 只是可选兼容路径,其私钥永不进入仓库、应用包、提示词或日志。 - **发布与提交。** 为发布打 tag,以及在 OctoSense-App-Hub 开 `Submit ` issue([SUBMITTING §7](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#7-开提交-issue)),都由人决定。 - 各流程特有的检查点(例如购买 Sketch 或设计套件)列在该流程的步骤表中。 4. **统一的交接。** 每个应用流程都以相同的方式结束。先设置这些变量: - `HUB_BIN` 和 `CARD_HOST_BIN`:`hub` 和 `card-host` 程序的路径。在 [OctoSense-App-Hub](https://github.com/OctoSense-org/OctoSense-App-Hub) 中用 `cargo build --release -p octosense-card-host -p octosense-app-hub` 构建([QUICKSTART §2](../docs/QUICKSTART.zh-CN.md#2-构建-hub-和-card-host))。 - `APP_REPO`:应用仓库的绝对路径,`bundle/` 就在其中。 - - `APP_SIGNING_KEY` 和 `APP_PUBLISHER_ID`:发布者的密钥文件和发布者 id,只由发布者本人设置。 如果构建失败并提示 `no variant … TextInputStateQuery`,请看 [构建 `card-host` 时报 `TextInputStateQuery` 错误](../docs/QUICKSTART.zh-CN.md#构建-card-host-时报-textinputstatequery-错误)。 @@ -49,10 +48,11 @@ | 5 | 截图 | 在另一个终端中、在本仓库目录下:`tools/octo shot 8141 "$APP_REPO/bundle/screenshots/01-main.png"`,然后 `curl -sS 127.0.0.1:8141/quit`。`shot` 会等应用的控件出现、画面稳定后再截图。 | PNG 显示的是应用,而不是错误画面(**HUMAN** 评审) | | 6 | 重新写入摘要并检查 | `"$HUB_BIN" stamp "$APP_REPO/bundle" && "$HUB_BIN" check "$APP_REPO/bundle" --allow-unsigned` | 只剩下未签名警告 | | 7 | 审核问题 | `mkdir -p "$APP_REPO/build" && "$HUB_BIN" scan "$APP_REPO/bundle" --packet "$APP_REPO/build/review.json"` | 已生成审核包,问题都已书面回答:七个;应用包附带 `tools.json`、`AGENT.md` 或 skills 时为八个 | - | 8 | 签名(**HUMAN**) | `"$HUB_BIN" sign-manifest "$APP_REPO/bundle" --key "$APP_SIGNING_KEY" --key-id "$APP_PUBLISHER_ID"`,放在所有其他修改之后,最后执行 | `"$HUB_BIN" check "$APP_REPO/bundle" --publisher-key "$APP_PUBLISHER_ID=$("$HUB_BIN" pubkey "$APP_SIGNING_KEY")"` 通过 | - | 9 | 发布并提交(**HUMAN**) | commit 代码、打 tag,在 tag 的全新克隆上运行 `hub check`,然后开 `Submit ` issue([SUBMITTING §6–7](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md#6-冻结并验证发布)) | 全新克隆上的 `hub check` 通过,issue 已开出 | + | 8 | 请求发布(**HUMAN**,可以提前) | 在 App Hub 开 `Submit `,附仓库/版本/commit、截图和权限 | issue 记录发布意图;之后可补充 release 产物 | + | 9 | 准备发布包(公开操作需 **HUMAN** 授权) | `tools/octo publish-github "$APP_REPO"`;审阅并 commit 已测试源码和工作流,再推送新的 `v` tag | GitHub 的 `publisher-verify` 和 `publisher-pack` 成功;把 release/pack/摘要补充到 issue | + | 10 | Hub 审核 | Hub 检查确切的候选版本,管理员审核并批准 | 经过身份验证的目录完成发布;GitHub release 本身不代表批准 | - `card-host` 拒绝运行已签名的清单,所以要在签名之前截图。本仓库的 [docs/PUBLISHING.zh-CN.md](../docs/PUBLISHING.zh-CN.md) 针对脚本应用讲解第 1–7 步。App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 讲解签名与提交,它的 [PUBLISHING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.zh-CN.md) 是每条准入规则的参考。 + `card-host` 拒绝封存的发布包,所以先测试可编辑源码并截图。新工作流需要契约 1.8.0 / `publisher-github-v1`,真实发布与兼容宿主安装尚未验证,兼容版本尚待发布。上表是通过条件,不是已完成的测试结果。本仓库的 [docs/PUBLISHING.zh-CN.md](../docs/PUBLISHING.zh-CN.md) 讲解完整流程。App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md) 讲解提交 issue 和审核,它的 [PUBLISHING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.zh-CN.md) 是每条准入规则的参考。 5. **购买的素材不外传。** 不要把购买的设计素材或本地日志当作通用示例分享。 ## 清理本地存储 diff --git a/flows/script-app/FLOW.md b/flows/script-app/FLOW.md index e3719d55..99f48ce9 100644 --- a/flows/script-app/FLOW.md +++ b/flows/script-app/FLOW.md @@ -74,8 +74,14 @@ runs, and tie the final evidence to the tested source. ## Hand-off Continue with [docs/PUBLISHING.md §3.6](../../docs/PUBLISHING.md#36-publisher-key--human). -The publisher key, signing, the release tag and the submission are **HUMAN** -steps, which App Hub's -[SUBMITTING §5–7](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md#5-produce-the-final-bytes) -describes. An agent drafts the submission text; a person signs, tags and -submits. +Open the App Hub submission issue to request publication; provide the +repository, version/commit, screenshots and permissions. It can precede the +release. `tools/octo publish-github "$A"` installs the tag workflow (`new` +already copies it); review/commit tested source and push a new version tag. +GitHub produces the attested release without a developer key. Add its successful +workflow and exact pack to the issue. Hub checks and administrator approval +control catalog publication, as App Hub's +[SUBMITTING](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) +describes. Workflow review, public release and submission are **HUMAN** steps +unless already authorized. Live keyless publishing and compatible-host +installation remain unverified; see the publishing guide's status. diff --git a/templates/script-app/AGENTS.md b/templates/script-app/AGENTS.md index ca087d06..1197c921 100644 --- a/templates/script-app/AGENTS.md +++ b/templates/script-app/AGENTS.md @@ -13,7 +13,7 @@ and do not invent requirements or APIs: - The language and every API an app may use: [SCRIPT-API](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/SCRIPT-API.md) - Capabilities: [CAPABILITIES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/CAPABILITIES.md) - Final bundle, screenshots and human checkpoints: [PUBLISHING](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/PUBLISHING.md) -- Signing and the submission issue: App Hub's [SUBMITTING](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) +- Publisher proof and the submission issue: App Hub's [SUBMITTING](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) Set `OCTO=/tools/octo`, then run this loop from this directory. The CLI lives in the harness repository, not here; on @@ -45,12 +45,26 @@ Follow these rules: structured resources retain their host/resource checks. - Capture screenshots from the unsigned bundle with `$OCTO shot`, and look at each one; never use a placeholder. -- Restamp after every edit (`$OCTO check` does it). Sign last; any edit - after signing needs a new stamp and a new signature. +- Restamp editable unsigned source after every edit (`$OCTO check` does it). + Never edit or restamp a sealed attested/signed release. Test and capture + screenshots before the publishing workflow seals the bundle. - Keys, `.local-state/`, `build/` and review packets never enter `bundle/` or Git. - Keep `.gitattributes` (`bundle/** -text`) committed: the digest covers every byte, and a line-ending conversion breaks it. -- Stop at human steps: publisher key, publisher details, platform claims, tag, - submission. +- Review `.github/workflows/publish-app.yml` before releasing. + `$OCTO publish-github .` installs it for an existing app; `new` copies it too. + No developer key or repository signing secret is required. Push a new + `v` tag of tested source to prepare, attest, verify and + pack it. The tag source and sealed release pack are different artifacts. +- Opening the App Hub issue is the request to publish; provide repository, + version/commit, screenshots and permissions, then add the verified release + pack when ready. A release alone does not submit or approve the app. +- Stop at human steps: publisher details, workflow review, platform claims, + tag and submission, unless already authorized in this session. Respect + actual approval; never fabricate it. Manual Ed25519 keys are only an + optional compatibility path, never a default setup step. +- `publisher-github-v1` needs contract 1.8.0 and a compatible Store host; + older hosts and `card-host` refuse the sealed release. Live publishing and + compatible-host installation remain unverified in this implementation. Add this app's own requirements, data sources and tests below. diff --git a/templates/script-app/README.md b/templates/script-app/README.md index 568ecc61..cb974c58 100644 --- a/templates/script-app/README.md +++ b/templates/script-app/README.md @@ -64,4 +64,23 @@ accident: when it creates the app, and the gate refuses them in an id you change later. +## Publishing the finished app + +`new` also installs `.github/workflows/publish-app.yml` from the harness's +reviewed publishing template; that workflow is outside `bundle/` and is not +shown as a template source file above. For an existing app, run +`tools/octo publish-github `. It does not push or submit anything. + +Open an App Hub issue to request publication, with repo/version/commit, +screenshots and permissions. Review/commit tested source and the workflow, then +push a new `v` tag. GitHub prepares, attests, verifies and packs +the release without a developer signing key. Add the successful release to the +issue; administrator approval still controls catalog publication. Routine +updates use new versions/tags under the same repository/owner/workflow identity. + +This path requires `publisher-github-v1` / contract 1.8.0. Live publishing and +compatible-host installation remain unverified, with a compatible host release +pending. See [PUBLISHING](../../docs/PUBLISHING.md); manual Ed25519 is optional +compatibility only. + Next: [docs/QUICKSTART.md](../../docs/QUICKSTART.md). diff --git a/templates/script-app/README.zh-CN.md b/templates/script-app/README.zh-CN.md index a1fb8c02..5c1c72a0 100644 --- a/templates/script-app/README.zh-CN.md +++ b/templates/script-app/README.zh-CN.md @@ -43,4 +43,19 @@ script-app/ - `platforms` 是空列表,准入检查会拒绝空列表(`listing names no platforms`)。`tools/octo new` 必须指定 `--platform`,并写入你传入的平台;每个平台写一次。传入平台只是声明,不是测试:发布之前,只保留你实际运行过的平台,并由人确认这一声明。在 Mac 上运行 `card-host` 测试的是 `macos`,不是 Android。 - 如果修改 id,它的最后一段不能是 App Hub 的保留名(`notes`、`weather`、`terminal` 等)。`tools/octo new` 创建应用时会拒绝保留名;之后改过的 id 若用了保留名,准入检查会拒绝。 +## 发布完成的应用 + +`new` 还会从开发工具集中经过评审的发布模板安装 `.github/workflows/publish-app.yml`; +它位于 `bundle/` 之外,不是上面列出的模板源文件。已有应用可运行 +`tools/octo publish-github `,命令不会推送或提交。 + +开 App Hub issue 来请求发布,附仓库/版本/commit、截图和权限。审阅并 commit +已测试源码和工作流,再推送新的 `v` tag。GitHub 会准备、证明、 +验证和打包,无需开发者签名密钥。把成功的 release 补充到 issue;目录发布仍需 +管理员批准。日常更新使用同一仓库、所有者和工作流身份下的新版本/新 tag。 + +此路径需要 `publisher-github-v1` / 契约 1.8.0。真实发布和兼容宿主安装尚未验证, +兼容宿主版本尚待发布。见 [PUBLISHING](../../docs/PUBLISHING.zh-CN.md);手动 Ed25519 +只保留为可选兼容路径。 + 下一步:[docs/QUICKSTART.zh-CN.md](../../docs/QUICKSTART.zh-CN.md)。 From e4e72f4073e442a370eb10cb12b79f46e93859c8 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:18:53 -0700 Subject: [PATCH 2/5] docs: explicitly select legacy catalogs for local rehearsals --- README.md | 3 ++- README.zh-CN.md | 2 +- docs/PUBLISHING.md | 8 +++++--- docs/PUBLISHING.zh-CN.md | 6 ++++-- docs/QUICKSTART.md | 3 ++- docs/QUICKSTART.zh-CN.md | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 353a82ae..dc5f6007 100644 --- a/README.md +++ b/README.md @@ -464,7 +464,8 @@ manifest policy. System apps are packed into the shell build from OctoSense's `apps/`; store apps are installed from the App Hub store out of the authenticated catalog. For an optional legacy rehearsal before submission, publish a test bundle into a local catalog with a throwaway trust anchor, -then point `OCTOSENSE_HUB` / `OCTOSENSE_HUB_ANCHOR` at that mirror. The +then set `OCTOSENSE_HUB_CATALOG=legacy` and point `OCTOSENSE_HUB` / +`OCTOSENSE_HUB_ANCHOR` at that mirror using a fresh app-data directory. The shell's store installs and opens the test app ([PUBLISHING §4](docs/PUBLISHING.md#4-rehearse-the-store-path-locally)). diff --git a/README.zh-CN.md b/README.zh-CN.md index 80dff55c..63d17780 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -279,7 +279,7 @@ OctoSense 每个 Shell 运行一个 octos Agent 内核,由用户在系统应 `on_render` 生成的控件与其他控件一样出现在 `/snap` 和 `/d` 中;应用稍后才添加的内容(来自定时器或响应)在绘制后才出现,请轮询 `/snap?q=` 等待它。`card-host` **不**注册任何宿主服务,所以类似 Mail 的应用在其中会得到 `no service answers "mail" on this device`。`card-host` 还会拒绝封存的证明/签名发布包:请在发布前测试可编辑源码并截图。 -**在 Shell 中。** OctoSense 桌面端 Shell 和手机 Home 通过 App Hub 的 Card runner(App Hub `crates/appstore` 中的 `card` 模块)运行应用,而不是 `card-host`;Card runner 执行同一套清单策略。系统应用从 OctoSense 的 `apps/` 打包进 Shell 构建;商店应用从 App Hub 商店根据签名目录安装。想在发布前在桌面端 Shell 中试用自己的应用:用一次性信任锚(一把测试用根密钥)把它发布到本地签名目录,再把桌面端 Shell 的 `OCTOSENSE_HUB` / `OCTOSENSE_HUB_ANCHOR` 指向该目录;Shell 的商店即可安装并打开该应用([PUBLISHING §4](docs/PUBLISHING.zh-CN.md#4-在本地演练商店流程))。 +**在 Shell 中。** OctoSense 桌面端 Shell 和手机 Home 通过 App Hub 的 Card runner(App Hub `crates/appstore` 中的 `card` 模块)运行应用,而不是 `card-host`;Card runner 执行同一套清单策略。系统应用从 OctoSense 的 `apps/` 打包进 Shell 构建;商店应用从 App Hub 商店根据签名目录安装。想在发布前在桌面端 Shell 中试用自己的应用:用一次性信任锚(一把测试用根密钥)把它发布到本地签名目录,使用新的应用数据目录,显式设置 `OCTOSENSE_HUB_CATALOG=legacy`,再把 `OCTOSENSE_HUB` / `OCTOSENSE_HUB_ANCHOR` 指向该镜像;Shell 的商店即可安装并打开该应用([PUBLISHING §4](docs/PUBLISHING.zh-CN.md#4-在本地演练商店流程))。 **目前在手机上**([QUICKSTART §9](docs/QUICKSTART.zh-CN.md#9-在-octosense-手机上运行)): diff --git a/docs/PUBLISHING.md b/docs/PUBLISHING.md index 16df39a9..b7d5f563 100644 --- a/docs/PUBLISHING.md +++ b/docs/PUBLISHING.md @@ -302,7 +302,9 @@ and their signatures are unchanged. in this section use Ed25519 publisher/catalog keys. They are not required by the GitHub publishing path and do not validate `publisher-github-v1`. Use an explicitly prepared legacy test bundle for this rehearsal, never restamp a -GitHub-attested release. +GitHub-attested release. Use `OCTOSENSE_HUB_CATALOG=legacy` explicitly for +this old-format mirror and a fresh app-data directory. A library that already +cached v2 refuses a legacy downgrade; it is not converted offline. Run the whole publish-and-install path on your own machine, signed with your own trust anchor (a throwaway root key in place of App Hub's), to see what a @@ -352,7 +354,7 @@ cd OctoSense && python3 tools/setup.py --cache .. ```sh cd /OctoSense -OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" \ +OCTOSENSE_HUB_CATALOG=legacy OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" \ OCTOSENSE_HOME="$APP/build/desktop-home" OCTOSENSE_APP_DATA="$APP/build/desktop-apps" \ MAKEPAD_REMOTE=8399 cargo run --release -p octosense ``` @@ -426,7 +428,7 @@ tree, and build the store in a second workspace: 4. Open the mirror in the store: ```sh - OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" OCTOSENSE_APP_DATA="$APP/build/store-data" \ + OCTOSENSE_HUB_CATALOG=legacy OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" OCTOSENSE_APP_DATA="$APP/build/store-data" \ MAKEPAD_REMOTE=8143 /OctoSense-App-Hub/target/release/appstore ``` diff --git a/docs/PUBLISHING.zh-CN.md b/docs/PUBLISHING.zh-CN.md index 955afead..d51da9dc 100644 --- a/docs/PUBLISHING.zh-CN.md +++ b/docs/PUBLISHING.zh-CN.md @@ -229,6 +229,8 @@ Hub 验证发布者证明和应用包,执行准入检查与审核,通过其 **可选的旧格式兼容演练。** 本节命令和历史结果使用 Ed25519 发布者/目录密钥, 不是 GitHub 发布的必需步骤,也不能验证 `publisher-github-v1`。请使用专门准备的 旧格式测试包,绝不要为附有 GitHub 证明的发布包重新写入摘要。 +此旧格式镜像需显式设置 `OCTOSENSE_HUB_CATALOG=legacy`,并使用新的应用数据目录。 +已经缓存 v2 的应用库拒绝降级到旧格式;不会离线转换。 在自己的机器上走一遍完整的发布和安装流程,用你自己的信任锚签名(以一把一次性根密钥代替 App Hub 的根密钥),看看设备上会发生什么。演练还会运行应用的宿主服务,这是 `card-host` 做不到的。镜像及其密钥放在 `build/` 下,绝不要放进 `bundle/`。 @@ -261,7 +263,7 @@ cd OctoSense && python3 tools/setup.py --cache .. ```sh cd /OctoSense -OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" \ +OCTOSENSE_HUB_CATALOG=legacy OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" \ OCTOSENSE_HOME="$APP/build/desktop-home" OCTOSENSE_APP_DATA="$APP/build/desktop-apps" \ MAKEPAD_REMOTE=8399 cargo run --release -p octosense ``` @@ -309,7 +311,7 @@ App Hub 的独立商店 `appstore` 不需要 Shell 也能从同一个镜像安 4. 在商店中打开镜像: ```sh - OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" OCTOSENSE_APP_DATA="$APP/build/store-data" \ + OCTOSENSE_HUB_CATALOG=legacy OCTOSENSE_HUB="$M" OCTOSENSE_HUB_ANCHOR="$ANCHOR" OCTOSENSE_APP_DATA="$APP/build/store-data" \ MAKEPAD_REMOTE=8143 /OctoSense-App-Hub/target/release/appstore ``` diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index de11b2ed..8e29dc98 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -551,7 +551,8 @@ What exists today: environment variables, which the Android launcher does not set; no on-device setting for them was found. **Unverified on a device.** - **An optional legacy test path is on the desktop:** publish into a local catalog - with your own throwaway anchor and install it with App Hub's store, + with your own throwaway anchor, explicitly set `OCTOSENSE_HUB_CATALOG=legacy` + with a fresh app-data directory, and install it with App Hub's store, which runs the same install code as a phone ([PUBLISHING §4](PUBLISHING.md#4-rehearse-the-store-path-locally)). The OctoSense desktop shell reads `OCTOSENSE_HUB` and `OCTOSENSE_HUB_ANCHOR` diff --git a/docs/QUICKSTART.zh-CN.md b/docs/QUICKSTART.zh-CN.md index d597fda7..3c69781f 100644 --- a/docs/QUICKSTART.zh-CN.md +++ b/docs/QUICKSTART.zh-CN.md @@ -325,7 +325,7 @@ my-notes 0.1.0 — PASSED 目前的情况: - **无法把任意应用包侧载到普通 OctoSense 手机上。** 手机商店读取内置的 Hub 地址(`DEFAULT_HUB`,即 `raw.githubusercontent.com/OctoSense-org/OctoSense-App-Hub/main/`),并且只信任编译进构建的信任锚(App Hub 的根公钥)。`OCTOSENSE_HUB` 和 `OCTOSENSE_HUB_ANCHOR`(镜像目录或 URL,及其信任锚)是环境变量,Android 启动器不会设置它们;也没有找到在设备上设置它们的选项。**在设备上未验证。** -- **桌面端的可选旧格式测试路径:** 用你自己的一次性信任锚把应用发布到本地签名目录,再用 App Hub 的商店安装;这个商店运行的安装代码与手机上的相同([PUBLISHING §4](PUBLISHING.zh-CN.md#4-在本地演练商店流程))。OctoSense 桌面端 Shell 同样读取 `OCTOSENSE_HUB` 和 `OCTOSENSE_HUB_ANCHOR`;它的商店会从这个签名目录安装你的应用,并在 Shell 的 Card runner 中打开。 +- **桌面端的可选旧格式测试路径:** 用你自己的一次性信任锚把应用发布到本地签名目录,显式设置 `OCTOSENSE_HUB_CATALOG=legacy` 并使用新的应用数据目录,再用 App Hub 的商店安装;这个商店运行的安装代码与手机上的相同([PUBLISHING §4](PUBLISHING.zh-CN.md#4-在本地演练商店流程))。OctoSense 桌面端 Shell 同样读取 `OCTOSENSE_HUB` 和 `OCTOSENSE_HUB_ANCHOR`;它的商店会从这个签名目录安装你的应用,并在 Shell 的 Card runner 中打开。 - **第一方应用**作为系统应用进入手机:应用包位于 [OctoSense `apps/`](https://github.com/OctoSense-org/OctoSense/tree/main/apps),列在 Shell 的 `system-apps.json` 中(手机上是 OctoSense 的 `phone/system-apps.json`),由 App Hub 的 `crates/app-hub-app/build.rs` 打包,再经过 Home 或 ROM 构建。这条路径用于 OctoSense 维护的 `os.*` 应用,不用于商店应用。 - **连接账户的应用**(`auth`)无法安装到手机上:目前没有任何已发布的手机版本接受 `auth` 能力。 - **Hub 准入之后**,只有兼容宿主才能安装应用。已发布手机版本不支持 `auth` 和 `publisher-github-v1`;目录可见不等于运行时兼容。 From 3999bac64fa655a13b47763bab9ba235c86ee5a8 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:33:44 -0700 Subject: [PATCH 3/5] Publish apps through GitHub provenance and issue review without developer keys --- AGENTS.md | 6 +- README.md | 10 +- README.zh-CN.md | 8 +- docs/CODE-WALKTHROUGH.md | 4 +- docs/PUBLISHING.md | 14 +- docs/PUBLISHING.zh-CN.md | 11 +- docs/QUICKSTART.md | 6 +- docs/QUICKSTART.zh-CN.md | 6 +- templates/script-app/AGENTS.md | 6 +- templates/script-app/bundle/main.splash | 4 +- templates/script-app/bundle/manifest.json | 2 +- tools/octo | 124 ++++++++++++++++-- tools/publish-app.template.yml | 153 ++++++++++++++++++++++ tools/publisher-toolchain.json | 5 + tools/test_github_publish.py | 146 +++++++++++++++++++++ 15 files changed, 466 insertions(+), 39 deletions(-) create mode 100644 tools/publish-app.template.yml create mode 100644 tools/publisher-toolchain.json create mode 100644 tools/test_github_publish.py diff --git a/AGENTS.md b/AGENTS.md index 793dad0e..6f933903 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -212,8 +212,10 @@ The gate checks some of these; reviewers and the shells hold you to the rest. publisher-proof verification. The workflow must pass `publisher-verify` and `publisher-pack`; no restamping after attestation. `card-host` refuses sealed releases. Contract 1.8.0 / `publisher-github-v1` support and a - compatible host are required; live publishing and installation remain - unverified until separately exercised. See [PUBLISHING §3.6](docs/PUBLISHING.md#36-publisher-key--human). + compatible host are required. Real GitHub publishing and native Store + install/update checks passed with an isolated test catalog; shipped-shell + and phone installation remain unverified, and a compatible release is pending. + See [PUBLISHING §3.6](docs/PUBLISHING.md#36-publisher-key--human). - **An issue requests publication.** Include repository, version/commit, screenshots and permissions; it may precede the release. Attach the successful workflow and exact release pack when ready. The Hub checks it, diff --git a/README.md b/README.md index dc5f6007..215f10dc 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Use `main` of each repository. | The gate (`hub`) | App Hub `main`, app contract 1.7 (the manifest rules `hub` enforces), which admits the connected-account capabilities `auth`, `github`, `gmail` and `gcalendar`, the [Host API v1](docs/HOST-API-V1.md) declarations and the `wasm` capability. | | `card-host` | App Hub `main`. It runs one bundle and serves no host services except `runtime` discovery. Build it as the [Quick path](#quick-path) shows. | | The shells | OctoSense `main`; its latest desktop release is `desktop-v0.1.0-beta.2`. The desktop shell and the phone's Home run system and store apps; the desktop also serves connected accounts and app agents' host-service tools. | -| GitHub publishing | Working-branch implementation: contract 1.8.0 / `publisher-github-v1`, no developer key. Live attestation and compatible-host installation remain unverified; compatible release pending. | +| GitHub publishing | Contract 1.8.0 / `publisher-github-v1`, no developer key. Real releases and native Store install/update checks passed with an isolated test catalog; shipped-shell and phone installation remain unverified, compatible release pending. | | Submission | An issue on OctoSense-App-Hub, as App Hub's [SUBMITTING.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.md) describes. | | Installing your own bundle on a phone | Not supported. See [Running an app](#running-an-app). | @@ -539,9 +539,11 @@ channel or automatic approval. See App Hub's Routine updates use new versions/tags from the same repository/owner/workflow. Never move a released tag or hand-edit the Hub's admitted catalog/artifacts. -This working-branch path requires contract 1.8.0 / `publisher-github-v1`. -Live publisher attestation and compatible-host installation remain unverified; -a compatible host release is pending. Manual Ed25519 signing is optional +This path requires contract 1.8.0 / `publisher-github-v1`. Real GitHub releases +and native Store install/update checks passed with an isolated test catalog +([evidence](docs/PUBLISHING.md#36-publisher-key--human)). Shipped-shell and phone +installation remain unverified; a compatible host release is pending. +Manual Ed25519 signing is optional compatibility, and old reference releases remain unchanged. ## Repository layout diff --git a/README.zh-CN.md b/README.zh-CN.md index 63d17780..cd11c773 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -98,7 +98,7 @@ App Hub 签名目录中有三个应用通过宿主使用用户的 GitHub 或 Goo | 准入检查(`hub`) | App Hub `main`,应用契约 1.7(即 `hub` 执行的清单规则),准入连接账户所需的 `auth`、`github`、`gmail` 和 `gcalendar` 能力、[Host API v1](docs/HOST-API-V1.zh-CN.md) 的各项声明,以及 `wasm` 能力。 | | `card-host` | App Hub `main`。它运行单个应用包,除了用于发现宿主 API 的 `runtime`,不提供任何宿主服务。构建方法见[快速上手](#快速上手)。 | | Shell | OctoSense `main`;桌面端最新的发布版本是 `desktop-v0.1.0-beta.2`。桌面端 Shell 和手机 Home 运行系统应用与商店应用;桌面端还支持已连接账户,并为应用 Agent 提供宿主服务工具。 | -| GitHub 发布 | 工作分支中的实现:应用契约 1.8.0 / `publisher-github-v1`,无需开发者密钥。真实证明和兼容宿主安装尚未验证,兼容版本尚待发布。 | +| GitHub 发布 | 应用契约 1.8.0 / `publisher-github-v1`,无需开发者密钥。真实发布及原生 Store 的安装、更新检查已在隔离测试目录中通过;已发行 Shell 和手机中的安装仍未验证,兼容版本尚待发布。 | | 提交途径 | 在 OctoSense-App-Hub 开 issue,见 App Hub 的 [SUBMITTING.zh-CN.md](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/SUBMITTING.zh-CN.md)。 | | 在手机上安装自己的应用包 | 不支持。见[运行应用](#运行应用)。 | @@ -324,8 +324,10 @@ curl -s 127.0.0.1:8161/quit; curl -s 127.0.0.1:8162/quit 日常更新使用同一仓库、所有者和工作流下的新版本/新 tag。不要移动已发布 tag, 也不要手改 Hub 已准入的目录和产物。 -此工作分支路径需要契约 1.8.0 / `publisher-github-v1`。真实发布证明和兼容宿主安装 -尚未验证,兼容宿主版本尚待发布。手动 Ed25519 签名仅是可选兼容路径,旧参考版本保持原样。 +此路径需要契约 1.8.0 / `publisher-github-v1`。真实 GitHub 发布及原生 Store 的安装、 +更新检查已在隔离测试目录中通过([证据](docs/PUBLISHING.zh-CN.md#36-发布者密钥human))。 +已发行 Shell 和手机中的安装仍未验证,兼容宿主版本尚待发布。 +手动 Ed25519 签名仅是可选兼容路径,旧参考版本保持原样。 ## 仓库结构 diff --git a/docs/CODE-WALKTHROUGH.md b/docs/CODE-WALKTHROUGH.md index 48b06cba..306a32a7 100644 --- a/docs/CODE-WALKTHROUGH.md +++ b/docs/CODE-WALKTHROUGH.md @@ -125,7 +125,9 @@ contains the sealed pack, canonical manifest and release receipt. The developer supplies no private signing key; GitHub supplies the job/OIDC identity. `publisher-github-v1` needs contract 1.8.0 and a compatible Store verifier. -Live proof and installation remain unverified; a compatible release is pending. +Real GitHub proof and native Store install/update checks passed with an isolated +test catalog ([evidence](PUBLISHING.md#36-publisher-key--human)); shipped-shell +and phone installation remain unverified, and a compatible release is pending. Opening an App Hub issue expresses publication intent and can happen first; the workflow provides verifiable bytes for that issue. Hub checks, administrator approval and authenticated catalog publication remain separate steps. diff --git a/docs/PUBLISHING.md b/docs/PUBLISHING.md index b7d5f563..aada9cf8 100644 --- a/docs/PUBLISHING.md +++ b/docs/PUBLISHING.md @@ -215,11 +215,15 @@ Actions attestation. You do not generate `publisher.key` or add a signing secret to the repository. Review the publisher details and the workflow before releasing under your account. -**Availability:** this path is being implemented with app contract 1.8.0 and -`publisher-github-v1`. Live publisher attestation and installation of such a -release remain unverified; a compatible OctoSense host release is pending. -Older hosts refuse this requirement. The installer fails closed until its -`publisher-toolchain.json` names a reviewed, immutable App Hub revision. +**Availability:** this path requires app contract 1.8.0 and +`publisher-github-v1`. Two real GitHub releases passed attestation and the native +Store's install, verified-launch, update, withdrawal and tamper checks +([acceptance receipt](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/reviews/github-publisher-v1/acceptance.json)). +Those Store checks used an isolated test catalog; the fixture has no Hub +submission or admission. Installation in the shipped shell and on a phone +remains unverified, and a compatible OctoSense host release is pending. +Older hosts refuse this requirement. `publisher-toolchain.json` must name a +reviewed, immutable App Hub revision; the installer refuses a missing or moving pin. For an existing editable app directory, install the workflow from Design Flow: diff --git a/docs/PUBLISHING.zh-CN.md b/docs/PUBLISHING.zh-CN.md index d51da9dc..75149552 100644 --- a/docs/PUBLISHING.zh-CN.md +++ b/docs/PUBLISHING.zh-CN.md @@ -156,10 +156,13 @@ no --reviewer given; the packet holds 7 questions for one `publisher.key`,也无需添加仓库签名 secret。用自己的账户发布前,请审阅发布者 信息和工作流。 -**可用状态:** 此路径正在实现,使用应用契约 1.8.0 和 `publisher-github-v1`。 -真实 GitHub 发布者证明及其安装尚未验证,兼容的 OctoSense 宿主版本尚待发布。 -旧宿主会拒绝这个要求。`publisher-toolchain.json` 尚未指定经过评审的不可变 -App Hub commit 时,安装命令会拒绝继续,不会改用浮动版本。 +**可用状态:** 此路径需要应用契约 1.8.0 和 `publisher-github-v1`。 +两个真实 GitHub release 已通过证明验证,以及原生 Store 的安装、启动校验、更新、 +撤回和篡改拒绝检查([验收记录](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/reviews/github-publisher-v1/acceptance.json))。 +这些 Store 检查使用隔离的测试目录;测试应用没有提交或获准进入 Hub。 +已发行 Shell 和手机中的安装仍未验证,兼容的 OctoSense 宿主版本尚待发布。 +旧宿主会拒绝这个要求。`publisher-toolchain.json` 必须指定经过评审的不可变 +App Hub commit;安装命令会拒绝缺失或浮动的版本。 对已有的可编辑应用目录,在 Design Flow 中安装工作流: diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 8e29dc98..a6689cff 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -595,8 +595,10 @@ Attach the successful workflow and exact release pack to the submission issue. Neither installing the workflow nor creating a GitHub release submits or approves the app. Routine updates use new versions/tags from the same identity. -This working-branch path needs contract 1.8.0 / `publisher-github-v1`; a compatible -host release is pending, and live publishing/installation remain unverified. +This path needs contract 1.8.0 / `publisher-github-v1`. Real publishing and native +Store install/update checks passed with an isolated test catalog +([evidence](PUBLISHING.md#36-publisher-key--human)). Shipped-shell and phone +installation remain unverified; a compatible host release is pending. Older hosts and `card-host` refuse the sealed release. The local Ed25519 store rehearsal is optional compatibility, not a required publishing step. diff --git a/docs/QUICKSTART.zh-CN.md b/docs/QUICKSTART.zh-CN.md index 3c69781f..7c6ffd83 100644 --- a/docs/QUICKSTART.zh-CN.md +++ b/docs/QUICKSTART.zh-CN.md @@ -350,8 +350,10 @@ tools/octo package-help 提交 issue。安装工作流、创建 GitHub release 都不会自动提交或批准应用。 日常更新使用同一身份下的新版本/新 tag。 -此工作分支路径需要契约 1.8.0 / `publisher-github-v1`;兼容宿主版本尚待发布, -真实发布与安装尚未验证。旧宿主和 `card-host` 会拒绝封存的发布包。 +此路径需要契约 1.8.0 / `publisher-github-v1`。真实发布及原生 Store 的安装、更新 +检查已在隔离测试目录中通过([证据](PUBLISHING.zh-CN.md#36-发布者密钥human))。 +已发行 Shell 和手机中的安装仍未验证,兼容宿主版本尚待发布。 +旧宿主和 `card-host` 会拒绝封存的发布包。 本地 Ed25519 商店演练是可选兼容路径,不是发布的必需步骤。 ## 故障排查 diff --git a/templates/script-app/AGENTS.md b/templates/script-app/AGENTS.md index 1197c921..067d85b4 100644 --- a/templates/script-app/AGENTS.md +++ b/templates/script-app/AGENTS.md @@ -64,7 +64,9 @@ Follow these rules: actual approval; never fabricate it. Manual Ed25519 keys are only an optional compatibility path, never a default setup step. - `publisher-github-v1` needs contract 1.8.0 and a compatible Store host; - older hosts and `card-host` refuse the sealed release. Live publishing and - compatible-host installation remain unverified in this implementation. + older hosts and `card-host` refuse the sealed release. Real GitHub publishing + and native Store install/update checks passed with an isolated test catalog. + Shipped-shell and phone installation remain unverified; a compatible release + is pending. Follow the linked publishing guide for current evidence. Add this app's own requirements, data sources and tests below. diff --git a/templates/script-app/bundle/main.splash b/templates/script-app/bundle/main.splash index 72e7de88..007622f5 100644 --- a/templates/script-app/bundle/main.splash +++ b/templates/script-app/bundle/main.splash @@ -35,8 +35,8 @@ SolidView{width: Fill height: Fill flow: Down padding: 16 spacing: 12 draw_bg.co draw_bg +: {color: #xf2f2f7 color_hover: #xf2f2f7 color_focus: #xf2f2f7 color_empty: #xf2f2f7 border_radius: 10.0} draw_text +: {color: ink color_hover: ink color_focus: ink color_empty: secondary color_empty_hover: secondary}} ButtonFlat{text: "Add" height: 40 padding: Inset{left: 18 right: 18} on_click: || add() - draw_bg +: {border_radius: 20.0 color: #x007aff color_hover: #x0a84ff color_down: #x0062cc border_size: 0.0} - draw_text +: {color: #xffffff color_hover: #xffffff color_down: #xffffff}} + draw_bg +: {border_radius: 20.0 color: #x007aff color_hover: #x0a84ff color_down: #x0062cc color_focus: #x007aff border_size: 1.0 border_color: #x007aff border_color_hover: #x0a84ff border_color_down: #x0062cc border_color_focus: #x007aff} + draw_text +: {color: #xffffff color_hover: #xffffff color_down: #xffffff color_focus: #xffffff}} } list := ScrollYView{width: Fill height: Fill flow: Down spacing: 8 on_render: || { if notes.len() == 0 { diff --git a/templates/script-app/bundle/manifest.json b/templates/script-app/bundle/manifest.json index a5fce1f5..c6a5d0d1 100644 --- a/templates/script-app/bundle/manifest.json +++ b/templates/script-app/bundle/manifest.json @@ -4,7 +4,7 @@ ], "id": "my-notes", "integrity": { - "bundle_blake3": "afd7482b98daef48b79b28f4dc3215ce2fec8393b549f4d40608cad2a1b5d476" + "bundle_blake3": "3540c35d1531a8f2883a589687fc84492ee0a64e17d4167294a0841bd07bd998" }, "name": "My Notes", "schema": 1, diff --git a/tools/octo b/tools/octo index 578c112a..ad44ac67 100755 --- a/tools/octo +++ b/tools/octo @@ -10,6 +10,7 @@ exactly what `hub check` prints and exits with its status. tools/octo run [--port N] [--hidden] [--system] [--detach] [--no-stamp] [--app-data DIR] tools/octo shot tools/octo check [hub check flags ...] + tools/octo publish-github [--replace] tools/octo package-help Binaries are found, in order, from $OCTO_HUB / $OCTO_CARD_HOST, then @@ -27,6 +28,7 @@ import signal import socket import subprocess import sys +import tempfile import time import urllib.error import urllib.request @@ -47,6 +49,57 @@ PLATFORMS = ("android", "ios", "macos", "windows", "linux", "openharmony", "web" PNG_MAGIC = b"\x89PNG\r\n\x1a\n" +def sealed_release(manifest): + integrity = manifest.get("integrity") or {} + # Typed unsigned manifests may contain signature:null. Any non-null + # signature, GitHub field or declared GitHub seal must remain untouched. + return (integrity.get("signature") is not None or "github" in integrity + or "publisher-github-v1" in (manifest.get("requires") or [])) + + +def publisher_workflow(): + """Use the reviewed immutable Hub toolchain, never a moving branch.""" + config = json.loads((REPO / "tools/publisher-toolchain.json").read_text()) + revision = config.get("revision") + if (config.get("schema") != 1 + or config.get("repository") != "OctoSense-org/OctoSense-App-Hub" + or not isinstance(revision, str) + or re.fullmatch(r"[0-9a-f]{40}", revision) is None): + raise ValueError("GitHub publishing needs a reviewed immutable App Hub toolchain revision") + template = (REPO / "tools/publish-app.template.yml").read_text() + if template.count("__HUB_REVISION__") != 1: + raise ValueError("GitHub publishing workflow template is invalid") + return template.replace("__HUB_REVISION__", revision) + + +def install_publisher_workflow(app, content, replace=False): + """Never follow an app's workflow symlinks or overwrite custom automation.""" + folder = app / ".github" / "workflows" + target = folder / "publish-app.yml" + for path in (app / ".github", folder, target): + if path.is_symlink(): + raise ValueError("Refusing a symlink in the publishing workflow path") + if target.exists(): + if target.is_file() and target.read_text() == content: + return False + if not replace: + raise ValueError(".github/workflows/publish-app.yml already exists; review it before using --replace") + if not target.is_file(): + raise ValueError(".github/workflows/publish-app.yml is not a regular file") + folder.mkdir(parents=True, exist_ok=True) + temporary = None + try: + with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", newline="\n", dir=folder, delete=False) as stream: + temporary = Path(stream.name) + stream.write(content) + temporary.chmod(0o644) + os.replace(temporary, target) + finally: + if temporary is not None: + temporary.unlink(missing_ok=True) + return True + + # --------------------------------------------------------------------- finding def hub_repo(): """The App Hub checkout: $OCTOSENSE_APP_HUB, else a sibling of this repo.""" @@ -197,6 +250,11 @@ def cmd_new(args): if app_id in RESERVED_NAMES or namespace in RESERVED_NAMES: die(f"id {app_id!r} uses reserved native/host namespace {namespace!r}; choose an app-specific name") name = args.name or "My Notes" + # Resolve the release tooling before creating a partially usable project. + try: + workflow = publisher_workflow() + except (OSError, ValueError) as error: + die(str(error)) dest.mkdir(parents=True, exist_ok=True) shutil.copytree(TEMPLATE / "bundle", dest / "bundle") @@ -221,6 +279,7 @@ def cmd_new(args): main = dest / "bundle" / "main.splash" if args.name: main.write_text(main.read_text().replace('text: "My Notes"', "text: " + json.dumps(name), 1)) + install_publisher_workflow(dest, workflow) hub, _, _ = find_binary("hub", "OCTO_HUB") if hub: @@ -348,6 +407,12 @@ def cmd_run(args): bundle = Path(args.bundle).expanduser().resolve() if not (bundle / "manifest.json").is_file(): die(f"{bundle} has no manifest.json; pass the bundle directory (…/bundle)") + try: + manifest = json.loads((bundle / "manifest.json").read_text()) + if sealed_release(manifest): + die("card-host cannot run a sealed release. Use the editable source bundle or install the release in a compatible OctoSense host.") + except (OSError, ValueError) as error: + die(str(error)) card_host = need("card-host", "OCTO_CARD_HOST") # card-host would start anyway, without a bridge, and every curl would # silently drive whatever already holds the port (#119). @@ -471,9 +536,9 @@ def cmd_check(args, extra): die(f"{bundle} has no manifest.json") hub = need("hub", "OCTO_HUB") manifest = json.loads((bundle / "manifest.json").read_text()) - signed = bool((manifest.get("integrity") or {}).get("signature")) + signed = sealed_release(manifest) if signed: - print("octo: the manifest is signed; not restamping (a restamp would invalidate the signature).") + print("octo: the manifest carries signing metadata; checking the exact bytes without restamping.") else: r = subprocess.run([str(hub), "stamp", str(bundle)], capture_output=True, text=True) if r.returncode != 0: @@ -501,6 +566,31 @@ def cmd_check(args, extra): return r.returncode +# -------------------------------------------------------------- publish-github +def cmd_publish_github(args): + app = Path(args.dir).expanduser().resolve() + manifest_path = app / "bundle" / "manifest.json" + if not manifest_path.is_file(): + die("Expected an app directory containing bundle/manifest.json") + try: + manifest = json.loads(manifest_path.read_text()) + if sealed_release(manifest): + die("Use the editable source repository, not a sealed release bundle") + workflow = publisher_workflow() + changed = install_publisher_workflow(app, workflow, args.replace) + except (OSError, ValueError) as error: + die(str(error)) + print(("installed" if changed else "already current") + ": .github/workflows/publish-app.yml") + print("No publisher key or repository signing secret is required.") + print("Request Hub publication by opening an issue on OctoSense-org/OctoSense-App-Hub;") + print("include the repository, version/commit, screenshots and requested permissions.") + print("Review and commit this workflow with the tested app in its public GitHub repository.") + print("Then push a NEW tag v. GitHub checks and attests the app and creates its release assets.") + print("Add the successful release link and review evidence to the submission issue for maintainer review.") + print("Installing this workflow does not push, release, submit, or approve the app.") + return 0 + + # ---------------------------------------------------------------- package-help CHECKLIST = """\ Publish checklist (full text: docs/PUBLISHING.md). Run top to bottom; stop at HUMAN. @@ -518,15 +608,22 @@ Publish checklist (full text: docs/PUBLISHING.md). Run top to bottom; stop at HU curl -s 127.0.0.1:8141/quit 7. tools/octo check $B # stamps, then gate: PASSED 8. hub scan $B --packet build/review.json # answer its questions - 9. HUMAN: create/hold the publisher key outside the repo - hub keygen /secure/path/publisher.key (once) - hub sign-manifest $B --key /secure/path/publisher.key --key-id - hub check $B --publisher-key =$(hub pubkey /secure/path/publisher.key) - Any edit after signing: restamp and sign again. - 10. HUMAN: tag the commit and open an issue "Submit " on - OctoSense-org/OctoSense-App-Hub (docs/PUBLISHING.md 3.8). Never edit its - catalog.json/index/artifacts. Never claim it was submitted or approved - unless a person did it. + 9. HUMAN: request publication by opening an issue "Submit " + on OctoSense-org/OctoSense-App-Hub, with repository, version/commit, + screenshots and permissions. The issue can open before the release is ready. + 10. tools/octo publish-github # install release workflow + HUMAN: review the app, permissions, screenshots and workflow, then commit. + Push a NEW v tag in the app's public GitHub repository. + GitHub checks, attests and packs the release without a publisher key. + Do not modify/restamp its sealed release asset. Edit the development + bundle instead and release a new version with a new tag. + 11. After the workflow passes, add the release link and review evidence to + the submission issue. + A maintainer reviews the exact bytes before catalog admission. Never edit + its catalog/index/artifacts or claim release equals Hub approval. + +The sealed app requires a host supporting publisher-github-v1. Keep legacy +key-based publication only when deliberately targeting the older protocol. """ @@ -578,6 +675,10 @@ def main(): c.add_argument("--catalog", metavar="PATH", help="forward the catalog path to hub check") c.add_argument("--publisher-key", action="append", default=[], metavar="KEY", help="forward a trusted publisher key to hub check (repeatable)") + g = sub.add_parser("publish-github", help="install the GitHub release workflow; no separate developer signing key") + g.add_argument("dir", help="app repository directory containing bundle/manifest.json") + g.add_argument("--replace", action="store_true", help="replace an existing publishing workflow after reviewing it") + sub.add_parser("package-help", help="print the publish checklist") args, extra = p.parse_known_args() @@ -588,6 +689,7 @@ def main(): "new": cmd_new, "run": cmd_run, "shot": cmd_shot, + "publish-github": cmd_publish_github, "package-help": cmd_package_help, } if args.cmd == "check": diff --git a/tools/publish-app.template.yml b/tools/publish-app.template.yml new file mode 100644 index 00000000..76b52514 --- /dev/null +++ b/tools/publish-app.template.yml @@ -0,0 +1,153 @@ +name: Publish OctoSense app + +# Generated by tools/octo publish-github. No publisher signing secret is needed. +# Push a new v tag after reviewing the app and screenshots. +on: + push: + tags: ['v*'] + +permissions: {} + +concurrency: + group: octosense-release-${{ github.ref }} + cancel-in-progress: false + +jobs: + prepare: + runs-on: ubuntu-24.04 + timeout-minutes: 45 + permissions: + contents: read + steps: + - name: Require a public tagged release + env: + REPOSITORY_PRIVATE: ${{ github.event.repository.private }} + run: | + if [ "$REPOSITORY_PRIVATE" != false ] || [ "$GITHUB_REF_TYPE" != tag ]; then + echo '::error::OctoSense publishing requires a tag in a public app repository.' + exit 1 + fi + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + with: + ref: ${{ github.sha }} + path: app + persist-credentials: false + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + with: + repository: OctoSense-org/OctoSense-App-Hub + ref: __HUB_REVISION__ + path: tools/app-hub + persist-credentials: false + - name: Read the pinned native runtime + id: runtime + run: | + python3 - <<'PY' + import os, pathlib, re + pins = set() + for manifest in pathlib.Path('tools/app-hub/crates').glob('*/Cargo.toml'): + for line in manifest.read_text().splitlines(): + if 'git = "https://github.com/OctoSense-org/Octoscript-Makepad.git"' in line: + pin = re.search(r'rev\s*=\s*"([0-9a-f]{40})"', line) + assert pin, 'Missing immutable runtime revision' + pins.add(pin[1]) + assert len(pins) == 1, 'Expected one runtime revision' + with open(os.environ['GITHUB_OUTPUT'], 'a') as out: + out.write('revision=' + pins.pop() + '\n') + PY + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + with: + repository: OctoSense-org/Octoscript-Makepad + ref: ${{ steps.runtime.outputs.revision }} + path: tools/octoscript-makepad + persist-credentials: false + - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de + with: + toolchain: 1.97.1 + - name: Build trusted tools + run: | + python3 tools/octoscript-makepad/tools/runtime.py prepare --root "$GITHUB_WORKSPACE/tools" + cargo build --manifest-path tools/app-hub/Cargo.toml --locked --release -p octosense-app-hub + - name: Check final files and prepare their signing subject + run: | + mkdir -p "$RUNNER_TEMP/prepared" + tools/app-hub/target/release/hub publisher-prepare app/bundle \ + --repository "$GITHUB_REPOSITORY" \ + --repository-id "$GITHUB_REPOSITORY_ID" \ + --owner-id "$GITHUB_REPOSITORY_OWNER_ID" \ + --workflow .github/workflows/publish-app.yml \ + --tag "$GITHUB_REF_NAME" --commit "$GITHUB_SHA" \ + --out "$RUNNER_TEMP/prepared/octosense-app-manifest.json" + cp -R app/bundle "$RUNNER_TEMP/prepared/bundle" + cp tools/app-hub/target/release/hub "$RUNNER_TEMP/prepared/hub" + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: prepared-app-${{ github.run_id }}-${{ github.run_attempt }} + path: ${{ runner.temp }}/prepared/ + include-hidden-files: true + if-no-files-found: error + retention-days: 7 + + publish: + needs: prepare + runs-on: ubuntu-24.04 + timeout-minutes: 15 + permissions: + contents: write + id-token: write + attestations: write + steps: + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: prepared-app-${{ github.run_id }}-${{ github.run_attempt }} + path: ${{ runner.temp }}/prepared + - name: GitHub attests the exact manifest and bundle digest + id: attest + uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + with: + subject-path: ${{ runner.temp }}/prepared/octosense-app-manifest.json + - name: Verify the proof and pack the sealed app + env: + ATTESTATION_PATH: ${{ steps.attest.outputs.bundle-path }} + run: | + chmod 700 "$RUNNER_TEMP/prepared/hub" + "$RUNNER_TEMP/prepared/hub" publisher-attach "$RUNNER_TEMP/prepared/bundle" \ + --attestation "$ATTESTATION_PATH" + "$RUNNER_TEMP/prepared/hub" publisher-verify "$RUNNER_TEMP/prepared/bundle" + "$RUNNER_TEMP/prepared/hub" publisher-pack "$RUNNER_TEMP/prepared/bundle" \ + --out "$RUNNER_TEMP/prepared/app.bundle.pack.json" + - name: Write the submission receipt + run: | + python3 - <<'PY' + import hashlib, json, os + from pathlib import Path + root = Path(os.environ['RUNNER_TEMP']) / 'prepared' + manifest = json.loads((root / 'bundle/manifest.json').read_text()) + receipt = { + 'schema': 1, 'app_id': manifest['id'], 'version': manifest['version'], + 'repository': os.environ['GITHUB_REPOSITORY'], + 'commit': os.environ['GITHUB_SHA'], 'tag': os.environ['GITHUB_REF_NAME'], + 'run': os.environ['GITHUB_RUN_ID'], + 'pack_sha256': hashlib.sha256((root / 'app.bundle.pack.json').read_bytes()).hexdigest(), + 'hub_admission': 'not submitted', + } + (root / 'release-receipt.json').write_text(json.dumps(receipt, indent=2) + '\n') + (root / 'SUBMISSION.md').write_text( + 'This release was checked and sealed by the OctoSense publishing workflow.\n\n' + 'Submit this release link and app review evidence at ' + 'https://github.com/OctoSense-org/OctoSense-App-Hub/issues. ' + 'A maintainer still needs to review and admit the exact app files.\n\n' + 'Download `app.bundle.pack.json` for the sealed app; the repository keeps ' + 'the editable development bundle. A compatible OctoSense host must support ' + '`publisher-github-v1`.\n\n' + '```json\n' + json.dumps(receipt, indent=2) + '\n```\n') + PY + - name: Create the immutable release assets + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" \ + --verify-tag --title "$GITHUB_REF_NAME" \ + --notes-file "$RUNNER_TEMP/prepared/SUBMISSION.md" \ + "$RUNNER_TEMP/prepared/app.bundle.pack.json" \ + "$RUNNER_TEMP/prepared/octosense-app-manifest.json" \ + "$RUNNER_TEMP/prepared/release-receipt.json" diff --git a/tools/publisher-toolchain.json b/tools/publisher-toolchain.json new file mode 100644 index 00000000..48782f62 --- /dev/null +++ b/tools/publisher-toolchain.json @@ -0,0 +1,5 @@ +{ + "schema": 1, + "repository": "OctoSense-org/OctoSense-App-Hub", + "revision": "c11de1d7c2533c32b9bf02b3e830e2013b64fc88" +} diff --git a/tools/test_github_publish.py b/tools/test_github_publish.py new file mode 100644 index 00000000..11da82f4 --- /dev/null +++ b/tools/test_github_publish.py @@ -0,0 +1,146 @@ +"""Publishing setup preserves developer files and sealed release bytes.""" +import argparse +import contextlib +import importlib.machinery +import importlib.util +import io +import json +from pathlib import Path +import tempfile +import unittest +from unittest.mock import patch + +HERE = Path(__file__).resolve().parent +loader = importlib.machinery.SourceFileLoader('publisher_octo', str(HERE / 'octo')) +spec = importlib.util.spec_from_loader(loader.name, loader) +octo = importlib.util.module_from_spec(spec) +loader.exec_module(octo) + + +class PublishingSetup(unittest.TestCase): + def app(self, root, integrity=None): + app = Path(root) / 'app' + (app / 'bundle').mkdir(parents=True) + (app / 'bundle/manifest.json').write_text(json.dumps({ + 'id': 'dev.example.quicknotes', 'version': '0.1.0', + 'integrity': integrity or {'bundle_blake3': 'development'}, + })) + return app + + def test_installer_is_idempotent_and_does_not_publish(self): + with tempfile.TemporaryDirectory() as temp: + app = self.app(temp) + args = argparse.Namespace(dir=str(app), replace=False) + with patch.object(octo, 'publisher_workflow', return_value='name: fixture\n'), \ + patch.object(octo.subprocess, 'run') as external, \ + contextlib.redirect_stdout(io.StringIO()): + self.assertEqual(octo.cmd_publish_github(args), 0) + workflow = app / '.github/workflows/publish-app.yml' + before = workflow.stat().st_mtime_ns + self.assertEqual(octo.cmd_publish_github(args), 0) + self.assertEqual(workflow.stat().st_mtime_ns, before) + external.assert_not_called() + + def test_custom_workflow_needs_explicit_replacement(self): + with tempfile.TemporaryDirectory() as temp: + app = self.app(temp) + octo.install_publisher_workflow(app, 'name: custom\n') + with self.assertRaises(ValueError): + octo.install_publisher_workflow(app, 'name: new\n') + workflow = app / '.github/workflows/publish-app.yml' + self.assertEqual(workflow.read_text(), 'name: custom\n') + self.assertTrue(octo.install_publisher_workflow(app, 'name: new\n', True)) + self.assertEqual(workflow.read_text(), 'name: new\n') + + def test_symlinks_cannot_redirect_workflow_writes(self): + for component in ('.github', '.github/workflows', '.github/workflows/publish-app.yml'): + with self.subTest(component=component), tempfile.TemporaryDirectory() as temp: + app = self.app(temp) + outside = Path(temp) / 'outside' + outside.mkdir() + target = app / component + target.parent.mkdir(parents=True, exist_ok=True) + try: + target.symlink_to(outside, target_is_directory=True) + except OSError as error: + self.skipTest('Symlink creation unavailable: ' + str(error)) + with self.assertRaises(ValueError): + octo.install_publisher_workflow(app, 'name: fixture\n', True) + self.assertEqual(list(outside.iterdir()), []) + + def test_sealed_bundle_is_not_used_as_editable_repository(self): + with tempfile.TemporaryDirectory() as temp: + app = self.app(temp, {'github': {'attestation': {'fixture': True}}}) + with contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit): + octo.cmd_publish_github(argparse.Namespace(dir=str(app), replace=False)) + self.assertFalse((app / '.github').exists()) + + def test_github_metadata_never_gets_restamped_or_unsigned_escape(self): + for github in ({'attestation': {'fixture': True}}, {}, None): + with self.subTest(github=github), tempfile.TemporaryDirectory() as temp: + app = self.app(temp, {'github': github}) + bundle = app / 'bundle' + original = (bundle / 'manifest.json').read_bytes() + args = argparse.Namespace(bundle=str(bundle), catalog=None, publisher_key=[]) + with patch.object(octo, 'need', return_value=Path('/fixture/hub')), \ + patch.object(octo.subprocess, 'run') as run, \ + contextlib.redirect_stdout(io.StringIO()): + run.return_value.returncode = 1 + self.assertEqual(octo.cmd_check(args, []), 1) + self.assertEqual(run.call_count, 1) + self.assertEqual(run.call_args.args[0], ['/fixture/hub', 'check', str(bundle.resolve())]) + self.assertEqual((bundle / 'manifest.json').read_bytes(), original) + + def test_run_refuses_sealed_releases_before_startup_or_file_writes(self): + for integrity in ({'github': {}}, {'github': None}, {'signature': 'legacy-signed'}, {'signature': {}}): + with self.subTest(integrity=integrity), tempfile.TemporaryDirectory() as temp: + app = self.app(temp, integrity) + bundle = app / 'bundle' + original = (bundle / 'manifest.json').read_bytes() + args = argparse.Namespace(bundle=str(bundle)) + with patch.object(octo, 'need') as binary, \ + patch.object(octo.subprocess, 'Popen') as start, \ + patch.object(octo, 'port_owner') as port, \ + contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit): + octo.cmd_run(args) + binary.assert_not_called() + start.assert_not_called() + port.assert_not_called() + self.assertFalse((app / '.local-state').exists()) + self.assertEqual((bundle / 'manifest.json').read_bytes(), original) + + def test_typed_unsigned_null_signature_remains_authorable(self): + with tempfile.TemporaryDirectory() as temp: + app = self.app(temp, {'signature': None}) + args = argparse.Namespace(bundle=str(app / 'bundle')) + with patch.object(octo, 'need', side_effect=RuntimeError('authoring path reached')) as binary: + with self.assertRaisesRegex(RuntimeError, 'authoring path reached'): + octo.cmd_run(args) + binary.assert_called_once_with('card-host', 'OCTO_CARD_HOST') + args.catalog, args.publisher_key = None, [] + with patch.object(octo, 'need', return_value=Path('/fixture/hub')), \ + patch.object(octo.subprocess, 'run') as run, \ + contextlib.redirect_stdout(io.StringIO()): + run.return_value.returncode = 0 + self.assertEqual(octo.cmd_check(args, []), 0) + self.assertEqual(run.call_count, 2) + self.assertEqual(run.call_args_list[0].args[0][1], 'stamp') + self.assertIn('--allow-unsigned', run.call_args_list[1].args[0]) + + def test_toolchain_ref_cannot_be_mutable_or_inject_workflow(self): + with tempfile.TemporaryDirectory() as temp: + root = Path(temp) + (root / 'tools').mkdir() + (root / 'tools/publish-app.template.yml').write_text('ref: __HUB_REVISION__\n') + config = root / 'tools/publisher-toolchain.json' + with patch.object(octo, 'REPO', root): + for ref in (None, 'main', 'v1.8.0', 'a' * 40 + '\nrun: bad'): + config.write_text(json.dumps({'schema': 1, 'repository': 'OctoSense-org/OctoSense-App-Hub', 'revision': ref})) + with self.assertRaises(ValueError): + octo.publisher_workflow() + config.write_text(json.dumps({'schema': 1, 'repository': 'OctoSense-org/OctoSense-App-Hub', 'revision': 'a' * 40})) + self.assertEqual(octo.publisher_workflow(), 'ref: ' + 'a' * 40 + '\n') + + +if __name__ == '__main__': + unittest.main() From f164821783e7f568aafc356ccddb8359b031047e Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:47:23 -0700 Subject: [PATCH 4/5] Pin the merged keyless publisher toolchain --- tools/publisher-toolchain.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/publisher-toolchain.json b/tools/publisher-toolchain.json index 48782f62..82b83fd4 100644 --- a/tools/publisher-toolchain.json +++ b/tools/publisher-toolchain.json @@ -1,5 +1,5 @@ { "schema": 1, "repository": "OctoSense-org/OctoSense-App-Hub", - "revision": "c11de1d7c2533c32b9bf02b3e830e2013b64fc88" + "revision": "655114c4943cd2490daaefa2173e7b5aaa20669f" } From 00d1e87f6d8602a13dde00d52d0a3ee50dda51a9 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:50:05 -0700 Subject: [PATCH 5/5] Use native path spelling in publisher regression on Windows --- tools/test_github_publish.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/test_github_publish.py b/tools/test_github_publish.py index 11da82f4..8126baf3 100644 --- a/tools/test_github_publish.py +++ b/tools/test_github_publish.py @@ -88,7 +88,7 @@ def test_github_metadata_never_gets_restamped_or_unsigned_escape(self): run.return_value.returncode = 1 self.assertEqual(octo.cmd_check(args, []), 1) self.assertEqual(run.call_count, 1) - self.assertEqual(run.call_args.args[0], ['/fixture/hub', 'check', str(bundle.resolve())]) + self.assertEqual(run.call_args.args[0], [str(Path('/fixture/hub')), 'check', str(bundle.resolve())]) self.assertEqual((bundle / 'manifest.json').read_bytes(), original) def test_run_refuses_sealed_releases_before_startup_or_file_writes(self):