@metasession.co/devaudit-plugin-evidence-export 1.1.0 → 1.1.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/README.md CHANGED
@@ -30,7 +30,7 @@ export DEVAUDIT_USER_TOKEN=$(jq -r '.token' ~/.config/devaudit/auth.json)
30
30
  ```jsonc
31
31
  {
32
32
  "project_slug": "wawagardenbar-app",
33
- "base_url": "https://devaudit.metasession.co",
33
+ "base_url": "https://devaudit.ai",
34
34
  "generated_at": "2026-05-19T08:19:00.123Z",
35
35
  "total_files": 42,
36
36
  "successful": 42,
package/dist/plugin.js CHANGED
@@ -63,7 +63,7 @@ var EvidenceApi = class {
63
63
  };
64
64
 
65
65
  // src/util/token.ts
66
- var DEFAULT_BASE_URL = "https://devaudit.metasession.co";
66
+ var DEFAULT_BASE_URL = "https://devaudit.ai";
67
67
  function resolveAuth(sdlcBaseUrl) {
68
68
  const token = process.env["DEVAUDIT_USER_TOKEN"];
69
69
  if (!token) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/client.ts","../src/util/token.ts","../src/commands/list.ts","../src/commands/bundle.ts","../src/hooks/on-doctor.ts","../src/plugin.ts"],"names":["fs"],"mappings":"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","file":"plugin.js","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\n\nexport interface RequirementSummary {\n readonly requirement_id: string;\n readonly evidence_count: number;\n readonly latest_upload: string | null;\n}\n\nexport interface ComplianceEvidence {\n readonly id: string;\n readonly requirement_id: string;\n readonly file_path: string;\n readonly file_name: string;\n readonly file_size_bytes: number | null;\n readonly mime_type: string | null;\n readonly uploaded_at: string;\n}\n\nexport interface SignedUrlResponse {\n readonly signedUrl: string;\n}\n\nexport class EvidenceApiError extends Error {\n constructor(message: string, public readonly status: number) {\n super(message);\n this.name = 'EvidenceApiError';\n }\n}\n\nexport interface EvidenceApiOptions {\n readonly baseUrl: string;\n readonly token: string;\n}\n\nexport class EvidenceApi {\n private readonly baseUrl: string;\n private readonly token: string;\n\n constructor(opts: EvidenceApiOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.token = opts.token;\n }\n\n async listRequirements(projectSlug: string): Promise<readonly RequirementSummary[]> {\n const url = `${this.baseUrl}/api/evidence?projectSlug=${encodeURIComponent(projectSlug)}`;\n const res = await this.fetchJson<RequirementSummary[]>(url);\n return res;\n }\n\n async listEvidence(projectSlug: string, requirementId: string): Promise<readonly ComplianceEvidence[]> {\n const params = new URLSearchParams({ projectSlug, requirementId });\n const url = `${this.baseUrl}/api/evidence?${params.toString()}`;\n return this.fetchJson<ComplianceEvidence[]>(url);\n }\n\n async getSignedUrl(filePath: string): Promise<string> {\n const url = `${this.baseUrl}/api/evidence/download?filePath=${encodeURIComponent(filePath)}`;\n const res = await this.fetchJson<SignedUrlResponse>(url);\n return res.signedUrl;\n }\n\n async download(signedUrl: string, destPath: string): Promise<number> {\n const res = await fetch(signedUrl);\n if (!res.ok || !res.body) {\n throw new EvidenceApiError(`Download failed: HTTP ${res.status}`, res.status);\n }\n const handle = await fs.open(destPath, 'w');\n let bytes = 0;\n try {\n const nodeStream = Readable.fromWeb(res.body as never);\n nodeStream.on('data', (chunk: Buffer | string) => {\n bytes += typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.length;\n });\n await pipeline(nodeStream, handle.createWriteStream());\n } finally {\n await handle.close();\n }\n return bytes;\n }\n\n private async fetchJson<T>(url: string): Promise<T> {\n const res = await fetch(url, { headers: { 'x-devaudit-token': this.token } });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new EvidenceApiError(`GET ${url} → HTTP ${res.status}${text ? ': ' + text : ''}`, res.status);\n }\n return (await res.json()) as T;\n }\n}\n","const DEFAULT_BASE_URL = 'https://devaudit.metasession.co';\n\nexport interface ResolvedAuth {\n readonly token: string;\n readonly baseUrl: string;\n}\n\nexport function resolveAuth(sdlcBaseUrl: string | undefined): ResolvedAuth {\n const token = process.env['DEVAUDIT_USER_TOKEN'];\n if (!token) {\n throw new Error(\n 'DEVAUDIT_USER_TOKEN env var is required. Run `devaudit auth login` or set the env var directly.',\n );\n }\n const baseUrl = process.env['DEVAUDIT_BASE_URL'] ?? sdlcBaseUrl ?? DEFAULT_BASE_URL;\n return { token, baseUrl };\n}\n","import type { PluginContext } from '@metasession.co/devaudit-plugin-sdk';\nimport { EvidenceApi } from '../api/client.js';\nimport { resolveAuth } from '../util/token.js';\n\nexport async function list(ctx: PluginContext, args: readonly string[]): Promise<void> {\n const projectSlug = args[0];\n if (!projectSlug) {\n ctx.logger.error('Usage: devaudit evidence-export list <project-slug>');\n return;\n }\n const sdlcBaseUrl = (ctx.sdlcConfig['devaudit'] as { base_url?: string } | undefined)?.base_url;\n const { token, baseUrl } = resolveAuth(sdlcBaseUrl);\n const api = new EvidenceApi({ token, baseUrl });\n const summaries = await api.listRequirements(projectSlug);\n if (summaries.length === 0) {\n ctx.logger.info(`No evidence for project '${projectSlug}'.`);\n return;\n }\n ctx.logger.info(`Project '${projectSlug}' — ${summaries.length} requirement(s):`);\n for (const s of summaries) {\n ctx.logger.info(\n ` ${s.requirement_id}: ${s.evidence_count} file(s)${s.latest_upload ? ` (latest ${s.latest_upload})` : ''}`,\n );\n }\n ctx.emit({\n type: 'evidence-export-list',\n payload: { projectSlug, requirementCount: summaries.length },\n });\n}\n","import { promises as fs } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport type { PluginContext } from '@metasession.co/devaudit-plugin-sdk';\nimport { EvidenceApi, type ComplianceEvidence } from '../api/client.js';\nimport { resolveAuth } from '../util/token.js';\n\ninterface CliArgs {\n readonly projectSlug: string;\n readonly outputDir: string;\n}\n\ninterface BundleEntry {\n readonly requirement_id: string;\n readonly file_path: string;\n readonly file_name: string;\n readonly file_size_bytes: number | null;\n readonly bundled_to: string;\n readonly error?: string;\n}\n\nfunction parseArgs(args: readonly string[]): CliArgs | null {\n let projectSlug = '';\n let outputDir = '';\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a === '--output' || a === '-o') {\n outputDir = args[i + 1] ?? '';\n i++;\n } else if (a !== undefined && !a.startsWith('-') && !projectSlug) {\n projectSlug = a;\n }\n }\n if (!projectSlug || !outputDir) return null;\n return { projectSlug, outputDir: resolve(outputDir) };\n}\n\nasync function downloadOne(\n api: EvidenceApi,\n outputDir: string,\n evidence: ComplianceEvidence,\n): Promise<BundleEntry> {\n const dir = join(outputDir, evidence.requirement_id);\n await fs.mkdir(dir, { recursive: true });\n const dest = join(dir, evidence.file_name);\n try {\n const signedUrl = await api.getSignedUrl(evidence.file_path);\n await api.download(signedUrl, dest);\n return {\n requirement_id: evidence.requirement_id,\n file_path: evidence.file_path,\n file_name: evidence.file_name,\n file_size_bytes: evidence.file_size_bytes,\n bundled_to: dest,\n };\n } catch (err) {\n return {\n requirement_id: evidence.requirement_id,\n file_path: evidence.file_path,\n file_name: evidence.file_name,\n file_size_bytes: evidence.file_size_bytes,\n bundled_to: dest,\n error: (err as Error).message,\n };\n }\n}\n\nexport async function bundle(ctx: PluginContext, args: readonly string[]): Promise<void> {\n const parsed = parseArgs(args);\n if (!parsed) {\n ctx.logger.error('Usage: devaudit evidence-export bundle <project-slug> --output <dir>');\n return;\n }\n const sdlcBaseUrl = (ctx.sdlcConfig['devaudit'] as { base_url?: string } | undefined)?.base_url;\n const { token, baseUrl } = resolveAuth(sdlcBaseUrl);\n const api = new EvidenceApi({ token, baseUrl });\n await fs.mkdir(parsed.outputDir, { recursive: true });\n const summaries = await api.listRequirements(parsed.projectSlug);\n const requirementsWithEvidence = summaries.filter((s) => s.evidence_count > 0);\n ctx.logger.info(\n `Bundling evidence for '${parsed.projectSlug}': ${requirementsWithEvidence.length} requirement(s) → ${parsed.outputDir}`,\n );\n const entries: BundleEntry[] = [];\n for (const summary of requirementsWithEvidence) {\n // eslint-disable-next-line no-await-in-loop\n const evidence = await api.listEvidence(parsed.projectSlug, summary.requirement_id);\n for (const e of evidence) {\n // eslint-disable-next-line no-await-in-loop\n const entry = await downloadOne(api, parsed.outputDir, e);\n entries.push(entry);\n if (entry.error) ctx.logger.error(` ✗ ${e.requirement_id}/${e.file_name}: ${entry.error}`);\n else ctx.logger.info(` ✓ ${e.requirement_id}/${e.file_name}`);\n }\n }\n const manifest = {\n project_slug: parsed.projectSlug,\n base_url: baseUrl,\n generated_at: new Date().toISOString(),\n total_files: entries.length,\n successful: entries.filter((e) => !e.error).length,\n failed: entries.filter((e) => e.error).length,\n entries,\n };\n await fs.writeFile(join(parsed.outputDir, 'manifest.json'), JSON.stringify(manifest, null, 2));\n ctx.emit({ type: 'evidence-export-bundle', payload: { total: entries.length, failed: manifest.failed } });\n ctx.logger.info(`Bundle complete: ${manifest.successful} succeeded, ${manifest.failed} failed.`);\n}\n","import type { PluginContext } from '@metasession.co/devaudit-plugin-sdk';\n\nexport async function onDoctor(ctx: PluginContext): Promise<void> {\n if (process.env['DEVAUDIT_USER_TOKEN']) {\n ctx.logger.info('evidence-export: DEVAUDIT_USER_TOKEN present — bundle/list will work.');\n return;\n }\n ctx.logger.warn(\n 'evidence-export: DEVAUDIT_USER_TOKEN is not set. Run `devaudit auth login` or export the env var before using `evidence-export list/bundle`.',\n );\n}\n","import type { Plugin } from '@metasession.co/devaudit-plugin-sdk';\nimport { list } from './commands/list.js';\nimport { bundle } from './commands/bundle.js';\nimport { onDoctor } from './hooks/on-doctor.js';\n\nconst plugin: Plugin = {\n name: '@metasession.co/devaudit-plugin-evidence-export',\n apiVersion: '1',\n hooks: { onDoctor },\n commands: { list, bundle },\n};\n\nexport default plugin;\n"]}
1
+ {"version":3,"sources":["../src/api/client.ts","../src/util/token.ts","../src/commands/list.ts","../src/commands/bundle.ts","../src/hooks/on-doctor.ts","../src/plugin.ts"],"names":["fs"],"mappings":";;;;;;AAwBO,IAAM,gBAAA,GAAN,cAA+B,KAAA,CAAM;AAAA,EAC1C,WAAA,CAAY,SAAiC,MAAA,EAAgB;AAC3D,IAAA,KAAA,CAAM,OAAO,CAAA;AAD8B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAE3C,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AAAA,EAH6C,MAAA;AAI/C,CAAA;AAOO,IAAM,cAAN,MAAkB;AAAA,EACN,OAAA;AAAA,EACA,KAAA;AAAA,EAEjB,YAAY,IAAA,EAA0B;AACpC,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC7C,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAAA,EACpB;AAAA,EAEA,MAAM,iBAAiB,WAAA,EAA6D;AAClF,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,0BAAA,EAA6B,kBAAA,CAAmB,WAAW,CAAC,CAAA,CAAA;AACvF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAgC,GAAG,CAAA;AAC1D,IAAA,OAAO,GAAA;AAAA,EACT;AAAA,EAEA,MAAM,YAAA,CAAa,WAAA,EAAqB,aAAA,EAA+D;AACrG,IAAA,MAAM,SAAS,IAAI,eAAA,CAAgB,EAAE,WAAA,EAAa,eAAe,CAAA;AACjE,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,cAAA,EAAiB,MAAA,CAAO,UAAU,CAAA,CAAA;AAC7D,IAAA,OAAO,IAAA,CAAK,UAAgC,GAAG,CAAA;AAAA,EACjD;AAAA,EAEA,MAAM,aAAa,QAAA,EAAmC;AACpD,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,gCAAA,EAAmC,kBAAA,CAAmB,QAAQ,CAAC,CAAA,CAAA;AAC1F,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAA6B,GAAG,CAAA;AACvD,IAAA,OAAO,GAAA,CAAI,SAAA;AAAA,EACb;AAAA,EAEA,MAAM,QAAA,CAAS,SAAA,EAAmB,QAAA,EAAmC;AACnE,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,SAAS,CAAA;AACjC,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,IAAM,CAAC,IAAI,IAAA,EAAM;AACxB,MAAA,MAAM,IAAI,gBAAA,CAAiB,CAAA,sBAAA,EAAyB,IAAI,MAAM,CAAA,CAAA,EAAI,IAAI,MAAM,CAAA;AAAA,IAC9E;AACA,IAAA,MAAM,MAAA,GAAS,MAAMA,QAAA,CAAG,IAAA,CAAK,UAAU,GAAG,CAAA;AAC1C,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,IAAa,CAAA;AACrD,MAAA,UAAA,CAAW,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAA2B;AAChD,QAAA,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,GAAW,OAAO,UAAA,CAAW,KAAK,IAAI,KAAA,CAAM,MAAA;AAAA,MACxE,CAAC,CAAA;AACD,MAAA,MAAM,QAAA,CAAS,UAAA,EAAY,MAAA,CAAO,iBAAA,EAAmB,CAAA;AAAA,IACvD,CAAA,SAAE;AACA,MAAA,MAAM,OAAO,KAAA,EAAM;AAAA,IACrB;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,MAAc,UAAa,GAAA,EAAyB;AAClD,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,OAAA,EAAS,EAAE,kBAAA,EAAoB,IAAA,CAAK,KAAA,EAAM,EAAG,CAAA;AAC5E,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,gBAAA,CAAiB,CAAA,IAAA,EAAO,GAAG,gBAAW,GAAA,CAAI,MAAM,CAAA,EAAG,IAAA,GAAO,IAAA,GAAO,IAAA,GAAO,EAAE,CAAA,CAAA,EAAI,IAAI,MAAM,CAAA;AAAA,IACpG;AACA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AACF,CAAA;;;AC1FA,IAAM,gBAAA,GAAmB,qBAAA;AAOlB,SAAS,YAAY,WAAA,EAA+C;AACzE,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,qBAAqB,CAAA;AAC/C,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,mBAAmB,KAAK,WAAA,IAAe,gBAAA;AACnE,EAAA,OAAO,EAAE,OAAO,OAAA,EAAQ;AAC1B;;;ACZA,eAAsB,IAAA,CAAK,KAAoB,IAAA,EAAwC;AACrF,EAAA,MAAM,WAAA,GAAc,KAAK,CAAC,CAAA;AAC1B,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,GAAA,CAAI,MAAA,CAAO,MAAM,qDAAqD,CAAA;AACtE,IAAA;AAAA,EACF;AACA,EAAA,MAAM,WAAA,GAAe,GAAA,CAAI,UAAA,CAAW,UAAU,CAAA,EAAyC,QAAA;AACvF,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAQ,GAAI,YAAY,WAAW,CAAA;AAClD,EAAA,MAAM,MAAM,IAAI,WAAA,CAAY,EAAE,KAAA,EAAO,SAAS,CAAA;AAC9C,EAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,gBAAA,CAAiB,WAAW,CAAA;AACxD,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,CAAA,yBAAA,EAA4B,WAAW,CAAA,EAAA,CAAI,CAAA;AAC3D,IAAA;AAAA,EACF;AACA,EAAA,GAAA,CAAI,OAAO,IAAA,CAAK,CAAA,SAAA,EAAY,WAAW,CAAA,SAAA,EAAO,SAAA,CAAU,MAAM,CAAA,gBAAA,CAAkB,CAAA;AAChF,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,GAAA,CAAI,MAAA,CAAO,IAAA;AAAA,MACT,CAAA,EAAA,EAAK,CAAA,CAAE,cAAc,CAAA,EAAA,EAAK,CAAA,CAAE,cAAc,CAAA,QAAA,EAAW,CAAA,CAAE,aAAA,GAAgB,CAAA,SAAA,EAAY,CAAA,CAAE,aAAa,MAAM,EAAE,CAAA;AAAA,KAC5G;AAAA,EACF;AACA,EAAA,GAAA,CAAI,IAAA,CAAK;AAAA,IACP,IAAA,EAAM,sBAAA;AAAA,IACN,OAAA,EAAS,EAAE,WAAA,EAAa,gBAAA,EAAkB,UAAU,MAAA;AAAO,GAC5D,CAAA;AACH;ACRA,SAAS,UAAU,IAAA,EAAyC;AAC1D,EAAA,IAAI,WAAA,GAAc,EAAA;AAClB,EAAA,IAAI,SAAA,GAAY,EAAA;AAChB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACpC,IAAA,MAAM,CAAA,GAAI,KAAK,CAAC,CAAA;AAChB,IAAA,IAAI,CAAA,KAAM,UAAA,IAAc,CAAA,KAAM,IAAA,EAAM;AAClC,MAAA,SAAA,GAAY,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,IAAK,EAAA;AAC3B,MAAA,CAAA,EAAA;AAAA,IACF,CAAA,MAAA,IAAW,MAAM,MAAA,IAAa,CAAC,EAAE,UAAA,CAAW,GAAG,CAAA,IAAK,CAAC,WAAA,EAAa;AAChE,MAAA,WAAA,GAAc,CAAA;AAAA,IAChB;AAAA,EACF;AACA,EAAA,IAAI,CAAC,WAAA,IAAe,CAAC,SAAA,EAAW,OAAO,IAAA;AACvC,EAAA,OAAO,EAAE,WAAA,EAAa,SAAA,EAAW,OAAA,CAAQ,SAAS,CAAA,EAAE;AACtD;AAEA,eAAe,WAAA,CACb,GAAA,EACA,SAAA,EACA,QAAA,EACsB;AACtB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,EAAW,QAAA,CAAS,cAAc,CAAA;AACnD,EAAA,MAAMA,SAAG,KAAA,CAAM,GAAA,EAAK,EAAE,SAAA,EAAW,MAAM,CAAA;AACvC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,EAAK,QAAA,CAAS,SAAS,CAAA;AACzC,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,YAAA,CAAa,SAAS,SAAS,CAAA;AAC3D,IAAA,MAAM,GAAA,CAAI,QAAA,CAAS,SAAA,EAAW,IAAI,CAAA;AAClC,IAAA,OAAO;AAAA,MACL,gBAAgB,QAAA,CAAS,cAAA;AAAA,MACzB,WAAW,QAAA,CAAS,SAAA;AAAA,MACpB,WAAW,QAAA,CAAS,SAAA;AAAA,MACpB,iBAAiB,QAAA,CAAS,eAAA;AAAA,MAC1B,UAAA,EAAY;AAAA,KACd;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO;AAAA,MACL,gBAAgB,QAAA,CAAS,cAAA;AAAA,MACzB,WAAW,QAAA,CAAS,SAAA;AAAA,MACpB,WAAW,QAAA,CAAS,SAAA;AAAA,MACpB,iBAAiB,QAAA,CAAS,eAAA;AAAA,MAC1B,UAAA,EAAY,IAAA;AAAA,MACZ,OAAQ,GAAA,CAAc;AAAA,KACxB;AAAA,EACF;AACF;AAEA,eAAsB,MAAA,CAAO,KAAoB,IAAA,EAAwC;AACvF,EAAA,MAAM,MAAA,GAAS,UAAU,IAAI,CAAA;AAC7B,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,GAAA,CAAI,MAAA,CAAO,MAAM,sEAAsE,CAAA;AACvF,IAAA;AAAA,EACF;AACA,EAAA,MAAM,WAAA,GAAe,GAAA,CAAI,UAAA,CAAW,UAAU,CAAA,EAAyC,QAAA;AACvF,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAQ,GAAI,YAAY,WAAW,CAAA;AAClD,EAAA,MAAM,MAAM,IAAI,WAAA,CAAY,EAAE,KAAA,EAAO,SAAS,CAAA;AAC9C,EAAA,MAAMA,SAAG,KAAA,CAAM,MAAA,CAAO,WAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AACpD,EAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,gBAAA,CAAiB,OAAO,WAAW,CAAA;AAC/D,EAAA,MAAM,2BAA2B,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,iBAAiB,CAAC,CAAA;AAC7E,EAAA,GAAA,CAAI,MAAA,CAAO,IAAA;AAAA,IACT,CAAA,uBAAA,EAA0B,OAAO,WAAW,CAAA,GAAA,EAAM,yBAAyB,MAAM,CAAA,uBAAA,EAAqB,OAAO,SAAS,CAAA;AAAA,GACxH;AACA,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,KAAA,MAAW,WAAW,wBAAA,EAA0B;AAE9C,IAAA,MAAM,WAAW,MAAM,GAAA,CAAI,aAAa,MAAA,CAAO,WAAA,EAAa,QAAQ,cAAc,CAAA;AAClF,IAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AAExB,MAAA,MAAM,QAAQ,MAAM,WAAA,CAAY,GAAA,EAAK,MAAA,CAAO,WAAW,CAAC,CAAA;AACxD,MAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAClB,MAAA,IAAI,KAAA,CAAM,KAAA,EAAO,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA,SAAA,EAAO,CAAA,CAAE,cAAc,CAAA,CAAA,EAAI,CAAA,CAAE,SAAS,CAAA,EAAA,EAAK,KAAA,CAAM,KAAK,CAAA,CAAE,CAAA;AAAA,WACrF,GAAA,CAAI,OAAO,IAAA,CAAK,CAAA,SAAA,EAAO,EAAE,cAAc,CAAA,CAAA,EAAI,CAAA,CAAE,SAAS,CAAA,CAAE,CAAA;AAAA,IAC/D;AAAA,EACF;AACA,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,cAAc,MAAA,CAAO,WAAA;AAAA,IACrB,QAAA,EAAU,OAAA;AAAA,IACV,YAAA,EAAA,iBAAc,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACrC,aAAa,OAAA,CAAQ,MAAA;AAAA,IACrB,UAAA,EAAY,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAC,CAAA,CAAE,KAAK,CAAA,CAAE,MAAA;AAAA,IAC5C,QAAQ,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA,CAAE,MAAA;AAAA,IACvC;AAAA,GACF;AACA,EAAA,MAAMA,QAAAA,CAAG,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,SAAA,EAAW,eAAe,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,QAAA,EAAU,IAAA,EAAM,CAAC,CAAC,CAAA;AAC7F,EAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,wBAAA,EAA0B,OAAA,EAAS,EAAE,KAAA,EAAO,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,CAAS,MAAA,IAAU,CAAA;AACxG,EAAA,GAAA,CAAI,MAAA,CAAO,KAAK,CAAA,iBAAA,EAAoB,QAAA,CAAS,UAAU,CAAA,YAAA,EAAe,QAAA,CAAS,MAAM,CAAA,QAAA,CAAU,CAAA;AACjG;;;ACvGA,eAAsB,SAAS,GAAA,EAAmC;AAChE,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,qBAAqB,CAAA,EAAG;AACtC,IAAA,GAAA,CAAI,MAAA,CAAO,KAAK,4EAAuE,CAAA;AACvF,IAAA;AAAA,EACF;AACA,EAAA,GAAA,CAAI,MAAA,CAAO,IAAA;AAAA,IACT;AAAA,GACF;AACF;;;ACLA,IAAM,MAAA,GAAiB;AAAA,EACrB,IAAA,EAAM,iDAAA;AAAA,EACN,UAAA,EAAY,GAAA;AAAA,EACZ,KAAA,EAAO,EAAE,QAAA,EAAS;AAAA,EAClB,QAAA,EAAU,EAAE,IAAA,EAAM,MAAA;AACpB,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"plugin.js","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\n\nexport interface RequirementSummary {\n readonly requirement_id: string;\n readonly evidence_count: number;\n readonly latest_upload: string | null;\n}\n\nexport interface ComplianceEvidence {\n readonly id: string;\n readonly requirement_id: string;\n readonly file_path: string;\n readonly file_name: string;\n readonly file_size_bytes: number | null;\n readonly mime_type: string | null;\n readonly uploaded_at: string;\n}\n\nexport interface SignedUrlResponse {\n readonly signedUrl: string;\n}\n\nexport class EvidenceApiError extends Error {\n constructor(message: string, public readonly status: number) {\n super(message);\n this.name = 'EvidenceApiError';\n }\n}\n\nexport interface EvidenceApiOptions {\n readonly baseUrl: string;\n readonly token: string;\n}\n\nexport class EvidenceApi {\n private readonly baseUrl: string;\n private readonly token: string;\n\n constructor(opts: EvidenceApiOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.token = opts.token;\n }\n\n async listRequirements(projectSlug: string): Promise<readonly RequirementSummary[]> {\n const url = `${this.baseUrl}/api/evidence?projectSlug=${encodeURIComponent(projectSlug)}`;\n const res = await this.fetchJson<RequirementSummary[]>(url);\n return res;\n }\n\n async listEvidence(projectSlug: string, requirementId: string): Promise<readonly ComplianceEvidence[]> {\n const params = new URLSearchParams({ projectSlug, requirementId });\n const url = `${this.baseUrl}/api/evidence?${params.toString()}`;\n return this.fetchJson<ComplianceEvidence[]>(url);\n }\n\n async getSignedUrl(filePath: string): Promise<string> {\n const url = `${this.baseUrl}/api/evidence/download?filePath=${encodeURIComponent(filePath)}`;\n const res = await this.fetchJson<SignedUrlResponse>(url);\n return res.signedUrl;\n }\n\n async download(signedUrl: string, destPath: string): Promise<number> {\n const res = await fetch(signedUrl);\n if (!res.ok || !res.body) {\n throw new EvidenceApiError(`Download failed: HTTP ${res.status}`, res.status);\n }\n const handle = await fs.open(destPath, 'w');\n let bytes = 0;\n try {\n const nodeStream = Readable.fromWeb(res.body as never);\n nodeStream.on('data', (chunk: Buffer | string) => {\n bytes += typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.length;\n });\n await pipeline(nodeStream, handle.createWriteStream());\n } finally {\n await handle.close();\n }\n return bytes;\n }\n\n private async fetchJson<T>(url: string): Promise<T> {\n const res = await fetch(url, { headers: { 'x-devaudit-token': this.token } });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new EvidenceApiError(`GET ${url} → HTTP ${res.status}${text ? ': ' + text : ''}`, res.status);\n }\n return (await res.json()) as T;\n }\n}\n","const DEFAULT_BASE_URL = 'https://devaudit.ai';\n\nexport interface ResolvedAuth {\n readonly token: string;\n readonly baseUrl: string;\n}\n\nexport function resolveAuth(sdlcBaseUrl: string | undefined): ResolvedAuth {\n const token = process.env['DEVAUDIT_USER_TOKEN'];\n if (!token) {\n throw new Error(\n 'DEVAUDIT_USER_TOKEN env var is required. Run `devaudit auth login` or set the env var directly.',\n );\n }\n const baseUrl = process.env['DEVAUDIT_BASE_URL'] ?? sdlcBaseUrl ?? DEFAULT_BASE_URL;\n return { token, baseUrl };\n}\n","import type { PluginContext } from '@metasession.co/devaudit-plugin-sdk';\nimport { EvidenceApi } from '../api/client.js';\nimport { resolveAuth } from '../util/token.js';\n\nexport async function list(ctx: PluginContext, args: readonly string[]): Promise<void> {\n const projectSlug = args[0];\n if (!projectSlug) {\n ctx.logger.error('Usage: devaudit evidence-export list <project-slug>');\n return;\n }\n const sdlcBaseUrl = (ctx.sdlcConfig['devaudit'] as { base_url?: string } | undefined)?.base_url;\n const { token, baseUrl } = resolveAuth(sdlcBaseUrl);\n const api = new EvidenceApi({ token, baseUrl });\n const summaries = await api.listRequirements(projectSlug);\n if (summaries.length === 0) {\n ctx.logger.info(`No evidence for project '${projectSlug}'.`);\n return;\n }\n ctx.logger.info(`Project '${projectSlug}' — ${summaries.length} requirement(s):`);\n for (const s of summaries) {\n ctx.logger.info(\n ` ${s.requirement_id}: ${s.evidence_count} file(s)${s.latest_upload ? ` (latest ${s.latest_upload})` : ''}`,\n );\n }\n ctx.emit({\n type: 'evidence-export-list',\n payload: { projectSlug, requirementCount: summaries.length },\n });\n}\n","import { promises as fs } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport type { PluginContext } from '@metasession.co/devaudit-plugin-sdk';\nimport { EvidenceApi, type ComplianceEvidence } from '../api/client.js';\nimport { resolveAuth } from '../util/token.js';\n\ninterface CliArgs {\n readonly projectSlug: string;\n readonly outputDir: string;\n}\n\ninterface BundleEntry {\n readonly requirement_id: string;\n readonly file_path: string;\n readonly file_name: string;\n readonly file_size_bytes: number | null;\n readonly bundled_to: string;\n readonly error?: string;\n}\n\nfunction parseArgs(args: readonly string[]): CliArgs | null {\n let projectSlug = '';\n let outputDir = '';\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a === '--output' || a === '-o') {\n outputDir = args[i + 1] ?? '';\n i++;\n } else if (a !== undefined && !a.startsWith('-') && !projectSlug) {\n projectSlug = a;\n }\n }\n if (!projectSlug || !outputDir) return null;\n return { projectSlug, outputDir: resolve(outputDir) };\n}\n\nasync function downloadOne(\n api: EvidenceApi,\n outputDir: string,\n evidence: ComplianceEvidence,\n): Promise<BundleEntry> {\n const dir = join(outputDir, evidence.requirement_id);\n await fs.mkdir(dir, { recursive: true });\n const dest = join(dir, evidence.file_name);\n try {\n const signedUrl = await api.getSignedUrl(evidence.file_path);\n await api.download(signedUrl, dest);\n return {\n requirement_id: evidence.requirement_id,\n file_path: evidence.file_path,\n file_name: evidence.file_name,\n file_size_bytes: evidence.file_size_bytes,\n bundled_to: dest,\n };\n } catch (err) {\n return {\n requirement_id: evidence.requirement_id,\n file_path: evidence.file_path,\n file_name: evidence.file_name,\n file_size_bytes: evidence.file_size_bytes,\n bundled_to: dest,\n error: (err as Error).message,\n };\n }\n}\n\nexport async function bundle(ctx: PluginContext, args: readonly string[]): Promise<void> {\n const parsed = parseArgs(args);\n if (!parsed) {\n ctx.logger.error('Usage: devaudit evidence-export bundle <project-slug> --output <dir>');\n return;\n }\n const sdlcBaseUrl = (ctx.sdlcConfig['devaudit'] as { base_url?: string } | undefined)?.base_url;\n const { token, baseUrl } = resolveAuth(sdlcBaseUrl);\n const api = new EvidenceApi({ token, baseUrl });\n await fs.mkdir(parsed.outputDir, { recursive: true });\n const summaries = await api.listRequirements(parsed.projectSlug);\n const requirementsWithEvidence = summaries.filter((s) => s.evidence_count > 0);\n ctx.logger.info(\n `Bundling evidence for '${parsed.projectSlug}': ${requirementsWithEvidence.length} requirement(s) → ${parsed.outputDir}`,\n );\n const entries: BundleEntry[] = [];\n for (const summary of requirementsWithEvidence) {\n // eslint-disable-next-line no-await-in-loop\n const evidence = await api.listEvidence(parsed.projectSlug, summary.requirement_id);\n for (const e of evidence) {\n // eslint-disable-next-line no-await-in-loop\n const entry = await downloadOne(api, parsed.outputDir, e);\n entries.push(entry);\n if (entry.error) ctx.logger.error(` ✗ ${e.requirement_id}/${e.file_name}: ${entry.error}`);\n else ctx.logger.info(` ✓ ${e.requirement_id}/${e.file_name}`);\n }\n }\n const manifest = {\n project_slug: parsed.projectSlug,\n base_url: baseUrl,\n generated_at: new Date().toISOString(),\n total_files: entries.length,\n successful: entries.filter((e) => !e.error).length,\n failed: entries.filter((e) => e.error).length,\n entries,\n };\n await fs.writeFile(join(parsed.outputDir, 'manifest.json'), JSON.stringify(manifest, null, 2));\n ctx.emit({ type: 'evidence-export-bundle', payload: { total: entries.length, failed: manifest.failed } });\n ctx.logger.info(`Bundle complete: ${manifest.successful} succeeded, ${manifest.failed} failed.`);\n}\n","import type { PluginContext } from '@metasession.co/devaudit-plugin-sdk';\n\nexport async function onDoctor(ctx: PluginContext): Promise<void> {\n if (process.env['DEVAUDIT_USER_TOKEN']) {\n ctx.logger.info('evidence-export: DEVAUDIT_USER_TOKEN present — bundle/list will work.');\n return;\n }\n ctx.logger.warn(\n 'evidence-export: DEVAUDIT_USER_TOKEN is not set. Run `devaudit auth login` or export the env var before using `evidence-export list/bundle`.',\n );\n}\n","import type { Plugin } from '@metasession.co/devaudit-plugin-sdk';\nimport { list } from './commands/list.js';\nimport { bundle } from './commands/bundle.js';\nimport { onDoctor } from './hooks/on-doctor.js';\n\nconst plugin: Plugin = {\n name: '@metasession.co/devaudit-plugin-evidence-export',\n apiVersion: '1',\n hooks: { onDoctor },\n commands: { list, bundle },\n};\n\nexport default plugin;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metasession.co/devaudit-plugin-evidence-export",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Bulk evidence bundle export for DevAudit consumers — for handing evidence to external auditors.",
5
5
  "type": "module",
6
6
  "main": "./dist/plugin.js",
@@ -20,7 +20,7 @@
20
20
  "typecheck": "tsc --noEmit"
21
21
  },
22
22
  "dependencies": {
23
- "@metasession.co/devaudit-plugin-sdk": "^1.1.0"
23
+ "@metasession.co/devaudit-plugin-sdk": "^1.1.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^22.9.0",