Skip to content

ci: publish Dart packages with OIDC#4

Merged
Fermionic-Lyu merged 5 commits into
mainfrom
codex/add-pubdev-publishing
Jul 16, 2026
Merged

ci: publish Dart packages with OIDC#4
Fermionic-Lyu merged 5 commits into
mainfrom
codex/add-pubdev-publishing

Conversation

@Fermionic-Lyu

@Fermionic-Lyu Fermionic-Lyu commented Jul 15, 2026

Copy link
Copy Markdown
Member

What changed

  • add separate OIDC publishing workflows for insforge and insforge_flutter
  • use package-specific stable/prerelease tag patterns required for pub.dev monorepos
  • validate each tag against pubspec.yaml and enforce lockstep package/runtime versions
  • delegate publication to Dart's official reusable workflow pinned at v1.7.2
  • add formatting and both package publish dry-runs to normal CI
  • document the required core-first release order and update version-tool guidance
  • apply the repository's existing Dart formatting/lint rules so the new format gate starts green

Release behavior

The packages remain versioned in lockstep but are published with separate tags:

  1. insforge-vX.Y.Z
  2. wait for that core version on pub.dev
  3. insforge_flutter-vX.Y.Z from the same release commit

No pub.dev token or GitHub deployment environment is used.

Validation

  • Dart format: 126 files checked, 0 changes
  • Dart analyze: no issues
  • version sync check: 0.1.0 in sync across both packages and runtime constant
  • core: 181 tests passed; publish dry-run with 0 warnings
  • Flutter wrapper: 5 tests passed; analyze clean; publish dry-run with 0 warnings
  • actionlint and tag/version positive/negative cases

pub.dev setup after merge

Enable GitHub Actions automated publishing on both existing packages:

  • insforge: repository InsForge/insforge-flutter, tag pattern insforge-v{{version}}
  • insforge_flutter: repository InsForge/insforge-flutter, tag pattern insforge_flutter-v{{version}}

Do not require a GitHub Actions environment.


Summary by cubic

Adds OIDC-based publishing for insforge and insforge_flutter using package-specific tags, with release gating and auto GitHub Releases for stable tags. CI enforces format/analyze/tests, runs publish dry-runs, pins actions, and trims published artifacts.

  • New Features

    • Publish via dart-lang/setup-dart/.github/workflows/publish.yml@v1.7.2 using OIDC; stable tags auto-create a GitHub Release after pub.dev succeeds; no pub.dev token or GitHub environment.
    • Strong validation: tag must match pubspec.yaml, lockstep versions via tool/set_version.dart --check, and insforge_flutter waits for the matching insforge version to be live on pub.dev; release jobs reuse CI via workflow_call.
    • CI: dart format --set-exit-if-changed, analyze, tests, and dart pub publish --dry-run for both packages; actions pinned by commit SHA; weekly Dependabot for github-actions.
    • .pubignore updated in both packages to exclude .dart_tool/, build/, and test/.
  • Migration

    • Enable pub.dev automated publishing:
      • insforge: repo InsForge/insforge-flutter, tag pattern insforge-v{{version}}
      • insforge_flutter: repo InsForge/insforge-flutter, tag pattern insforge_flutter-v{{version}}
    • Release order: push insforge-vX.Y.Z, wait until live on pub.dev, then push insforge_flutter-vX.Y.Z from the same commit.

Written for commit 9e9917f. Summary will update on new commits.

Review in cubic

@Fermionic-Lyu
Fermionic-Lyu marked this pull request as ready for review July 15, 2026 23:57

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds OIDC-based per-package pub.dev publishing workflows, a version-lockstep validate gate, CI format + dry-run checks, and a repo-wide dart format sweep to make the new format gate green — solid and mostly idiomatic, but the publish validate job can't resolve the workspace without the Flutter SDK, which will fail every release.

Requirements context

No spec/plan under docs/superpowers/ matches this change — the specs there (docs/superpowers/specs/2026-06-08-insforge-flutter-sdk-design.md and the plans/ files) cover the SDK's core/auth/database/storage/functions/ai design, not CI or release automation. Assessed against the PR description, CONTRIBUTING.md, and repo conventions (analysis_options.yaml, melos.yaml, root pub workspace). External action/workflow references were verified live: actions/checkout@v7 (exists, Jun 2026), dart-lang/setup-dart@v1.7.2 and the reusable .../publish.yml@v1.7.2 (exists, Mar 2026; sets up both Flutter and Dart, so the publish jobs themselves are fine).

