From aa08acce33f49ec6fe9e4dacc6d9a462ea6bb200 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Thu, 27 Aug 2026 18:20:19 +0800 Subject: [PATCH] ci: publish models index via GitHub Releases (index-v* tags) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runtimes must pin DEFAULT_INDEX_URL to a Release asset + sha256 sidecar — never raw.githubusercontent.com, never main. Workflow release-index.yml stages models-index.yaml and its .sha256 on every index-v* tag (or workflow_dispatch). --- .github/workflows/release-index.yml | 59 +++++++++++++++++++++++++++++ models.yaml | 31 ++++++++++----- 2 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/release-index.yml diff --git a/.github/workflows/release-index.yml b/.github/workflows/release-index.yml new file mode 100644 index 0000000..ef7db5b --- /dev/null +++ b/.github/workflows/release-index.yml @@ -0,0 +1,59 @@ +name: release-index + +# Publishes models.yaml as a GitHub Release asset (models-index.yaml + +# .sha256 sidecar). Runtimes pin DEFAULT_INDEX_URL to a specific index-v* +# tag — never raw.githubusercontent.com, never main. +# +# Trigger: push of an index-v* tag, or workflow_dispatch with a tag name. +on: + push: + tags: + - "index-v*" + workflow_dispatch: + inputs: + tag: + description: "Release tag (e.g. index-v1). Created if missing." + required: true + type: string + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Stage index assets + run: | + test -f models.yaml + cp models.yaml models-index.yaml + shasum -a 256 models-index.yaml | awk '{print $1 " models-index.yaml"}' > models-index.yaml.sha256 + echo "--- models-index.yaml.sha256 ---" + cat models-index.yaml.sha256 + echo "--- head models-index.yaml ---" + head -20 models-index.yaml + + - name: Create or update GitHub Release + env: + GH_TOKEN: ${{ github.token }} + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + tag="${{ inputs.tag }}" + else + tag="${GITHUB_REF_NAME}" + fi + case "$tag" in + index-v*) ;; + *) echo "tag must match index-v*: got '$tag'" >&2; exit 1 ;; + esac + if ! gh release view "$tag" >/dev/null 2>&1; then + gh release create "$tag" \ + --title "$tag" \ + --notes "Interscript ML model index ($tag). Runtimes resolve DEFAULT_INDEX_URL against this release asset + sha256 sidecar." \ + --target "$GITHUB_SHA" + fi + gh release upload "$tag" models-index.yaml models-index.yaml.sha256 --clobber + echo "published $tag" + gh release view "$tag" --json assets --jq '.assets[].name' diff --git a/models.yaml b/models.yaml index 9768132..2006f5b 100644 --- a/models.yaml +++ b/models.yaml @@ -1,20 +1,31 @@ -# interscript-ml model index — the stable URL every runtime resolves -# model ids against (Ruby / TypeScript / Python implement the same -# algorithm; this file is the contract). +# interscript-ml model index — the contract every runtime resolves model +# ids against (Ruby / TypeScript / Python implement the same algorithm). +# +# DISTRIBUTION: this file is published as a GitHub Release asset, never +# via raw.githubusercontent.com. Tag shape: index-vN. Assets per release: +# models-index.yaml +# models-index.yaml.sha256 +# URL shape runtimes pin: +# https://github.com/interscript/interscript-ml/releases/download/index-vN/models-index.yaml +# Cut a new index-vN tag (or dispatch release-index.yml) whenever the +# index content changes in a way production consumers must see. # # Resolution algorithm (identical in all runtimes): -# 1. resolve `id` in models.models -# 2. prefer an installed cache copy at // +# 1. fetch the pinned index URL + its .sha256 sidecar; verify the body +# 2. resolve `id` in models.models +# 3. prefer an installed cache copy at // # whose whole-file sha256 matches `sha256` -# 3. else download `url` to a temp file in the same directory, +# 4. else download `url` (or assemble `parts`) to a temp file, # verify sha256, atomically rename into place -# 4. load the zip (IMF v1: member sha256 verification on load) +# 5. load the zip (IMF v1: member sha256 verification on load) # -# Overrides: SECRYST_INDEX (URL or path to an index like this one), -# SECRYST_CACHE (cache directory; default ~/.cache/secryst). +# Overrides: SECRYST_INDEX (URL or path to an index like this one — +# HTTP sources must ship a sibling .sha256), SECRYST_CACHE (cache +# directory; default ~/.cache/secryst or ~/.cache/interscript). # # Adding a model: it must have passed the WO03 gate (strict validation, -# parity written into the zip) before an entry ships here. +# parity written into the zip) before an entry ships here. Then cut a +# new index-vN so runtimes pick it up on their next pin bump. version: 1 models: khm-latn-1.0: