@xcelera/cli 1.2.0 → 1.2.2
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/.github/workflows/ci.yml +0 -40
- package/.github/workflows/release.yml +56 -0
- package/dist/cli.js +307 -0
- package/package.json +1 -2
package/.github/workflows/ci.yml
CHANGED
|
@@ -68,43 +68,3 @@ jobs:
|
|
|
68
68
|
- name: Print Output
|
|
69
69
|
id: output
|
|
70
70
|
run: echo "${{ steps.test-action.outputs.status }}"
|
|
71
|
-
|
|
72
|
-
- name: Release
|
|
73
|
-
env:
|
|
74
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
75
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
76
|
-
run: npx semantic-release
|
|
77
|
-
|
|
78
|
-
release:
|
|
79
|
-
name: Release
|
|
80
|
-
runs-on: ubuntu-latest
|
|
81
|
-
permissions:
|
|
82
|
-
contents: write # to be able to publish a GitHub release
|
|
83
|
-
issues: write # to be able to comment on released issues
|
|
84
|
-
pull-requests: write # to be able to comment on released pull requests
|
|
85
|
-
id-token: write # to enable use of OIDC for npm provenance
|
|
86
|
-
|
|
87
|
-
steps:
|
|
88
|
-
- name: Checkout
|
|
89
|
-
uses: actions/checkout@v4
|
|
90
|
-
with:
|
|
91
|
-
fetch-depth: 0
|
|
92
|
-
|
|
93
|
-
- name: Setup Node.js
|
|
94
|
-
uses: actions/setup-node@v4
|
|
95
|
-
with:
|
|
96
|
-
node-version: 'lts/*'
|
|
97
|
-
|
|
98
|
-
- name: Install dependencies
|
|
99
|
-
run: npm clean-install
|
|
100
|
-
|
|
101
|
-
- name:
|
|
102
|
-
Verify the integrity of provenance attestations and registry
|
|
103
|
-
signatures for installed dependencies
|
|
104
|
-
run: npm audit signatures
|
|
105
|
-
|
|
106
|
-
- name: Release
|
|
107
|
-
env:
|
|
108
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
109
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
110
|
-
run: npx semantic-release
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
workflow_run:
|
|
11
|
+
workflows: [Continuous Integration]
|
|
12
|
+
types: [completed]
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
release:
|
|
19
|
+
name: Release
|
|
20
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
permissions:
|
|
23
|
+
contents: write # to be able to publish a GitHub release
|
|
24
|
+
issues: write # to be able to comment on released issues
|
|
25
|
+
pull-requests: write # to be able to comment on released pull requests
|
|
26
|
+
id-token: write # to enable use of OIDC for npm provenance
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout
|
|
30
|
+
uses: actions/checkout@v4
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 0
|
|
33
|
+
|
|
34
|
+
- name: Setup Node.js
|
|
35
|
+
id: setup-node
|
|
36
|
+
uses: actions/setup-node@v4
|
|
37
|
+
with:
|
|
38
|
+
node-version-file: .node-version
|
|
39
|
+
cache: npm
|
|
40
|
+
|
|
41
|
+
- name: Install dependencies
|
|
42
|
+
run: npm clean-install
|
|
43
|
+
|
|
44
|
+
- name:
|
|
45
|
+
Verify the integrity of provenance attestations and registry
|
|
46
|
+
signatures for installed dependencies
|
|
47
|
+
run: npm audit signatures
|
|
48
|
+
|
|
49
|
+
- name: package
|
|
50
|
+
run: npm run package
|
|
51
|
+
|
|
52
|
+
- name: Release
|
|
53
|
+
env:
|
|
54
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
55
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
56
|
+
run: npx semantic-release
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import require$$0 from 'url';
|
|
5
|
+
|
|
6
|
+
async function requestAudit(url, token, github) {
|
|
7
|
+
const apiUrl = `${getApiBaseUrl()}/api/v1/audit`;
|
|
8
|
+
const response = await fetch(apiUrl, {
|
|
9
|
+
method: 'POST',
|
|
10
|
+
headers: {
|
|
11
|
+
'Content-Type': 'application/json',
|
|
12
|
+
Authorization: `Bearer ${token}`
|
|
13
|
+
},
|
|
14
|
+
body: JSON.stringify({
|
|
15
|
+
url,
|
|
16
|
+
github
|
|
17
|
+
})
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const errorText = await response.text();
|
|
21
|
+
throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
22
|
+
}
|
|
23
|
+
const data = await response.json();
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
function getApiBaseUrl() {
|
|
27
|
+
if (process.env.NODE_ENV === 'development' ||
|
|
28
|
+
process.env.GITHUB_ACTIONS !== 'true') {
|
|
29
|
+
return 'http://localhost:3000';
|
|
30
|
+
}
|
|
31
|
+
return 'https://xcelera.dev';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getDefaultExportFromCjs (x) {
|
|
35
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*!
|
|
39
|
+
* parse-github-url <https://github.com/jonschlinkert/parse-github-url>
|
|
40
|
+
*
|
|
41
|
+
* Copyright (c) 2015-2017, Jon Schlinkert.
|
|
42
|
+
* Released under the MIT License.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
var parseGithubUrl$1;
|
|
46
|
+
var hasRequiredParseGithubUrl;
|
|
47
|
+
|
|
48
|
+
function requireParseGithubUrl () {
|
|
49
|
+
if (hasRequiredParseGithubUrl) return parseGithubUrl$1;
|
|
50
|
+
hasRequiredParseGithubUrl = 1;
|
|
51
|
+
|
|
52
|
+
var url = require$$0;
|
|
53
|
+
var cache = { __proto__: null };
|
|
54
|
+
|
|
55
|
+
function isChecksum(str) {
|
|
56
|
+
return (/^[a-f0-9]{40}$/i).test(str);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getBranch(str, obj) {
|
|
60
|
+
var segs = str.split('#');
|
|
61
|
+
var branch;
|
|
62
|
+
if (segs.length > 1) {
|
|
63
|
+
branch = segs[segs.length - 1];
|
|
64
|
+
}
|
|
65
|
+
if (!branch && obj.hash && obj.hash.charAt(0) === '#') {
|
|
66
|
+
branch = obj.hash.slice(1);
|
|
67
|
+
}
|
|
68
|
+
return branch || 'master';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function trimSlash(path) {
|
|
72
|
+
return path.charAt(0) === '/' ? path.slice(1) : path;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function name(str) {
|
|
76
|
+
return str ? str.replace(/\.git$/, '') : null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function owner(str) {
|
|
80
|
+
if (!str) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
var idx = str.indexOf(':');
|
|
84
|
+
if (idx > -1) {
|
|
85
|
+
return str.slice(idx + 1);
|
|
86
|
+
}
|
|
87
|
+
return str;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parse(str) {
|
|
91
|
+
if (typeof str !== 'string' || !str.length) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (str.indexOf('git@gist') !== -1 || str.indexOf('//gist') !== -1) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// parse the URL
|
|
100
|
+
var obj = url.parse(str);
|
|
101
|
+
if (typeof obj.path !== 'string' || !obj.path.length || typeof obj.pathname !== 'string' || !obj.pathname.length) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!obj.host && (/^git@/).test(str) === true) {
|
|
106
|
+
// return the correct host for git@ URLs
|
|
107
|
+
obj.host = url.parse('http://' + str.replace(/git@([^:]+):/, '$1/')).host;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
obj.path = trimSlash(obj.path);
|
|
111
|
+
obj.pathname = trimSlash(obj.pathname);
|
|
112
|
+
obj.filepath = null;
|
|
113
|
+
|
|
114
|
+
if (obj.path.indexOf('repos') === 0) {
|
|
115
|
+
obj.path = obj.path.slice(6);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
var seg = obj.path.split('/').filter(Boolean);
|
|
119
|
+
var hasBlob = seg[2] === 'blob';
|
|
120
|
+
if (hasBlob && !isChecksum(seg[3])) {
|
|
121
|
+
obj.branch = seg[3];
|
|
122
|
+
if (seg.length > 4) {
|
|
123
|
+
obj.filepath = seg.slice(4).join('/');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
var blob = str.indexOf('blob');
|
|
128
|
+
if (hasBlob && blob !== -1) {
|
|
129
|
+
obj.blob = str.slice(blob + 5);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var hasTree = seg[2] === 'tree';
|
|
133
|
+
var tree = str.indexOf('tree');
|
|
134
|
+
if (hasTree && tree !== -1) {
|
|
135
|
+
var idx = tree + 5;
|
|
136
|
+
var branch = str.slice(idx);
|
|
137
|
+
var slash = branch.indexOf('/');
|
|
138
|
+
if (slash !== -1) {
|
|
139
|
+
branch = branch.slice(0, slash);
|
|
140
|
+
}
|
|
141
|
+
obj.branch = branch;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
obj.owner = owner(seg[0]);
|
|
145
|
+
obj.name = name(seg[1]);
|
|
146
|
+
|
|
147
|
+
if (seg.length > 1 && obj.owner && obj.name) {
|
|
148
|
+
obj.repo = obj.owner + '/' + obj.name;
|
|
149
|
+
} else {
|
|
150
|
+
var href = obj.href.split(':');
|
|
151
|
+
if (href.length === 2 && obj.href.indexOf('//') === -1) {
|
|
152
|
+
obj.repo = obj.repo || href[href.length - 1];
|
|
153
|
+
var repoSegments = obj.repo.split('/');
|
|
154
|
+
obj.owner = repoSegments[0];
|
|
155
|
+
obj.name = repoSegments[1];
|
|
156
|
+
|
|
157
|
+
} else {
|
|
158
|
+
var match = obj.href.match(/\/([^/]*)$/);
|
|
159
|
+
obj.owner = match ? match[1] : null;
|
|
160
|
+
obj.repo = null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (obj.repo && (!obj.owner || !obj.name)) {
|
|
164
|
+
var segs = obj.repo.split('/');
|
|
165
|
+
if (segs.length === 2) {
|
|
166
|
+
obj.owner = segs[0];
|
|
167
|
+
obj.name = segs[1];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!obj.branch) {
|
|
173
|
+
obj.branch = seg[2] || getBranch(obj.path, obj);
|
|
174
|
+
if (seg.length > 3) {
|
|
175
|
+
obj.filepath = seg.slice(3).join('/');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
obj.host = obj.host || 'github.com';
|
|
180
|
+
obj.owner = obj.owner || null;
|
|
181
|
+
obj.name = obj.name || null;
|
|
182
|
+
obj.repository = obj.repo;
|
|
183
|
+
return obj;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
parseGithubUrl$1 = function parseGithubUrl(str) {
|
|
187
|
+
if (!cache[str]) {
|
|
188
|
+
cache[str] = parse(str);
|
|
189
|
+
}
|
|
190
|
+
return cache[str];
|
|
191
|
+
};
|
|
192
|
+
return parseGithubUrl$1;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
var parseGithubUrlExports = requireParseGithubUrl();
|
|
196
|
+
var parseGithubUrl = /*@__PURE__*/getDefaultExportFromCjs(parseGithubUrlExports);
|
|
197
|
+
|
|
198
|
+
function inferGitContext() {
|
|
199
|
+
if (!isGitRepository()) {
|
|
200
|
+
throw new Error('Not git repository detected.');
|
|
201
|
+
}
|
|
202
|
+
const remoteUrl = getRemoteUrl();
|
|
203
|
+
const parsed = parseGithubUrl(remoteUrl);
|
|
204
|
+
if (!parsed || !parsed.owner || !parsed.repo) {
|
|
205
|
+
throw new Error(`Could not parse GitHub URL: ${remoteUrl}. Expected format: https://github.com/owner/repo or git@github.com:owner/repo`);
|
|
206
|
+
}
|
|
207
|
+
const { owner, repo } = parsed;
|
|
208
|
+
const sha = getCurrentSha();
|
|
209
|
+
// repo is parsed as owner/repo but we want to use just the repo name
|
|
210
|
+
const repoName = repo.replace(`${owner}/`, '');
|
|
211
|
+
return { owner, repo: repoName, sha };
|
|
212
|
+
}
|
|
213
|
+
function isGitRepository() {
|
|
214
|
+
try {
|
|
215
|
+
execSync('git rev-parse --git-dir', { stdio: 'ignore' });
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function getRemoteUrl() {
|
|
223
|
+
try {
|
|
224
|
+
const remoteUrl = execSync('git remote get-url origin', {
|
|
225
|
+
encoding: 'utf8',
|
|
226
|
+
stdio: 'pipe'
|
|
227
|
+
}).trim();
|
|
228
|
+
if (!remoteUrl) {
|
|
229
|
+
throw new Error('No origin remote found');
|
|
230
|
+
}
|
|
231
|
+
return remoteUrl;
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
throw new Error('Could not determine git remote URL. Please ensure you have an origin remote configured.');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function getCurrentSha() {
|
|
238
|
+
try {
|
|
239
|
+
return execSync('git rev-parse HEAD', {
|
|
240
|
+
encoding: 'utf8',
|
|
241
|
+
stdio: 'pipe'
|
|
242
|
+
}).trim();
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
throw new Error('Could not determine current commit SHA');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const options = {
|
|
250
|
+
url: {
|
|
251
|
+
type: 'string',
|
|
252
|
+
required: true
|
|
253
|
+
},
|
|
254
|
+
token: {
|
|
255
|
+
type: 'string',
|
|
256
|
+
required: true,
|
|
257
|
+
default: process.env.XCELERA_TOKEN
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const { positionals, values } = parseArgs({
|
|
261
|
+
options,
|
|
262
|
+
allowPositionals: true,
|
|
263
|
+
args: process.argv.slice(2)
|
|
264
|
+
});
|
|
265
|
+
const command = positionals[0];
|
|
266
|
+
if (!command) {
|
|
267
|
+
console.error('A command is required. Only "audit" is currently supported.');
|
|
268
|
+
printHelp();
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
if (command === 'help') {
|
|
272
|
+
printHelp();
|
|
273
|
+
}
|
|
274
|
+
if (command !== 'audit') {
|
|
275
|
+
console.error('Invalid command. Only "audit" is currently supported.');
|
|
276
|
+
printHelp();
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
const { url, token } = values;
|
|
280
|
+
if (!url) {
|
|
281
|
+
console.error('URL is required. Use --url <url> to specify the URL to audit.');
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
if (!token) {
|
|
285
|
+
console.error('A token is required. Use --token or set XCELERA_TOKEN environment variable.');
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
const githubContext = inferGitContext();
|
|
290
|
+
await requestAudit(url, token, githubContext);
|
|
291
|
+
console.log('✅ Audit scheduled successfully!');
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
295
|
+
console.error(`❌ ${errorMessage}`);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
function printHelp() {
|
|
299
|
+
console.log('Usage: xcelera audit --url <url> [--token <token>]');
|
|
300
|
+
console.log('');
|
|
301
|
+
console.log('Options:');
|
|
302
|
+
console.log(' --token <token> The xcelera API token to use for authentication.');
|
|
303
|
+
console.log('Can also be set with the XCELERA_TOKEN environment variable.');
|
|
304
|
+
console.log(' --url <url> The URL to audit.');
|
|
305
|
+
console.log('');
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=cli.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcelera/cli",
|
|
3
3
|
"description": "CLI for xcelera.dev",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.2",
|
|
5
5
|
"author": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"node": ">=20"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
|
-
"bundle": "npm run format:write && npm run package",
|
|
31
30
|
"ci-test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest --passWithNoTests",
|
|
32
31
|
"coverage": "npx make-coverage-badge --output-path ./badges/coverage.svg",
|
|
33
32
|
"format:write": "npx prettier --write .",
|