Skip to content

contractual next version - #15

Open
omermorad wants to merge 48 commits into
masterfrom
next
Open

omermorad wants to merge 48 commits into
masterfrom
next

Conversation

@omermorad

Copy link
Copy Markdown
Contributor

No description provided.

@omermorad omermorad self-assigned this Mar 12, 2026
@omermorad omermorad added the next label Mar 12, 2026
Change `npx contractual` to `npx @contractual/cli` to ensure
the correct package is used from the Verdaccio registry instead
of an unrelated `contractual` package from npm.
Changed JSON output from { results: [...] } to { contracts: { name: {...} } }
to match expected format in e2e tests and provide better ergonomics for
scripting (e.g., parsed.contracts.order.changes).
omermorad and others added 2 commits March 27, 2026 16:38
 - @contractual/changesets@0.1.0-dev.0
 - @contractual/cli@0.1.0-dev.0
 - @contractual/differs.json-schema@0.1.0-dev.0
 - @contractual/governance@0.1.0-dev.0
 - @contractual/types@0.1.0-dev.0
- Change openapi-diff from ^0.24.1 to ^0.23.7
- Version 0.24.x doesn't exist on npm, latest is 0.23.7
- Fixes npm install errors when using published packages
omermorad and others added 18 commits April 2, 2026 20:00
Update tests to use new contracts object format instead of results array:
- Old format: { results: [...] }
- New format: { contracts: { contractName: {...} } }

Fixes:
- --format json test: check for contracts object instead of results array
- --severity breaking test: iterate over contracts object
- --severity non-breaking test: iterate over contracts object

All 17 tests now passing.
 - @contractual/cli@0.1.0-dev.1
 - @contractual/governance@0.1.0-dev.1
Replace the `openapi-diff` npm package (3.0 only) with a custom OpenAPI
differ built on @redocly/openapi-core, supporting both 3.0 and 3.1 specs.

Extract shared schema diffing primitives (walker, classifiers, ref-resolver)
into @contractual/differs.core so they can be reused across differs.

New packages:
- @contractual/differs.core — shared walker, classifiers, ref-resolver
- @contractual/differs.openapi — OpenAPI 3.0/3.1 differ via Redocly

Changes:
- @contractual/differs.json-schema now wraps differs.core (backward compat)
- @contractual/governance drops openapi-diff dep, registers new differ
- @contractual/types extended with 15 OpenAPI structural change types
- Add e2e tests for OpenAPI 3.1 (type arrays, type narrowing/widening)

Spec version sync:
- New utility `updateSpecVersion()` in @contractual/changesets that updates
  the version field inside spec files (info.version for OpenAPI/AsyncAPI,
  top-level version for ODCS, skipped for JSON Schema)
- Preserves YAML comments/formatting via parseDocument(), detects JSON indent
- Creates missing version fields (e.g., missing info object) automatically
- Called before bump/setVersion so snapshot copies include the updated version
- Per-contract opt-out via `syncVersion: false` in contractual.config.json
- CLI flag `--no-sync-version` to skip for all contracts in a run
- Integrated into `contract add` command for initial version sync
- 22 e2e tests covering all spec types, bump types, missing fields,
  pre-release, multi-contract, config opt-out, and CLI flag

# Conflicts:
#	pnpm-lock.yaml
 - @contractual/changesets@0.1.0-dev.1
 - @contractual/cli@0.1.0-dev.2
 - @contractual/differs.core@0.1.0-dev.1
 - @contractual/differs.json-schema@0.1.0-dev.1
 - @contractual/differs.openapi@0.1.0-dev.1
 - @contractual/governance@0.1.0-dev.2
 - @contractual/types@0.1.0-dev.1
…flow

Redocly's bundle with dereference:true creates JS object cycles for
circular schemas (e.g. Category referencing itself). Our deepEqual
recurses infinitely on these cycles.

