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

Update license Component for Github SBOM #9755

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

DonXavierdev
Copy link
Contributor

@DonXavierdev DonXavierdev commented Jan 5, 2025

Proposed Changes

Merge Checklist

  • Add specs that demonstrate bug / test a new feature.
  • Update product documentation.
  • Ensure that UI text is kept in I18n files.
  • Prep screenshot or demo video for changelog entry, and attach it to issue.
  • Request for Peer Reviews
  • Completion of QA

Summary by CodeRabbit

  • New Features

    • Enhanced Software Bill of Materials (SBOM) viewer with internationalization support.
    • Implemented dynamic data fetching for frontend and backend SBOM information from GitHub.
  • Bug Fixes

    • Updated data structure and rendering logic to improve SBOM data display.
  • Refactor

    • Restructured component to align with the new SBOM data format.

@DonXavierdev DonXavierdev requested a review from a team as a code owner January 5, 2025 08:13
Copy link
Contributor

coderabbitai bot commented Jan 5, 2025

Walkthrough

The changes to the SBOMViewer.tsx component introduce a new approach to fetching Software Bill of Materials (SBOM) data directly from local JSON files instead of manual JSON files. The component now incorporates internationalization and restructures data handling to align with the new SBOM format. The rendering logic has been updated to utilize translation functions and reflect the new data structure, enhancing the component's functionality.

Changes

File Change Summary
src/components/Licenses/SBOMViewer.tsx - Integrated internationalization using useTranslation
- Updated imports for SBOM data to local JSON files
- Removed CycloneDX interface definitions
- Redefined bomData to reference sbom property
- Introduced packages variable for package information
- Adjusted rendering logic for translated text and new data structure
- Renamed "components" section to "Packages"
.gitignore - Added entries to ignore beBomData.json and feBomData.json
package.json - Updated "postinstall" script to include fetchSbomData.js execution
scripts/fetchSbomData.js - Added functionality to fetch SBOM data from GitHub and write to JSON files

Assessment against linked issues

