fix(snap): build from locked python inputs and verify artifacts (#1041)
* fix(snap): build and verify payload from locked python inputs * docs(snap): document locked inputs and artifact verification * test(clipboard): isolate restore workers between tests * test(packaging): tighten isolation and clarify snap audit guarantees * fix(ci): run snap recipe tests on snap-only changes A change to snap/snapcraft.yaml or snap/local/smoke-test.sh only matched the snap filter, so the Python tests that guard the recipe (including the portable whisper.cpp flags from #957) and the smoke script were skipped. Match all of snap/ in the python filter, as scripts/ already is. * docs(snap): use a version placeholder in the smoke-test example --------- Co-authored-by: Jatin <jatinkrmalik@gmail.com>
This commit is contained in:
@@ -170,6 +170,9 @@ Desktop shortcuts only toggle dictation, so they cannot support push-to-talk.
|
||||
|
||||
Listing: [snapcraft.io/vocalinux](https://snapcraft.io/vocalinux) (issue [#48](https://github.com/VocaHQ/vocalinux/issues/48)). Recipe: `snap/snapcraft.yaml`. Tagged `v*` releases attach `vocalinux_<version>_amd64.snap` to the GitHub Release and try Snap Store `edge` and `candidate` when credentials are set. `stable` is promoted from `candidate` after QA.
|
||||
|
||||
Build inputs, the PR/release artifact gate, and its verification limits are
|
||||
documented in [SNAP.md](SNAP.md).
|
||||
|
||||
Store install, once Canonical lists the revision:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -451,7 +451,9 @@ After pushing the tag, the GitHub Actions workflow will automatically:
|
||||
`FLATPAK_GPG_PRIVATE_KEY` + `FLATPAK_REPO_TOKEN` are configured — see
|
||||
docs/FLATPAK_REMOTE.md)
|
||||
8. Deploy the website to vocalinux.com
|
||||
9. Build the amd64 snap, attach it to the GitHub Release, and try Snap Store
|
||||
9. Build the amd64 snap from locked Python exports and run the installed-artifact
|
||||
gate described in [SNAP.md](SNAP.md), then attach it to the GitHub Release and
|
||||
try Snap Store
|
||||
`edge`/`candidate`. Store human review (for example a super-privileged
|
||||
`allow-installation` plug) must not block the GitHub `.snap`. `stable` does not auto-release (#783):
|
||||
after candidate QA, dispatch `snap-promote.yml`, which releases the
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Snap build inputs and verification
|
||||
|
||||
The supported Snap build is **amd64, core24 (Ubuntu 24.04 / Python 3.12),
|
||||
strict confinement, GNOME extension**. whisper.cpp is built for the portable
|
||||
CPU baseline, not Vulkan/CUDA. Optional local engines are not bundled.
|
||||
User installation and interface connections are documented in
|
||||
[INSTALL.md](INSTALL.md#snap-ubuntu-snap-store).
|
||||
|
||||
## Python inputs
|
||||
|
||||
`uv.lock` owns Python versions. The Snap reuses these generated exports:
|
||||
|
||||
- `requirements/installer-build.txt`: the complete hash-pinned build toolchain,
|
||||
installed wheel-only into a temporary, isolated build virtualenv;
|
||||
- `requirements/runtime.txt`: the runtime pins, platform markers and SHA-256
|
||||
hashes, already excluding PyGObject.
|
||||
|
||||
`snap/local/build.py` replaces the Python plugin's implicit resolution. A distro
|
||||
`ensurepip` seeds the build environment offline; its first network operation
|
||||
installs the locked toolchain with `--require-hashes --no-deps`. Runtime
|
||||
dependencies use the same flags plus `--no-build-isolation`. Native builds find
|
||||
the locked CMake/Ninja on PATH. pywhispercpp always builds from its pinned sdist,
|
||||
without a wheel cache, with the portable `GGML_*` CPU options in the recipe.
|
||||
|
||||
The project installs with `--no-deps --no-build-isolation --no-index`. Neither
|
||||
`pyproject.toml` nor its dependency metadata is patched. PyGObject/GTK come from
|
||||
the GNOME platform, not pip. The packaged virtualenv contains no pip or build
|
||||
toolchain. Its launchers are relocatable and prioritize the locked Python
|
||||
packages over incidental copies in the GNOME platform.
|
||||
|
||||
The build audits build-tool and installed runtime versions against the active
|
||||
export pins and records expected runtime versions and both export digests in
|
||||
`usr/share/vocalinux/python-inputs.json` inside the snap. Missing or wrong-version
|
||||
build tools fail the build. For the packaged runtime, extra and duplicate
|
||||
Python distributions are rejected as well.
|
||||
|
||||
Regenerate exports with the repository's `just lock` workflow, not by editing
|
||||
them or adding independent pins to `snapcraft.yaml`. `just export-check` checks
|
||||
them against `uv.lock` in CI.
|
||||
|
||||
## Build and artifact gate
|
||||
|
||||
On a Linux machine with Snapcraft and LXD or Multipass:
|
||||
|
||||
```bash
|
||||
snapcraft pack
|
||||
```
|
||||
|
||||
On a **disposable Ubuntu host with snapd**, inspect the resulting artifact:
|
||||
|
||||
```bash
|
||||
bash snap/local/smoke-test.sh ./vocalinux_<version>_amd64.snap
|
||||
```
|
||||
|
||||
Replace `<version>` with the version that was built. The script refuses to overwrite an
|
||||
existing Vocalinux snap. It installs the supplied file with `--dangerous`,
|
||||
runs the actual application launcher with `--version`, then enters the GNOME
|
||||
command-chain environment to audit Python versions and import the native,
|
||||
GTK, recognition and text-injection modules. It leaves the installation in
|
||||
place for inspection; use a disposable host, not your normal Vocalinux install.
|
||||
|
||||
`unified-pipeline.yml` builds and runs this gate on relevant Python/Snap PRs and
|
||||
main pushes, including recipe-only changes. `release.yml` runs it before the
|
||||
snap artifact can be attached or sent to the Store. Both use the same pinned
|
||||
builder action and Ubuntu 24.04 runner. PR checks need no Store credentials and
|
||||
never publish. Historical-tag backfills retain the tagged recipe's behavior.
|
||||
|
||||
## Deliberate limits
|
||||
|
||||
- This pins Python downloads and build tools, **not every native input**.
|
||||
Ubuntu packages are controlled by the core24/Ubuntu archive policy; the
|
||||
GNOME SDK/platform, Snapcraft and base snaps follow their upstream channels.
|
||||
Their exact revisions and native package versions remain visible in the
|
||||
Snapcraft build records. They are not an immutable snapshot owned by our
|
||||
Python lock.
|
||||
- This is not a claim of byte-for-byte reproducible `.snap` archives. There is
|
||||
no independent Snap rebuild comparison, and native inputs can change.
|
||||
- The smoke imports real modules under confinement but does not download a
|
||||
model, run inference, capture audio, test shortcuts, or type into an app.
|
||||
Candidate desktop QA and promotion to stable remain separate operations;
|
||||
this gate does not trigger `snap-promote.yml`.
|
||||
Reference in New Issue
Block a user