Skip to content

ci(release): switch release-please to packages/cli component and add OIDC publish workflow#1183

Merged
pedrofuentes merged 1 commit into
mainfrom
ci/release-automation
Jun 19, 2026
Merged

ci(release): switch release-please to packages/cli component and add OIDC publish workflow#1183
pedrofuentes merged 1 commit into
mainfrom
ci/release-automation

Conversation

@pedrofuentes

Copy link
Copy Markdown
Owner

Summary

T-P5: Switch release-please to proper monorepo/manifest mode targeting packages/cli (the only publishable package), and add a tokenless OIDC + provenance npm publish workflow.

Changes

  • release-please-config.json: Replaced the root . package entry with packages/cli. Added "component": "cli" and "include-component-in-tag": true so release tags are component-scoped (e.g. cli-v0.1.1), appropriate for a monorepo with one current publishable package plus future packages. release-type: node, bump-minor-pre-major: true, bump-patch-for-minor-pre-major: false, and the full changelog-sections array are unchanged.
  • .release-please-manifest.json: Repointed from { ".": "0.1.0" } to { "packages/cli": "0.1.0" }.
  • .github/workflows/release.yml (new): Publishes @council-ai/cli to npm on GitHub Release published, using OIDC trusted publishing + provenance — no stored npm token.

bootstrap-sha choice

Updated bootstrap-sha from the stale pre-monorepo SHA (aad17e6…) to the current post-monorepo main HEAD (a3c1ff6942d7cf8a95daaf2bd4f85b31affcc778). Because we are introducing a new packages/cli component path, release-please treats it as a new package; anchoring at current HEAD ensures the first generated release PR has a clean changelog scoped to new commits rather than replaying the entire pre-monorepo history.

