Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ jobs:
run: |
cargo test --locked -p octosense-kernel
cargo clippy --locked -p octosense-kernel --all-targets --no-deps -- -D warnings
- name: OctoSense release updater
run: |
cargo test --locked -p octosense-updater
cargo clippy --locked -p octosense-updater --all-targets --no-deps -- -D warnings
- name: App peers
run: |
cargo test --locked -p octosense-app-peers
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ jobs:
python3 desktop/packaging/make_icons.py --check
# The release packaging script (no build; release-desktop.yml builds).
python3 -m unittest discover -s desktop/scripts -p 'test_package.py'
- name: In-app updater and installer handoff
run: |
cargo test --locked -p octosense-updater-ui --lib
cargo check --locked -p octosense-updater-ui --example updates
- name: One Makepad, App Hub, octos and Rinx in the locked graph
run: python3 tools/setup.py --check --cargo
- name: The native apps' generated places match native-apps.json
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ jobs:
# installer), plus what went into them: the binary, the kernel and
# the staged resources.
exe=octosense; [ "$RUNNER_OS" = Windows ] && exe=octosense.exe
python "$SRC/tools/release-scan.py" upload/packages/* resources kernel "$SRC/target/release/$exe"
target=$(python -c 'import json; print(json.load(open("receipt.json"))["target"])')
python "$SRC/tools/release-scan.py" upload/packages/* resources kernel "$SRC/target/$target/release/$exe"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: octosense-desktop-unsigned-${{ matrix.platform }}
Expand Down
113 changes: 113 additions & 0 deletions .github/workflows/sign-desktop-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Sign a desktop release with GitHub's signature, so the in-app updater
# (docs/updater.md) offers it. Run it on the draft that release-desktop.yml
# made, before publishing the draft (desktop/README.md, "Cutting a desktop
# release"):
#
# gh workflow run sign-desktop-release.yml --ref main -f tag=desktop-v0.2.0
#
# The job waits for a reviewer of the desktop-release-signing environment.
# It checks that the release's SHA256SUMS lists exactly the release's files,
# each with its GitHub digest; GitHub then signs SHA256SUMS (actions/attest:
# a Sigstore bundle, recorded in the public transparency log), and the job
# attaches that bundle to the release as SHA256SUMS.sigstore.json. The
# updater accepts a signature from this workflow only, run on main in that
# environment (crates/updater/src/signature.rs), the way devices accept App
# Hub's catalog.
name: Sign desktop release

on:
workflow_dispatch:
inputs:
tag:
description: "The desktop release to sign: desktop-v<major>.<minor>.<patch>[-<pre>]"
required: true
type: string

permissions: {}

concurrency:
group: sign-desktop-release
cancel-in-progress: false

jobs:
sign:
# The updater trusts this workflow on main only.
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-24.04
timeout-minutes: 15
environment: desktop-release-signing
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Check the release and its checksums
id: release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ inputs.tag }}
run: |
python3 - <<'PY'
import hashlib, json, os, re, subprocess, sys

tag, repo = os.environ["TAG"], os.environ["GITHUB_REPOSITORY"]
number = r"(?:0|[1-9][0-9]*)"
if not re.fullmatch(rf"desktop-v{number}\.{number}\.{number}(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?", tag):
sys.exit(f"{tag!r} is not a desktop release tag")

def api(path, *args):
return subprocess.run(["gh", "api", *args, path], check=True, capture_output=True).stdout

# Drafts are listed for this token; a draft has no tag URL yet.
pages = json.loads(api(f"repos/{repo}/releases?per_page=100", "--paginate", "--slurp"))
matches = [r for page in pages for r in page if r["tag_name"] == tag]
if len(matches) != 1:
sys.exit(f"{tag}: expected one release, found {len(matches)}")
assets = {a["name"]: a for a in matches[0]["assets"]}
if "SHA256SUMS.sigstore.json" in assets:
sys.exit(f"{tag} is already signed; delete its SHA256SUMS.sigstore.json to sign it again")
if "SHA256SUMS" not in assets:
sys.exit(f"{tag} has no SHA256SUMS")
sums_asset = assets.pop("SHA256SUMS")
sums = api(f"repos/{repo}/releases/assets/{sums_asset['id']}", "-H", "Accept: application/octet-stream")
if sums_asset.get("digest") != "sha256:" + hashlib.sha256(sums).hexdigest():
sys.exit("SHA256SUMS does not match its GitHub digest")

listed = {}
for line in sums.decode("utf-8").splitlines():
if not line:
continue
m = re.fullmatch(r"([0-9a-f]{64}) [ *]([0-9A-Za-z_+-][0-9A-Za-z._+-]*)", line)
if not m or m.group(2) in listed:
sys.exit(f"malformed SHA256SUMS line: {line!r}")
listed[m.group(2)] = m.group(1)
# What GitHub signs must describe the whole release, file for file.
if set(listed) != set(assets):
sys.exit("SHA256SUMS does not list exactly the release's files: "
f"unlisted {sorted(set(assets) - set(listed))}, missing {sorted(set(listed) - set(assets))}")
for name, asset in assets.items():
if asset.get("digest") != "sha256:" + listed[name]:
sys.exit(f"{name} does not match its line in SHA256SUMS")

subject = os.path.join(os.environ["RUNNER_TEMP"], "subject", f"{tag}.SHA256SUMS")
os.makedirs(os.path.dirname(subject))
with open(subject, "wb") as out:
out.write(sums)
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
out.write(f"subject={subject}\n")
state = "draft" if matches[0]["draft"] else "published"
print(f"{tag} ({state}): SHA256SUMS lists its {len(assets)} files with their GitHub digests")
PY
- name: GitHub signs the checksums
id: attest
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
subject-path: ${{ steps.release.outputs.subject }}
- name: Attach the signature to the release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ inputs.tag }}
BUNDLE: ${{ steps.attest.outputs.bundle-path }}
run: |
cp "$BUNDLE" "$RUNNER_TEMP/SHA256SUMS.sigstore.json"
gh release upload "$TAG" "$RUNNER_TEMP/SHA256SUMS.sigstore.json" -R "$GITHUB_REPOSITORY"
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
| AppCard (opt-in) | `apps/appcard/` | [apps/appcard/AGENTS.md](apps/appcard/AGENTS.md), `apps.yml` |
| A native app (App Hub, Rinx, Terminal, Sheets, Reference, AppCard, and the Makepad apps made native: Calculator, Clock, Notes, Reminders, Weather, and Task, which runs only as its own process; and OctosCode, whose `kernel` port the coding scope holds, `crates/shell/src/coding_scope.rs`): its crate, pin, features, hosting per target, sandbox, storage, its tools, which of them the system agent may call (`agent.system_tools`) and which its own agent may (`agent.own_tools`) | `native-apps.json` only; `python3 tools/native_apps.py` writes the marked blocks in the `Cargo.toml`s, `crates/shell/src/native_apps.rs` and `Cargo.lock` | `python3 tools/native_apps.py --check`, `python3 -m unittest discover -s tools -p 'test_*.py'` |
| An external pin (Makepad, OctoScript, App Hub, octos, Rinx) | root `Cargo.toml` `[workspace.dependencies]` (a native app's in `native-apps.json`), `native-runtime.lock.json`, `runtime-patches.lock.json` | `python3 tools/setup.py --update`, then `--check --cargo` and `python3 tools/native_apps.py --check` |
| OctoSense application updates (release channels, verified downloads, native installer handoff) | `crates/updater/`, `crates/updater-ui/`, Home's `HomeUpdaterClient.java`; [updater guide](docs/updater.md) | `cargo test --locked -p octosense-updater -p octosense-updater-ui`; `python3 -m unittest discover -s rom/tests -p 'test_home_app_updater.py'`; then both packagings' checks |
| A decision | `docs/adr/` (next free number) | — |

Start every session with `python3 tools/setup.py` (it prepares `.sources/`, and changes nothing that is already right).
Expand Down
41 changes: 36 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 9 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ members = [
"crates/wasm-host",
"crates/skill-gen",
"crates/engine-area",
"crates/updater",
"crates/updater-ui",
"apps/reference",
"apps/news/host-service",
"apps/sheets/host-service",
Expand Down Expand Up @@ -86,12 +88,13 @@ authors = ["octos-app contributors"]
# Reference and AppCard. A git source shares its repository's revision with
# the pins below; tools/native_apps.py writes this block and checks that.
# BEGIN native-apps: pins (generated by tools/native_apps.py from native-apps.json; do not edit)
octosense-updater-ui = { path = "crates/updater-ui" }
rinx = { git = "https://github.com/hagency-org/Rinx.git", tag = "v1.1.0", default-features = false, features = ["octosense-module"] }
octosense-reference = { path = "apps/reference" }
makepad-sheets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19", default-features = false }
makepad-terminal = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19" }
octosense-appcard = { path = "apps/appcard/module" }
octosense-app-hub-app = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "c317f787ea2f620543000561c2470106644c1fc7" }
octosense-app-hub-app = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "386359153ed6377b5f047bd9ed2767a6a2ac2bc7" }
makepad-calculator = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19", default-features = false }
makepad-clock = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19", default-features = false }
makepad-notes = { git = "https://github.com/OctoSense-org/makepad.git", rev = "d653bc4493619ab979ccff165cf48c0c63b77d19", default-features = false }
Expand Down Expand Up @@ -131,12 +134,12 @@ makepad-d3 = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git",
octoscript-node = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "6cf2d90aa33ff4ae603f49c7557f3ecf986207f0" }
# --- App Hub's host service registry the Mail and llm services register
# into; the same revision as App Hub's app crate (a native app, above).
octosense-appstore = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "c317f787ea2f620543000561c2470106644c1fc7" }
octosense-appstore = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "386359153ed6377b5f047bd9ed2767a6a2ac2bc7" }
# The app policy (resolution, isolate settings, the Splash adapter) and the
# Hub client the Card runner resolves an app's policy with; the shell's
# glance tiles run cards under it (crates/shell/src/glance_card.rs).
octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "c317f787ea2f620543000561c2470106644c1fc7" }
octosense-app-hub = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "c317f787ea2f620543000561c2470106644c1fc7" }
octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "386359153ed6377b5f047bd9ed2767a6a2ac2bc7" }
octosense-app-hub = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "386359153ed6377b5f047bd9ed2767a6a2ac2bc7" }
# The app contract (ADR 0005), from crates.io by version: App Hub, the shell
# and Rinx all depend on `octosense-app-contract = "1"`, so Cargo links ONE
# 1.x for the whole build (Cargo.lock pins the exact version OctoSense ships)
Expand Down Expand Up @@ -191,6 +194,7 @@ octosense-l0-chat = { path = "crates/l0-chat" }
octosense-oauth-service = { path = "crates/oauth-service" }
octosense-markdown-editor = { path = "crates/markdown-editor" }
octosense-wasm-host = { path = "crates/wasm-host" }
octosense-updater = { path = "crates/updater" }
# The craft engines' skill references (ADR 0013): the engine services'
# tests generate and check `commands.md` and `safety.json` with it.
octosense-skill-gen = { path = "crates/skill-gen" }
Expand Down Expand Up @@ -439,7 +443,7 @@ ruma = { git = "https://github.com/project-robius/ruma.git", branch = "tsp" }
# -i octos-core` still sees one octos source.
[patch.crates-io]
# Keep the contract identical to the pinned SDK for this release candidate.
octosense-app-contract = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "c317f787ea2f620543000561c2470106644c1fc7" }
octosense-app-contract = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "386359153ed6377b5f047bd9ed2767a6a2ac2bc7" }
nix = { git = "https://github.com/octos-org/octos.git", rev = "18fcd3f16e527d2b601d7ae244f056fb711bb6b8" }

# pdfcraft's bootstrap PDF stack: its workspace patches these five
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ English | [简体中文](README.zh-CN.md)

[Host OS API status](docs/host-os-api-status.md) tracks file, location and external-link support, existing services, remaining gaps and validation limits.

[OctoSense Updates](docs/updater.md) checks and downloads verified host releases, then opens the OS installation flow. It ships in builds containing this change; older releases need one manual upgrade first.

[Capabilities and execution boundaries](docs/capabilities.md) explains declaration-only APIs, consent, accounts and app isolation.

**Desktop prerelease download:** [OctoSense 0.1.0-rc.4](https://github.com/OctoSense-org/OctoSense/releases/tag/desktop-v0.1.0-rc.4) includes app-contract 1.11.0, shared Wasm components, GitHub-attested app installation and declaration-only public API capabilities. Choose an asset for your operating system and architecture; the release notes record signing, prerequisites and platform acceptance limits. This desktop release does not update Android Home.
Expand Down
2 changes: 2 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

[宿主 OS API 状态](docs/host-os-api-status.zh-CN.md)记录文件、定位和外部链接支持,以及已有服务、剩余缺口和验证范围。

[OctoSense Updates](docs/updater.zh-CN.md) 检查并下载经过校验的宿主发行版,再打开操作系统安装流程。此功能随本次变更引入;旧版本需要先手动升级一次。

[能力声明与执行边界](docs/capabilities.zh-CN.md)说明声明式 API、用户同意、账户和应用隔离。

**桌面预发布版下载**:[OctoSense 0.1.0-rc.4](https://github.com/OctoSense-org/OctoSense/releases/tag/desktop-v0.1.0-rc.4) 包含应用契约 1.11.0、共享 Wasm 组件、GitHub 证明应用安装,以及“能力仅用于声明”的公开 API 策略。请选择与操作系统和架构对应的文件;签名、前置条件及各平台验收限制见发行说明。此桌面版本不会更新 Android Home。
Expand Down
Loading
Loading