Skip to content

Commit

Permalink
Don't attach spdx.xlsx to build attachments; it can be generated dyna…
Browse files Browse the repository at this point in the history
…mically from the spdx.json
  • Loading branch information
rhyskoedijk committed Dec 27, 2024
1 parent 4a71078 commit f0c12b9
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 31 deletions.
2 changes: 1 addition & 1 deletion task/utils/sbomToolRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ export class SbomToolRunner {
if (xlsx) {
const xlsxPath = path.format({ ...path.parse(spdxPath), base: '', ext: '.xlsx' });
await fs.writeFile(xlsxPath, xlsx);
addAttachment(`${MANIFEST_FORMAT}.xlsx`, path.basename(xlsxPath), xlsxPath);
}
}

Expand All @@ -155,6 +154,7 @@ export class SbomToolRunner {
if (svg) {
const svgPath = path.format({ ...path.parse(spdxPath), base: '', ext: '.svg' });
await fs.writeFile(svgPath, svg);
// TODO: Remove this attachment once web browser SPDX to SVG generation is implemented
addAttachment(`${MANIFEST_FORMAT}.svg`, path.basename(svgPath), svgPath);
}
}
Expand Down
44 changes: 14 additions & 30 deletions ui/sbom-report-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { SbomDocumentPage } from './components/sbom/SbomDocumentPage';
import './sbom-report-tab.scss';

const SPDX_JSON_ATTACHMENT_TYPE = 'spdx.json';
const SPDX_XLSX_ATTACHMENT_TYPE = 'spdx.xlsx';
const SPDX_SVG_ATTACHMENT_TYPE = 'spdx.svg';

interface State {
Expand Down Expand Up @@ -75,27 +74,27 @@ export class Root extends React.Component<{}, State> {
throw new Error('Unable to access the current build data');
}

// Get the SBOM artifact attachments for the current build
// Get all SPDX JSON artifact attachments for the current build
const buildClient = getClient(BuildRestClient);
const sbomAttachments = await buildClient.getAttachments(projectId, buildId, SPDX_JSON_ATTACHMENT_TYPE);
console.info(`Detected ${sbomAttachments.length} SBOM artifact attachment(s) for build ${buildId}`);
const spdxJsonAttachments = await buildClient.getAttachments(projectId, buildId, SPDX_JSON_ATTACHMENT_TYPE);
console.info(`Detected ${spdxJsonAttachments.length} SBOM artifact attachment(s) for build ${buildId}`);

// Download and process each SBOM artifact attachment
const sbomArtifacts: ISbomBuildArtifact[] = [];
for (const sbomAttachment of sbomAttachments) {
for (const spdxJsonAttachment of spdxJsonAttachments) {
try {
// Extract the attachment identifiers from the url
// Format: `/{projectId}/_apis/build/builds/{buildId}/{timelineId}/{timelineRecordId}/attachments/{attachmentType}/{attachmentName}`
// TODO: Change this if/when the DevOps API provides a better way to get the attachment stream
const spdxUrl = sbomAttachment._links?.self?.href;
const spdxUrl = spdxJsonAttachment._links?.self?.href;
if (!spdxUrl) {
throw new Error(`Attachment url not found for '${sbomAttachment.name}'`);
throw new Error(`Attachment url not found for '${spdxJsonAttachment.name}'`);
}
const spdxUrlMatch = spdxUrl.match(
/([a-f-0-9]*)\/_apis\/build\/builds\/([a-f-0-9]*)\/([a-f-0-9]*)\/([a-f-0-9]*)\/attachments\//i,
);
if (!spdxUrlMatch) {
throw new Error(`Attachment url format not recognized for '${sbomAttachment.name}'`);
throw new Error(`Attachment url format not recognized for '${spdxJsonAttachment.name}'`);
}

// Download the SPDX document
Expand All @@ -105,34 +104,20 @@ export class Root extends React.Component<{}, State> {
spdxUrlMatch[3],
spdxUrlMatch[4],
SPDX_JSON_ATTACHMENT_TYPE,
sbomAttachment.name,
spdxJsonAttachment.name,
);
if (!spdxStream) {
throw new Error(`Attachment stream '${sbomAttachment.name}' could not be retrieved`);
throw new Error(`Attachment stream '${spdxJsonAttachment.name}' could not be retrieved`);
}

// Parse the SPDX document JSON
const spdxDocument = JSON.parse(new TextDecoder().decode(spdxStream)) as IDocument;
if (!spdxDocument) {
throw new Error(`Attachment stream '${sbomAttachment.name}' could not be parsed as JSON`);
}

// Attempt to download the SPDX document XLSX spreadsheet, if available
let spdxXlsxDocumentStream: ArrayBuffer | undefined;
try {
spdxXlsxDocumentStream = await buildClient.getAttachment(
spdxUrlMatch[1],
spdxUrlMatch[2],
spdxUrlMatch[3],
spdxUrlMatch[4],
SPDX_XLSX_ATTACHMENT_TYPE,
sbomAttachment.name.replace(SPDX_JSON_ATTACHMENT_TYPE, SPDX_XLSX_ATTACHMENT_TYPE),
);
} catch (error) {
console.warn(`Unable find SPDX XLSX artifact for '${sbomAttachment.name}'. ${error}`);
throw new Error(`Attachment stream '${spdxJsonAttachment.name}' could not be parsed as JSON`);
}

// Attempt to download the SPDX document SVG graph, if available
// TODO: Remove this once web browser SPDX to SVG generation is implemented
let spdxSvgDocumentStream: ArrayBuffer | undefined;
try {
spdxSvgDocumentStream = await buildClient.getAttachment(
Expand All @@ -141,19 +126,18 @@ export class Root extends React.Component<{}, State> {
spdxUrlMatch[3],
spdxUrlMatch[4],
SPDX_SVG_ATTACHMENT_TYPE,
sbomAttachment.name.replace(SPDX_JSON_ATTACHMENT_TYPE, SPDX_SVG_ATTACHMENT_TYPE),
spdxJsonAttachment.name.replace(SPDX_JSON_ATTACHMENT_TYPE, SPDX_SVG_ATTACHMENT_TYPE),
);
} catch (error) {
console.warn(`Unable find SPDX SVG artifact for '${sbomAttachment.name}'. ${error}`);
console.warn(`Unable find SPDX SVG artifact for '${spdxJsonAttachment.name}'. ${error}`);
}

sbomArtifacts.push({
spdxDocument: spdxDocument,
xlsxDocument: spdxXlsxDocumentStream,
svgDocument: spdxSvgDocumentStream,
});
} catch (error) {
throw new Error(`Unable to parse build attachment '${sbomAttachment.name}'. ${error}`.trim());
throw new Error(`Unable to parse build attachment '${spdxJsonAttachment.name}'. ${error}`.trim());
}
}

Expand Down

0 comments on commit f0c12b9

Please sign in to comment.