DEV Community

Thomas.G for NodeSecure

Posted on

NodeSecure hidden capability: mama

Hello πŸ‘‹

I'm starting a new short-article series focused on highlighting lesser-known parts of the NodeSecure project. The goal is to help new contributors by giving them a clearer view of the back-end building blocks that power the project.

Chapter 1: mama

Mama stand for ManifestManager. This package was designed to manage and load an npm manifest (a package.json file, for simplicity).

Under the hood, it uses @nodesecure/npm-types to provide precise, up-to-date types (including runtime-related fields). We will dive into that package in another article.

import { ManifestManager } from "@nodesecure/mama";

// synchronous version: ManifestManager.fromPackageJSONSync
const mama = await ManifestManager.fromPackageJSON(
  process.cwd()
);
console.log(mama.document);
Enter fullscreen mode Exit fullscreen mode

This package provides many utilities used across back-end components in the Scanner monorepo.

Here are a few of them:

Integrity

You can easily extract a hash by using the readonly getter integrity.

console.log(mama.integrity);
Enter fullscreen mode Exit fullscreen mode

Scanner uses this to assert that the package.json in the tarball matches the one uploaded to the registry (known as manifest confusion).

Here are the properties we hash:

{
  name,
  version,
  dependencies,
  license: license ?? "NONE",
  scripts
}
Enter fullscreen mode Exit fullscreen mode

When a mismatch is detected, the tool reports it as a global warning, as shown in the CLI UI:

NodeSecure global warnings

module type

Inspired by the recent node-modules-inspector tool built by Antfu, we re-implemented the same module type detection:

// "dts" | "faux" | "dual" | "esm" | "cjs"
console.log(mama.moduleType);
Enter fullscreen mode Exit fullscreen mode

entry files

mama can recursively extract entry files using the Node.js exports field (or legacy fields like main). The API is lazy and returns an IterableIterator<string>:

console.log([...mama.getEntryFiles()]);
Enter fullscreen mode Exit fullscreen mode

This API is used in the tarball package in combination with JS-X-Ray’s EntryFilesAnalyser.

async scanFiles(): Promise<ScannedFilesResult> {
  const location = this.manifest.location;
  const [
    composition,
    spdx
  ] = await Promise.all([
    getTarballComposition(location),
    conformance.extractLicenses(location)
  ]);

  const code = await new SourceCodeScanner(this.manifest).iterate({
    manifest: [...this.manifest.getEntryFiles()]
      .flatMap(filterJavaScriptFiles()),
    javascript: composition.files
      .flatMap(filterJavaScriptFiles())
  });

  return {
    conformance: spdx,
    composition,
    code
  };
}
Enter fullscreen mode Exit fullscreen mode

author

Parse the NPM author field if present and then return a Contact interface.

interface Contact {
  email?: string;
  url?: string;
  name: string;
}
Enter fullscreen mode Exit fullscreen mode

For example, John Doe <john.doe@gmail.com> produces the following object:

{
  "name": "John Doe",
  "email": "john.doe@gmail.com"
}
Enter fullscreen mode Exit fullscreen mode

Others

The module also provides additional utilities around reading and managing manifests, such as:

  • Parsing package specs (including scope/org, package name, and semver range)
  • Detecting local lockfiles

The end

The full module documentation is available here.

Thanks you for reading

Top comments (0)