Fix: use Redocly for bundling only (resolves external refs), then use
our own ref-resolver from differs.core which has circular detection
and replaces cycles with $circularRef placeholders.

Also:
- Move @redocly/openapi-core from optional peer dep to regular dep
  in differs.openapi so users don't need to install it separately
- Remove peer dep from governance (gets it transitively)
- Add e2e tests for circular ref schemas
- Add timeout option to e2e test helper
 - @contractual/cli@0.1.0-dev.3
 - @contractual/differs.openapi@0.1.0-dev.2
 - @contractual/governance@0.1.0-dev.3
 - @contractual/changesets@0.1.0-dev.4
 - @contractual/cli@0.1.0-dev.4
 - @contractual/differs.core@0.1.0-dev.4
 - @contractual/differs.json-schema@0.1.0-dev.4
 - @contractual/differs.openapi@0.1.0-dev.4
 - @contractual/governance@0.1.0-dev.4
 - @contractual/types@0.1.0-dev.4
… changes

- Adding optional parameter is now non-breaking (was incorrectly breaking)
- Adding required parameter uses new parameter-required-added type (breaking)
- Detect operation-level metadata changes: description, summary, deprecated
- Detect top-level info.description and info.title changes
- All metadata changes classified as patch (creates changesets, not breaking)
…nter paths

formatChangeMessage() had no cases for OpenAPI structural types
(path-added, operation-added, parameter-*, response-*, etc.) so
they were falling through to "Unknown change at /paths/~1v2~1media".

Now shows "New path added: /v2/media" instead.

- Add cases for all 16 OpenAPI structural change types
- Decode JSON Pointer paths for display (~1 → /, ~0 → ~)
- Add e2e tests for message formatting
 - @contractual/changesets@0.1.0-dev.5
 - @contractual/cli@0.1.0-dev.5
 - @contractual/differs.core@0.1.0-dev.5
 - @contractual/differs.json-schema@0.1.0-dev.5
 - @contractual/differs.openapi@0.1.0-dev.5
 - @contractual/governance@0.1.0-dev.5
 - @contractual/types@0.1.0-dev.5
anyOf/oneOf/allOf and conditional schema changes were falling through
to the default case, producing "Unknown change" messages in PR comments.
 - @contractual/cli@0.1.0-next.0
 - @contractual/differs.core@0.1.0-next.0
 - @contractual/differs.json-schema@0.1.0-next.0
 - @contractual/differs.openapi@0.1.0-next.0
 - @contractual/governance@0.1.0-next.0
 - @contractual/cli@0.1.0-dev.6
 - @contractual/differs.core@0.1.0-dev.6
 - @contractual/differs.json-schema@0.1.0-dev.6
 - @contractual/differs.openapi@0.1.0-dev.6
 - @contractual/governance@0.1.0-dev.6
… double slashes

OpenAPI path keys like /v1/extract were producing //v1/extract in
changeset output. Decode per-segment and bracket keys containing slashes.
 - @contractual/cli@0.1.0-dev.7
 - @contractual/differs.core@0.1.0-dev.7
 - @contractual/differs.json-schema@0.1.0-dev.7
 - @contractual/differs.openapi@0.1.0-dev.7
 - @contractual/governance@0.1.0-dev.7
updateYamlSpec parsed leniently with parseDocument() then called
doc.toString() unconditionally, which throws 'Document with errors
cannot be stringified' whenever the spec has any recoverable parse
error (e.g. an under-indented multi-line scalar deep in the file).
A cosmetic version sync would then take down the entire release.

Now: clean docs use the structured setIn + toString path; docs with
parse errors fall back to a surgical in-place splice of just the
version field's source range, leaving malformed regions untouched;
if the field cannot be located we warn and continue instead of
throwing. Numeric-looking versions are kept as strings.

Adds a co-located unit test (vitest devDep + lockfile entry) and
excludes *.test.ts / *.spec.ts from tsconfig.build.json so tests are
never compiled into the published dist.
## Summary