Findings

Critical

Functionality — the publish validate job installs only Dart but must resolve a Flutter workspace.github/workflows/publish-insforge.yml:18,31 and .github/workflows/publish-insforge-flutter.yml:18,31

The validate job sets up only the standalone Dart SDK (dart-lang/setup-dart@v1.7.2, line 18) and then runs dart run tool/set_version.dart --check (line 31). On a fresh runner there is no resolved package config — .dart_tool/ and pubspec.lock are both gitignored (.gitignore), so nothing is checked out. dart run therefore triggers an implicit resolution of the root pub workspace (pubspec.yaml: _insforge_workspace), whose members include packages/insforge_flutter, which depends on flutter: sdk: flutter. Pub cannot resolve an sdk: flutter dependency without the Flutter SDK installed, so the step fails before _check()'s file-reading logic ever runs — and because publish has needs: validate, publication never happens.

This is exactly the constraint the author already documented in .github/workflows/ci.yaml:9-11: "the whole workspace must be resolved with the Flutter toolchain (which bundles Dart)." The analyze-and-test job honors it (subosito/flutter-action + flutter pub get); the two new validate jobs do not. The PR's "version sync check" validation was presumably run in that Flutter-enabled context, so this path is untested (it only fires on a tag push).

Suggested fix: set up Flutter in the validate job (mirror CI with subosito/flutter-action@v2.23.0 + flutter pub get before the check), or make the check self-contained so it doesn't require workspace resolution.

Suggestion

  • Security / supply chain — pin third-party actions by commit SHA (publish-*.yml:16-18, ci.yaml). These workflows carry id-token: write publish privileges. subosito/flutter-action@v2.23.0 in particular is a third-party action pinned to a mutable tag; pinning to a full commit SHA is the standard hardening for release-privileged workflows. dart-lang/setup-dart and actions/checkout are first-party/reputable, so this is lower risk there. Non-blocking.
  • Functionality — core-before-flutter release order is doc-only (CONTRIBUTING.md:139-160, publish-insforge-flutter.yml). Nothing stops someone pushing insforge_flutter-vX.Y.Z before the matching insforge version is live on pub.dev. The failure mode is a failed publish (fail-safe, not data loss), but the flutter validate job could assert the core version is already available on pub.dev to fail fast with a clear message. Non-blocking.

Information

  • Software engineering — large formatting sweep bundled with the feature (~25 lib/test files). This is justified — the new dart format --set-exit-if-changed gate plus the existing require_trailing_commas lint (analysis_options.yaml) require the tree to be pre-formatted, and the PR body calls this out. It does enlarge the diff and mix concerns; a separate "style" PR (like the earlier 9833ade style: apply Dart formatter) would keep the feature diff focused. No behavior change in the reformatted code.
  • Scope — actions/checkout@v4 → v7 (ci.yaml) is unrelated to the OIDC goal, but v7 is valid and harmless.
  • Functionality — tag/version sed extraction is whitespace-sensitive (publish-*.yml:24). sed -n 's/^version:[[:space:]]*//p' is correct for the current clean version: 0.1.0 line, but would misbehave if a trailing comment were ever added to the version line. Minor.
  • Security (positive) — good practices: OIDC with no stored pub.dev token, minimal permissions (contents: read for validate, id-token: write for publish), and RELEASE_TAG passed via env: rather than interpolated into the shell script (avoids injection).
  • Performance — no performance-relevant changes; this is CI/release tooling only.

Verdict

request_changes — one Critical: the Dart-only publish validate jobs cannot resolve the Flutter-containing workspace and will fail on every tagged release, blocking publication. Everything else is non-blocking. Once the validate jobs set up Flutter (or the check is made resolution-free), this is in good shape.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 34 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/workflows/publish-insforge.yml Outdated
Comment thread CONTRIBUTING.md Outdated
Comment thread .github/workflows/publish-insforge-flutter.yml

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: ci: publish Dart packages with OIDC

Summary: A well-constructed release-infra PR that adds OIDC-based pub.dev publishing for both monorepo packages with lockstep version gating; the substantive workflow logic is correct and security-conscious, and the large remaining diff is behavior-preserving auto-formatting to make the new dart format gate start green.

Requirements context