Objective Addressed Explanation
Use GitHub-provided SBOMs instead of manual JSON files [#9534]
Fetch SBOM for frontend and backend components [#9534]
Ensure accurate and up-to-date dependency information [#9534]

Poem

🐰 Hop, hop, through GitHub's green domain,
SBOM data flows, no more manual pain!
Packages dance, licenses take flight,
Dynamic fetching brings pure delight!
Code rabbits rejoice, dependencies clear! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

netlify bot commented Jan 5, 2025

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit 13852f0
🔍 Latest deploy log https://app.netlify.com/sites/care-ohc/deploys/677cfefc37ce1e0008f658ee
😎 Deploy Preview https://deploy-preview-9755--care-ohc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (7)
src/components/Licenses/SBOMViewer.tsx (7)

52-66: Consider more robust error handling.
Currently, any fetch failure logs an error to the console and returns null. Think about handling errors more gracefully in the UI, for instance by showing a user-facing alert or fallback message.


86-86: Tab naming could be more descriptive.
Using "bom" vs "beBom" might be confusing. Renaming them to “frontendBom” / “backendBom” can improve clarity.


118-118: Consider displaying additional SBOM metadata.
Alongside spdxVersion, you might also display the dataLicense or other relevant metadata for a more comprehensive SBOM overview.


131-131: Use stable keys when rendering lists.
Consider using a unique identifier from each package (e.g., pkg.SPDXID or pkg.name) instead of the array index for improved React performance.


137-137: Commented-out externalRefs link.
This might be leftover debug code or a temporary workaround. Consider removing or adding a rationale comment if intentionally disabled.


150-150: Fallback anchor for unrecognized license IDs.
Navigating to "#" might not provide user feedback. Consider a placeholder page or tooltip to clarify no recognized license URL is available.


172-172: Consider stable keys for external references.
Using idx as the key can lead to React diffing issues if references change order. Prefer a unique property from each reference, if available.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4850743 and 385c8b4.

📒 Files selected for processing (1)
  • src/components/Licenses/SBOMViewer.tsx (3 hunks)
🔇 Additional comments (14)
src/components/Licenses/SBOMViewer.tsx (14)

2-2: Imports look good.
The newly added import for React hooks is appropriate and aligns with best practices in functional components.


15-27: Validate optional fields for GitHubPackage.
All fields in this interface appear to match the GitHub SBOM format. Consider verifying whether any additional fields from GitHub’s SBOM API may need to be included or marked optional for better type safety.


30-41: Interface structure aligns with GitHub SBOM data.
It’s good that each property is optional, preventing runtime errors when the SBOM might be missing certain fields.


49-51: Separate state variables for frontend and backend SBOM.
Assigning each SBOM to its own state variable is clear and logical.


68-85: Concise async loading for both FE/BE.
Fetching FE and BE SBOM data in parallel is efficient. If partial fetch success is acceptable (only one resource might load), confirm that null states are handled correctly in the UI.


93-93: Array fallback for safe rendering.
The usage of || [] ensures no errors when bomData or sbom is null. Nice defensive coding.


122-123: Date formatting is handled gracefully.
Falling back to "N/A" if a date is missing ensures the UI won’t break.


129-129: Package header is clear.
Labeling this section is helpful in guiding the user to the package list.


143-143: Package name and version.
Displaying both name and version in the same heading is user-friendly and concise.


146-146: Conditional rendering of the license.
Filtering out packages without a licenseConcluded field reduces UI clutter. Implementation is clear.


155-155: License fallback "N/A."
Good to maintain a sensible default text if the license field is somehow empty.


175-175: External reference link fallback.
If referenceLocator is missing, a fallback of "#" prevents errors. This maintains a functioning UI.


178-178: Optional reference locator text.
Gracefully handles missing locator content by providing "N/A."


180-182: Category display is optional.
The checks for ref.referenceCategory and ref.referenceLocator align with the optional nature of external references.

Comment on lines 52 to 84
useEffect(() => {
const fetchSBOMData = async (url: string): Promise<GitHubSBOM | null> => {
try {
const response = await fetch(url, {
headers: {
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
});
return response.ok ? await response.json() : null;
} catch (error) {
console.error("Error fetching SBOM data:", error);
return null;
}
};

const fetchData = async () => {
const feUrl =
"https://api.github.com/repos/ohcnetwork/care_fe/dependency-graph/sbom";
const beUrl =
"https://api.github.com/repos/ohcnetwork/care/dependency-graph/sbom";

const [frontendData, backendData] = await Promise.all([
fetchSBOMData(feUrl),
fetchSBOMData(beUrl),
]);

setFeBomData(frontendData);
setBeBomData(backendData);
};

fetchData();
}, []);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use useQuery with fetch instead.

Also, instead of fetching dynamically everytime on runtime, i'd recommend adding this data-fetching logic to postinstall step or build step.

Refer npm scripts: https://docs.npmjs.com/cli/v9/using-npm/scripts#examples

During the step, fetch the data using gh's APIs and save it as a JSON (gitignore it).
Lazy import the JSON directly in this file, and render accordingly.

cc: @bodhish

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
scripts/fetchSbomData.js (1)

49-49: Add proper error handling for unhandled rejections.

The script should handle unhandled promise rejections properly.

Add this error handling:

+process.on('unhandledRejection', (error) => {
+  console.error('Unhandled promise rejection:', error);
+  process.exit(1);
+});
+
 fetchData();
src/components/Licenses/SBOMViewer.tsx (1)

Line range hint 134-157: Add error handling for clipboard operations.

The clipboard functionality should handle potential errors.

-  const handleCopy = () => {
+  const handleCopy = (text: string, result: boolean) => {
+    if (!result) {
+      console.error('Failed to copy to clipboard');
+      return;
+    }
     setCopyStatus(true);
     setTimeout(() => setCopyStatus(false), 2000);
   };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 385c8b4 and 13852f0.

📒 Files selected for processing (4)
  • .gitignore (1 hunks)
  • package.json (1 hunks)
  • scripts/fetchSbomData.js (1 hunks)
  • src/components/Licenses/SBOMViewer.tsx (4 hunks)
🧰 Additional context used
🪛 GitHub Actions: Lint Code Base
package.json

[warning] Node.js version incompatibility - Required: >=22.8.0, Current: v20.18.1


[warning] Multiple deprecated package dependencies: sourcemap-codec, rimraf, npmlog, inflight, gauge, are-we-there-yet, boolean, @humanwhocodes/config-array, @humanwhocodes/object-schema, glob, eslint

scripts/fetchSbomData.js

[error] 1-1: Cannot use import statement outside a module. Need to set "type": "module" in package.json or use .mjs extension

🔇 Additional comments (5)
.gitignore (1)

68-70: LGTM! Appropriate entries added to .gitignore.

The new entries correctly exclude the generated SBOM data files from version control.

src/components/Licenses/SBOMViewer.tsx (2)

1-13: LGTM! Good implementation of i18n and SBOM data imports.

The changes properly implement internationalization and correctly update the SBOM data imports to use the new GitHub SBOM format.


Line range hint 34-133: LGTM! Well-structured UI with proper i18n implementation.

The UI components are well-organized with proper internationalization of all strings and good TypeScript/React patterns.

package.json (2)

38-38: LGTM! Appropriate addition to postinstall script.

The script is correctly added to run after platform dependencies are installed.

🧰 Tools
🪛 GitHub Actions: Lint Code Base

[warning] Node.js version incompatibility - Required: >=22.8.0, Current: v20.18.1


[warning] Multiple deprecated package dependencies: sourcemap-codec, rimraf, npmlog, inflight, gauge, are-we-there-yet, boolean, @humanwhocodes/config-array, @humanwhocodes/object-schema, glob, eslint


Line range hint 1-1: Update Node.js version and deprecated dependencies.

The pipeline shows several issues that need attention:

  1. Node.js version incompatibility (required >=22.8.0, current v20.18.1)
  2. Multiple deprecated package dependencies

Please update the Node.js version in your CI environment and update the following deprecated packages:

  • sourcemap-codec
  • rimraf
  • npmlog
  • inflight
  • gauge
  • are-we-there-yet
  • boolean
  • @humanwhocodes/config-array
  • @humanwhocodes/object-schema
  • glob
  • eslint

Run this script to check for the latest versions:

🧰 Tools
🪛 GitHub Actions: Lint Code Base

[warning] Node.js version incompatibility - Required: >=22.8.0, Current: v20.18.1


[warning] Multiple deprecated package dependencies: sourcemap-codec, rimraf, npmlog, inflight, gauge, are-we-there-yet, boolean, @humanwhocodes/config-array, @humanwhocodes/object-schema, glob, eslint

Comment on lines +1 to +15
import fs from "fs";
import fetch from "node-fetch";

const fetchSBOMData = async (url) => {
const response = await fetch(url, {
headers: {
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
});
if (!response.ok) {
throw new Error(`Error fetching SBOM data from ${url}`);
}
return await response.json();
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix ESM compatibility and add GitHub authentication.

The code has several issues that need to be addressed:

  1. ES modules syntax requires "type": "module" in package.json
  2. GitHub API calls should use authentication to avoid rate limiting
  3. API version should be configurable for future compatibility

Apply these changes:

+// Add to package.json
+{
+  "type": "module"
+}

 import fs from "fs";
 import fetch from "node-fetch";
+import dotenv from "dotenv";
+
+dotenv.config();
+
+const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
 
 const fetchSBOMData = async (url) => {
   const response = await fetch(url, {
     headers: {
       Accept: "application/vnd.github+json",
+      Authorization: `Bearer ${GITHUB_TOKEN}`,
       "X-GitHub-Api-Version": "2022-11-28",
     },
   });

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Actions: Lint Code Base

[error] 1-1: Cannot use import statement outside a module. Need to set "type": "module" in package.json or use .mjs extension

Comment on lines +17 to +47
const fetchData = async () => {
const feUrl =
"https://api.github.com/repos/ohcnetwork/care_fe/dependency-graph/sbom";
const beUrl =
"https://api.github.com/repos/ohcnetwork/care/dependency-graph/sbom";

try {
const [frontendData, backendData] = await Promise.all([
fetchSBOMData(feUrl),
fetchSBOMData(beUrl),
]);

// Write frontend SBOM data
fs.writeFileSync(
"./src/components/Licenses/feBomData.json",
JSON.stringify(frontendData, null, 2),
);

// Write backend SBOM data
fs.writeFileSync(
"./src/components/Licenses/beBomData.json",
JSON.stringify(backendData, null, 2),
);

console.log(
"SBOM data successfully saved as feBomData.json and beBomData.json",
);
} catch (error) {
console.error("Error fetching SBOM data:", error.message);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling and configuration management.

The function needs several improvements:

  1. Repository URLs should be configurable
  2. File operations need proper error handling
  3. SBOM data structure should be validated

Apply these changes:

+const CONFIG = {
+  repositories: {
+    frontend: "ohcnetwork/care_fe",
+    backend: "ohcnetwork/care"
+  },
+  outputPath: "./src/components/Licenses"
+};
+
+const validateSBOMData = (data) => {
+  if (!data?.sbom?.packages) {
+    throw new Error("Invalid SBOM data structure");
+  }
+};
+
 const fetchData = async () => {
-  const feUrl =
-    "https://api.github.com/repos/ohcnetwork/care_fe/dependency-graph/sbom";
-  const beUrl =
-    "https://api.github.com/repos/ohcnetwork/care/dependency-graph/sbom";
+  const feUrl = `https://api.github.com/repos/${CONFIG.repositories.frontend}/dependency-graph/sbom`;
+  const beUrl = `https://api.github.com/repos/${CONFIG.repositories.backend}/dependency-graph/sbom`;

   try {
     const [frontendData, backendData] = await Promise.all([
       fetchSBOMData(feUrl),
       fetchSBOMData(beUrl),
     ]);

+    validateSBOMData(frontendData);
+    validateSBOMData(backendData);
+
+    fs.mkdirSync(CONFIG.outputPath, { recursive: true });
+
     // Write frontend SBOM data
     fs.writeFileSync(
-      "./src/components/Licenses/feBomData.json",
+      `${CONFIG.outputPath}/feBomData.json`,
       JSON.stringify(frontendData, null, 2),
     );

     // Write backend SBOM data
     fs.writeFileSync(
-      "./src/components/Licenses/beBomData.json",
+      `${CONFIG.outputPath}/beBomData.json`,
       JSON.stringify(backendData, null, 2),
     );

     console.log(
       "SBOM data successfully saved as feBomData.json and beBomData.json",
     );
   } catch (error) {
     console.error("Error fetching SBOM data:", error.message);
+    process.exit(1);
   }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fetchData = async () => {
const feUrl =
"https://api.github.com/repos/ohcnetwork/care_fe/dependency-graph/sbom";
const beUrl =
"https://api.github.com/repos/ohcnetwork/care/dependency-graph/sbom";
try {
const [frontendData, backendData] = await Promise.all([
fetchSBOMData(feUrl),
fetchSBOMData(beUrl),
]);
// Write frontend SBOM data
fs.writeFileSync(
"./src/components/Licenses/feBomData.json",
JSON.stringify(frontendData, null, 2),
);
// Write backend SBOM data
fs.writeFileSync(
"./src/components/Licenses/beBomData.json",
JSON.stringify(backendData, null, 2),
);
console.log(
"SBOM data successfully saved as feBomData.json and beBomData.json",
);
} catch (error) {
console.error("Error fetching SBOM data:", error.message);
}
};
const CONFIG = {
repositories: {
frontend: "ohcnetwork/care_fe",
backend: "ohcnetwork/care"
},
outputPath: "./src/components/Licenses"
};
const validateSBOMData = (data) => {
if (!data?.sbom?.packages) {
throw new Error("Invalid SBOM data structure");
}
};
const fetchData = async () => {
const feUrl = `https://api.github.com/repos/${CONFIG.repositories.frontend}/dependency-graph/sbom`;
const beUrl = `https://api.github.com/repos/${CONFIG.repositories.backend}/dependency-graph/sbom`;
try {
const [frontendData, backendData] = await Promise.all([
fetchSBOMData(feUrl),
fetchSBOMData(beUrl),
]);
validateSBOMData(frontendData);
validateSBOMData(backendData);
fs.mkdirSync(CONFIG.outputPath, { recursive: true });
// Write frontend SBOM data
fs.writeFileSync(
`${CONFIG.outputPath}/feBomData.json`,
JSON.stringify(frontendData, null, 2),
);
// Write backend SBOM data
fs.writeFileSync(
`${CONFIG.outputPath}/beBomData.json`,
JSON.stringify(backendData, null, 2),
);
console.log(
"SBOM data successfully saved as feBomData.json and beBomData.json",
);
} catch (error) {
console.error("Error fetching SBOM data:", error.message);
process.exit(1);
}
};

Comment on lines +25 to +32
const bomData = activeTab === "bom" ? feBomData : beBomData;

const handleCopy = () => {
setCopyStatus(true);
setTimeout(() => setCopyStatus(false), 2000);
};

const bomData = (activeTab === "bom" ? feBomData : beBomData) as CycloneDXBOM;
const packages = bomData?.sbom?.packages || [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add TypeScript interfaces for the GitHub SBOM format.

The code lacks type definitions for the new GitHub SBOM format, which could lead to runtime errors.

Add these type definitions:

interface GitHubSBOM {
  sbom: {
    spdxVersion: string;
    creationInfo: {
      created: string;
    };
    packages: Array<{
      name: string;
      versionInfo?: string;
      licenseConcluded?: string;
      externalRefs?: Array<{
        referenceLocator?: string;
        referenceCategory?: string;
      }>;
    }>;
  };
}

const bomData = (activeTab === "bom" ? feBomData : beBomData) as GitHubSBOM;
const packages = bomData?.sbom?.packages || [];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update License Page to Use GitHub-Provided SBOMs
3 participants