All files / packages/sds-release-manager/src/services nexus-fetcher.ts

100% Statements 26/26
100% Branches 9/9
100% Functions 2/2
100% Lines 26/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68                                              7x 7x       5x 5x   5x 5x 1x   4x 4x   5x 4x 4x 1x     3x 3x 3x 3x   3x 3x 3x 3x 3x 1x       2x         2x 2x      
import { createHash } from 'node:crypto';
import { mkdir, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { execa } from 'execa';
import { DEFAULT_NEXUS_SLDS_SCS_BASE } from '../config.js';
import type { Logger } from '../utils/logger.js';
 
export type NexusArtifact = {
  url: string;
  sha1: string;
  sha256: string;
  sizeBytes: number;
  localPath: string;
};
 
export interface INexusFetcher {
  fetchSldsScsJar(version: string): Promise<NexusArtifact>;
}
 
// Download slds-scs jar from Nexus and verify checksums (nexus-fetch recipe).
export class NexusFetcher implements INexusFetcher {
  constructor(
    private readonly logger: Logger,
    private readonly nexusSldsScsBase = DEFAULT_NEXUS_SLDS_SCS_BASE,
  ) {}
 
  async fetchSldsScsJar(version: string): Promise<NexusArtifact> {
    const url = `${this.nexusSldsScsBase}/${version}/slds-scs-${version}.jar`;
    this.logger.step(`Nexus fetch ${url}`);
 
    const head = await execa('curl', ['-sI', '--netrc', '--max-time', '30', url]);
    if (!/HTTP\/\S+\s+200\b/.test(head.stdout)) {
      throw new Error(`Nexus HEAD failed for ${url}:\n${head.stdout}`);
    }
    const sizeMatch = head.stdout.match(/Content-Length:\s*(\d+)/i);
    const sizeBytes = sizeMatch ? Number(sizeMatch[1]) : 0;
 
    const { stdout: sha1Raw } = await execa('curl', ['-s', '--netrc', '--max-time', '30', `${url}.sha1`]);
    const sha1 = sha1Raw.trim().split(/\s+/)[0];
    if (!/^[a-f0-9]{40}$/i.test(sha1)) {
      throw new Error(`Invalid SHA1 sidecar for ${url}: ${sha1Raw}`);
    }
 
    const dir = path.join(os.tmpdir(), 'sds-release-manager', 'nexus');
    await mkdir(dir, { recursive: true });
    const localPath = path.join(dir, `slds-scs-${version}.jar`);
    await execa('curl', ['-s', '--netrc', '--max-time', '120', '-o', localPath, url]);
 
    const { readFile } = await import('node:fs/promises');
    const buf = await readFile(localPath);
    const sha256 = createHash('sha256').update(buf).digest('hex');
    const localSha1 = createHash('sha1').update(buf).digest('hex');
    if (localSha1.toLowerCase() !== sha1.toLowerCase()) {
      throw new Error(`SHA1 mismatch: sidecar=${sha1} local=${localSha1}`);
    }
 
    // Keep a small marker file for debugging dry vs live
    await writeFile(
      path.join(dir, `slds-scs-${version}.meta.json`),
      JSON.stringify({ url, sha1, sha256, sizeBytes }, null, 2),
    );
 
    this.logger.success(`Nexus ok size=${sizeBytes} sha1=${sha1} sha256=${sha256}`);
    return { url, sha1, sha256, sizeBytes, localPath };
  }
}