Mitigate the reachable glob-parsing stack-exhaustion path identified in
the separate risk review for
[GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm).

- Check the exact resolved pattern before calling `fast-glob`: maximum
length 1,024 JavaScript string code units and maximum brace/parenthesis
nesting 32.
- Use a bounded, non-recursive scan that respects escapes, quotes,
character classes, and matching delimiters.
- Reject excessive patterns with a clear `ConfigError` without logging
the supplied pattern. Literal paths and ordinary glob matching retain
their existing behavior.
- Add 19 regression cases to the existing configuration E2E suite,
covering the reproduced input, boundary limits, quoted/escaped/class
closers, mixed nesting, normal matches, and literal paths. No new test
files or test infrastructure.
- Include the dependency overrides and lockfile updates from #31. The
live audit now reports only the two reviewed advisories below, instead
of the 23 findings on the original branch.
- Keep audit handling inline in the existing GitHub Actions workflow. No
scripts folder, custom action, or additional workflow is introduced.

## Verification

- `pnpm build`: passed.
- `pnpm lint`: passed.
- `pnpm test`: 8 passed.
- `pnpm test:e2e`: 358 passed, 1 existing skip.
- `git diff --check`: passed.
- Workflow linting: passed. Existing Node 22/24/26 matrix unchanged.
- Live audit gate: passed with the two explicitly accepted risks, not a
clean vulnerability report.
- Clean-worktree audit: passed after a frozen, scripts-disabled install.
This install is required because pnpm returns empty dependency paths
without `node_modules`; the gate deliberately rejects incomplete paths.
- 17 ephemeral gate probes passed: expiry boundaries, clean reports
after expiry, additional low-severity findings,
registry/malformed-report errors, unexpected statuses, muted findings,
changed advisory IDs/packages/versions, unreviewed cache paths, and
inconsistent metadata. No repository test files were added for these
probes.

## Scope and remaining risk

- Targets `next`. Security changes are also integrated into #31 without
rewriting either branch's existing commits. Review this security PR
first; #31 retains the separate beta-workflow changes.
- Changes the CLI config loader, its existing E2E suite, dependency
overrides/lockfile, and existing dependency-audit workflow. No package
release versions, CI matrix, rulesets, or release workflows change here.
- This addresses the reported recursive glob-input path, not every
possible glob-complexity denial of service or every transitive `braces`
consumer.
- Omer approved two temporary CI risk exceptions on 2026-10-08. They
expire at **2026-10-22 05:37:00 UTC**, with no automatic extension:
- [braces /
GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm),
only version 3.0.3. CLI glob guards mitigate the reviewed input path;
other tooling consumers remain affected.
- [http-cache-semantics /
GHSA-ch52-4w7c-c8xp](GHSA-ch52-4w7c-c8xp),
only version 4.2.0 through the reviewed root Lerna 9.0.7 paths. Reviewed
callers use private caches on fresh runners; this is not approval for
shared-cache usage.
- Every other advisory remains blocking, regardless of severity.
Registry/schema errors fail closed. At expiry, either remaining advisory
blocks again; a clean audit still passes. Warnings and the job summary
make accepted risk visible. Remove these exceptions when patched; no
security alert is dismissed.
- The Action still bundles the published CLI. It receives this
mitigation only after a separately approved Contractual publication
followed by an Action dependency/bundle update. No SHA substitution or
release is performed here.
- These exceptions apply to CI only. The publishing audit in #31 remains
strict; any publishing-gate exception needs separate approval. No
approval to merge, create/move tags, publish packages, or create GitHub
Releases is implied or exercised.
## Scope

