Skip to content

Commit

Permalink
doc: add typeDoc annotations
Browse files Browse the repository at this point in the history
Signed-off-by: Ilona Shishov <[email protected]>
  • Loading branch information
IlonaShishov committed Jul 14, 2024
1 parent 48e58de commit c949f03
Show file tree
Hide file tree
Showing 18 changed files with 308 additions and 64 deletions.
10 changes: 10 additions & 0 deletions src/artifactHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { Inputs, Outputs } from './generated/inputs-outputs.js';

const artifact = new DefaultArtifactClient();

/**
* Uploads artifacts to GitHub Actions.
* @param artifactName The name of the artifact.
* @param files The files to upload as artifacts.
* @returns The ID of the uploaded artifact.
*/
async function uploadArtifacts(
artifactName: string,
files: string[],
Expand All @@ -22,6 +28,10 @@ async function uploadArtifacts(
return uploadedArtifact.id;
}

/**
* Generates artifacts if enabled.
* @param files The files to upload as artifacts.
*/
export async function generateArtifacts(files: string[]) {
const uploadArtifact = ghCore.getBooleanInput(Inputs.UPLOAD_ARTIFACT);
const artifactName = ghCore.getInput(Inputs.ARTIFACT_FILENAME);
Expand Down
11 changes: 11 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
// Source of UTM for telemetry.
export const UTM_SOURCE = 'github-actions';

// URL of the SARIF schema.
export const SARIF_SCHEMA_URL =
'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json';

// Version of the SARIF schema.
export const SARIF_SCHEMA_VERSION = '2.1.0';

// Default directory to look for manifest files.
export const DEFAULT_MANIFEST_DIR = '.';

// Supported manifests and files
const GO_MOD = 'go.mod';
const POM_XML = 'pom.xml';
const PACKAGE_JSON = 'package.json';
Expand All @@ -14,13 +20,15 @@ const BUILD_GRADLE = 'build.gradle';
const DOCKERFILE = 'Dockerfile';
const CONTAINERFILE = 'Containerfile';

// Supported ecosystems
export const GRADLE = 'gradle';
export const MAVEN = 'maven';
const GOLANG = 'golang';
const NPM = 'npm';
const PYPI = 'pypi';
export const DOCKER = 'docker';

// Mapping of file names to their corresponding ecosystems.
export const fileNameToEcosystemMappings: { [key: string]: string } = {
[BUILD_GRADLE]: GRADLE,
[POM_XML]: MAVEN,
Expand All @@ -31,7 +39,10 @@ export const fileNameToEcosystemMappings: { [key: string]: string } = {
[CONTAINERFILE]: DOCKER,
};

// Type representing the severity of vulnerabilities.
export type VulnerabilitySeverity = 'none' | 'warning' | 'error';

// Order of vulnerability severities for comparison purposes.
export const vulnerabilitySeverityOrder: Record<VulnerabilitySeverity, number> =
{
none: 0,
Expand Down
4 changes: 2 additions & 2 deletions src/exhortServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { IImageRef, IOptions } from './imageAnalysis.js';
* Executes RHDA image analysis using the provided images and options.
* @param images - The images to analyze.
* @param options - The options for running image analysis.
* @returns A Promise resolving to the analysis response in HTML format.
* @returns A Promise resolving to the analysis response in JSON format.
*/
function imageAnalysisService(
images: IImageRef[],
Expand Down Expand Up @@ -51,7 +51,7 @@ function imageAnalysisService(
* Performs RHDA stack analysis based on the provided manifest path and options.
* @param pathToManifest The path to the manifest file for analysis.
* @param options Additional options for the analysis.
* @returns A promise resolving to the stack analysis report in HTML format.
* @returns A promise resolving to the stack analysis report in JSON format.
*/
async function stackAnalysisService(
pathToManifest,
Expand Down
6 changes: 4 additions & 2 deletions src/imageAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { UTM_SOURCE } from './constants.js';
* Represents options for image analysis.
*/
interface IOptions {
// RHDA_TOKEN: string;
RHDA_SOURCE: string;
EXHORT_SYFT_PATH: string;
EXHORT_SYFT_CONFIG_PATH: string;
Expand Down Expand Up @@ -64,7 +63,6 @@ interface IImageAnalysis {
*/
class DockerImageAnalysis implements IImageAnalysis {
options: IOptions = {
// 'RHDA_TOKEN': globalConfig.telemetryId,
RHDA_SOURCE: UTM_SOURCE,
EXHORT_SYFT_PATH: ghCore.getInput(Inputs.SYFT_EXECUTABLE_PATH),
EXHORT_SYFT_CONFIG_PATH: ghCore.getInput(Inputs.SYFT_CONFIG_PATH),
Expand Down Expand Up @@ -98,6 +96,10 @@ class DockerImageAnalysis implements IImageAnalysis {
*/
AS_REGEX: RegExp = /\s+AS\s+\S+/gi;

/**
* Constructs a new DockerImageAnalysis instance.
* @param filePath - The path to the Dockerfile to analyze.
*/
constructor(filePath: string) {
const lines = this.parseTxtDoc(filePath);

Expand Down
14 changes: 3 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ let originalCheckoutBranch: string;
let sha;
let ref;

/**
* Main function to run the action.
*/
export async function run(): Promise<void> {
ghCore.info(`ℹ️ Working directory is ${process.cwd()}`);

ghCore.debug(`Runner OS is ${utils.getOS()}`);
ghCore.debug(`Node version is ${process.version}`);

// checkout branch securly when payload originates from a pull request
prData = await isPr();
if (prData) {
originalCheckoutBranch = await getOriginalCheckoutBranch();
Expand All @@ -43,17 +45,13 @@ export async function run(): Promise<void> {
ghCore.info(`ℹ️ Ref to analyze is "${ref}"`);
ghCore.info(`ℹ️ Commit to analyze is "${sha}"`);

/* Generated RHDA report */

const { manifestFilePath, ecosystem } = await resolveManifestFilePath();

const { rhdaReportJson, rhdaReportJsonFilePath } = await generateRHDAReport(
manifestFilePath,
ecosystem,
);

/* Convert to SARIF and upload SARIF */

const { rhdaReportSarifFilePath, vulSeverity: vulSeverity } =
await handleSarif(
rhdaReportJson,
Expand All @@ -65,12 +63,8 @@ export async function run(): Promise<void> {
prData,
);

/* Handle artifacts */

await generateArtifacts([rhdaReportJsonFilePath, rhdaReportSarifFilePath]);

/* Label the PR with the scan status, if applicable */

if (prData) {
let resultLabel: string;

Expand All @@ -89,8 +83,6 @@ export async function run(): Promise<void> {
await addLabelsToPr(prData.number, [resultLabel]);
}

/* Evaluate fail_on and set the workflow step exit code accordingly */

const failOn = ghCore.getInput(Inputs.FAIL_ON) || 'error';

if (constants.vulnerabilitySeverityOrder[vulSeverity] > 0) {
Expand Down
16 changes: 16 additions & 0 deletions src/manifestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import {
DEFAULT_MANIFEST_DIR,
} from './constants.js';

/**
* Resolves the manifest file path and its corresponding ecosystem.
* @returns A promise that resolves to an object containing the manifest file path and ecosystem.
* @throws If the specified manifest file is not supported.
*/
export async function resolveManifestFilePath(): Promise<{
manifestFilePath: string;
ecosystem: string;
Expand Down Expand Up @@ -49,6 +54,12 @@ export async function resolveManifestFilePath(): Promise<{
};
}

/**
* Auto-detects the manifest file in the specified directory.
* @param manifestDir - The directory to search for the manifest file.
* @returns A promise that resolves to the name of the detected manifest file.
* @throws If no supported manifest file is found in the directory.
*/
async function autoDetectManifest(manifestDir: string): Promise<string> {
const manifestDirContents = await fs.readdir(manifestDir);

Expand All @@ -61,6 +72,11 @@ async function autoDetectManifest(manifestDir: string): Promise<string> {
throw new Error(getUnknownManifestError(manifestDir));
}

/**
* Generates an error message when no supported manifest file is found.
* @param manifestDir - The directory where the manifest file was expected.
* @returns The error message.
*/
function getUnknownManifestError(manifestDir: string): string {
return (
`Failed to find a manifest file in "${manifestDir}" matching one of the expected project types. ` +
Expand Down
28 changes: 23 additions & 5 deletions src/pr/checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import * as ghCore from '@actions/core';

import { getGitExecutable, execCommand } from '../utils.js';

/**
* Retrieves the name of the original checkout branch.
* @returns The name of the original checkout branch.
*/
export async function getOriginalCheckoutBranch(): Promise<string> {
const branch = (
await execCommand(getGitExecutable(), ['branch', '--show-current'])
Expand All @@ -10,9 +14,10 @@ export async function getOriginalCheckoutBranch(): Promise<string> {
}

/**
* Checkout PR code to run the CRDA Analysis on a PR,
* After completion of the scan this created remote and branch
* will be deleted and branch will be checkedout the present branch
* Checks out a pull request branch from a remote repository.
* After scan completion, this remote and branch will be deleted and original branch will be checked out.
* @param baseRepoUrl - The URL of the base repository.
* @param prNumber - The number of the pull request.
*/
export async function checkoutPr(
baseRepoUrl: string,
Expand All @@ -38,8 +43,11 @@ export async function checkoutPr(
await execCommand(getGitExecutable(), ['checkout', localbranchName]);
}

// Do cleanup after the crda scan and checkout
// back to the original branch
/**
* Cleans up the branches and remotes created during the pull request checkout process.
* @param prNumber - The number of the pull request.
* @param originalCheckoutBranch - The name of the original checkout branch.
*/
export async function checkoutCleanup(
prNumber: number,
originalCheckoutBranch: string,
Expand All @@ -57,10 +65,20 @@ export async function checkoutCleanup(
await execCommand(getGitExecutable(), ['branch', '-D', `${branchName}`]);
}

/**
* Gets the remote name for a pull request.
* @param prNumber - The number of the pull request.
* @returns The remote name for the pull request.
*/
function getPRRemoteName(prNumber: number): string {
return `remote-${prNumber}`;
}

/**
* Gets the branch name for a pull request.
* @param prNumber - The number of the pull request.
* @returns The branch name for the pull request.
*/
function getPRBranchName(prNumber: number): string {
return `pr-${prNumber}`;
}
19 changes: 14 additions & 5 deletions src/pr/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import * as checkout from './checkout.js';

type PullRequest = components['schemas']['pull-request-simple'];

/**
* Checks if the current event is a pull request and returns the pull request data if it is.
* @returns The pull request data if the event is a pull request, otherwise undefined.
*/
async function isPr(): Promise<types.IPrData | undefined> {
// check if event is pull request
const prRawData = github.context.payload.pull_request as PullRequest;
if (!prRawData) {
ghCore.info(`No checkout required, item is not a pull request`);
return;
}

// parse PR data
const pr = parsePrData(prRawData);
ghCore.debug(`PR number is ${pr.number}`);
ghCore.info(
Expand All @@ -26,17 +28,24 @@ async function isPr(): Promise<types.IPrData | undefined> {
return pr;
}

/**
* Handles a pull request by creating repository labels, cleaning up existing labels, and checking out the pull request.
* @param pr - The pull request data.
*/
async function handlePr(pr: types.IPrData): Promise<void> {
// create and load pr labels
await createRepoLabels();

// remove existing rhda labels before run
await cleanupLabels(pr.number);

// checkout pr
await checkout.checkoutPr(pr.baseRepo.htmlUrl, pr.number);
}

/**
* Parses the pull request data.
* @param pr - The raw pull request data from the GitHub API.
* @returns The parsed pull request data.
* @throws If the owner of the pull request base or head repository cannot be determined.
*/
function parsePrData(pr: PullRequest): types.IPrData {
const baseOwner = pr.base.repo.owner?.login;
if (!baseOwner) {
Expand Down
Loading

0 comments on commit c949f03

Please sign in to comment.