diff --git a/.github/agents/cve-audit.agent.md b/.github/agents/cve-audit.agent.md index 31f677089af1..6bd23d49f62c 100644 --- a/.github/agents/cve-audit.agent.md +++ b/.github/agents/cve-audit.agent.md @@ -6,10 +6,12 @@ tools: ["vscode/askQuestions", "execute", "read", "agent/runSubagent", "edit", " You are a security-focused agent for CVE remediation in the iTwin.js monorepo. +**Prerequisite:** This agent depends on the `cve-remediation` skill for domain knowledge about `pnpm-config.json` structure, fix strategies (direct vs transitive), severity policy, and validation workflows. Ensure that skill is loaded for file structure and fix-ordering guidance. + ## Scope - Primary target: **Critical** and **High** vulnerabilities from `rush audit`. -- Fix through dependency updates and `pnpm-config.json` overrides. +- Fix through dependency updates and `pnpm-config.json` overrides — follow the fix strategy order defined in the `cve-remediation` skill. - Keep API compatibility unless explicitly approved otherwise. - Use non-interactive commands only. @@ -103,23 +105,13 @@ rush audit --level high Re-run the audit immediately after `rush update --full`. If High/Critical vulnerabilities are cleared, proceed to Step 4 (verify) — no further manual changes are needed. -3. If High/Critical remain after step 2, **first classify each remaining CVE as direct or transitive**, then remediate using the appropriate path. Do not apply a transitive-fix strategy to a direct CVE, or vice versa. - - **For DIRECT dependency CVEs** (the vulnerable package is a direct dependency of a project package): - - **Step D1:** Update the version range of the vulnerable package in the affected `package.json` directly. Run `rush update` and `rush audit --level high`. - - **Step D2 (last resort):** If no safe version range exists, add a `globalOverride`. Document why a direct version bump was not viable. +3. If High/Critical remain after step 2, remediate using the fix strategy defined in the `cve-remediation` skill: - **For TRANSITIVE dependency CVEs** (the vulnerable package is pulled in by a parent): - - **Step T1 — Semver range update (try first):** Update the semver range of the direct parent dependency in the affected `package.json` to a version that resolves the transitive dep to a patched release. Example: if `foo@^1.2.0` pulls in vulnerable `bar@1.0.0` and `bar@1.0.1` is patched, bump `foo` to a range that resolves to `bar >= 1.0.1`. Run `rush update` and `rush audit --level high`. - - **Step T2 (last resort):** If no safe parent version resolves the transitive dep, add a `globalOverride`. Document why a semver range update was not viable, including the advisory link and dependency path. + - **Classify** each remaining CVE as direct or transitive. + - **Direct CVEs:** Update the affected `package.json` version range first. Fall back to `globalOverride` only if no safe version exists. + - **Transitive CVEs:** Try semver range update of the parent dependency first. Fall back to `globalOverride` only if no safe parent version exists. - For `globalOverrides`, add to `common/config/rush/pnpm-config.json`: - ```json - "globalOverrides": { - "": "" - // CVE-XXXX-XXXXX: https://advisory-url — — semver fix not viable: - } - ``` + For `globalOverride` and `ignoreCves` syntax and placement, refer to the `cve-remediation` skill's "pnpm-config.json Structure" section. Every override must document why a semver range fix was not viable. 4. Re-resolve and verify after each meaningful change: @@ -138,33 +130,20 @@ rush extract-api ## Fix Rules +Follow the fix strategy order defined in the `cve-remediation` skill. Key rules: + - For direct dependency CVEs, update the affected package's own `package.json` dependency version range first. -- For transitive CVEs, use this strict order: - 1. **Semver range update**: update the direct parent's `package.json` range to a version that resolves the transitive dependency to a patched version. - 2. **`globalOverrides`**: only if a semver range fix is not viable (e.g., no safe parent version exists, upstream has not released a fix). Document the reason in a comment with the advisory link and dependency path. -- Never add a `globalOverride` without first documenting why semver range resolution was not sufficient. -- `ignoreCves` is a last resort for non-production/dev-tooling risk only — with explicit rationale. Add it under the correct nested path in `common/config/rush/pnpm-config.json`: - ```json - "unsupportedPackageJsonSettings": { - "pnpm": { - "auditConfig": { - "ignoreCves": [ - "CVE-XXXX-XXXXX" // https://advisory-url — dev-only, no production path — reason - ] - } - } - } - ``` +- For transitive CVEs: semver range update first, `globalOverride` only as last resort. +- Never add a `globalOverride` without documenting why semver range resolution was not sufficient. +- `ignoreCves` is a last resort for non-production/dev-tooling risk only — refer to the `cve-remediation` skill for syntax and placement. - Never ignore a Critical/High production-path CVE when a patch is available. - `common/config/rush/common-versions.json` is Rush version-consistency policy (`preferredVersions`). - If a direct dependency bump triggers Rush consistency errors, update `common/config/rush/common-versions.json` to align versions. -- If `common-versions.json` changes, commit the generated `common/config/rush/repo-state.json` hash update. +- If `common/config/rush/common-versions.json` changes, commit the generated `common/config/rush/repo-state.json` hash update. ## Severity Policy -- **Critical:** Always fix or explicitly document blocker and risk. -- **High:** Fix unless it requires unacceptable breakage; if deferred, create a tracking issue with risk tradeoff and remediation plan. -- **Moderate/Low:** Defer and create a tracking issue with recommendation for follow-up. +Follow the severity policy defined in the `cve-remediation` skill: Critical always fix, High fix unless unacceptable breakage, Moderate/Low defer with tracking issue. ## Deferral Workflow (Required for Unresolved CVEs) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1a3120a47f04..92cefba3a9ad 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -41,89 +41,11 @@ iTwin.js is a **monorepo** containing TypeScript packages for creating Infrastru - **RPC (Remote Procedure Call)**: For web apps with loosely-coupled frontend/backend over HTTPS. Classes extend `RpcInterface` from `@itwin/core-common` - **IPC (Inter-Process Communication)**: For tightly-coupled Electron/mobile apps with stateful connections -### Documentation and Code Examples +### Packages -The **`example-code/`** directory contains tested code snippets that are automatically extracted into documentation: +See `rush.json` for the full list of packages and their paths. Key structural areas: `core/` (frontend, backend, common, geometry), `domains/`, `presentation/`, `editor/`, `extensions/`, `tools/`, `ui/`, `utils/`. -- Code examples are marked with special comment blocks: `// __PUBLISH_EXTRACT_START__ ExampleName` and `// __PUBLISH_EXTRACT_END__` -- Documentation markdown files reference these extracts using `[[include:ExampleName]]` syntax, wrapped inside a multi-line code block -- This ensures documentation code examples stay in sync with tested, working code - -**When generating documentation**: Instead of hardcoding code blocks in markdown files, consider suggesting the user create extraction blocks and reference them in documentation. This maintains consistency and ensures examples remain testable and up-to-date. - -### Core Packages - -**Foundation (Common to Frontend & Backend):** - -- **`@itwin/core-bentley`** (`core/bentley/`): Low-level utilities, logging, events, Id64, GUIDs, and common data structures -- **`@itwin/core-common`** (`core/common/`): Shared types, RPC interfaces, element/model props, rendering definitions -- **`@itwin/core-geometry`** (`core/geometry/`): Computational geometry library (curves, surfaces, solids, transformations) -- **`@itwin/core-quantity`** (`core/quantity/`): Quantity formatting and parsing (units, conversions, display) -- **`@itwin/core-i18n`** (`core/i18n/`): Internationalization and localization support -- **`@itwin/core-orbitgt`** (`core/orbitgt/`): Point cloud and reality data processing - -**Backend Packages:** - -- **`@itwin/core-backend`** (`core/backend/`): Node.js services - IModelDb, elements, models, schemas, native bindings -- **`@itwin/core-electron`** (`core/electron/`): Electron-specific utilities (ElectronHost, IPC, window management) -- **`@itwin/core-mobile`** (`core/mobile/`): Mobile platform utilities (iOS/Android RPC, authentication) -- **`@itwin/express-server`** (`core/express-server/`): Express web server utilities for backend services -- **`@itwin/ecschema-locaters`** (`core/ecschema-locaters/`): Schema location and loading on backend -- **`@itwin/ecschema-editing`** (`core/ecschema-editing/`): Schema creation and modification APIs - -**Frontend Packages:** - -- **`@itwin/core-frontend`** (`core/frontend/`): Browser-based visualization - IModelConnection, ViewState, Viewport, rendering -- **`@itwin/frontend-devtools`** (`core/frontend-devtools/`): Developer tools UI for debugging and diagnostics -- **`@itwin/frontend-tiles`** (`extensions/frontend-tiles/`): Advanced tile loading and caching strategies -- **`@itwin/webgl-compatibility`** (`core/webgl-compatibility/`): WebGL feature detection and compatibility checks -- **`@itwin/core-markup`** (`core/markup/`): SVG-based markup creation and editing for viewports -- **`@itwin/hypermodeling-frontend`** (`core/hypermodeling/`): 2D/3D drawing sheet integration - -**Schema & Metadata:** - -- **`@itwin/ecschema-metadata`** (`core/ecschema-metadata/`): EC (Entity-Class) schema management for BIS -- **`@itwin/ecsql-common`** (`core/ecsql/common/`): ECSQL query types and interfaces -- **`@itwin/ecschema-rpcinterface-common`** (`core/ecschema-rpc/common/`): RPC interfaces for schema access -- **`@itwin/ecschema-rpcinterface-impl`** (`core/ecschema-rpc/impl/`): Backend implementation of schema RPC - -**Extension & Plugin System:** - -- **`@itwin/core-extension`** (`core/extension/`): Extension loading and lifecycle management - -**Domain Packages:** - -- **`@itwin/analytical-backend`** (`domains/analytical/backend/`): Analytical modeling domain -- **`@itwin/linear-referencing-backend`** (`domains/linear-referencing/backend/`): Linear referencing for infrastructure -- **`@itwin/linear-referencing-common`** (`domains/linear-referencing/common/`): Linear referencing shared types -- **`@itwin/physical-material-backend`** (`domains/physical-material/backend/`): Physical material properties - -**Presentation Layer:** - -- **`@itwin/presentation-common`** (`presentation/common/`): Rule-driven UI presentation (shared types) -- **`@itwin/presentation-backend`** (`presentation/backend/`): Presentation rules processing on backend -- **`@itwin/presentation-frontend`** (`presentation/frontend/`): Presentation data consumption on frontend - -**Editing:** - -- **`@itwin/editor-common`** (`editor/common/`): Interactive editing shared types -- **`@itwin/editor-backend`** (`editor/backend/`): Element editing operations on backend -- **`@itwin/editor-frontend`** (`editor/frontend/`): Interactive editing tools and UI - -**Build & Testing Tools:** - -- **`@itwin/build-tools`** (`tools/build/`): Build scripts, API extraction, documentation generation -- **`@itwin/certa`** (`tools/certa/`): Full-stack test runner (Mocha + Chrome/Electron) -- **`@itwin/perf-tools`** (`tools/perf-tools/`): Performance measurement and profiling -- **`@itwin/ecschema2ts`** (`tools/ecschema2ts/`): Generate TypeScript from EC schemas - -**UI Abstractions:** - -- **`@itwin/appui-abstract`** (`ui/appui-abstract/`): Abstract UI component definitions - -**Utilities:** - -- **`@itwin/workspace-editor`** (`utils/workspace-editor/`): Workspace and settings management +Documentation code examples live in `example-code/` using extract markers (`__PUBLISH_EXTRACT_START__`/`__PUBLISH_EXTRACT_END__`) referenced in docs via `[[include:ExampleName]]`. ## Rush Monorepo Workflow @@ -190,36 +112,20 @@ All published packages use **lockstep versioning** (`prerelease-monorepo-lockSte ## Code Organization Patterns -### Class Registration - -Backend entities use registration pattern: +**Every exported symbol MUST have a release tag** (`@public`, `@beta`, `@alpha`, `@internal`). Missing tags will fail `rush extract-api`. -```typescript -// In Entity subclass -public static override get className() { return "MyEntity"; } -ClassRegistry.register(MyEntity, MyEntity.schema); -``` - -### TSDoc Release Tags +### Internal/Cross-Package Exports -Use release tags consistently - **these determine API stability contracts**: +Packages use `src/internal/` directories for non-public implementation. Inter-package internal APIs are curated in `src/internal/cross-package.ts` files with inline comments documenting which sibling packages consume them. The ESLint rule `@itwin/no-internal-barrel-imports` enforces this boundary — do not import from internal barrels outside of `cross-package.ts`. -- **`@public`**: Stable public API with strong backward compatibility guarantees. Breaking changes ONLY in major releases -- **`@beta`**: Public but may change in minor releases. Requires migration documentation -- **`@alpha`**: Experimental API, may change or be removed. Use with caution -- **`@internal`**: Private implementation details, not part of API surface, excluded from docs -- `@packageDocumentation`: Module-level documentation +### ESLint Configuration -**Every exported symbol MUST have a release tag.** Missing tags will fail the `rush extract-api` check. +Shared ESLint configs live at `common/config/eslint/` (flat config format). Packages reference these centrally via their lint scripts. Custom rules come from `@itwin/eslint-plugin` (e.g., `@itwin/no-internal-barrel-imports`, deprecation policy enforcement). -### ECSchema and BIS +### CI Pipelines -iTwin.js uses **EC (Entity-Class)** schemas based on BIS: - -- Schema classes in `core/ecschema-metadata` -- Backend locators in `core/ecschema-locators` -- Schemas define Elements, Aspects, Relationships, and Models -- Elements inherit from `Element` base class with required properties: `classFullName`, `code`, `model` +- GitHub Actions workflows: `.github/workflows/` +- Azure Pipelines configs: `common/config/azure-pipelines/` ## Documentation @@ -279,40 +185,10 @@ Valid formats recognized by the ESLint rule: ## Build Tools -- **`@itwin/build-tools`**: Custom build utilities (`betools` commands) - - `betools extract-api`: Generate API reports - - `betools docs`: Generate TypeDoc documentation -- **`@itwin/certa`**: Custom test runner for full-stack tests (Mocha wrapper with Chrome/Electron support) -- TypeScript compilation: Dual output (CJS in `lib/cjs/`, ESM in `lib/esm/`) +TypeScript compilation outputs dual format: CJS in `lib/cjs/`, ESM in `lib/esm/`. ## Common Patterns -### IModelConnection (Frontend) ↔ IModelDb (Backend) - -Frontend uses `IModelConnection` (from `@itwin/core-frontend`) to interact with backend `IModelDb` (from `@itwin/core-backend`) via RPC interfaces like `IModelReadRpcInterface`. - -### Element Querying - -Use ECSQL (ECMAScript SQL dialect) via: - -- Backend: `IModelDb.createQueryReader()` or `ECSqlStatement` -- Frontend: `IModelConnection.createQueryReader()` - -### Geometry Handling - -`@itwin/core-geometry` provides immutable geometry classes: - -- `Point3d`, `Vector3d`, `Range3d` for basic types -- `CurvePrimitive`, `SolidPrimitive` for complex shapes -- Use static methods for construction, avoid mutation - -## Debugging Tips - -1. Use VS Code launch configurations (`.vscode/launch.json`) for package-specific debugging -2. For frontend tests in browser: Check `vitest.config.mts` for browser provider settings -3. For RPC debugging: Enable `RpcConfiguration.developmentMode = true` -4. Native debugging: `@bentley/imodeljs-native` requires Node.js with N-API support - ## Don't Do This ### Critical - Breaking Changes diff --git a/.github/skills/cve-remediation/SKILL.md b/.github/skills/cve-remediation/SKILL.md new file mode 100644 index 000000000000..66470a457efd --- /dev/null +++ b/.github/skills/cve-remediation/SKILL.md @@ -0,0 +1,145 @@ +--- +name: cve-remediation +description: Domain knowledge for remediating CVEs in the iTwin.js Rush monorepo — pnpm-config.json structure, fix strategies, validation, and audit workflows. +--- + +# CVE Remediation in iTwin.js + +This skill covers the domain knowledge for fixing security vulnerabilities in the iTwin.js Rush monorepo. It is referenced by the CVE audit agent and the merge conflict resolution skill. + +## Key Files + +| File | Purpose | +| --- | --- | +| `common/config/rush/pnpm-config.json` | Global dependency overrides and audit exceptions | +| `common/config/rush/pnpm-lock.yaml` | Resolved dependency tree (never manually edit) | +| `common/config/rush/common-versions.json` | Rush version-consistency policy (`preferredVersions`) | +| `common/config/rush/repo-state.json` | Auto-generated hash of repo state (commit alongside `common-versions.json`) | +| `/package.json` | Direct dependency version ranges per package | + +## pnpm-config.json Structure + +This file has two conflict-prone sections: + +### globalOverrides + +Forces specific dependency versions across the entire monorepo. Used when a transitive dependency cannot be updated via its parent's semver range. + +```json +{ + "globalOverrides": { + "": "", + "@": "" + } +} +``` + +Each override should include a trailing comment with: +- The advisory URL (GHSA or CVE link) +- The dependency path that pulls in the vulnerable package + +Illustrative example (always consult the current `common/config/rush/pnpm-config.json` before editing): + +```jsonc +"globalOverrides": { + "rollup-plugin-copy>globby": "^11.0.0", // https://github.com/vladshcherbin/rollup-plugin-copy/issues/77 + "elliptic": "^6.6.1", // https://github.com/advisories/GHSA-vjh7-7g9h-fjfh crypto-browserify>browserify-sign>elliptic + "fast-xml-parser": "^5.3.6", // https://github.com/advisories/GHSA-jmr7-xgp7-cmfj @google-cloud/storage > fast-xml-parser + "axios@<1.0.0": "^1.13.5", // https://github.com/advisories/GHSA-43fc-jf86-j433 + "serialize-javascript": "^7.0.3" // https://github.com/advisories/GHSA-5c6j-r48x-rmvq mocha>serialize-javascript +} +``` + +**Important:** The last entry must NOT have a trailing comma (valid JSON). When adding entries, ensure the previously-last entry gets a comma added. + +### ignoreCves (Audit Exceptions) + +Located under a nested path. Used only for dev-tooling dependencies with no production path. + +```json +{ + "unsupportedPackageJsonSettings": { + "pnpm": { + "auditConfig": { + "ignoreCves": [ + "CVE-XXXX-XXXXX" // https://advisory-url — dev-only reason + ] + } + } + } +} +``` + +## Fix Strategy (Strict Order) + +Always attempt fixes in this order. Do not skip to overrides without trying the earlier steps. + +### 1. Classify: Direct vs Transitive + +- **Direct:** The vulnerable package is listed in a project's `package.json` +- **Transitive:** The vulnerable package is pulled in by another dependency + +### 2a. Direct Dependency Fix + +1. Update the version range in the affected `package.json` +2. Run `rush update` and `rush audit --level high` +3. If no safe version range exists, fall through to globalOverride (document why) + +### 2b. Transitive Dependency Fix + +1. **Semver range update (try first):** Update the direct parent's `package.json` range to a version that resolves the transitive dep to a patched release +2. **globalOverride (last resort):** Only if no safe parent version exists. Document why in the override comment + +### 3. ignoreCves (Absolute Last Resort) + +Only for non-production/dev-tooling risk. Requires: +- Explicit rationale in comment +- Advisory link +- Confirmation that the dependency has no production code path + +**Never ignore a Critical/High production-path CVE when a patch is available.** + +## Severity Policy + +| Severity | Action | +| --- | --- | +| Critical | Always fix or explicitly document blocker and risk | +| High | Fix unless unacceptable breakage; if deferred, create tracking issue | +| Moderate/Low | Defer and create tracking issue with recommendation | + +## Validation Workflow + +After any remediation change: + +```bash +rush update # Regenerate lock file +rush audit --level high # Verify CVE is resolved +rush build # Ensure no build breakage +rush test # Ensure no test regressions +``` + +When direct dependency version ranges were changed in a `package.json`: + +```bash +rush extract-api # Check for API surface changes +``` + +Skip `extract-api` only when the sole change is a `globalOverride` in `pnpm-config.json`. + +## Rush Change Files + +After remediation, Rush requires changelog entries: + +```bash +# Check if change files are needed +rush change --verify -b origin/ + +# If needed for internal dependency-only updates, create blank entries non-interactively +rush change --bulk --message "" --bump-type none -b origin/ +``` + +Change files land in `common/changes/@itwin//` as JSON files with unique filenames. + +## common-versions.json + +If a direct dependency bump triggers Rush consistency errors, update `common/config/rush/common-versions.json` to align versions. Always commit the auto-generated `common/config/rush/repo-state.json` hash update alongside it. diff --git a/.github/skills/merge-conflict-resolving/SKILL.md b/.github/skills/merge-conflict-resolving/SKILL.md new file mode 100644 index 000000000000..1f8fa8d44898 --- /dev/null +++ b/.github/skills/merge-conflict-resolving/SKILL.md @@ -0,0 +1,263 @@ +--- +name: merge-conflict-resolving +description: You resolve merge conflicts in code repositories, ensuring that the final merged code is functional and free of errors, and adheres to our code quality standards. +--- + +# Merge Conflict Resolution + +Resolve merge conflicts in backport PRs from Mergify. Mergify uses **cherry-pick** (not merge) to create backport branches with the pattern `mergify/bp/release/X.X.x/pr-NNNN`. When cherry-pick fails, Mergify comments with the conflict details and the branch must be fixed locally. + +**Prerequisite:** This skill references the `cve-remediation` skill for understanding `pnpm-config.json` structure (globalOverrides, ignoreCves). Load that skill when resolving conflicts in security-related backports. + +## How Mergify Backports Work + +1. A PR merges to `master` +2. Mergify cherry-picks the commit(s) onto a new branch: `mergify/bp/release/X.X.x/pr-NNNN` +3. If cherry-pick fails, Mergify marks the PR as conflicted and posts a generic comment (it does **not** list specific files — use `git status` locally to identify conflicts) +4. A developer checks out the branch, resolves conflicts, and pushes + +To start resolving: + +```bash +git fetch origin +git checkout mergify/bp/release/X.X.x/pr-NNNN +git cherry-pick --continue # If mid cherry-pick +# OR +git merge origin/release/X.X.x # If syncing with target branch +``` + +## Lock Files (common/config/rush/pnpm-lock.yaml) + +**Always regenerate. Never manually edit.** + +```bash +rush update +# or for persistent issues: +rush update --full +``` + +Commit with: `git commit -m "resolve pnpm-lock conflicts"` + +**Examples:** [PR #8902](https://github.com/iTwin/itwinjs-core/pull/8902), [PR #8954](https://github.com/iTwin/itwinjs-core/pull/8954) + +## pnpm-config.json Conflicts + +**File:** `common/config/rush/pnpm-config.json` + +This is the **most common conflict file** in security backports. It contains `globalOverrides` (dependency version overrides) and `ignoreCves` (audit exceptions). For detailed structure, see the `cve-remediation` skill. + +### Resolution Strategy + +**Keep all existing entries from the release branch (HEAD). Add new entries from the incoming change.** + +1. Open the file and identify the conflicting sections (usually `globalOverrides` or `ignoreCves`) +2. Keep every existing override/exception from the release branch +3. Add the new override/exception being backported from the incoming change +4. Fix JSON syntax — especially trailing commas: + - The last entry in a JSON object must NOT have a trailing comma + - When adding a new last entry, add a comma to the previously-last entry + +### Example Resolution + +Release branch (HEAD) has: + +```json +"globalOverrides": { + "cross-spawn": "^7.0.5", + "axios": "^1.13.5" +} +``` + +Incoming change adds `serialize-javascript` override: + +```json +"globalOverrides": { + "cross-spawn": "^7.0.5", + "axios": "^1.13.5", + "serialize-javascript": "^7.0.3" +} +``` + +After resolving, always run `rush update` to regenerate the lock file. + +**Examples:** [PR #9007](https://github.com/iTwin/itwinjs-core/pull/9007), [PR #9041](https://github.com/iTwin/itwinjs-core/pull/9041), [PR #9049](https://github.com/iTwin/itwinjs-core/pull/9049) + +## Package.json Conflicts in Backports + +**Rule:** When backporting to `release/X.X.x`, keep the release branch's version information and only accept new functional changes. + +### Keep from Release Branch (HEAD) + +- Version numbers: `"version": "5.5.0"` +- Internal workspace dependencies (this repo uses `workspace:*` for internal deps — do not convert to hardcoded versions unless the release branch already uses them) +- Branch-specific scripts and configurations + +### Accept from Incoming (master) + +- New dependencies being added +- New scripts being added +- External dependency updates (if that's the purpose of the backport) + +After resolving, always run `rush update` to regenerate the lock file. + +**Avoid:** + +- Accepting master's version numbers in release branches +- Forgetting to run `rush update` after editing package.json + +## API Signature Files (common/api/*.api.md) + +**Always regenerate. Never manually edit.** + +These files track the public API surface and are generated by `rush extract-api`. They conflict when the release branch has a different API surface than master. + +```bash +rush build +rush extract-api +``` + +Also regenerate the export summary files: `common/api/summary/*.exports.csv` + +**Example:** [PR #8986](https://github.com/iTwin/itwinjs-core/pull/8986) — backport of `integrityCheck()` modified `common/api/core-backend.api.md` + +## Rush Change Files (common/changes/@itwin/) + +Rush change files are JSON files in `common/changes/@itwin//` created by `rush change`. They usually have unique filenames and rarely conflict. + +**If they do conflict:** Keep both files. If the same file has conflicts, merge the JSON content. + +**If change files are needed for the backport:** Generate them non-interactively: + +```bash +rush change --verify -b origin/release/X.X.x +# If needed: +rush change --bulk --message "" --bump-type none -b origin/release/X.X.x +``` + +**Example:** [PR #8345](https://github.com/iTwin/itwinjs-core/pull/8345) — had 30+ rush change files for a multi-package backport + +## Documentation Conflicts (NextVersion.md) + +**Merge both versions intelligently.** Preserve unique content from both branches, organize by category, and maintain the table of contents. + +### Resolution Process + +1. Extract unique sections from both versions +2. Merge into logical category order +3. Update table of contents to match headers +4. Remove duplicate content + +Example: If one branch adds Electron support and another adds Presentation changes, include both sections in the proper order. + +Verify after resolving: + +```bash +npx markdownlint docs/changehistory/NextVersion.md +rush docs # Ensure documentation builds +``` + +**Avoid:** + +- Discarding content from either version +- Leaving mismatched table of contents +- Keeping duplicate sections + +## CI/Config File Conflicts (.github/) + +CI workflows and configuration files can diverge significantly between major release branches. + +Common conflicting files: +- `.github/workflows/extract-api.yaml` — node version, action versions +- `.github/mergify.yml` — backport target branches +- `.github/workflows/*.yaml` — CI pipeline changes + +**Resolution:** Generally keep the release branch's CI configuration. Only accept incoming changes that are specifically being backported (e.g., a node version bump needed for compatibility). + +**Example:** [PR #9049](https://github.com/iTwin/itwinjs-core/pull/9049) — needed additional edit to bump node version in `extract-api.yaml` for the older release branch + +## Source Code Conflicts (.ts files) + +Rare in backports but possible when the same code area was modified on both branches. + +**Resolution:** +- Understand the intent of the backported change +- Apply the functional change to the release branch's version of the code +- Do not blindly accept incoming — the release branch may have different surrounding context + +## Combined Backports + +Sometimes Mergify cannot cherry-pick cleanly because multiple related changes need to land together. In this case, combine the changes into a single backport PR. + +**Example:** [PR #9007](https://github.com/iTwin/itwinjs-core/pull/9007) — combined 3 separate PRs into one backport due to dependency conflicts + +When combining: +- List all original PR numbers in the PR description +- Ensure all changes are compatible with each other on the release branch +- Sometimes backport-specific edits are needed beyond the original PRs + +## Resolution Workflow + +1. **Identify conflict type:** Run `git status` to see which files need resolution + +2. **Apply strategy:** + - **Lock file:** `rush update` → stage → commit + - **pnpm-config.json:** Edit manually → `rush update` → stage both files → commit + - **package.json:** Edit manually → `rush update` → stage both files → commit + - **API files (common/api/):** `rush build` → `rush extract-api` → stage → commit + - **Rush change files:** Keep both / generate fresh → stage → commit + - **NextVersion.md:** Merge both versions → verify formatting → stage → commit + - **CI/config files:** Manual edit favoring release branch → stage → commit + +3. **Check for residual conflict markers:** + + ```bash + grep -r "<<<<<<< " . --include="*.ts" --include="*.json" --include="*.md" --include="*.yaml" --include="*.yml" + ``` + +4. **Verify:** Run `rush build` and ensure CI passes + +5. **Commit messages:** + - Lock files: `"resolve pnpm-lock conflicts"` + - pnpm-config.json: `"resolve pnpm-config.json conflicts in backport"` + - Package.json: `"resolve package.json conflicts in backport"` + - API files: `"regenerate api files after backport"` + - Documentation: `"merge NextVersion.md from both branches"` + - Multiple files: `"resolve conflicts"` + +## Rollback + +If resolution goes wrong: + +```bash +# Abort an in-progress cherry-pick +git cherry-pick --abort + +# Or reset to the last good state (before the cherry-pick) +git reset --hard ORIG_HEAD +git clean -fd + +# Then re-attempt +rush update +``` + +## Quick Reference + +| File Type | Path | Resolution | Key Points | +| --- | --- | --- | --- | +| Lock file | `common/config/rush/pnpm-lock.yaml` | `rush update` | Never manually edit | +| pnpm-config | `common/config/rush/pnpm-config.json` | Manual edit + `rush update` | Keep release entries, add new. See `cve-remediation` skill for structure | +| package.json | `/package.json` | Manual edit + `rush update` | Keep release versions, add new deps only | +| API signatures | `common/api/*.api.md` | `rush build` + `rush extract-api` | Never manually edit | +| Rush change files | `common/changes/@itwin/*/` | Keep both or regenerate | Usually unique filenames, rarely conflict | +| NextVersion.md | `docs/changehistory/NextVersion.md` | Manual merge | Combine both, organize by category | +| CI/config | `.github/workflows/*.yaml` | Manual edit | Favor release branch config | + +## For Automated Agents + +- **Check target branch first** — Strategy differs for `master` vs `release/X.X.x` +- **Mergify uses cherry-pick** — Recovery is `git cherry-pick --continue`, not merge +- **Parse structured data** — Extract version fields from package.json programmatically +- **Always check for conflict markers** — `grep -r "<<<<<<< " .` before committing +- **Verify after resolution** — Run `rush build`, `rush extract-api`, and check `git diff` +- **Never commit without testing** — Ensure no syntax errors or breaking changes +- **Reference the `cve-remediation` skill** — For understanding pnpm-config.json structure when resolving security backport conflicts