Publish workflow details

  • Trigger: on: release: types: [published] — release-please creates the cli-v* GitHub Release when its release PR merges, which fires this workflow.
  • permissions: { contents: read, id-token: write }id-token: write is required for OIDC trusted publishing.
  • Steps (all actions SHA-pinned with # vX.Y.Z comments matching ci.yml): checkout → pnpm setup → setup-node 22 with registry-urlnpm install -g npm@latest (npm >= 11.5 required for OIDC; Node 22 ships npm 10.x) → pnpm install --frozen-lockfilepnpm --filter @council-ai/cli build → validation gate (publint, attw, npm pack --dry-run) → npm publish --provenance --access public in packages/cli.
  • No NODE_AUTH_TOKEN/NPM_TOKEN — tokenless by design. A human must configure the Trusted Publisher on npmjs.com before the first successful publish; the workflow is correct and tokenless now.

Validation

  • release-please-config.json and .release-please-manifest.json parse as valid JSON.
  • release.yml parses as valid YAML; all actions SHA-pinned with version comments.
  • git diff --stat shows exactly the 3 intended files.

This is a ci-type change (TDD-exempt; single commit). No source/tests/package.json touched, no deps changed.

…OIDC publish workflow

Repoints release-please manifest mode from repo-root to packages/cli with
component-scoped tags, and adds .github/workflows/release.yml that publishes
@council-ai/cli to npm via OIDC trusted publishing with provenance.

Co-authored-by: Copilot <175574315+pedrofuentes@users.noreply.github.com>
@pedrofuentes

Copy link
Copy Markdown
Owner Author

Status: CONDITIONAL

Sentinel Review Report

Ref: ci/release-automation → main
Report ID: sentinel-1183-0fc82d4-20260618
Reviewed SHA: 0fc82d4
Sentinel ruleset: v1
Reviewed at: 2026-06-18T21:53:55-07:00
Mode: standard
Review depth: Tier 2 (full)
Required action: FILE_ISSUES_AND_MERGE

Phase 0 — Binding

Bound to PR #1183, branch ci/release-automation, SHA 0fc82d4 (confirmed HEAD == reviewed SHA via git rev-parse HEAD). PR baseRefName: main; GitHub-computed PR scope = exactly 3 files (gh pr view 1183 --json files): .github/workflows/release.yml (new), release-please-config.json (M), .release-please-manifest.json (M). The local main..HEAD two-dot range shows 7 files because local main lags PRs #1176/#1177; those are already in the PR merge-base on GitHub and are NOT part of this PR's reviewable scope. Single commit: ci(release): switch release-please to packages/cli component and add OIDC publish workflow.

Phase 1 — TDD / Test Evidence

PR type = ci only (single ci(release) commit; all 3 changed files are CI/release config). Per ruleset §Exemptions, checks 1–4 are N/A (no behavior-bearing source). Check 6 (coverage) N/A.

  • Tests exist & meaningful: N/A (ci-exempt — no source/behavior changed)
  • Test-first history verified: N/A (ci-exempt)
  • Full suite green on SHA: ✅ ⚠️ parent/CI-provided evidence. gh pr checks 1183 → all 10 checks pass on 0fc82d4, incl. aggregate gate Typecheck, Lint & Test (ci-pass), Unit Tests (shard 1–4/4), E2E, Integration & Security Tests, Typecheck & Lint, CodeQL/Analyze. statusCheckRollup all SUCCESS/COMPLETED. Config/workflow files cannot affect the unit suite.
  • Coverage: N/A (threshold N/A; ci-exempt)

Phase 1.5 — Fast-path Evaluation

🔴 count: 0 | LOC: ~54 non-test (≤150: Y) | Security paths: Y (release/publish supply-chain workflow with id-token: write) | New deps: N | Commit types qualify: N (ci is not in the fast-path set {fix,refactor,docs,test,style,chore})
→ Fast-path eligible: NO → Phase 2 (Tier 2 full review)

Phase 2 — Execution Log

Dim Tool Call Agent ID / Ref Status
A1 task(general-purpose, sonnet-4.6, name="dim-a1") dim-a1 (background)
A2 task(general-purpose, sonnet-4.6, name="dim-a2") dim-a2 (background)
B N/A (exempt: ci — no resilience surface) ⏭️
C N/A (exempt: ci — no performance surface) ⏭️
D N/A (exempt: ci — no test/impl surface) ⏭️
E task(general-purpose, sonnet-4.6, name="dim-e") dim-e (background)
F task(general-purpose, sonnet-4.6, name="dim-f") dim-f (background)

Selective dispatch per §Selective dispatch: ci → A1, A2, E, F dispatched; B/C/D logged N/A (exempt). All dispatched rows returned distinct results.

Findings

  • 🔴 CRITICAL: 0
  • 🟡 IMPORTANT: 1 new / 0 known
  • 🟢 MINOR: 5

Details (ordered by severity)

  1. [🟡 IMPORTANT] Unpinned npm@latest installed in the OIDC publish critical path — .github/workflows/release.yml:27-29

    • Evidence:
      - name: Update npm for OIDC trusted publishing
        # OIDC trusted publishing requires npm >= 11.5; Node 22 ships npm 10.x.
        run: npm install -g npm@latest
    • Trigger→Mechanism→Consequence: On every release: published run, npm@latest resolves at runtime to a mutable registry version (mechanism) that then executes the privileged npm publish --provenance step inside a job holding id-token: write (trigger) → non-deterministic publish behavior across runs, and a floating-toolchain supply-chain exposure in the highest-trust step (consequence). Independently flagged by Dim A1, A2, and E.
    • Impact: Functionally correct (any current npm@latest ≥ 11.5 satisfies OIDC), so NOT a 🔴 misconfig and the maintainer-gated trigger limits exposure — but it violates the repo's own pinning convention (every GitHub Action here is pinned to a full commit SHA) and reproducibility/SLSA hardening guidance.
    • Remediation (file as issue, do NOT fix in-PR): pin to an explicit minimum-satisfying version, e.g. run: npm install -g npm@11.5.0, and track bumps via Dependabot/Renovate.
  2. [🟢 MINOR] id-token: write declared at workflow scope rather than job scope — .github/workflows/release.yml:7-9

    • Evidence:
      permissions:
        contents: read
        id-token: write
    • Impact: Zero risk today (single publish job). If a second job is later added without its own permissions: block it silently inherits OIDC mint capability. Least-privilege hardening only. (Dim A1, A2)
    • Remediation: move the permissions block under jobs.publish.
  3. [🟢 MINOR] pnpm/action-setup pinned to the annotated-tag-object SHA, not the underlying commit SHA — .github/workflows/release.yml:19

    • Evidence:
      - uses: pnpm/action-setup@d15e628ca66d93ee5f352c71671a7bc6a97af5c9 # v6.0.8
    • Impact: Functions correctly (Actions dereferences tag objects) and is byte-identical to the established .github/workflows/ci.yml convention (lines 20/48/76), which is CI-verified green — so consistent with the repo. Pinning tooling keys on commit SHAs; cosmetic supply-chain nit. (Dim A2)
    • Remediation (optional, repo-wide): if changed, update ci.yml in lockstep to the commit SHA 0e279bb959325dab635dd2c09392533439d90093.
  4. [🟢 MINOR] README install command references @council/cli (package is @council-ai/cli) — README.md:66 (pre-existing, OUTSIDE this PR's changed-file scope)

    • Evidence:
      npm install -g @council/cli   # coming soon — not yet on npm
    • Impact: packages/cli/package.json name is @council-ai/cli; once published, this README line yields a 404. Pre-existing defect in an unchanged file — capped 🟢 per Phase 2 scope. Worth an issue. (Dim F)
    • Remediation: file an issue to correct README to @council-ai/cli.
  5. [🟢 MINOR] Release/publish process & OIDC trusted-publishing decision undocumented — .github/workflows/release.yml:3-5, 47-49

    • Evidence:
      on:
        release:
          types: [published]
    • Impact: No DECISIONS.md ADR for choosing OIDC tokenless publishing over NPM_TOKEN, and the one-time npmjs.com Trusted Publisher setup prerequisite (without which the first publish fails) is undocumented. Operational/docs gap; non-blocking (Dim F cap 🟡, reclassified 🟢 — maintainer-gated, no user-impact-under-normal-usage path). (Dim F)
    • Remediation: file an issue to add an ADR + a Release Process note in docs/DEVELOPMENT-WORKFLOW.md, incl. the npmjs.com trusted-publisher setup step.
  6. [🟢 MINOR] $schema references the floating main branch — release-please-config.json:2 (unchanged context line)

    • Evidence:
      "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
    • Impact: Editor-time schema fetch only; never executed in CI/publish. Pre-existing unchanged line. Negligible. (Dim E)
    • Remediation: optionally pin to a tagged schema ref.

Verified-good (no findings)

  • Trigger release: published is maintainer-gated; no pull_request_target, no checkout of untrusted PR code, no ${{ github.event.* }} in run: blocks (Dim A1).
  • permissions is least-privilege: contents: read + id-token: write (required for OIDC); no over-broad grants (A1/A2).
  • Tokenless OIDC: no NODE_AUTH_TOKEN/NPM_TOKEN/secrets present or required; npm publish --provenance --access public correct; TLS registry URL (A2).
  • All three actions pinned to full SHAs with # vX.Y.Z comments, byte-identical to ci.yml (A1/E).
  • Validation gate ordering correct: build → publint → attw → npm pack --dry-run precede npm publish (publish cannot run without the gate) (A1/E).
  • release-please config/manifest consistency: package key packages/cli (not .), release-type: node, component: cli, include-component-in-tag: true, changelog-sections preserved; manifest { "packages/cli": "0.1.0" } matches packages/cli/package.json version 0.1.0; bootstrap-sha a3c1ff6 is a real recent branch/main commit (Merge #1177), sane (E/F).
  • JSON parses (validated via JSON.parse); release.yml valid YAML (50 lines). CHANGELOG check skipped — Release Please generates it (Dim F).

Follow-ups & Actions

Decision rationale

  • Zero 🔴 across all four dispatched dimensions; HEAD == reviewed SHA 0fc82d4.
  • One new 🟡 (unpinned npm@latest) with a concrete trigger→mechanism→consequence path → CONDITIONAL per Phase 4.
  • Security design is sound: tokenless OIDC + provenance, least-privilege permissions, maintainer-gated trigger, SHA-pinned actions, validation gate before publish.
  • Config/manifest are internally consistent and match the package version; CI (incl. ci-pass aggregate) is green on the reviewed SHA.

@pedrofuentes

Copy link
Copy Markdown
Owner Author

Sentinel review CONDITIONAL (sentinel-1183-0fc82d4-20260618) — 0 blockers; full report posted above. Per process, the new findings are filed as follow-up issues (not fixed in this PR) and this PR is cleared to merge:

@pedrofuentes pedrofuentes merged commit cf50b74 into main Jun 19, 2026
10 checks passed
@pedrofuentes pedrofuentes deleted the ci/release-automation branch June 19, 2026 05:06
pedrofuentes added a commit that referenced this pull request Jun 19, 2026
…, RELEASING, issue/PR templates

Sentinel Report: SENTINEL-1198-a92c3dc-20260618 - CONDITIONAL (0 blockers; 2 yellow were stale-base, resolved by PR #1183 on main; green tracked in #1200). Reviewed SHA: a92c3dc
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.

1 participant