Skip to content
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

Typescript migration #409

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@ json/
reports/
preview/
dist/
asset/
.nodesecurerc
.DS_Store
9 changes: 8 additions & 1 deletion bin/commands/execute.js → bin/commands/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ export async function execute(options = {}) {
const config = configResult.unwrap();
const { report } = config;

if (report.reporters.length === 0) {
if (!report) {
throw new Error("Report configuration is missing");
}

if (!hasReporter(report.reporters)) {
throw new Error("At least one reporter must be selected (either 'HTML' or 'PDF')");
}

Expand Down Expand Up @@ -85,3 +89,6 @@ function debug(obj) {
writeFileSync(filePath, inspect(obj, { showHidden: true, depth: null }), "utf8");
}

function hasReporter<T extends NonNullable<rc.RC["report"]>["reporters"]>(reporters: T): reporters is NonNullable<T> {
return reporters !== undefined && reporters.length > 0;
}
File renamed without changes.
2 changes: 1 addition & 1 deletion bin/commands/init.js → bin/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as rc from "@nodesecure/rc";
import kleur from "kleur";

export async function init() {
export async function init(): Promise<void> {
const configLocation = process.cwd();

const result = await rc.read(configLocation, {
Expand Down
0 bin/index.js → bin/index.ts
100755 → 100644
File renamed without changes.
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const compat = new FlatCompat({
});

export default [{
ignores: ["**/node_modules/", "**/tmp/", "**/dist/", "**/coverage/", "**/fixtures/", "**/public/lib"]
ignores: ["**/node_modules/", "**/tmp/", "**/dist/", "**/asset/", "**/coverage/", "**/fixtures/", "**/public/lib"]
}, ...compat.extends("@nodesecure/eslint-config"), {
languageOptions: {
sourceType: "module",
Expand Down
17 changes: 13 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
"name": "@nodesecure/report",
"version": "3.0.0",
"description": "NodeSecure HTML & PDF graphic security report",
"main": "./bin/index.js",
"main": "./dist/bin/index.js",
"type": "module",
"bin": {
"nreport": "./bin/index.js"
"nreport": "./dist/bin/index.js"
},
"exports": {
".": {
"import": "./src/index.js"
}
},
"scripts": {
"build": "rimraf ./dist && npm run copy-views && npm run copy-public && npm run copy-package && tsc",
"copy-views": "copyfiles views/template.html dist/",
"copy-public": "copyfiles public/** dist/",
"copy-package": "copyfiles package.json dist/",
"lint": "eslint src test",
"test-only": "glob -c \"node --test-reporter=spec --test\" \"./test/**/*.spec.js\"",
"test": "c8 --all --src ./src -r html npm run test-only",
Expand Down Expand Up @@ -60,12 +64,17 @@
"zup": "0.0.2"
},
"devDependencies": {
"@nodesecure/eslint-config": "2.0.0-beta.0",
"@openally/config.eslint": "^1.0.0",
"@openally/config.typescript": "^1.0.3",
"@types/node": "^22.2.0",
"c8": "^10.1.2",
"copyfiles": "^2.4.1",
"eslint": "^9.8.0",
"glob": "^11.0.0",
"open": "^10.1.0"
"open": "^10.1.0",
"rimraf": "^6.0.1",
"tsx": "^4.17.0",
"typescript": "^5.4.2"
},
"engines": {
"node": ">=18"
Expand Down
8 changes: 4 additions & 4 deletions scripts/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ payload.report_theme = theme;
const config = {
theme,
includeTransitiveInternal: false,
reporters: [ "html" ],
reporters: ["html"],
npm: {
organizationPrefix: "@nodesecure",
packages: [ "@nodesecure/js-x-ray" ]
packages: ["@nodesecure/js-x-ray"]
},
git: {
organizationUrl: "https://github.com/NodeSecure",
Expand Down Expand Up @@ -87,7 +87,7 @@ const config = {

const HTMLReport = new HTMLTemplateGenerator(
payload, config
).render({ asset_location: "./dist" });
).render({ asset_location: "./asset" });

const previewLocation = path.join(kPreviewDir, "preview.html");
writeFileSync(
Expand All @@ -96,7 +96,7 @@ writeFileSync(
);

await buildFrontAssets(
path.join(kPreviewDir, "dist"),
path.join(kPreviewDir, "asset"),
{ theme }
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,47 @@ import fs from "node:fs";

// Import Third-party Dependencies
import { formatBytes, getScoreColor, getVCSRepositoryPathAndPlatform } from "@nodesecure/utils";
import * as Flags from "@nodesecure/flags";
import { getFlags, getManifest } from "@nodesecure/flags/web";
import * as scorecard from "@nodesecure/ossf-scorecard-sdk";

// Import Internal Dependencies
import * as localStorage from "../localStorage.js";
import { type Dependencies, type Payload } from "@nodesecure/scanner";
import type { RC } from "@nodesecure/rc";

export interface ReportStat {
size: {
all: number, internal: number, external: number
};
deps: {
transitive: Record<PropertyKey, any>;
node: Record<PropertyKey, any>
},
licenses: {
Unknown: number
},
flags: Record<PropertyKey, any>;
flagsList: any;
extensions: Record<PropertyKey, any>;
warnings: Record<PropertyKey, any>;
authors: Record<PropertyKey, any>;
packages: Record<PropertyKey, any>;
packages_count: {
all: number, internal: number, external: number
};
scorecards: Record<PropertyKey, any>;
showFlags: boolean;
}

interface BuildStatOptions {
isJson: boolean;
reportConfig: RC["report"]

}

// CONSTANTS
const kFlagsList = Object.values(Flags.getManifest());
const kWantedFlags = Flags.getFlags();
const kFlagsList = Object.values(getManifest());
const kWantedFlags = getFlags();
const kScorecardVisualizerUrl = `https://kooltheba.github.io/openssf-scorecard-api-visualizer/#/projects`;
const kNodeVisualizerUrl = `https://nodejs.org/dist/latest/docs/api`;

Expand All @@ -28,13 +60,19 @@ function splitPackageWithOrg(pkg) {
* @param {string[] | NodeSecure.Payload | NodeSecure.Payload[]} payloadFiles
* @param {object} options
* @param {boolean} options.isJson
* @returns
* @returns {ReportStat}
*/
export async function buildStatsFromNsecurePayloads(payloadFiles = [], options = Object.create(null)) {
const { isJson = false, reportConfig } = options;

type PayloadFile = string[] | Payload | Payload[] | Payload["dependencies"];

export async function buildStatsFromNsecurePayloads(
payloadFiles: PayloadFile = [],
options: BuildStatOptions = Object.create(null)
): Promise<ReportStat> {
const { isJson = false, reportConfig = localStorage.getConfig().report } = options;

const config = reportConfig ?? localStorage.getConfig().report;
const stats = {
const stats: ReportStat = {
size: {
all: 0, internal: 0, external: 0
},
Expand All @@ -55,15 +93,15 @@ export async function buildStatsFromNsecurePayloads(payloadFiles = [], options =
all: 0, internal: 0, external: 0
},
scorecards: {},
showFlags: config.showFlags
showFlags: reportConfig.showFlags
};

/**
* @param {string | NodeSecure.Payload} fileOrJson
* @returns {NodeSecure.Payload}
*/
function getJSONPayload(fileOrJson) {
if (isJson) {
function getJSONPayload(fileOrJson: string | Payload | Dependencies) {
if (isPayload(isJson, fileOrJson)) {
return fileOrJson;
}

Expand Down Expand Up @@ -171,3 +209,7 @@ export async function buildStatsFromNsecurePayloads(payloadFiles = [], options =
return stats;
}

function isPayload(isJson: boolean, fileOrJson: string | Payload | Dependencies): fileOrJson is Payload | Dependencies {
return isJson === true;
}

37 changes: 26 additions & 11 deletions src/analysis/fetch.js → src/analysis/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,25 @@ import * as scanner from "./scanner.js";
import * as localStorage from "../localStorage.js";
import * as utils from "../utils/index.js";
import * as CONSTANTS from "../constants.js";
import { type RC } from "@nodesecure/rc";

export async function fetchPackagesAndRepositoriesData(
verbose = true
) {
const config = localStorage.getConfig().report;
const config = localStorage.getConfig()?.report;
// TODO: handle undefined ?


const fetchNpm = hasReportConfig(config) && canFetchNpm(config.npm);
const fetchGit = hasReportConfig(config) && canFetchGit(config.git);

const fetchNpm = config.npm?.packages.length > 0;
const fetchGit = config.git?.repositories.length > 0;
if (!fetchGit && !fetchNpm) {
throw new Error(
"No git repositories and no npm packages to fetch in the local configuration!"
);
}

const pkgStats = fetchNpm ?
const pkgStats = canFetchNpm(config.npm) ?
await fetchPackagesStats(
utils.formatNpmPackages(
config.npm.organizationPrefix,
Expand All @@ -34,11 +38,10 @@ export async function fetchPackagesAndRepositoriesData(
) :
null;

const { repositories, organizationUrl } = config.git;
const repoStats = fetchGit ?
const repoStats = canFetchGit(config.git) ?
await fetchRepositoriesStats(
repositories,
organizationUrl,
config.git.repositories,
config.git.organizationUrl,
verbose
) :
null;
Expand All @@ -47,7 +50,7 @@ export async function fetchPackagesAndRepositoriesData(
}

async function fetchPackagesStats(
packages,
packages: string[],
verbose = true
) {
const jsonFiles = await utils.runInSpinner(
Expand All @@ -65,8 +68,8 @@ async function fetchPackagesStats(
}

async function fetchRepositoriesStats(
repositories,
organizationUrl,
repositories: string[],
organizationUrl: string,
verbose = true
) {
const jsonFiles = await utils.runInSpinner(
Expand Down Expand Up @@ -96,3 +99,15 @@ async function fetchRepositoriesStats(
jsonFiles.filter((value) => value !== null)
);
}

function hasReportConfig(config: RC["report"]): config is NonNullable<RC["report"]> {
return config !== undefined;
}

function canFetchGit<T extends NonNullable<RC["report"]>["git"]>(gitConfig: T): gitConfig is NonNullable<T> {
return gitConfig !== undefined && gitConfig.repositories.length > 0;
}

function canFetchNpm<T extends NonNullable<RC["report"]>["npm"]>(npmConfig: T): npmConfig is NonNullable<T> {
return npmConfig !== undefined && npmConfig.packages.length > 0;
}
12 changes: 6 additions & 6 deletions src/analysis/scanner.js → src/analysis/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ const kMaxAnalysisLock = new Mutex({ concurrency: 2 });
* @param {!string} packageName
* @returns {Promise<string>}
*/
export async function from(packageName) {
export async function from(packageName: string): Promise<string | null> {
const release = await kMaxAnalysisLock.acquire();

try {
const name = `${packageName}.json`;
const { dependencies } = await scanner.from(packageName, {
maxDepth: 4, verbose: false
maxDepth: 4, vulnerabilityStrategy: "none"
});

const filePath = path.join(CONSTANTS.DIRS.JSON, name);
Expand All @@ -34,7 +34,7 @@ export async function from(packageName) {

return filePath;
}
catch (error) {
catch {
return null;
}
finally {
Expand All @@ -49,21 +49,21 @@ export async function from(packageName) {
* @param {!string} dir
* @returns {Promise<string>}
*/
export async function cwd(dir) {
export async function cwd(dir: string): Promise<string | null> {
const release = await kMaxAnalysisLock.acquire();

try {
const name = `${path.basename(dir)}.json`;
const { dependencies } = await scanner.cwd(dir, {
maxDepth: 4, verbose: false, usePackageLock: false
maxDepth: 4, vulnerabilityStrategy: "none"
});

const filePath = path.join(CONSTANTS.DIRS.JSON, name);
await fs.writeFile(filePath, JSON.stringify(dependencies, null, 2));

return filePath;
}
catch (error) {
catch {
return null;
}
finally {
Expand Down
Loading
Loading