@xcelera/cli 2.3.1 → 2.4.0

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/dist/cli.js CHANGED
@@ -9338,13 +9338,88 @@ async function inferBuildContext() {
9338
9338
  };
9339
9339
  }
9340
9340
 
9341
+ function readNetscapeCookieFileSync(filePath, now = new Date()) {
9342
+ try {
9343
+ const contents = readFileSync(filePath, 'utf8');
9344
+ return parseNetscapeCookieFileContents(contents, filePath, now);
9345
+ }
9346
+ catch (error) {
9347
+ const message = error instanceof Error ? error.message : String(error);
9348
+ throw new Error(`Unable to read cookie file "${filePath}": ${message}`);
9349
+ }
9350
+ }
9351
+ function parseNetscapeCookieFileContents(contents, sourceLabel = 'cookie file', now = new Date()) {
9352
+ const cookies = [];
9353
+ const expiredCookieNames = [];
9354
+ const nowEpochSeconds = Math.floor(now.getTime() / 1000);
9355
+ const lines = contents.split(/\r?\n/);
9356
+ for (let index = 0; index < lines.length; index++) {
9357
+ const rawLine = lines[index];
9358
+ const line = rawLine.trim();
9359
+ if (!line) {
9360
+ continue;
9361
+ }
9362
+ if (line.startsWith('#') && !line.startsWith('#HttpOnly_')) {
9363
+ continue;
9364
+ }
9365
+ const fields = line.split('\t');
9366
+ if (fields.length !== 7) {
9367
+ throw new Error(`Invalid Netscape cookie line ${index + 1} in ${sourceLabel}: expected 7 tab-separated fields`);
9368
+ }
9369
+ let domain = fields[0];
9370
+ const path = fields[2] || undefined;
9371
+ const secure = toBool(fields[3]);
9372
+ const expiresEpochSeconds = parseEpochSeconds(fields[4], index + 1, sourceLabel);
9373
+ const name = fields[5];
9374
+ const value = fields[6] ?? '';
9375
+ let httpOnly;
9376
+ if (domain.startsWith('#HttpOnly_')) {
9377
+ httpOnly = true;
9378
+ domain = domain.slice('#HttpOnly_'.length);
9379
+ }
9380
+ const isExpired = expiresEpochSeconds > 0 && expiresEpochSeconds < nowEpochSeconds;
9381
+ if (isExpired) {
9382
+ expiredCookieNames.push(name);
9383
+ continue;
9384
+ }
9385
+ const cookie = {
9386
+ name,
9387
+ value,
9388
+ ...(domain && { domain }),
9389
+ ...(path && { path }),
9390
+ ...(secure && { secure: true }),
9391
+ ...(httpOnly && { httpOnly: true })
9392
+ };
9393
+ cookies.push(cookie);
9394
+ }
9395
+ const warnings = [];
9396
+ if (expiredCookieNames.length > 0) {
9397
+ const preview = expiredCookieNames.slice(0, 5).join(', ');
9398
+ const suffix = expiredCookieNames.length > 5 ? ', …' : '';
9399
+ warnings.push(`⚠️ Dropped ${expiredCookieNames.length} expired cookie(s) from ${sourceLabel}: ${preview}${suffix}`);
9400
+ }
9401
+ return { cookies, warnings };
9402
+ }
9403
+ function toBool(value) {
9404
+ return value.trim().toUpperCase() === 'TRUE';
9405
+ }
9406
+ function parseEpochSeconds(value, lineNumber, sourceLabel) {
9407
+ const trimmed = value.trim();
9408
+ const num = Number.parseInt(trimmed, 10);
9409
+ if (Number.isNaN(num)) {
9410
+ throw new Error(`Invalid expiration epoch seconds at line ${lineNumber} in ${sourceLabel}`);
9411
+ }
9412
+ return num;
9413
+ }
9414
+
9341
9415
  async function runAuditCommand(url, token, authOptions) {
9342
9416
  const output = [];
9343
9417
  const errors = [];
9344
9418
  try {
9345
9419
  const buildContext = await inferBuildContext();
9346
9420
  output.push(...formatBuildContext(buildContext));
9347
- const auth = parseAuthCredentials(authOptions);
9421
+ const { auth, warnings } = parseAuthCredentials(authOptions);
9422
+ errors.push(...warnings);
9348
9423
  if (auth) {
9349
9424
  output.push('🔐 Authentication credentials detected');
9350
9425
  output.push('');
@@ -9442,35 +9517,26 @@ function formatGitHubIntegrationStatus(context) {
9442
9517
  return { output, errors };
9443
9518
  }
9444
9519
  function parseAuthCredentials(options) {
9445
- const envAuth = process.env.XCELERA_AUTH;
9446
- if (envAuth) {
9447
- try {
9448
- return JSON.parse(envAuth);
9449
- }
9450
- catch {
9451
- throw new Error('XCELERA_AUTH environment variable contains invalid JSON');
9452
- }
9520
+ const warnings = [];
9521
+ const cookies = [];
9522
+ if (options?.cookieFile) {
9523
+ const parsed = readNetscapeCookieFileSync(options.cookieFile);
9524
+ warnings.push(...parsed.warnings);
9525
+ cookies.push(...parsed.cookies);
9453
9526
  }
9454
- // Check for --auth JSON option
9455
- if (options?.authJson) {
9456
- try {
9457
- return JSON.parse(options.authJson);
9458
- }
9459
- catch {
9460
- throw new Error('--auth option contains invalid JSON');
9461
- }
9527
+ if (options?.cookies && options.cookies.length > 0) {
9528
+ cookies.push(...options.cookies.map(parseCookie));
9462
9529
  }
9463
- // Build auth from --cookie and --header options
9464
- const hasCookies = options?.cookies && options.cookies.length > 0;
9465
9530
  const hasHeaders = options?.headers && options.headers.length > 0;
9531
+ const hasCookies = cookies.length > 0;
9466
9532
  if (!hasCookies && !hasHeaders) {
9467
- return undefined;
9533
+ return { auth: undefined, warnings };
9468
9534
  }
9469
9535
  const auth = {};
9470
- if (hasCookies && options.cookies) {
9471
- auth.cookies = options.cookies.map(parseCookie);
9536
+ if (hasCookies) {
9537
+ auth.cookies = cookies;
9472
9538
  }
9473
- if (hasHeaders && options.headers) {
9539
+ if (hasHeaders && options?.headers) {
9474
9540
  auth.headers = {};
9475
9541
  for (const header of options.headers) {
9476
9542
  const colonIndex = header.indexOf(':');
@@ -9482,7 +9548,7 @@ function parseAuthCredentials(options) {
9482
9548
  auth.headers[name] = value;
9483
9549
  }
9484
9550
  }
9485
- return auth;
9551
+ return { auth, warnings };
9486
9552
  }
9487
9553
  function parseCookie(cookie) {
9488
9554
  const equalsIndex = cookie.indexOf('=');
@@ -9506,7 +9572,7 @@ const options = {
9506
9572
  required: true,
9507
9573
  default: process.env.XCELERA_TOKEN
9508
9574
  },
9509
- auth: {
9575
+ 'cookie-file': {
9510
9576
  type: 'string'
9511
9577
  },
9512
9578
  cookie: {
@@ -9538,7 +9604,8 @@ if (command !== 'audit') {
9538
9604
  printHelp();
9539
9605
  process.exit(1);
9540
9606
  }
9541
- const { url, token, auth, cookie, header } = values;
9607
+ const { url, token, cookie, header } = values;
9608
+ const cookieFile = values['cookie-file'];
9542
9609
  if (!url) {
9543
9610
  console.error('URL is required. Use --url <url> to specify the URL to audit.');
9544
9611
  process.exit(1);
@@ -9548,7 +9615,7 @@ if (!token) {
9548
9615
  process.exit(1);
9549
9616
  }
9550
9617
  const result = await runAuditCommand(url, token, {
9551
- authJson: auth,
9618
+ cookieFile,
9552
9619
  cookies: cookie,
9553
9620
  headers: header
9554
9621
  });
@@ -9568,8 +9635,8 @@ function printHelp() {
9568
9635
  console.log(' Can be specified multiple times.');
9569
9636
  console.log(' --header <header> Header in "Name: Value" format.');
9570
9637
  console.log(' Can be specified multiple times.');
9571
- console.log(' --auth <json> Full auth config as JSON.');
9572
- console.log(' Can also be set with XCELERA_AUTH env var.');
9638
+ console.log(' --cookie-file <path> Netscape cookie file (cookies.txt).');
9639
+ console.log(' Expired cookies are ignored with a warning.');
9573
9640
  console.log('');
9574
9641
  console.log('Examples:');
9575
9642
  console.log(' # Basic audit');
@@ -9586,9 +9653,8 @@ function printHelp() {
9586
9653
  console.log(' xcelera audit --url https://myapp.com/dashboard \\');
9587
9654
  console.log(' --cookie "session=abc123" --cookie "csrf=xyz"');
9588
9655
  console.log('');
9589
- console.log(' # Full auth JSON (multiple cookies and headers)');
9590
- console.log(' xcelera audit --url https://myapp.com/dashboard \\');
9591
- console.log(' --auth \'{"cookies":[{"name":"session","value":"abc123"}],"headers":{"X-Custom":"value"}}\'');
9656
+ console.log(' # With cookie file (Netscape cookies.txt format)');
9657
+ console.log(' xcelera audit --url https://myapp.com/dashboard --cookie-file ./cookies.txt');
9592
9658
  console.log('');
9593
9659
  }
9594
9660
  //# sourceMappingURL=cli.js.map