- Keep `release-preview.yml`, `release-packages.yml`,
`publish-packages.yml`, and `tag-global.yml`; no replacement workflows
or new test files.
- Use matching beta versioning inputs/commands in preview and
preparation, refresh the lockfile, and create scoped Conventional Commit
release PRs targeting `next`.
- Keep preparation, publishing, and tagging separate. Require manual
dispatch, the existing `release` environment approval, and reviewed
commit verification for release operations.
- Publish only beta package versions to the `beta` dist-tag. Validate
immutable tags and registry commit metadata; never move exact-version
tags.
- Update dependency overrides and the lockfile to available patched
versions. No package release versions changed.
- Integrate #32's CLI glob hardening, existing E2E regression cases, and
approved time-limited CI audit exceptions without rewriting branch
history. Review #32 first; this PR retains the separate beta-workflow
changes.

## Validation

- Workflow linting and `git diff --check` pass.
- Combined dependency and CLI changes pass existing build, lint, unit
tests (8), and E2E tests (358 passed, 1 existing skip).
- Live CI audit gate and 17 ephemeral failure/expiry probes pass. No new
test files or test infrastructure were added. The Node 22/24/26 matrix
and Lerna configuration are unchanged.
- Clean-worktree audit passes with a frozen, scripts-disabled install.
The audit workflow now performs that install so pnpm can report the
dependency paths required by the exception checks.

## Remaining blockers

This is a draft, not approval to merge or release. The underlying audit
still reports two high-severity advisories with no patched versions
listed. Omer approved temporary CI-only risk exceptions on 2026-10-08,
expiring at **2026-10-22 05:37:00 UTC**:

- [braces:
GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm),
only version 3.0.3. CLI length/depth guards mitigate the reviewed
glob-input path; tooling consumers remain affected.
- [http-cache-semantics:
GHSA-ch52-4w7c-c8xp](GHSA-ch52-4w7c-c8xp),
only version 4.2.0 through the reviewed root Lerna 9.0.7 paths, whose
callers use private caches on fresh runners.

The existing dependency-audit workflow enforces this fixed expiry and
reports warnings/job summaries. All other findings remain blocking,
including low severity; registry and malformed-report errors fail
closed. At expiry, either remaining advisory blocks again. Exceptions
should be removed when patched, and no security alert is dismissed.

**Publishing remains blocked:** `publish-packages.yml` keeps its strict
`pnpm audit --audit-level low` gate. Applying these exceptions to
publishing was blocked by the approval safeguard and requires separate
explicit approval. The manual release/environment approvals remain
intact regardless. The Action still needs a separately approved
Contractual publication and dependency/bundle update to receive the CLI
mitigation.

No workflows have been dispatched, and no tags, packages, or releases
have been published. Existing history and version tags are unchanged.
Omer must explicitly approve any future tagging or publishing operation.
omermorad and others added 4 commits October 8, 2026 16:52
## Summary

