Skip to content

Commit 8983391

Browse files
committed
0.1.9. - error handling/logging
Fixed GitHub token authentication issue: Modified the Octokit configuration to only use authentication when a token is provided, preventing "Bad credentials" errors when accessing the public microsoft/component-detection repository. Enhanced error handling: Added comprehensive error handling and validation throughout the component detection process: Better error messages when download fails Verification that the executable file was created successfully Validation that the executable has proper permissions on Unix systems Verification that the output.json file was created after running component-detection Improved logging: Added debug logging to help troubleshoot issues: Shows the download URL being used Lists available assets from the GitHub release Shows which asset was matched for the current platform Logs the exact command being executed Enhanced input validation: Added validation in the ADO entry point to ensure required inputs (GitHub repository and token) are provided before proceeding. Set GitHub token environment variable: Ensured the GitHub token is available to the dependency-submission-toolkit.
1 parent 92417e6 commit 8983391

File tree

10 files changed

+456
-71
lines changed

10 files changed

+456
-71
lines changed

ado-dist/index.js

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35979,6 +35979,21 @@ function run() {
3597935979
var _a, _b, _c, _d, _e, _f;
3598035980
const platform = providers_1.PlatformProviderFactory.create(providers_1.Platform.AzureDevOps);
3598135981
try {
35982+
// Validate required inputs
35983+
const githubRepository = platform.input.getInput("githubRepository");
35984+
const githubToken = platform.input.getInput("token");
35985+
if (!githubRepository) {
35986+
platform.logger.setFailed("githubRepository input is required. Please provide the GitHub repository in format 'owner/repo'");
35987+
return;
35988+
}
35989+
if (!githubToken) {
35990+
platform.logger.setFailed("token input is required. Please provide a GitHub Personal Access Token with 'Contents' repository permissions");
35991+
return;
35992+
}
35993+
platform.logger.debug(`GitHub Repository: ${githubRepository}`);
35994+
platform.logger.debug(`GitHub Token provided: ${githubToken ? 'Yes' : 'No'}`);
35995+
// Set the GitHub token in environment for dependency-submission-toolkit
35996+
process.env.GITHUB_TOKEN = githubToken;
3598235997
let manifests = yield componentDetection_1.default.scanAndGetManifests(platform.input.getInput("filePath") || ".", platform);
3598335998
const correlatorInput = ((_a = platform.input.getInput("correlator")) === null || _a === void 0 ? void 0 : _a.trim()) || platform.context.getJobId();
3598435999
// Get detector configuration inputs
@@ -36143,27 +36158,68 @@ class ComponentDetection {
3614336158
try {
3614436159
this.platform.logger.debug(`Downloading latest release for ${process.platform}`);
3614536160
const downloadURL = yield this.getLatestReleaseURL();
36146-
const blob = yield (yield (0, cross_fetch_1.default)(new URL(downloadURL))).blob();
36161+
if (!downloadURL) {
36162+
throw new Error(`No download URL found for platform: ${process.platform}`);
36163+
}
36164+
this.platform.logger.debug(`Download URL: ${downloadURL}`);
36165+
const response = yield (0, cross_fetch_1.default)(new URL(downloadURL));
36166+
if (!response.ok) {
36167+
throw new Error(`Failed to download component-detection: ${response.status} ${response.statusText}`);
36168+
}
36169+
const blob = yield response.blob();
3614736170
const arrayBuffer = yield blob.arrayBuffer();
3614836171
const buffer = new Uint8Array(arrayBuffer);
3614936172
// Write the blob to a file
3615036173
this.platform.logger.debug(`Writing binary to file ${this.componentDetectionPath}`);
3615136174
fs_1.default.writeFileSync(this.componentDetectionPath, buffer, { mode: 0o777, flag: 'w' });
36175+
// Verify the file was created and is executable
36176+
if (!fs_1.default.existsSync(this.componentDetectionPath)) {
36177+
throw new Error(`Failed to create component-detection executable at ${this.componentDetectionPath}`);
36178+
}
36179+
this.platform.logger.debug(`Successfully downloaded and saved component-detection to ${this.componentDetectionPath}`);
3615236180
}
3615336181
catch (error) {
36154-
this.platform.logger.error(error);
36182+
this.platform.logger.error(`Error downloading component-detection: ${error.message}`);
36183+
throw error;
3615536184
}
3615636185
});
3615736186
}
3615836187
// Run the component-detection CLI on the path specified
3615936188
static runComponentDetection(path) {
3616036189
return __awaiter(this, void 0, void 0, function* () {
3616136190
this.platform.logger.info("Running component-detection");
36191+
// Verify the executable exists before trying to run it
36192+
if (!fs_1.default.existsSync(this.componentDetectionPath)) {
36193+
throw new Error(`Component detection executable not found at ${this.componentDetectionPath}. Download may have failed.`);
36194+
}
36195+
// Verify the file is executable (on Unix systems)
36196+
if (process.platform !== "win32") {
36197+
try {
36198+
fs_1.default.accessSync(this.componentDetectionPath, fs_1.default.constants.X_OK);
36199+
}
36200+
catch (error) {
36201+
this.platform.logger.warning(`Component detection file may not be executable. Attempting to set execute permissions.`);
36202+
try {
36203+
fs_1.default.chmodSync(this.componentDetectionPath, 0o755);
36204+
}
36205+
catch (chmodError) {
36206+
this.platform.logger.error(`Failed to set execute permissions: ${chmodError}`);
36207+
}
36208+
}
36209+
}
36210+
const command = `${this.componentDetectionPath} scan --SourceDirectory ${path} --ManifestFile ${this.outputPath} ${this.getComponentDetectionParameters()}`;
36211+
this.platform.logger.debug(`Executing command: ${command}`);
3616236212
try {
36163-
yield exec.exec(`${this.componentDetectionPath} scan --SourceDirectory ${path} --ManifestFile ${this.outputPath} ${this.getComponentDetectionParameters()}`);
36213+
yield exec.exec(command);
36214+
// Verify the output file was created
36215+
if (!fs_1.default.existsSync(this.outputPath)) {
36216+
throw new Error(`Component detection completed but output file ${this.outputPath} was not created`);
36217+
}
36218+
this.platform.logger.debug(`Component detection completed successfully. Output file: ${this.outputPath}`);
3616436219
}
3616536220
catch (error) {
36166-
this.platform.logger.error(error);
36221+
this.platform.logger.error(`Component detection execution failed: ${error.message}`);
36222+
throw error;
3616736223
}
3616836224
});
3616936225
}
@@ -36179,10 +36235,23 @@ class ComponentDetection {
3617936235
static getManifestsFromResults() {
3618036236
return __awaiter(this, void 0, void 0, function* () {
3618136237
this.platform.logger.info("Getting manifests from results");
36182-
const results = yield fs_1.default.readFileSync(this.outputPath, 'utf8');
36183-
var json = JSON.parse(results);
36184-
let dependencyGraphs = this.normalizeDependencyGraphPaths(json.dependencyGraphs, this.platform.input.getInput('filePath'));
36185-
return this.processComponentsToManifests(json.componentsFound, dependencyGraphs);
36238+
if (!fs_1.default.existsSync(this.outputPath)) {
36239+
throw new Error(`Output file ${this.outputPath} does not exist. Component detection may have failed.`);
36240+
}
36241+
try {
36242+
const results = yield fs_1.default.readFileSync(this.outputPath, 'utf8');
36243+
if (!results.trim()) {
36244+
this.platform.logger.warning(`Output file ${this.outputPath} is empty`);
36245+
return [];
36246+
}
36247+
var json = JSON.parse(results);
36248+
let dependencyGraphs = this.normalizeDependencyGraphPaths(json.dependencyGraphs, this.platform.input.getInput('filePath'));
36249+
return this.processComponentsToManifests(json.componentsFound, dependencyGraphs);
36250+
}
36251+
catch (error) {
36252+
this.platform.logger.error(`Failed to parse component detection results: ${error.message}`);
36253+
throw error;
36254+
}
3618636255
});
3618736256
}
3618836257
static processComponentsToManifests(componentsFound, dependencyGraphs) {
@@ -36355,30 +36424,50 @@ class ComponentDetection {
3635536424
if (ghesMode) {
3635636425
githubToken = "";
3635736426
}
36358-
const octokit = new octokit_1.Octokit({ auth: githubToken, baseUrl: githubAPIURL, request: { fetch: cross_fetch_1.default }, log: {
36427+
// For accessing public repositories, don't use auth if no token is provided
36428+
// This prevents "Bad credentials" errors when accessing public repos
36429+
const octokitConfig = {
36430+
baseUrl: githubAPIURL,
36431+
request: { fetch: cross_fetch_1.default },
36432+
log: {
3635936433
debug: this.platform.logger.debug,
3636036434
info: this.platform.logger.info,
3636136435
warn: this.platform.logger.warning,
3636236436
error: this.platform.logger.error
36363-
}, });
36437+
}
36438+
};
36439+
// Only add auth if we have a token, since microsoft/component-detection is public
36440+
if (githubToken) {
36441+
octokitConfig.auth = githubToken;
36442+
}
36443+
const octokit = new octokit_1.Octokit(octokitConfig);
3636436444
const owner = "microsoft";
3636536445
const repo = "component-detection";
3636636446
this.platform.logger.debug("Attempting to download latest release from " + githubAPIURL);
3636736447
try {
3636836448
const latestRelease = yield octokit.request("GET /repos/{owner}/{repo}/releases/latest", { owner, repo });
3636936449
var downloadURL = "";
3637036450
const assetName = process.platform === "win32" ? "component-detection-win-x64.exe" : "component-detection-linux-x64";
36451+
this.platform.logger.debug(`Looking for asset: ${assetName}`);
36452+
this.platform.logger.debug(`Available assets: ${latestRelease.data.assets.map(a => a.name).join(', ')}`);
3637136453
latestRelease.data.assets.forEach((asset) => {
3637236454
if (asset.name === assetName) {
3637336455
downloadURL = asset.browser_download_url;
36456+
this.platform.logger.debug(`Found matching asset: ${asset.name} -> ${downloadURL}`);
3637436457
}
3637536458
});
36459+
if (!downloadURL) {
36460+
throw new Error(`No matching asset found for platform ${process.platform}. Expected asset name: ${assetName}`);
36461+
}
3637636462
return downloadURL;
3637736463
}
3637836464
catch (error) {
36379-
this.platform.logger.error(error);
36380-
this.platform.logger.debug(error.message);
36381-
this.platform.logger.debug(error.stack);
36465+
this.platform.logger.error(`Failed to get latest release: ${error.message}`);
36466+
if (error.response) {
36467+
this.platform.logger.debug(`HTTP Status: ${error.response.status}`);
36468+
this.platform.logger.debug(`Response: ${JSON.stringify(error.response.data)}`);
36469+
}
36470+
this.platform.logger.debug(`Stack trace: ${error.stack}`);
3638236471
throw new Error("Failed to download latest release");
3638336472
}
3638436473
});
@@ -36452,7 +36541,12 @@ class AzureDevOpsInputProvider {
3645236541
getInput(name) {
3645336542
// ADO task inputs are available as environment variables with INPUT_ prefix
3645436543
const envName = `INPUT_${name.toUpperCase().replace(/-/g, '_')}`;
36455-
return process.env[envName] || '';
36544+
const value = process.env[envName] || '';
36545+
// Special handling for token input - also check GITHUB_TOKEN for backward compatibility
36546+
if (name === 'token' && !value) {
36547+
return process.env['GITHUB_TOKEN'] || '';
36548+
}
36549+
return value;
3645636550
}
3645736551
getBooleanInput(name) {
3645836552
const value = this.getInput(name).toLowerCase();

ado-dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ado-index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@ async function run() {
1313
const platform = PlatformProviderFactory.create(Platform.AzureDevOps);
1414

1515
try {
16+
// Validate required inputs
17+
const githubRepository = platform.input.getInput("githubRepository");
18+
const githubToken = platform.input.getInput("token");
19+
20+
if (!githubRepository) {
21+
platform.logger.setFailed("githubRepository input is required. Please provide the GitHub repository in format 'owner/repo'");
22+
return;
23+
}
24+
25+
if (!githubToken) {
26+
platform.logger.setFailed("token input is required. Please provide a GitHub Personal Access Token with 'Contents' repository permissions");
27+
return;
28+
}
29+
30+
platform.logger.debug(`GitHub Repository: ${githubRepository}`);
31+
platform.logger.debug(`GitHub Token provided: ${githubToken ? 'Yes' : 'No'}`);
32+
33+
// Set the GitHub token in environment for dependency-submission-toolkit
34+
process.env.GITHUB_TOKEN = githubToken;
35+
1636
let manifests = await ComponentDetection.scanAndGetManifests(
1737
platform.input.getInput("filePath") || ".",
1838
platform

0 commit comments

Comments
 (0)