-
Notifications
You must be signed in to change notification settings - Fork 0
Hard-cutover LocalNet to @fairmint/canton-dev-tools@0.1.1 (ENG-1635) #398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4eba7d7
1c88572
0e31389
7b2ff5f
d55bac5
38de371
7186cf0
bb8482e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,16 @@ | ||
| # LocalNet testing | ||
|
|
||
| Read the public [LocalNet guide](https://github.com/Fairmint/canton-node-sdk/wiki/LocalNet-testing) | ||
| first. This repository's current `package.json`, `bin/canton-localnet`, and integration tests are | ||
| the source of truth for `localnet:start`, `localnet:stop`, `test:integration`, and related commands. | ||
| first. | ||
|
|
||
| **ENG-1635:** `@fairmint/canton-dev-tools@0.1.1+` owns LocalNet lifecycle, pins, and shared test | ||
| helpers. This repository does not ship LocalNet scripts or a `canton-localnet` binary. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Describe the retained compatibility paths. The PR retains 🧰 Tools🪛 SkillSpector (2.5.1)[warning] 10: [RP1] null: npx commands without a version suffix (e.g. Remediation: Pin the version: npx (MCP Rug Pull (RP1)) 🤖 Prompt for AI Agents |
||
|
|
||
| - Commands: `npm run localnet:*` (wired to `canton-dev-tools`) or | ||
| `npx @fairmint/canton-dev-tools <command>` | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| - Helpers: `@fairmint/canton-dev-tools/testing` | ||
| - Pins: Dev Tools | ||
| [COMPATIBILITY.md](https://github.com/Fairmint/canton-dev-tools/blob/main/COMPATIBILITY.md) | ||
|
|
||
| Domain integration tests under `test/integration/localnet/**` remain in this repo; only their | ||
| imports come from Dev Tools. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,8 +31,9 @@ jobs: | |
| registry-url: 'https://registry.npmjs.org' | ||
|
|
||
| - name: Upgrade npm | ||
| # Trusted publishing requires npm CLI >= 11.5.1 | ||
| run: npm install --global npm@^11.10.0 | ||
| # Trusted publishing requires npm CLI >= 11.5.1; | ||
| # npm >=11.17 required for .npmrc min-release-age-exclude (@fairmint/*). | ||
| run: npm install --global npm@^11.17.0 | ||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
if rg -n --glob '*.yml' --glob '*.yaml' \
'npm install --global npm@\^' .github/workflows; then
echo "Floating npm version found" >&2
exit 1
fiRepository: Fairmint/canton-node-sdk Length of output: 450 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- workflow files ---'
for f in .github/workflows/publish.yml .github/workflows/test-cn-quickstart.yml .github/workflows/package-artifacts.yml; do
echo "### $f"
sed -n '1,90p' "$f"
done
printf '%s\n' '--- npm configuration and version references ---'
rg -n --hidden --glob '!node_modules' \
'min-release-age-exclude|npm@|setup-node|node-version|packageManager|engines|trusted publishing' \
.npmrc package.json package-lock.json .github . 2>/dev/null | head -250Repository: Fairmint/canton-node-sdk Length of output: 17193 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import json
import re
import urllib.request
from pathlib import Path
files = [
Path(".github/workflows/publish.yml"),
Path(".github/workflows/test-cn-quickstart.yml"),
Path(".github/workflows/package-artifacts.yml"),
]
pattern = re.compile(r"npm install --global npm@(\S+)")
found = {}
for path in files:
text = path.read_text()
matches = pattern.findall(text)
found[str(path)] = matches
print(f"{path}: {matches}")
if any(matches != ["^11.17.0"] for matches in found.values()):
raise SystemExit("The three workflows do not all use ^11.17.0")
with urllib.request.urlopen("https://registry.npmjs.org/npm", timeout=10) as response:
metadata = json.load(response)
def version_tuple(version):
match = re.fullmatch(r"(\d+)\.(\d+)\.(\d+)", version)
return tuple(map(int, match.groups())) if match else None
matching = []
for version in metadata.get("versions", {}):
parsed = version_tuple(version)
if parsed and parsed >= (11, 17, 0) and parsed < (12, 0, 0):
matching.append(version)
print("Published versions accepted by ^11.17.0:")
print(", ".join(sorted(matching, key=version_tuple)[-10:]))
if not any(version_tuple(v) > (11, 17, 0) for v in matching):
raise SystemExit("Registry data does not demonstrate floating resolution")
PYRepository: Fairmint/canton-node-sdk Length of output: 2602 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
files = [
Path(".github/workflows/publish.yml"),
Path(".github/workflows/test-cn-quickstart.yml"),
Path(".github/workflows/package-artifacts.yml"),
]
pattern = re.compile(r"npm install --global npm@(\S+)")
for path in files:
matches = pattern.findall(path.read_text())
print(f"{path}: {matches}")
if matches != ["^11.17.0"]:
raise SystemExit(f"Unexpected npm range in {path}")
def parse(version):
return tuple(map(int, version.split(".")))
# For a major version greater than zero, ^MAJOR.MINOR.PATCH means
# >=MAJOR.MINOR.PATCH and <(MAJOR+1).0.0.
lower = parse("11.17.0")
upper = (lower[0] + 1, 0, 0)
examples = ["11.17.0", "11.17.1", "11.18.0", "11.99.99", "12.0.0"]
for version in examples:
value = parse(version)
accepted = lower <= value < upper
print(f"{version}: accepted_by_^11.17.0={accepted}")
if not (parse("11.17.1") >= lower and parse("11.17.1") < upper):
raise SystemExit("The range must accept a later npm 11 release")
if parse("12.0.0") < upper:
raise SystemExit("The range must exclude npm 12")
PYRepository: Fairmint/canton-node-sdk Length of output: 491 Pin the npm CLI version in all three workflows.
🧰 Tools🪛 zizmor (1.29.0)[warning] 36-36: ad-hoc installation of packages (adhoc-packages): installs a package outside of a lockfile (adhoc-packages) 📍 Affects 3 files
🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| - name: Install dependencies | ||
| run: npm i | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| min-release-age=1 | ||
| # Fairmint-owned packages are published by us; allow immediate consumption after cutovers. | ||
| min-release-age-exclude[]=@fairmint/* | ||
|
Comment on lines
+2
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: printf '%s\n' '--- .npmrc ---'
cat -n .npmrc 2>/dev/null || true
printf '%s\n' '--- Fairmint package references ---'
rg -n --hidden -g '!node_modules' -g '!dist' -g '!build' '`@fairmint/`' . 2>/dev/null | head -200
printf '%s\n' '--- package manifests ---'
find . -name package.json -not -path '*/node_modules/*' -printRepository: Fairmint/canton-node-sdk Length of output: 5509 🏁 Script executed: printf '%s\n' '--- package.json dependency/config context ---'
sed -n '1,115p' package.json
printf '%s\n' '--- workflow npm setup ---'
sed -n '1,70p' .github/workflows/publish.yml
sed -n '1,55p' .github/workflows/package-artifacts.yml
sed -n '1,55p' .github/workflows/test-cn-quickstart.yml
printf '%s\n' '--- local npm availability and config metadata ---'
npm --version 2>/dev/null || true
npm config get min-release-age 2>/dev/null || true
npm config get min-release-age-exclude 2>/dev/null || trueRepository: Fairmint/canton-node-sdk Length of output: 8886 🌐 Web query:
💡 Result: The npm CLI configuration option min-release-age-exclude allows you to exempt specific packages or groups of packages from the min-release-age and before publish-time filters [1][2]. Key details regarding this configuration: Glob Patterns: The option supports minimatch glob patterns [1][2]. This allows you to exclude entire scopes or namespaces (e.g., Citations:
🏁 Script executed: npm_root="$(npm root -g 2>/dev/null || true)"
printf '%s\n' "--- npm global root: $npm_root ---"
if [ -n "$npm_root" ]; then
rg -n -C 4 'min-release-age-exclude|min-release-age' "$npm_root/npm" 2>/dev/null | head -160
fi
printf '%s\n' '--- all Fairmint package names in manifests ---'
python3 - <<'PY'
import json
from pathlib import Path
for path in Path(".").rglob("package.json"):
if any(part in {"node_modules", "dist", "build"} for part in path.parts):
continue
data = json.loads(path.read_text())
names = []
for section in ("dependencies", "devDependencies", "optionalDependencies", "peerDependencies"):
names.extend(k for k in data.get(section, {}) if k.startswith("`@fairmint/`"))
print(f"{path}: name={data.get('name')!r}, Fairmint dependencies={names}")
PYRepository: Fairmint/canton-node-sdk Length of output: 31847 Restrict
🤖 Prompt for AI Agents🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
rg -n \
--glob '*.yml' \
--glob '*.yaml' \
--glob 'package.json' \
--glob 'README.md' \
--glob 'AGENTS.md' \
'npm (install|i|ci)|npm@|min-release-age-exclude' \
.github package.json README.md AGENTS.md 2>/dev/null || trueRepository: Fairmint/canton-node-sdk Length of output: 1509 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- npm references ---'
rg -n -i \
--glob '!node_modules' \
--glob '!dist' \
--glob '!build' \
'(^|[^[:alnum:]_])npm([[:space:]@:/]|$)|min-release-age-exclude|corepack|setup-node|node-version|engines' \
. 2>/dev/null || true
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/*' | sort
printf '%s\n' '--- package metadata ---'
cat -n package.json | sed -n '1,220p'
printf '%s\n' '--- workflow contents ---'
for f in $(git ls-files '.github/workflows/*' | sort); do
printf '\n### %s\n' "$f"
cat -n "$f"
done
printf '%s\n' '--- setup and documentation files ---'
for f in AGENTS.md README.md .npmrc; do
if [ -f "$f" ]; then
printf '\n### %s\n' "$f"
cat -n "$f"
fi
doneRepository: Fairmint/canton-node-sdk Length of output: 34526 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- repository tool/version files ---'
git ls-files | rg '(^|/)(\.nvmrc|\.node-version|\.tool-versions|package-lock\.json|npm-shrinkwrap\.json|pnpm-lock\.yaml|yarn\.lock|Dockerfile[^/]*|devcontainer\.json|.*\.md)$' | sort
printf '%s\n' '--- all npm and npx command entry points ---'
rg -n -i \
--glob '!node_modules' \
--glob '!dist' \
--glob '!build' \
'(^|[^[:alnum:]_])(npm|npx)([[:space:]]|$)' \
. 2>/dev/null || true
printf '%s\n' '--- package manager metadata ---'
if [ -f package-lock.json ]; then
jq '{lockfileVersion, name, version, packageManager}' package-lock.json
fi
if jq -e '.packageManager or .engines.npm' package.json >/dev/null 2>&1; then
jq '{packageManager, engines}' package.json
else
jq '{packageManager, engines}' package.json
fi
printf '%s\n' '--- workflow npm setup adjacency ---'
python3 - <<'PY'
from pathlib import Path
import re
for path in sorted(Path(".github/workflows").glob("*")):
if not path.is_file():
continue
lines = path.read_text().splitlines()
hits = [
(i + 1, line.strip())
for i, line in enumerate(lines)
if re.search(r'(?<![A-Za-z0-9_])(npm|npx)(?:\s|$)', line, re.I)
]
if hits:
print(f"\n{path}")
for line_no, text in hits:
print(f"{line_no}: {text}")
print("has_setup_node:", any("setup-node@" in line for line in lines))
print("has_npm_11_17_install:", any(re.search(r'npm@\\^?11\\.17(?:\\.0)?', line) for line in lines))
PYRepository: Fairmint/canton-node-sdk Length of output: 7672 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Node version declaration ---'
cat -n .nvmrc
printf '%s\n' '--- documented and automation setup references ---'
for f in CLAUDE.md .cursor/skills/localnet-testing/SKILL.md .github/copilot-instructions.md; do
if [ -f "$f" ]; then
printf '\n### %s\n' "$f"
rg -n -i -C 3 'node|npm|npx|install|setup' "$f" || true
fi
done
printf '%s\n' '--- workflow command/setup summary ---'
python3 - <<'PY'
from pathlib import Path
import re
for path in sorted(Path(".github/workflows").glob("*")):
if not path.is_file():
continue
lines = path.read_text().splitlines()
hits = []
for i, line in enumerate(lines):
if re.search(r"(?<![A-Za-z0-9_])(npm|npx)(?:\s|$)", line, re.I):
hits.append(i)
if hits:
print(f"\n{path}")
print("commands:")
for i in hits:
print(f" {i+1}: {lines[i].strip()}")
print("setup-node:", [f"{i+1}: {lines[i].strip()}" for i in range(len(lines)) if "setup-node@" in lines[i]])
print("npm-upgrade:", [f"{i+1}: {lines[i].strip()}" for i in range(len(lines)) if re.search(r"npm@(?:\\^)?11\\.17(?:\\.0)?", lines[i])])
printf("\nAll setup-node declarations:\n")
for path in sorted(Path(".github/workflows").glob("*")):
if path.is_file():
for i, line in enumerate(path.read_text().splitlines()):
if "setup-node@" in line or "node-version:" in line:
print(f"{path}:{i+1}: {line.strip()}")
PYRepository: Fairmint/canton-node-sdk Length of output: 4321 🌐 Web query:
💡 Result: Node.js version 22.14.0 is bundled with npm version 10.9.2 [1][2]. Citations:
🌐 Web query:
💡 Result: Yes, the min-release-age-exclude configuration option was introduced in npm v11.17.0, which was released on June 11, 2026 [1][2]. This configuration option allows users to specify a list of package names or minimatch glob patterns that are exempt from the min-release-age and before filters [3]. By using min-release-age-exclude, packages can be permitted to resolve to their newest versions even when a release-age window is otherwise enforced, which is particularly useful for prioritizing immediate updates for internally maintained packages or urgent patches while maintaining strict age policies for third-party dependencies [3][4][5]. Citations:
Pin npm 11.17 or newer for every npm entry point. The workflows that run 🤖 Prompt for AI Agents
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intentional — Fairmint-owned packages are published by us and should be consumable immediately after cutovers. Keeping the @fairmint/* exclude rather than narrowing to a single package name. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,10 @@ Low-level TypeScript SDK for Canton Network nodes (Ledger JSON API, Validator AP | |
|
|
||
| ## Developer documentation | ||
|
|
||
| The public [GitHub wiki](https://github.com/Fairmint/canton-node-sdk/wiki) is the canonical guide for | ||
| configuration, API boundaries, external signing, LocalNet, examples, and contribution. The public | ||
| [`src/index.ts`](https://github.com/Fairmint/canton-node-sdk/blob/main/src/index.ts) defines the | ||
| supported package surface; use the installed declarations and public | ||
| The public [GitHub wiki](https://github.com/Fairmint/canton-node-sdk/wiki) is the canonical guide | ||
| for configuration, API boundaries, external signing, LocalNet, examples, and contribution. The | ||
| public [`src/index.ts`](https://github.com/Fairmint/canton-node-sdk/blob/main/src/index.ts) defines | ||
| the supported package surface; use the installed declarations and public | ||
| [`examples/`](https://github.com/Fairmint/canton-node-sdk/tree/main/examples) and | ||
| [`test/`](https://github.com/Fairmint/canton-node-sdk/tree/main/test) for exact methods, request | ||
| shapes, and error behavior. | ||
|
|
@@ -19,10 +19,10 @@ npm install @fairmint/canton-node-sdk | |
| ``` | ||
|
|
||
| ```ts | ||
| import { Canton } from "@fairmint/canton-node-sdk"; | ||
| import { Canton } from '@fairmint/canton-node-sdk'; | ||
|
|
||
| async function main(): Promise<void> { | ||
| const canton = new Canton({ network: "localnet" }); | ||
| const canton = new Canton({ network: 'localnet' }); | ||
| const version = await canton.ledger.getVersion(); | ||
| console.log(version); | ||
| } | ||
|
|
@@ -44,4 +44,31 @@ npm test | |
| npm run build | ||
| ``` | ||
|
|
||
| Run `npm run localnet:verify` for the full LocalNet smoke and integration path. | ||
| ### LocalNet (owned by `@fairmint/canton-dev-tools`) | ||
|
|
||
| LocalNet lifecycle and shared test helpers live in | ||
| [`@fairmint/canton-dev-tools@0.1.1`](https://www.npmjs.com/package/@fairmint/canton-dev-tools) | ||
| (see its [COMPATIBILITY.md](https://github.com/Fairmint/canton-dev-tools/blob/main/COMPATIBILITY.md)). | ||
| This SDK does not publish a LocalNet CLI or `scripts/localnet-cloud.sh`. | ||
|
|
||
| ```bash | ||
| npm install # installs @fairmint/canton-dev-tools as an exact-pinned devDependency | ||
| npm run localnet:start | ||
| npm run localnet:smoke | ||
| npm run localnet:stop | ||
|
|
||
| # Or call the Dev Tools CLI directly: | ||
| npx @fairmint/canton-dev-tools start | ||
| ``` | ||
|
|
||
| Integration helpers: | ||
|
|
||
| ```ts | ||
| import { | ||
| buildIntegrationTestClientConfig, | ||
| getLocalnetParticipantAdminLedgerClient, | ||
| } from '@fairmint/canton-dev-tools/testing'; | ||
|
Comment on lines
+67
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win Use
📍 Affects 4 files
🤖 Prompt for AI AgentsSource: MCP tools |
||
| ``` | ||
|
|
||
| See [docs/package-boundary.md](docs/package-boundary.md) for what the npm package publishes versus | ||
| CI-only surfaces (`npm run check:package-artifacts`). | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: Fairmint/canton-node-sdk
Length of output: 6866
Use the exact Dev Tools version in LocalNet guidance.
Replace
@fairmint/canton-dev-tools@0.1.1+with@fairmint/canton-dev-tools@0.1.1in.cursor/skills/localnet-testing/SKILL.mdandAGENTS.md.🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 10: [RP1] null: npx commands without a version suffix (e.g.
@1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.Remediation: Pin the version: npx
@scope/server@1.2.3(MCP Rug Pull (RP1))
📍 Affects 2 files
.cursor/skills/localnet-testing/SKILL.md#L6-L6(this comment)AGENTS.md#L3-L6🤖 Prompt for AI Agents
Source: Coding guidelines