docs/superpowers/ contains the SDK design spec and per-feature plans (specs/2026-06-08-insforge-flutter-sdk-design.md, plans/…-01…07), but none cover release/CI/publishing — this PR is release infrastructure not described by any spec. Assessed against the PR description, CONTRIBUTING.md, and the official dart.dev automated-publishing guidance. I verified the OIDC setup against dart.dev docs via context7 and the pinned action SHAs against the GitHub API.

Findings

Critical

(none)

Suggestion

  • Software engineering / DRY — version parsing duplicated (.github/workflows/publish-insforge.yml:24-29, .github/workflows/publish-insforge-flutter.yml:26-31). The tag/version match uses a sed -n 's/^version:[[:space:]]*//p' one-liner, while tool/set_version.dart already owns version parsing. The sed form doesn't strip a trailing inline comment or CR and re-implements logic that lives elsewhere. Low blast radius (pubspec version: lines are simple), but reusing the tool (or a shared composite step) would keep a single source of truth.
  • Testing — new strict SemVer regex is untested (tool/set_version.dart:21-26). _semver was rewritten from a loose pattern to a strict SemVer regex, but there's no test/ for tool/, and the regex is only exercised on the set path (not --check), so CI won't catch a regression. A handful of table cases (accept 0.1.0, 1.2.3-beta.1, 1.2.3+build; reject 01.2.3, 1.2) would lock the behavior cheaply.

Information

  • Security / hardening — no deployment environment (publish-insforge.yml:57-63, publish-insforge-flutter.yml:70-76). The PR deliberately opts out of a GitHub Actions environment: pub.dev (documented by dart.dev as optional). That's a valid choice; noting only that an environment with protection rules (required reviewers / ref restrictions) is the available defense-in-depth layer if you later want to constrain who/what can trigger a publish.
  • Security — action pinning verified. All three pinned SHAs resolve to exactly their claimed tags via the GitHub API: actions/checkout@9c091bb = v7, subosito/flutter-action@1a44944 = v2.23.0, dart-lang/setup-dart@65eb853 = v1.7.2 (action + reusable publish.yml pinned to the same SHA). Per-job permissions are minimal and the publish job's id-token: write-only grant matches the official dart.dev reusable-workflow pattern. OIDC replaces a stored pub.dev token — good.
  • Functionality — pub.dev propagation window (publish-insforge-flutter.yml:47-56). The "matching insforge version is published" gate polls with --retry 5 --retry-delay 10 (~50s). pub.dev propagation after a publish can occasionally exceed that; if it does, the flutter release job fails but is safely re-runnable, so this is acceptable — just flagging the tight-ish window.
  • Functionality — build-metadata tag pattern (publish-insforge.yml:8, publish-insforge-flutter.yml:9). The …\+* pattern admits +build tags, but build metadata is unusual for published packages and pub.dev strips it, so the …/versions/$RELEASE_VERSION lookup may not resolve a +build version. Edge case only.
  • Software engineering — the bulk diff is formatting. The library/test changes across packages/insforge/** and integration_tests/** are dart format reflows (line-wrapping, trailing-comma normalization, blank-line trims) landed to make the new dart format --set-exit-if-changed gate green. Spot-checked several semantically load-bearing spots (rpc_test.dart chained .rpc(...).execute(), database_test.dart inFilter(...).execute(), batch-insert maps) — all behavior-preserving.
  • Correctness cross-check. resolution: workspace in packages/insforge_flutter/pubspec.yaml means dart pub publish --dry-run resolves the insforge dep from the local workspace, so the dry-run in ci.yaml doesn't depend on pub.dev availability; the runtime ordering constraint (core live before flutter tag) is enforced only at the real publish step, which is correct. Current versions are in lockstep (0.1.0 across both pubspecs + insforge: ^0.1.0), so set_version.dart --check passes.

Verdict

approved (informational — a human still gives the explicit GitHub approval). Zero Critical findings; the Suggestions and Information items are non-blocking. This is a clean, docs-aligned release pipeline: OIDC over a stored token, SHA-pinned + verified actions, minimal per-job permissions, lockstep version validation, and a green-on-arrival formatter gate.

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - approved.

@Fermionic-Lyu
Fermionic-Lyu merged commit 3b2807e into main Jul 16, 2026
2 checks passed
@Fermionic-Lyu
Fermionic-Lyu deleted the codex/add-pubdev-publishing branch July 16, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants