Skip to content

Commit 1887425

Browse files
committed
Fixed submission by fixing calling of git to capture STDOUT properly
1 parent 3a89bfb commit 1887425

File tree

4 files changed

+84
-19
lines changed

4 files changed

+84
-19
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/componentDetection.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default class ComponentDetection {
6262

6363
// Run the component-detection CLI on the path specified
6464
public static runComponentDetection(path: string): Promise<boolean> {
65-
console.info(`Running component-detection on ${path}`);
65+
console.debug(`Running component-detection on ${path}`);
6666

6767
console.debug(`Writing to output file: ${this.outputPath}`);
6868

@@ -103,7 +103,7 @@ export default class ComponentDetection {
103103
}
104104

105105
public static async getManifestsFromResults(file: string, path: string): Promise<Manifest[] | undefined> {
106-
console.info(`Reading results from ${file}`);
106+
console.debug(`Reading results from ${file}`);
107107
const results = await fs.readFileSync(file, 'utf8');
108108
var json: any = JSON.parse(results);
109109

src/componentSubmission.ts

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import chalk from 'chalk';
2-
import { spawn, ChildProcess } from 'child_process';
2+
import { spawn, execFile } from 'child_process';
33
import path from 'path';
44
import fs from 'fs';
55
import os from 'os';
@@ -8,11 +8,12 @@ import ComponentDetection from './componentDetection.js';
88
import {
99
Job,
1010
Snapshot,
11-
submitSnapshot
1211
} from '@github/dependency-submission-toolkit';
12+
import { Octokit } from 'octokit';
13+
import { RequestError } from '@octokit/request-error'
1314

1415
export interface SubmitOpts {
15-
octokit?: any; // Octokit instance, optional
16+
octokit: Octokit;
1617
owner: string;
1718
repo: string;
1819
branch: string;
@@ -51,8 +52,9 @@ export async function sparseCheckout(owner: string, repo: string, branch: string
5152
await execGit(['fetch', '--depth=1', 'origin', branch], { cwd });
5253
await execGit(['checkout', 'FETCH_HEAD'], { cwd });
5354

54-
const process = await execGit(['rev-parse', 'HEAD'], { cwd: destDir });
55-
const sha = process?.stdout?.toString().trim();
55+
const { stdout: shaOut } = await execGit(['rev-parse', 'HEAD'], { cwd: destDir });
56+
const sha = shaOut.trim();
57+
console.debug(`Checked out ${owner}/${repo}@${branch} to ${destDir} at commit ${sha}`);
5658
return sha;
5759
}
5860

@@ -74,7 +76,7 @@ export async function submitSnapshotIfPossible(opts: SubmitOpts): Promise<boolea
7476
if (!opts.quiet) console.error(chalk.red(`Failed to determine SHA for ${opts.owner}/${opts.repo} on branch ${opts.branch}`));
7577
return false;
7678
}
77-
await run(tmp, opts.owner, opts.repo, sha, opts.branch, opts.componentDetectionBinPath);
79+
await run(opts.octokit, tmp, opts.owner, opts.repo, sha, opts.branch, opts.componentDetectionBinPath);
7880

7981
} catch (e) {
8082
if (!opts.quiet) console.error(chalk.red(`Component Detection failed: ${(e as Error).message}`));
@@ -127,15 +129,20 @@ function buildSparsePatterns(langs: string[]): string[] {
127129
return Array.from(set);
128130
}
129131

130-
async function execGit(args: string[], opts: { cwd: string, quiet?: boolean }): Promise<ChildProcess> {
131-
return await new Promise<ChildProcess>((resolve, reject) => {
132-
const child = spawn('git', args, { cwd: opts.cwd, stdio: 'pipe' });
133-
child.on('error', reject);
134-
child.on('exit', code => code === 0 ? resolve(child) : reject(new Error(`git ${args.join(' ')} exit ${code}`)));
132+
async function execGit(args: string[], opts: { cwd: string, quiet?: boolean }): Promise<{ stdout: string; stderr: string }> {
133+
return await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
134+
execFile('git', args, { cwd: opts.cwd, encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
135+
if (error) {
136+
const msg = stderr?.trim() || error.message;
137+
reject(new Error(`git ${args.join(' ')} failed: ${msg}`));
138+
} else {
139+
resolve({ stdout, stderr: stderr ?? '' });
140+
}
141+
});
135142
});
136143
}
137144

138-
export async function run(tmpDir: string, owner: string, repo: string, sha: string, ref: string, componentDetectionBinPath?: string) {
145+
export async function run(octokit: Octokit, tmpDir: string, owner: string, repo: string, sha: string, ref: string, componentDetectionBinPath?: string) {
139146

140147
let manifests = await ComponentDetection.scanAndGetManifests(
141148
tmpDir,
@@ -160,12 +167,70 @@ export async function run(tmpDir: string, owner: string, repo: string, sha: stri
160167
};
161168

162169
let snapshot = new Snapshot(detector, undefined, job);
170+
snapshot.ref = `refs/heads/${ref}`;
171+
snapshot.sha = sha;
172+
173+
console.debug(`Submitting snapshot for ${owner}/${repo} at ${snapshot.ref} (${snapshot.sha}) with ${manifests?.length || 0} manifests`);
163174

164175
manifests?.forEach((manifest) => {
165176
snapshot.addManifest(manifest);
166177
});
167178

179+
submitSnapshot(octokit, snapshot, { owner, repo });
180+
}
181+
182+
/**
183+
* submitSnapshot submits a snapshot to the Dependency Submission API - vendored in from @github/dependency-submission-toolkit, to make it work at the CLI, vs in Actions.
184+
*
185+
* @param {Snapshot} snapshot
186+
* @param {Repo} repo
187+
*/
188+
export async function submitSnapshot(
189+
octokit: Octokit,
190+
snapshot: Snapshot,
191+
repo: { owner: string; repo: string }
192+
) {
193+
console.debug('Submitting snapshot...')
168194
console.debug(snapshot.prettyJSON())
169195

170-
//submitSnapshot(snapshot);
171-
}
196+
try {
197+
const response = await octokit.request(
198+
'POST /repos/{owner}/{repo}/dependency-graph/snapshots',
199+
{
200+
headers: {
201+
accept: 'application/vnd.github.foo-bar-preview+json'
202+
},
203+
owner: repo.owner,
204+
repo: repo.repo,
205+
...snapshot
206+
}
207+
)
208+
const result = response.data.result
209+
if (result === 'SUCCESS' || result === 'ACCEPTED') {
210+
console.debug(
211+
`Snapshot successfully created at ${response.data.created_at.toString()}` +
212+
` with id ${response.data.id}`
213+
)
214+
} else {
215+
console.error(
216+
`Snapshot creation failed with result: "${result}: ${response.data.message}"`
217+
)
218+
}
219+
} catch (error) {
220+
if (error instanceof RequestError) {
221+
console.error(
222+
`HTTP Status ${error.status} for request ${error.request.method} ${error.request.url}`
223+
)
224+
if (error.response) {
225+
console.error(
226+
`Response body:\n${JSON.stringify(error.response.data, undefined, 2)}`
227+
)
228+
}
229+
}
230+
if (error instanceof Error) {
231+
console.error(error.message)
232+
if (error.stack) console.error(error.stack)
233+
}
234+
throw new Error(`Failed to submit snapshot: ${error}`)
235+
}
236+
}

src/sbomCollector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ export class SbomCollector {
305305
// Optionally perform dependency submission up front for the branch
306306
if (this.opts.forceSubmission) {
307307
try {
308-
console.log(chalk.blue(`Force-submission enabled: submitting component snapshot for ${fullName} branch ${b.name}...`));
308+
console.debug(chalk.blue(`Force-submission enabled: submitting component snapshot for ${fullName} branch ${b.name}...`));
309309
await submitSnapshotIfPossible({ octokit: this.octokit, owner: org, repo: repo.name, branch: b.name, languages: this.opts.submitLanguages, quiet: this.opts.quiet, componentDetectionBinPath: this.opts.componentDetectionBinPath });
310310
// brief delay to allow snapshot ingestion
311311
await new Promise(r => setTimeout(r, 1500));

0 commit comments

Comments
 (0)