ipk-verify: handle JS services that bundle their own Node runtime#7
Merged
Merged
Conversation
A Node service's ES level was derived from every `.js` under the
service directory (a recursive `collect_js` walk). That wrongly pulls in
vendored code — `node_modules`, or a streaming server the app spawns on
its own bundled Node — whose syntax level says nothing about what the
firmware's Node.js executes. A package that ships its own newer Node
would be failed against the TV's old Node purely on that vendored code.
Grade only the code the firmware Node actually runs: start at
`package.json` `main` (default `index.js`) and follow the static,
relative module graph via `require('./x')`, `import`/`export … from`,
`import('./x')`, and side-effect `import './x'`. Bare specifiers
(npm packages, built-ins) are not followed, and traversal is confined
to the service directory. Add unit tests covering entry-graph scoping,
require/import resolution, and exclusion of vendored/bare-specifier code.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtKyCd9ucV7PRGH9LQZRRg
A JS/Node service run by the firmware's Node can still ship native ELF binaries beside its scripts — its own `node`, `ffmpeg`, and `.so`s — but the report showed nothing about them (only native components list an exe/libs). That hides exactly the detail a reviewer needs to understand a "bundles its own runtime" package, e.g. that every binary is 32-bit ARM (so aarch64 TVs are out). Scan a non-native service's directory at parse time and classify each bundled ELF as an executable or shared library (a PT_INTERP program header distinguishes a PIE executable from a real shared object) with its architecture. Surface the list as supplementary `--details` info that never affects the verdict: folded into a <details> block on Markdown, a plain bullet list otherwise. New `bin_lib::BundledArtifact` does the header-only classification; `ServiceInfo` carries the list to the verifier and renderer. Adds unit tests for classification and the parse-time scan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XtKyCd9ucV7PRGH9LQZRRg
Building on the bundled-binary inventory, actually check whether the native runtime a JS service ships (its own node/ffmpeg + their .so's) can load on each target firmware — the same binary/library resolution a native component gets, but supplementary (it never gates the verdict). At parse time each bundled executable becomes a verifiable unit: its `exe` plus the libraries reachable via its rpath and its sibling `lib` dir (these runtimes locate libs through the loader's `--library-path` at spawn, not a DT_RPATH, so the sibling `lib/` is treated as a search path). `verify_for_firmware` then verifies each against the firmware's libraries. The report renders one native-style table — bundled executables, then the unique bundled libraries, OK/failed per firmware — folded into a <details> block. Also harden `BinaryInfo`/`LibraryInfo` parsing to treat an ELF with no `.dynstr`/`.dynsym` as having no dynamic deps instead of panicking; a bundled statically-linked `ffmpeg` hit that latent unwrap. Adds Clone to BinaryInfo/Component (to store bundled units), a `bundled` field on ComponentVerifyResult, and tests for the parse-time wiring. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XtKyCd9ucV7PRGH9LQZRRg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
A webOS JS service is normally run by the TV's firmware Node, so
ipk-verifygrades its JavaScript against that Node's version. But some apps ship their own Node runtime inside the IPK (e.g. a bundlednode18+ffmpeg) and run the heavy code off that, spawned as a child process. For those, the current checks are both wrong (they gate vendored server code against the firmware Node it never touches) and incomplete (they say nothing about whether the bundled runtime actually loads on the target firmware).This came up on a real submission (apps-repo#203) whose author correctly pointed out the app ships its own Node 18. This PR makes the tool model that packaging correctly.
Changes
1. Scope the service ES-level scan to the entry graph (
webdetect)The service ES level was derived from every
.jsunder the service directory, which sweeps innode_modulesand a bundled server written for a newer Node — code the firmware Node never runs. Now the scan starts atpackage.jsonmainand follows only the static, relative module graph (require('./x'),import/export … from,import('./x'), side-effectimport './x'); bare specifiers (npm/built-ins) are not followed. This fixes the false failure where a self-shipped-Node app was gated against the TV's old Node.2. Report a JS service's bundled native binaries (
ipk-verify)Scan a non-native service's directory and classify each bundled ELF (executable vs shared library — a
PT_INTERPheader distinguishes a PIE executable from a real shared object) with its architecture. Surfaced as supplementary--detailsinfo, folded into a<details>block on Markdown. Newbin_lib::BundledArtifactdoes the header-only classification.3. Verify the bundled runtime against firmware libraries (
ipk-verify)Each bundled executable becomes a verifiable unit (its
exeplus the libraries reachable via its rpath and siblinglib/dir — these runtimes locate libs through the loader's--library-pathat spawn, not aDT_RPATH), then gets checked against each firmware's libraries like a native component. The report renders one native-style table — bundled executables, then the unique bundled libraries, OK/failed per firmware — folded into a<details>block. This is supplementary and never gates the package verdict.Also hardens
BinaryInfo/LibraryInfoparsing to treat an ELF with no.dynstr/.dynsymas having no dynamic deps instead of panicking (a bundled statically-linkedffmpeghit that latentunwrap()).What it catches
Run against real packages (Markdown output):
rsyncdynamically linkslibcrypto.so.1.1, present on only 3 of 13 firmware generations, so rsync silently won't run on the rest. dropbear/scp/sftp-server/telnetd are fine everywhere.Testing
cargo testgreen forwebdetect-lib,bin-lib,ipk-lib,ipk-verify.🤖 Generated with Claude Code
Generated by Claude Code