kedgeway

Docs / Reference / What it scans

What it scans

A diagnosis reads manifests and lockfiles. It does not score source code. migrate also lists up to 20 import lines of legacy packages, using the same depth and skipped directories.

Cargo.toml

It looks for the soroban-sdk crate in these forms:

toml
# string
soroban-sdk = "21.0.0"

# table
soroban-sdk = { version = "21.0.0", features = ["testutils"] }

# renamed
sdk = { package = "soroban-sdk", version = "21.0.0" }

# workspace
[workspace.dependencies]
soroban-sdk = "21.0.0"

[dependencies]
soroban-sdk = { workspace = true }
  • Tables read: [dependencies], [dev-dependencies], [build-dependencies], and the same three under [target.<cfg>].
  • Renames: a package = "soroban-sdk" key is followed to the real crate name.
  • Workspaces: a member with workspace = true takes its version from the nearest ancestor manifest that declares the same key in [workspace.dependencies]. A workspace dependency that no member uses is still reported, at the workspace manifest. If a workspace = true dependency cannot be resolved, it is reported with no version, which gives SDK_UNKNOWN.
  • Duplicates: identical findings (same file, crate and version) are reported once.

package.json

It reads dependencies and devDependencies only, for these packages:

  • @stellar/stellar-sdk
  • @stellar/stellar-base
  • soroban-client (legacy)
  • stellar-sdk (legacy, unscoped)

Peer and optional dependencies are not read.

npm aliases

A member that uses an npm: alias is read as the real package behind it. This one is the current SDK, not the legacy stellar-sdk:

package.json
"stellar-sdk": "npm:@stellar/stellar-sdk@17.4.0"

The version after the last @ is read as usual. An alias with no version (npm:@stellar/stellar-sdk) is unknown. This was found in a real manifest (stellar/freighter) while building the lockfile corpus. See Migration mode for how aliases are edited.

Where it looks

  • It walks the path you give, in alphabetical order, up to four folders deep.
  • It skips node_modules, target, dist, .git, .next, vendor, build and coverage.
  • Unreadable folders and files, and manifests that fail to parse, are reported as MANIFEST_UNPARSEABLE instead of being ignored.

How versions are read

kedgeway needs a single major version to compare. It strips leading range operators and reads the major from what is left.

DeclaredRead as
21.0.0, ^21.0.0, ~21.0major 21
>=21.0.0major 21 (the >= is stripped)
21.xmajor 21
<22, <=21.0.0unknown: an upper bound alone does not identify a major
>=20 || ^21unknown: compound ranges are not resolved
empty, *, a git or path sourceunknown

An unknown version produces SDK_UNKNOWN or JS_SDK_UNKNOWN, never a guess.

When a lockfile resolves the dependency, that exact version is used instead and this table only matters as a fallback. Where a JS range is matched against candidate versions, kedgeway uses the semver package, so hyphen ranges, ||, x-ranges and npm prerelease rules behave like npm. Cargo requirements use kedgeway's own matcher: a bare 1.2.3 is ^1.2.3, and *, = and >=, < combinations are understood.

Lockfiles

A manifest range like ^21 says little about what you build. When a lockfile exists, kedgeway reports the resolved version of each detected dependency and compares that instead of the manifest version. Evidence says which it used, for example resolved 21.7.6 from Cargo.lock; manifest ^21.

LockfileHow the direct dependency is found
Cargo.lockAmong the entries for the crate, the one whose version satisfies the manifest requirement (Cargo rules). If none or several do, the dependency stays unresolved and the evidence says ambiguous in Cargo.lock.
package-lock.jsonpackages["node_modules/<name>"] (v2 and v3), else dependencies[<name>] (v1).
pnpm-lock.yamlThe importer's own entry (the root or the workspace member), else the single package version that satisfies the manifest range. Several candidates are reported as ambiguous. Lockfile versions 5 to 9, with a minimal parser.
yarn.lockThe block whose descriptor is name@<manifest range> (classic) or name@npm:<range> (berry). Minimal parser.
  • Ambiguous means fallback. When a lockfile cannot give one answer, kedgeway uses the manifest version and says so in the evidence. It never guesses.
  • Where it looks. The nearest lockfile walking up from the manifest's folder to the scan root that has a verdict for that dependency. It never reads above the scan root. If a lockfile exists above it, the text report prints a hint:.
  • Ranges that do not pin a major (such as <21) are no longer unknown when a lockfile pins the dependency.
  • Limits. Only these four lockfiles are read. Unusual pnpm or yarn layouts resolve to nothing and fall back to the manifest. Prerelease tags are ignored when testing a version against a Cargo requirement.
  • Tested on real files. The parsers run against seven real lockfiles from public repositories (Cargo.lock v4, package-lock v3, pnpm-lock v9, yarn classic and berry). Repositories and commits are listed in fixtures/lockfiles/SOURCES.md in the kedgeway repo.

Remote repositories

diagnose and migrate can scan a repository you have not cloned. Pass a git URL or owner/repo instead of a path. See Commands for the accepted forms and --ref.

  • How it fetches. kedgeway runs git clone --depth 1 --single-branch --no-tags into a private temporary directory, scans it, and deletes it afterwards, also when the scan fails. Nothing from the repository is executed.
  • Private repositories. Git credentials must already be configured, through an SSH agent or a credential helper. kedgeway never asks for or stores them.
  • Without git. For GitHub repositories, kedgeway downloads the source tarball and unpacks it with Node only, capped at 50 MB and 20,000 entries.
  • Rejected. file:// and every other scheme, URLs with embedded credentials, and unsafe refs exit with 1.
  • Output. The report header shows github.com/o/r@main instead of the temporary path. Finding, SARIF and annotation paths stay relative to the repository root.
  • Migrate. A remote migrate is a dry run only.
Terminal
kedgeway diagnose https://github.com/o/r
kedgeway diagnose o/r --ref v1.2.0

Toolchain checks

Beyond the SDKs, kedgeway reads the toolchain the repo pins. Every finding points at a file and line.

  • Stellar CLI pins. They are read from workflows (cargo install ... --version X, stellar-cli@X, and the version: input of the stellar/stellar-cli action), Dockerfile*, Makefile, shell scripts in the root and scripts/, .tool-versions, and @stellar/stellar-cli in package.json. Each pin is compared by major with the Stellar CLI version on the official software versions page. Nothing is reported if the repo pins none.
  • Rust target. If a repo with soroban-sdk declares wasm32-unknown-unknown (rust-toolchain.toml, .cargo/config.toml, workflows, Makefiles, scripts) and never wasm32v1-none, RUST_TARGET_LEGACY tells you to run rustup target add wasm32v1-none.
  • Rust toolchain. A pinned Rust channel below 1.84.0 raises RUST_TOOLCHAIN_OLD, because the setup guide requires Rust v1.84.0 or higher. stable and nightly are not pins.