- Reuse the release branch already created by [Prepare
Release](https://github.com/codotech/contractual/actions/runs/37761823475),
without rerunning version preparation or rewriting history.
- Prepare all seven public Contractual packages as `0.1.0-beta.0`, with
generated package changelogs.
- Target `next`; this PR does not tag or publish anything.

## Verification

- Preparation completed installation, build, unit tests, and E2E tests
before versioning.
- The workflow failed only when creating the PR because Actions PR
creation was disabled.
- PR checks must now validate the prepared version commit before review
and merge.

## Release gates

- CI retains only the two approved temporary advisory exceptions,
expiring at 2026-10-22 05:37:00 UTC.
- The publishing workflow still uses its strict audit gate. No
release-time exception is approved by this PR.
- Omer must separately approve the exact publication commit, package
versions, and any tag or release operation.
- After an approved Contractual publication, update and rebuild
contractual-action against the published betas through its own PR to
next.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Scope

- Apply Omer's explicit 2026-10-08 approval for the two reviewed
publishing-audit risk exceptions. This is preparation only, not approval
to dispatch publication, tag, publish packages, or create releases.
- Change only the audit step in the existing `publish-packages.yml`; use
the same native inline audit logic and fixed expiry as CI.
- No package versions, source code, dependencies, scripts, custom
actions, test files, or other workflows change.

## Exact exceptions and expiry

Both exceptions expire at **2026-10-22 05:37:00 UTC**, with no
extension:

-
[GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm):
only `braces@3.0.3`. The merged CLI glob size/depth guards mitigate the
reviewed input path; tooling consumers remain affected.
-
[GHSA-ch52-4w7c-c8xp](GHSA-ch52-4w7c-c8xp):
only `http-cache-semantics@4.2.0` through the reviewed root
`lerna@9.0.7` dependency paths. Reviewed callers use private caches on
fresh runners; this does not authorize shared-cache usage.

Every other advisory remains blocking regardless of severity. Registry
errors, unexpected statuses, invalid reports, muted findings, missing
dependency paths, and inconsistent counts fail closed. At expiry, either
remaining advisory blocks again; a clean report still passes. Accepted
risks remain visible in warnings and the job summary. Remove the
exceptions when patches are available; no security alert is dismissed.

## Preserved release safeguards

- Manual dispatch on `next`, the `release` environment approval, and
exact approved-commit verification remain unchanged.
- Beta-only package metadata, immutable-tag checks, registry
ownership/commit checks, and the `beta` dist-tag remain unchanged.
- A structural comparison confirmed that replacing the new audit step
with the original single-line audit reproduces the previous workflow
exactly.
- Contractual only: this does not change contractual-action's release
audit.

## Validation

- Frozen install, build, lint: passed.
- Existing unit tests: 8 passed.
- Existing E2E suite: 358 passed, 1 existing skip.
- Actionlint and whitespace checks: passed.
- Audit logic/expiry parity with CI and unchanged release safeguards:
passed.
- Only the read-only audit step was executed locally against the live
registry; 19 ephemeral expiry/failure probes passed. No new test files
were added.

The separately approved Codecov allowlist correction is applied directly
in repository settings, adding only its exact `actions/github-script`
dependency. [Coverage
rerun](https://github.com/codotech/contractual/actions/runs/37787811167)
is green.

**Nothing has been merged, tagged, or published by this work. No release
workflow has been dispatched.**
## Summary

- preserve explicit consumer-relative `input`/`output` direction on
OpenAPI schema changes
- classify required-property changes contravariantly for requests and
covariantly for responses
- cover the direct differ, suggested bump, CLI breaking exit behavior,
and generated changeset severity

## Reproduction

Observed candidate removed `goals` from the `required` arrays of 12
successful task-agent response schemas. Contractual previously reported
all 12 as non-breaking and generated:

```yaml
---
"openapi": minor
---
```

With this change, the same baseline and candidate produce:

```text
breaking: 12
nonBreaking: 20
patch: 30
unknown: 0
suggestedBump: major
```

All 12 `required-removed` changes for `goals` are now breaking.

## Root cause

The OpenAPI request-body and response walkers both emitted the same
directionless `required-removed` change. The generic JSON Schema
classifier correctly treats that change as a relaxation for accepted
input, but the OpenAPI differ also reused it for produced output, where
it weakens an existing consumer guarantee.

The structural differ now records explicit schema direction on raw
changes. The OpenAPI classifier uses that context for requiredness
rather than inferring direction from rendered JSON Pointer paths.

## Compatibility matrix

| Contract position | Change | Classification | Bump |
| --- | --- | --- | --- |
| Request/input | required to optional | Non-breaking | Minor |
| Request/input | optional to required | Breaking | Major |
| Response/output | required to optional | Breaking | Major |
| Response/output | optional to required | Non-breaking | Minor |

## Test evidence

- `pnpm build`
- `pnpm lint`
- direct ESLint of every changed TypeScript file
- `pnpm test`: 14 passed
- `pnpm test:e2e`: 361 passed, 1 skipped
- focused OpenAPI/changeset E2E: 17 passed
- exact baseline/candidate: 12 `goals` response changes classified
breaking, suggested bump major

## Release dependency

This PR does not change package versions, publish packages, move tags,
or release the Contractual action. After merge, a future Contractual
package/action release is still required before the platform can consume
the fix through a supported major-version action tag such as
`codotech/contractual-action@v0`.
## Change

The dependency security audit on `next` fails with 23 findings,
including two critical Handlebars advisories. Its temporary audit
exceptions also expired on October 22. Update the affected dependencies
and require a clean audit in both CI and the publishing preflight.

- Upgrade Vite to 7.3.7 and align Vitest and coverage dependencies at
4.1.12 across workspace and E2E manifests.
- Apply targeted overrides for Handlebars, follow-redirects,
http-cache-semantics, ip-address, undici, and fast-uri, and regenerate
the lockfile. The live audit now reports zero known vulnerabilities.
- Remove the expired exceptions while retaining validation that rejects
registry errors, malformed reports, muted findings, inconsistent counts,
and every remaining advisory.

The http-cache-semantics update needs a distinction: upstream 4.3.0 is
outside the advisory's affected range, but its changes do not directly
patch the reported max-stale behavior. The maintainer disputes the
report in [upstream issue
#56](kornelski/http-cache-semantics#56). This
update uses the maintained upstream release without suppressing the
advisory.

## Validation

- GitHub checks passed: [CI on Node 22, 24, and
26](https://github.com/codotech/contractual/actions/runs/40757635603),
[dependency
audit](https://github.com/codotech/contractual/actions/runs/40757635583),
CodeQL, and PR title.
- Frozen dependency install, build, and lint: passed.
- Unit tests: 14 passed.
- E2E tests: 361 passed, 1 existing skip.
- Live `pnpm audit --json`: zero findings across all severities.
- Ten audit-gate probes: clean reports pass; vulnerable reports, former
exceptions, invalid responses, and inconsistent statuses/counts fail.
- Workflow YAML parsing, shell syntax, and `git diff --check`: passed.
Both audit gates match; all other workflow content is unchanged.

## Release impact

Package release versions are unchanged. Existing release approvals and
publishing safeguards remain in place; no release workflow, tagging, or
publication is requested by this PR.
## Change

Describe the problem and resulting behavior. Target `next` and use a
Conventional Commit title, for example `fix(cli): handle missing
snapshots`.

## Validation

List the relevant checks and their results.

## Release impact

Describe any compatibility change. Tagging or publishing requires Omer's
explicit approval; a PR is not release approval.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Change

Publishing stops before uploading any package because `npm access list
packages "$npm_user"` probes the organization endpoint for the
authenticated username. npm returns 403 for `/org/omerico/package`, and
the CLI only falls back to the user endpoint on 404. Authentication
succeeds, but the broad permission lookup prevents the release from
proceeding.

Check each workspace package with `npm access list collaborators`
instead, and require `read-write` permission for the authenticated user.
Lookup failures and denied permissions still stop publication, with
explicit package-specific errors. Commit selection, tag immutability,
package metadata, registry retry ownership, audit enforcement, and
release approvals are unchanged.

## Validation

- Executed the updated read-only preflight against the live npm registry
with the current credential: all seven `@contractual/*@0.1.0-beta.1`
packages passed, including existing tag and registry checks. No publish
command ran.
- Ten isolated preflight probes: write access passes for all seven
packages; read-only access, missing/wrong users, invalid JSON,
unexpected data, API failures, missing credentials, and authentication
failures are rejected.
- Frozen dependency install, build, lint, and 14 unit tests: passed.
- E2E tests: 361 passed, 1 existing skip.
- Workflow YAML parsing, shell syntax, and `git diff --check`: passed.
Structural comparison confirms all other workflow steps are unchanged.

## Release impact

No package versions or tags change. After this PR merges, start a new
Publish Packages run from `next` with the existing approved release
commit `93ac6a2c8082b8123d5acedcc99a2ebea394778d`. Re-running the old
workflow attempt retains its original workflow definition. The existing
release-environment approval remains required.
The beta release currently fails with `EOTP` because npm token
authentication requires interactive 2FA. Switch publishing to Lerna 9's
built-in npm Trusted Publishing support, using the existing GitHub OIDC
permission and protected `release` environment.

Remove `NPM_TOKEN` injection and the account-based `npm
whoami`/collaborator checks. Require GitHub's OIDC request credentials
instead, and retain the exact approved commit, beta-only publication,
dependency audit, tag consistency, and retry ownership checks.

All seven npm packages now have verified GitHub trusted publishers for
`codotech/contractual`, workflow `publish-packages.yml`, environment
`release`, with direct publishing permission. The configuration was
created through npm's official CLI after interactive 2FA and read back
from npm's API. Temporary login credentials were removed after
verification. This PR does not publish packages or change versions or
tags.

Validation: frozen dependency installation, build, lint, 14 unit tests,
and 361 E2E tests passed (1 skipped). YAML and Bash syntax checks
passed. The metadata/tag preflight passed for all seven packages without
an npm token; missing OIDC request credentials fail closed. Actual OIDC
exchange and publication require the approved GitHub release job.
The publish job in [run
41101906029](https://github.com/codotech/contractual/actions/runs/41101906029/job/124220430431)
stopped at the dependency audit before authentication or publication.
Newly reported
[minimatch](GHSA-g3hv-75wg-m249) and
[glob](GHSA-3g3m-2fjr-6pw4) advisories
affect the approved beta.1 commit.

Upgrade Lerna to 10, ESLint to 10 with typescript-eslint 8, and Redocly
OpenAPI Core to 2 so the dependency graph can use patched minimatch/glob
APIs. Apply scoped overrides for minimatch 11.0.3, glob 14.0.3, and
undici 7.30.1, and align conventional-commits-parser with Lerna's peer
requirement. The refreshed lockfile has zero audit findings. Development
now requires Node 22.22.2+, 24.15+, or 26; the OpenAPI differ,
governance, and CLI require Node 22.12+ at runtime.

Migrate the existing lint rules to flat configuration and import-x.
Import the enabled dependency-check rule through its public subpath
because the full plugin still imports minimatch's removed makeRe API in
an unused rule. The dependency check was verified to reject an
undeclared package.

Correct both audit validators to count affected versions rather than
distinct advisories; registry errors, malformed reports, muted findings,
and every vulnerability still fail the job. Set the publishing registry
directly so setup-node no longer creates an unresolved NODE_AUTH_TOKEN
placeholder for Trusted Publishing.

Validation: frozen install, `pnpm build`, `pnpm lint`, `pnpm test` (14
passed), `pnpm test:e2e` (361 passed, 1 skipped), and `pnpm audit
--json` (zero findings). Both workflow YAML files and shell blocks
parse; eight audit-validator cases cover clean, vulnerable, malformed,
muted, and registry-error reports. Lerna's existing publish flags remain
supported. GitHub CI also passed on Node 22, 24, and 26, along with the
dependency audit, CodeQL, and PR title checks.

Release dependency: the existing beta.1 tags still point to the
previously approved commit. Rerunning that commit will retain the
vulnerabilities. Publishing this fix needs separate approval of a
release commit and version/tag plan; this PR does not change package
versions or tags and does not publish anything.
The tagging workflow currently creates only the supplied tag and leaves
package tags unsigned. Replace that single-tag operation with a signed
batch covering every public package discovered by Lerna, plus an
optional global beta tag, at an explicitly approved commit on `next`.

Use `lerna list` and `lerna exec` with native Git/GPG signing so tagging
preserves the approved commit and existing package versions. Verify all
new signatures and push the complete batch atomically. Preserve existing
tags for unchanged independent packages; reject conflicting global tags
or changed packages that reuse an existing version. Retries create only
missing tags, and historical unsigned tags are not rewritten.

Keep the existing `release` environment approval and serialized release
concurrency. Import the dedicated signing key only for a nonempty batch,
validate its fingerprint/email, and clean the runner keyring even after
failure. The release environment's key, identity variables, and recovery
certificate are configured; the public key is registered to Omer's
GitHub account with a verified no-reply email and expires on 2027-10-31.
Update the release documentation with setup and usage.

Validation: `pnpm build`, `pnpm lint`, `pnpm test` (14 passed), and
`pnpm test:e2e` (361 passed, 1 skipped). Temporary repositories and a
disposable key exercised Lerna package discovery, private-package
exclusion, signed package/global tags, signature verification, retries,
preservation of old tags, conflicting package/global targets, version
reuse, missing keys, mismatched email, cleanup, and atomic rejection of
a concurrent remote tag conflict. Workflow YAML, shell syntax, and
actionlint 1.7.12 passed.

No real release tags were created or pushed, and the workflow has not
been dispatched. Publishing remains separately approved; its existing
requirement that package tags match the approved publishing commit is
unchanged.
Publishing currently requires every package tag and every existing npm
version's `gitHead` to match one release commit. This blocks independent
releases: run 41219632797 failed because unchanged `changesets`,
`differs.core`, and `types` retain their beta.1 tags at an earlier
commit, while four packages advanced to beta.2.

Plan publication per package. Accept older tags and already-published
source commits only when they are ancestors of the approved commit and
that package directory is unchanged. Preserve the original `gitHead` and
current `beta` distribution tag for existing versions, including a newer
beta or an absent beta tag. Treat only an explicit registry E404 as an
unpublished version. Changed contents under a reused version, unrelated
source history, malformed metadata, and registry errors still fail.

Keep native `lerna publish from-package` to publish missing versions and
skip its invocation when none are pending. Verify every package
afterward against its recorded commit and distribution tag, rather than
requiring every package to match the current release commit. Enable Bash
pipefail for workflow steps and document the independent release
lifecycle.

Validation: build, lint, 14 unit tests, and 361 end-to-end tests (1
skipped) passed; actionlint and shell/YAML syntax passed. Temporary Git
repositories with controlled npm responses cover mixed versions,
preserved older tags/source commits, private packages, all-published
retries, missing or newer beta tags, authentication/server failures,
malformed metadata, unknown commits, version reuse, and post-publish
ownership/tag regressions. Read-only preflight against the actual
release commit and npm succeeded: four beta.2 and three beta.1 versions
are currently unpublished.

No package versions or Git tags are changed. This PR does not publish
packages; publishing still requires Omer's explicit approval and the
release environment review.
#52)

Publishing can succeed while npm still returns E404 for the new version.
Run 41223628865 uploaded all seven packages successfully but failed its
immediate verification; the packages then became visible over the
following five minutes.

Wait up to ten minutes across the batch for newly published versions,
their beta tags, and downloadable tarballs to appear, refreshing
registry metadata every ten seconds. Retries only read metadata and
download tarballs with lifecycle scripts disabled. Wrong package
identities/source commits, changes to preserved versions, and errors
other than E404 still fail immediately. Document this behavior in
RELEASING.md.

Validation: pnpm build, pnpm lint, pnpm test (14 passed), pnpm test:e2e
(361 passed, 1 skipped), actionlint, and targeted shell regression
checks covering delayed version/tag/tarball visibility, timeout,
authentication/server errors, immutable versions, and preserved
distribution tags. Live verification passed for all seven published
packages, including package identity, source commit, beta tag, and
tarball download. The last tarball became downloadable roughly ten
minutes after npm accepted the upload. Rerun 41223628865 passed with all
uploads skipped.

This branch was successfully deployed

1 active (outdated) deployment
release — 77504b21 Deployed Oct 31, 2026 by omermorad via publish #23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants