Make the release pipeline actually publish, ship the real icon, and consume dmx from pub.dev - #1
Merged
Merged
Conversation
A called workflow may not request more than its caller grants, and GitHub enforces it statically: ci.yml's `security` job declares `pull-requests: write`, the `verify` job granted only `contents: read`, and every tag push died as `startup_failure` before a job existed. No tag had ever been pushed, so nothing caught it.
`vsce` opens the --out path but does not create its directory. `vsix` gets that directory from `build`; `vsix-universal` carries no binary, builds nothing, and so died with ENOENT on every fresh checkout — which is what a release runner always is. Reproduced by packaging into a missing directory.
Intel macs are no longer a deployment target: the darwin-x64 leg and its bundle are gone. The alpine-x64 leg built a binary that segfaulted (exit 139) on its own --version. Rust ships a musl libc and links that target self-contained; overriding CARGO_TARGET_..._LINKER with Ubuntu's musl-gcc produced a broken x86_64 static-PIE. CC_<triple> is still set — tree-sitter is C — but only a real cross-link (mingw) now names a linker.
publish and publish-pub are held to the same gates but run in parallel, so a missing Entra credential surfaces only after pub.dev has already published a version that cannot be withdrawn. Checked in preflight before the checkout instead, where being wrong costs a red tag. Presence only — no value is ever printed or compared.
…d token vsce 3.x takes --azure-credential and uses the session azure/login already established from this job's OIDC token, so the release no longer mints an access token, masks it, and exports it as VSCE_PAT. Nothing token-shaped is handled by the workflow at all.
Environment secrets are readable only by a job that declares the environment. The credentials guard sat in preflight, which declared none, so it read both as empty and refused a release whose secrets were set correctly.
The dry run ran on the unstamped tree, on the reasoning that publishability does not depend on the version string. It does: pub validates the changelog against the current version, so the 0.0.0 placeholder produced 'CHANGELOG.md doesn't mention current version' and, once 0.1.0 existed, 'your version is earlier than that'. --dry-run exits non-zero on any warning, so the step could never once have passed. Stamped first now, committed into the throwaway checkout so the uncommitted- changes warning cannot fire, then proven — which validates the archive actually being published rather than a differently-versioned one. Reproduced in a clean clone of the tag: 0 warnings.
The extension carried an older mark matching nothing else the project uses. Rebuilt from website/src/assets/images/dmx-mark.svg at 256x256 on the brand ground, in the proportions the apple-touch-icon already establishes. The Marketplace URL was written with the publisher in lowercase in six places. The gallery API accepts that form; the web page 404s on it. It is Nimblesite.dmx. The site and docs now offer the install itself — vscode:extension/Nimblesite.dmx opens the extension in the editor — alongside the Marketplace page, since the vscode: link is inert for a reader without VS Code. No new CSS: both CTAs reuse the existing button classes, and the budget stays at 1983 of 2000 lines. The docs claimed a macOS x64 bundle that 0.2.0 stopped publishing.
The examples, the golden corpus root and the corpus pubspec the Makefile generates all depended on src/dart_packages/dmx by path, so nothing in this repository ever exercised the package as published. They now resolve dmx ^0.3.0 from pub.dev, which is what a reader copying an example gets. examples/storefront/.dart_tool was tracked despite .dart_tool/ being ignored, and carried 48 absolute paths into a public repository. pub regenerates it, and switching to a hosted dependency would have written a pub-cache path under a developer's home directory into every future diff.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TLDR
Everything that had to be fixed to make a tag actually publish — six defects in a release pipeline that had never once executed — plus the real dmx icon, the install CTAs, and the examples now consuming
dmxfrom pub.dev instead of the copy beside them.Details
The release pipeline could not start, let alone publish. No tag had ever existed in this repository, so every step below failed the first time it ran:
verifycallsci.ymlgrantingcontents: read, butci.yml'ssecurityjob declarespull-requests: write. A called workflow may not exceed its caller's grant and GitHub checks that statically, before any job exists — so every tag died asstartup_failurewith zero jobs. Theif:that would have skippedsecuritynever got a say.vsix-universalpackages intosrc/dmx/target/, but unlikevsixit carries no binary, builds nothing, and so never creates that directory.vsceopens the--outpath rather than creating it:ENOENT, after the bundle was already assembled.alpine-x64binary segfaulted on its own--version(exit 139). Rust ships a musl libc and links that target self-contained; overridingCARGO_TARGET_..._LINKERwith Ubuntu'smusl-gccproduced a broken x86_64 static-PIE.CC_<triple>is still set — tree-sitter is C — but only a genuine cross-link (mingw) now names a linker.VSCE_PAT. vsce 3.x accepts--azure-credentialand consumes the Entra sessionazure/loginalready established from the job's OIDC token, so nothing token-shaped is handled at all. Microsoft retires Marketplace PATs on 1 December 2026.--dry-runran before stamping, on the reasoning that publishability does not depend on the version string. It does: pub validates the changelog against the current version, so the0.0.0placeholder always producedCHANGELOG.md doesn't mention current version, and once 0.1.0 existed, alsoyour version is earlier than that.--dry-runexits non-zero on any warning, so the step could never have passed. It now runs after the stamp, with the stamp committed into the throwaway checkout so the uncommitted-changes warning cannot fire — which also means it validates the archive actually being published rather than a differently-versioned one.releaseenvironment so it can actually read them. Environment secrets are visible only to a job declaring that environment; the guard's first version read them from a job that had none and refused a release whose secrets were set correctly.Intel macOS is no longer a deployment target. The
darwin-x64leg and its bundle are gone, and the docs no longer claim a macOS x64 build.The extension shipped an icon matching nothing else the project uses. Rebuilt from
website/src/assets/images/dmx-mark.svgat 256×256 on the brand ground, in the proportionsapple-touch-icon.pngalready establishes.The Marketplace URL was written with the publisher lowercase in six places. The gallery API accepts that form; the web page 404s on it. It is
Nimblesite.dmx.The site and docs now offer the install itself —
vscode:extension/Nimblesite.dmxopens the extension in the editor — alongside the Marketplace page, since thevscode:link is inert for a reader without VS Code. No new CSS: both CTAs reuse the existingbuttonclasses and the budget stays at 1983 of 2000 lines.The examples, golden corpus root, and the corpus pubspec the Makefile generates all depended on
src/dart_packages/dmxby path, so nothing here ever exercised the package as published. They now resolvedmx ^0.3.0from pub.dev — what a reader copying an example actually gets.examples/storefront/.dart_toolwas tracked despite.dart_tool/being gitignored, carrying 48 absolute paths under a developer's home directory into a public repository. pub regenerates it, and the switch to a hosted dependency would have written a pub-cache path into every future diff.How Do The Automated Tests Prove It Works?
The pipeline itself is the test, and it has now published twice from these commits:
Preflight, all sevenPackagelegs,Package universal,Verify / CI,Security gateacrossactions/rust/javascript-typescript,Publish, andPublish to pub.dev.Package alpine-x64executes the binary it just built and assertsdmx <version>; that step is what caught the SIGSEGV and is what proves the musl fix. It passed on two consecutive tags.Publish to pub.devsucceeded twice with the reordered stamp-then-prove path, so that fix is reproduced rather than lucky.dmx 0.3.0; the Marketplace gallery API returnsNimblesite.dmxat0.3.0acrossuniversal,win32-x64,alpine-x64,alpine-arm64,linux-x64,linux-arm64,darwin-arm64— and nodarwin-x64; the icon asset resolves underdmx/0.3.0/, so it is the new mark being served, not a cached one.make corpusregenerates all 11 golden samples against pub.devdmx 0.3.0anddart analyze --fatal-infosreports No issues found;make exampleruns the storefront suite — 179 tests, all passing — against the published package.make websitebuilds and all 24 Playwright e2e specs pass, includingnavigation.spec.tsassertions on the shared prose classes and the mobile navigation.Package has 0 warnings.For AI
mainwas truncated to a single parentless root commit and the repository was deleted and recreated to purgerefs/pull/*, which is read-only and cannot be removed any other way. Two consequences worth carrying forward:repo:Nimblesite@178527684/dmx@1334980307:environment:release; older repos presentrepo:Nimblesite/Deslop. Both reportuse_default: true/use_immutable_subject: false, so this is not a toggle — the prefix is assigned. The Entra app's flexible credential matchesrepo:Nimblesite/*:environment:releaseand cannot match the ID form; Entra also rejects@in the org segment of aclaimsMatchingExpressionfor the GitHub issuer, so an exact-subject federated credential (github-dmx-release) was added. Any Nimblesite repo recreated from here will hit this same wall.AZURE_CLIENT_ID/AZURE_TENANT_IDlive as environment secrets onrelease, not repo or org secrets. They are the app's publicappIdand the tenant GUID — identifiers, not credentials — readable fromaz.The
## Unreleasedheading is renamed by the release into its own checkout and never committed back, so shipped notes must be promoted to a real heading by hand or the next tag republishes them. This PR promotes 0.2.0's and opens a fresh## Unreleasedcarrying 0.3.0's.dbb34e5 "config"is an unrelated editor-settings commit swept in by a local auto-commit hook, not part of this work.