@socketsecurity/cli 1.1.29 → 1.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/cli.js +181 -25
- package/dist/cli.js.map +1 -1
- package/dist/constants.js +4 -4
- package/dist/constants.js.map +1 -1
- package/dist/tsconfig.dts.tsbuildinfo +1 -1
- package/dist/types/commands/fix/branch-cleanup.d.mts +23 -0
- package/dist/types/commands/fix/branch-cleanup.d.mts.map +1 -0
- package/dist/types/commands/fix/coana-fix.d.mts.map +1 -1
- package/dist/types/commands/fix/pull-request.d.mts +27 -1
- package/dist/types/commands/fix/pull-request.d.mts.map +1 -1
- package/dist/types/utils/dlx.d.mts.map +1 -1
- package/dist/utils.js +25 -4
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [1.1.30](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.30) - 2025-11-18
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Enhanced `SOCKET_CLI_COANA_LOCAL_PATH` to support compiled Coana CLI binaries alongside Node.js script files
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Resolved PR creation workflow to properly recreate pull requests after closing or merging
|
|
14
|
+
- Corrected API token selection to honor `SOCKET_CLI_API_TOKEN` environment variable in package alert requests
|
|
15
|
+
|
|
7
16
|
## [1.1.29](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.29) - 2025-11-16
|
|
8
17
|
|
|
9
18
|
### Added
|
package/dist/cli.js
CHANGED
|
@@ -3264,6 +3264,68 @@ const cmdConfig = {
|
|
|
3264
3264
|
}
|
|
3265
3265
|
};
|
|
3266
3266
|
|
|
3267
|
+
/**
|
|
3268
|
+
* Branch cleanup utilities for socket fix command.
|
|
3269
|
+
* Manages local and remote branch lifecycle during PR creation.
|
|
3270
|
+
*
|
|
3271
|
+
* Critical distinction: Remote branches are sacred when a PR exists, disposable when they don't.
|
|
3272
|
+
*/
|
|
3273
|
+
|
|
3274
|
+
|
|
3275
|
+
/**
|
|
3276
|
+
* Clean up a stale branch (both remote and local).
|
|
3277
|
+
* Safe to delete both since no PR exists for this branch.
|
|
3278
|
+
*
|
|
3279
|
+
* Returns true if cleanup succeeded or should continue, false if should skip GHSA.
|
|
3280
|
+
*/
|
|
3281
|
+
async function cleanupStaleBranch(branch, ghsaId, cwd) {
|
|
3282
|
+
logger.logger.warn(`Stale branch ${branch} found without open PR, cleaning up...`);
|
|
3283
|
+
require$$9.debugFn('notice', `cleanup: deleting stale branch ${branch}`);
|
|
3284
|
+
const deleted = await utils.gitDeleteRemoteBranch(branch, cwd);
|
|
3285
|
+
if (!deleted) {
|
|
3286
|
+
logger.logger.error(`Failed to delete stale remote branch ${branch}, skipping ${ghsaId}.`);
|
|
3287
|
+
require$$9.debugFn('error', `cleanup: remote deletion failed for ${branch}`);
|
|
3288
|
+
return false;
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3291
|
+
// Clean up local branch too to avoid conflicts.
|
|
3292
|
+
await utils.gitDeleteBranch(branch, cwd);
|
|
3293
|
+
return true;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
/**
|
|
3297
|
+
* Clean up branches after PR creation failure.
|
|
3298
|
+
* Safe to delete both remote and local since no PR was created.
|
|
3299
|
+
*/
|
|
3300
|
+
async function cleanupFailedPrBranches(branch, cwd) {
|
|
3301
|
+
// Clean up pushed branch since PR creation failed.
|
|
3302
|
+
// Safe to delete both remote and local since no PR exists.
|
|
3303
|
+
await utils.gitDeleteRemoteBranch(branch, cwd);
|
|
3304
|
+
await utils.gitDeleteBranch(branch, cwd);
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3307
|
+
/**
|
|
3308
|
+
* Clean up local branch after successful PR creation.
|
|
3309
|
+
* Keeps remote branch - PR needs it to be mergeable.
|
|
3310
|
+
*/
|
|
3311
|
+
async function cleanupSuccessfulPrLocalBranch(branch, cwd) {
|
|
3312
|
+
// Clean up local branch only - keep remote branch for PR merge.
|
|
3313
|
+
await utils.gitDeleteBranch(branch, cwd);
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
/**
|
|
3317
|
+
* Clean up branches in catch block after unexpected error.
|
|
3318
|
+
* Safe to delete both remote and local since no PR was created.
|
|
3319
|
+
*/
|
|
3320
|
+
async function cleanupErrorBranches(branch, cwd, remoteBranchExists) {
|
|
3321
|
+
// Clean up remote branch if it exists (push may have succeeded before error).
|
|
3322
|
+
// Safe to delete both remote and local since no PR was created.
|
|
3323
|
+
if (remoteBranchExists) {
|
|
3324
|
+
await utils.gitDeleteRemoteBranch(branch, cwd);
|
|
3325
|
+
}
|
|
3326
|
+
await utils.gitDeleteBranch(branch, cwd);
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3267
3329
|
const GITHUB_ADVISORIES_URL = 'https://github.com/advisories';
|
|
3268
3330
|
function getSocketFixBranchName(ghsaId) {
|
|
3269
3331
|
return `socket/fix/${ghsaId}`;
|
|
@@ -3323,17 +3385,66 @@ async function openSocketFixPr(owner, repo, branch, ghsaIds, options) {
|
|
|
3323
3385
|
require$$9.debugDir('inspect', {
|
|
3324
3386
|
octokitPullsCreateParams
|
|
3325
3387
|
});
|
|
3326
|
-
|
|
3388
|
+
const pr = await octokit.pulls.create(octokitPullsCreateParams);
|
|
3389
|
+
return {
|
|
3390
|
+
ok: true,
|
|
3391
|
+
pr
|
|
3392
|
+
};
|
|
3327
3393
|
} catch (e) {
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
const
|
|
3332
|
-
|
|
3394
|
+
// Handle RequestError from Octokit.
|
|
3395
|
+
if (e instanceof vendor.RequestError) {
|
|
3396
|
+
const errors = e.response?.data?.['errors'];
|
|
3397
|
+
const errorMessages = Array.isArray(errors) ? errors.map(d => d.message?.trim() ?? `${d.resource}.${d.field} (${d.code})`) : [];
|
|
3398
|
+
|
|
3399
|
+
// Check for "PR already exists" error.
|
|
3400
|
+
if (errorMessages.some(msg => msg.toLowerCase().includes('pull request already exists'))) {
|
|
3401
|
+
require$$9.debugFn('error', 'Failed to open pull request: already exists');
|
|
3402
|
+
return {
|
|
3403
|
+
ok: false,
|
|
3404
|
+
reason: 'already_exists',
|
|
3405
|
+
error: e
|
|
3406
|
+
};
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
// Check for validation errors (e.g., no commits between branches).
|
|
3410
|
+
if (errors && errors.length > 0) {
|
|
3411
|
+
const details = errorMessages.map(d => `- ${d}`).join('\n');
|
|
3412
|
+
require$$9.debugFn('error', `Failed to open pull request:\n${details}`);
|
|
3413
|
+
return {
|
|
3414
|
+
ok: false,
|
|
3415
|
+
reason: 'validation_error',
|
|
3416
|
+
error: e,
|
|
3417
|
+
details
|
|
3418
|
+
};
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
// Check HTTP status codes.
|
|
3422
|
+
if (e.status === 403 || e.status === 401) {
|
|
3423
|
+
require$$9.debugFn('error', 'Failed to open pull request: permission denied');
|
|
3424
|
+
return {
|
|
3425
|
+
ok: false,
|
|
3426
|
+
reason: 'permission_denied',
|
|
3427
|
+
error: e
|
|
3428
|
+
};
|
|
3429
|
+
}
|
|
3430
|
+
if (e.status && e.status >= 500) {
|
|
3431
|
+
require$$9.debugFn('error', 'Failed to open pull request: network error');
|
|
3432
|
+
return {
|
|
3433
|
+
ok: false,
|
|
3434
|
+
reason: 'network_error',
|
|
3435
|
+
error: e
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3333
3438
|
}
|
|
3334
|
-
|
|
3439
|
+
|
|
3440
|
+
// Unknown error.
|
|
3441
|
+
require$$9.debugFn('error', `Failed to open pull request: ${e}`);
|
|
3442
|
+
return {
|
|
3443
|
+
ok: false,
|
|
3444
|
+
reason: 'unknown',
|
|
3445
|
+
error: e
|
|
3446
|
+
};
|
|
3335
3447
|
}
|
|
3336
|
-
return undefined;
|
|
3337
3448
|
}
|
|
3338
3449
|
async function getSocketFixPrs(owner, repo, options) {
|
|
3339
3450
|
return (await getSocketFixPrsWithContext(owner, repo, options)).map(d => d.match);
|
|
@@ -3760,10 +3871,34 @@ async function coanaFix(fixConfig) {
|
|
|
3760
3871
|
overallFixed = true;
|
|
3761
3872
|
const branch = getSocketFixBranchName(ghsaId);
|
|
3762
3873
|
try {
|
|
3763
|
-
// Check if
|
|
3874
|
+
// Check if an open PR already exists for this GHSA.
|
|
3875
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3876
|
+
const existingOpenPrs = await getSocketFixPrs(fixEnv.repoInfo.owner, fixEnv.repoInfo.repo, {
|
|
3877
|
+
ghsaId,
|
|
3878
|
+
states: constants.GQL_PR_STATE_OPEN
|
|
3879
|
+
});
|
|
3880
|
+
if (existingOpenPrs.length > 0) {
|
|
3881
|
+
const prNum = existingOpenPrs[0].number;
|
|
3882
|
+
logger.logger.info(`PR #${prNum} already exists for ${ghsaId}, skipping.`);
|
|
3883
|
+
require$$9.debugFn('notice', `skip: open PR #${prNum} exists for ${ghsaId}`);
|
|
3884
|
+
continue ghsaLoop;
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
// If branch exists but no open PR, delete the stale branch.
|
|
3888
|
+
// This handles cases where PR creation failed but branch was pushed.
|
|
3764
3889
|
// eslint-disable-next-line no-await-in-loop
|
|
3765
3890
|
if (await utils.gitRemoteBranchExists(branch, cwd)) {
|
|
3766
|
-
|
|
3891
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3892
|
+
const shouldContinue = await cleanupStaleBranch(branch, ghsaId, cwd);
|
|
3893
|
+
if (!shouldContinue) {
|
|
3894
|
+
continue ghsaLoop;
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
// Check for GitHub token before doing any git operations.
|
|
3899
|
+
if (!fixEnv.githubToken) {
|
|
3900
|
+
logger.logger.error('Cannot create pull request: SOCKET_CLI_GITHUB_TOKEN environment variable is not set.\n' + 'Set SOCKET_CLI_GITHUB_TOKEN or GITHUB_TOKEN to enable PR creation.');
|
|
3901
|
+
require$$9.debugFn('error', `skip: missing GitHub token for ${ghsaId}`);
|
|
3767
3902
|
continue ghsaLoop;
|
|
3768
3903
|
}
|
|
3769
3904
|
require$$9.debugFn('notice', `pr: creating for ${ghsaId}`);
|
|
@@ -3794,31 +3929,21 @@ async function coanaFix(fixConfig) {
|
|
|
3794
3929
|
}
|
|
3795
3930
|
|
|
3796
3931
|
// Set up git remote.
|
|
3797
|
-
if (!fixEnv.githubToken) {
|
|
3798
|
-
logger.logger.error('Cannot create pull request: SOCKET_CLI_GITHUB_TOKEN environment variable is not set.\n' + 'Set SOCKET_CLI_GITHUB_TOKEN or GITHUB_TOKEN to enable PR creation.');
|
|
3799
|
-
// eslint-disable-next-line no-await-in-loop
|
|
3800
|
-
await utils.gitResetAndClean(fixEnv.baseBranch, cwd);
|
|
3801
|
-
// eslint-disable-next-line no-await-in-loop
|
|
3802
|
-
await utils.gitCheckoutBranch(fixEnv.baseBranch, cwd);
|
|
3803
|
-
// eslint-disable-next-line no-await-in-loop
|
|
3804
|
-
await utils.gitDeleteBranch(branch, cwd);
|
|
3805
|
-
continue ghsaLoop;
|
|
3806
|
-
}
|
|
3807
3932
|
// eslint-disable-next-line no-await-in-loop
|
|
3808
3933
|
await utils.setGitRemoteGithubRepoUrl(fixEnv.repoInfo.owner, fixEnv.repoInfo.repo, fixEnv.githubToken, cwd);
|
|
3809
3934
|
|
|
3810
3935
|
// eslint-disable-next-line no-await-in-loop
|
|
3811
|
-
const
|
|
3936
|
+
const prResult = await openSocketFixPr(fixEnv.repoInfo.owner, fixEnv.repoInfo.repo, branch,
|
|
3812
3937
|
// Single GHSA ID.
|
|
3813
3938
|
[ghsaId], {
|
|
3814
3939
|
baseBranch: fixEnv.baseBranch,
|
|
3815
3940
|
cwd,
|
|
3816
3941
|
ghsaDetails
|
|
3817
3942
|
});
|
|
3818
|
-
if (
|
|
3943
|
+
if (prResult.ok) {
|
|
3819
3944
|
const {
|
|
3820
3945
|
data
|
|
3821
|
-
} =
|
|
3946
|
+
} = prResult.pr;
|
|
3822
3947
|
const prRef = `PR #${data.number}`;
|
|
3823
3948
|
logger.logger.success(`Opened ${prRef} for ${ghsaId}.`);
|
|
3824
3949
|
if (autopilot) {
|
|
@@ -3838,16 +3963,47 @@ async function coanaFix(fixConfig) {
|
|
|
3838
3963
|
logger.logger.dedent();
|
|
3839
3964
|
spinner?.dedent();
|
|
3840
3965
|
}
|
|
3966
|
+
|
|
3967
|
+
// Clean up local branch only - keep remote branch for PR merge.
|
|
3968
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3969
|
+
await cleanupSuccessfulPrLocalBranch(branch, cwd);
|
|
3970
|
+
} else {
|
|
3971
|
+
// Handle PR creation failures.
|
|
3972
|
+
if (prResult.reason === 'already_exists') {
|
|
3973
|
+
logger.logger.info(`PR already exists for ${ghsaId} (this should not happen due to earlier check).`);
|
|
3974
|
+
// Don't delete branch - PR exists and needs it.
|
|
3975
|
+
} else if (prResult.reason === 'validation_error') {
|
|
3976
|
+
logger.logger.error(`Failed to create PR for ${ghsaId}:\n${prResult.details}`);
|
|
3977
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3978
|
+
await cleanupFailedPrBranches(branch, cwd);
|
|
3979
|
+
} else if (prResult.reason === 'permission_denied') {
|
|
3980
|
+
logger.logger.error(`Failed to create PR for ${ghsaId}: Permission denied. Check SOCKET_CLI_GITHUB_TOKEN permissions.`);
|
|
3981
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3982
|
+
await cleanupFailedPrBranches(branch, cwd);
|
|
3983
|
+
} else if (prResult.reason === 'network_error') {
|
|
3984
|
+
logger.logger.error(`Failed to create PR for ${ghsaId}: Network error. Please try again.`);
|
|
3985
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3986
|
+
await cleanupFailedPrBranches(branch, cwd);
|
|
3987
|
+
} else {
|
|
3988
|
+
logger.logger.error(`Failed to create PR for ${ghsaId}: ${prResult.error.message}`);
|
|
3989
|
+
// eslint-disable-next-line no-await-in-loop
|
|
3990
|
+
await cleanupFailedPrBranches(branch, cwd);
|
|
3991
|
+
}
|
|
3841
3992
|
}
|
|
3842
3993
|
|
|
3843
3994
|
// Reset back to base branch for next iteration.
|
|
3844
3995
|
// eslint-disable-next-line no-await-in-loop
|
|
3845
|
-
await utils.gitResetAndClean(
|
|
3996
|
+
await utils.gitResetAndClean(fixEnv.baseBranch, cwd);
|
|
3846
3997
|
// eslint-disable-next-line no-await-in-loop
|
|
3847
3998
|
await utils.gitCheckoutBranch(fixEnv.baseBranch, cwd);
|
|
3848
3999
|
} catch (e) {
|
|
3849
4000
|
logger.logger.warn(`Unexpected condition: Push failed for ${ghsaId}, skipping PR creation.`);
|
|
3850
4001
|
require$$9.debugDir('error', e);
|
|
4002
|
+
// Clean up branches (push may have succeeded before error).
|
|
4003
|
+
// eslint-disable-next-line no-await-in-loop
|
|
4004
|
+
const remoteBranchExists = await utils.gitRemoteBranchExists(branch, cwd);
|
|
4005
|
+
// eslint-disable-next-line no-await-in-loop
|
|
4006
|
+
await cleanupErrorBranches(branch, cwd, remoteBranchExists);
|
|
3851
4007
|
// eslint-disable-next-line no-await-in-loop
|
|
3852
4008
|
await utils.gitResetAndClean(fixEnv.baseBranch, cwd);
|
|
3853
4009
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -15114,5 +15270,5 @@ void (async () => {
|
|
|
15114
15270
|
await utils.captureException(e);
|
|
15115
15271
|
}
|
|
15116
15272
|
})();
|
|
15117
|
-
//# debugId=
|
|
15273
|
+
//# debugId=dbcc0fa8-7ea6-462d-9ebe-824e2129f7b8
|
|
15118
15274
|
//# sourceMappingURL=cli.js.map
|