code-provenance 0.1.2 → 0.1.4

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
@@ -27,11 +27,12 @@ npx code-provenance docker-compose.yml
27
27
  ```
28
28
 
29
29
  ```
30
- ┌─────────┬────────────────┬────────────────────────────┬──────────────┬──────────┬────────────┐
31
- │ SERVICE │ IMAGE │ REPO │ COMMIT │ STATUS │ CONFIDENCE │
32
- ├─────────┼────────────────┼────────────────────────────┼──────────────┼──────────┼────────────┤
33
- │ web │ traefik:v3.6.0 │ github.com/traefik/traefik │ 06db5168c0d9 │ resolved │ exact │
34
- └─────────┴────────────────┴────────────────────────────┴──────────────┴──────────┴────────────┘
30
+ web: traefik:v3.6.0
31
+ repo: github.com/traefik/traefik
32
+ commit: 06db5168c0d9
33
+ status: resolved
34
+ confidence: exact
35
+ url: https://github.com/traefik/traefik/commit/06db5168c0d9...
35
36
  ```
36
37
 
37
38
  ## Library Usage
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import { readFileSync } from "node:fs";
3
3
  import { existsSync } from "node:fs";
4
4
  import { parseCompose, parseImageRef } from "./composeParser.js";
5
5
  import { resolveImage } from "./resolver.js";
6
- import { formatJson, formatTable } from "./output.js";
6
+ import { formatJson, formatText } from "./output.js";
7
7
  function printHelp() {
8
8
  console.log(`usage: code-provenance [-h] [--json] [compose_file]
9
9
 
@@ -37,10 +37,17 @@ async function main() {
37
37
  "Create a token at https://github.com/settings/tokens with read:packages scope.\n");
38
38
  }
39
39
  const yamlContent = readFileSync(composeFile, "utf-8");
40
- const services = parseCompose(yamlContent);
40
+ let services;
41
+ try {
42
+ services = parseCompose(yamlContent);
43
+ }
44
+ catch (err) {
45
+ console.error(`Error: failed to parse ${composeFile} — ${err instanceof Error ? err.message : err}`);
46
+ return 1;
47
+ }
41
48
  if (services.length === 0) {
42
- console.error("No services with images found.");
43
- return 0;
49
+ console.error("No services with images found. Is this a valid docker-compose file?");
50
+ return 1;
44
51
  }
45
52
  // Resolve all images in parallel
46
53
  const results = await Promise.all(services.map(([serviceName, imageString]) => {
@@ -64,7 +71,7 @@ async function main() {
64
71
  console.log(formatJson(results));
65
72
  }
66
73
  else {
67
- console.log(formatTable(results));
74
+ console.log(formatText(results));
68
75
  }
69
76
  return 0;
70
77
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;yCAU2B,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAC7F,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,oBAAoB,CAAC;IAE9D,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,UAAU,WAAW,YAAY,CAAC,CAAC;QACjD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CACX,8FAA8F;YAC9F,wDAAwD;YACxD,kFAAkF,CACnF,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAE3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,iCAAiC;IACjC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QACvC,OAAO,YAAY,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CACH,CAAC;IAEF,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YAC7B,CAAC;YACD,OAAO,CAAC,KAAK,CACX,OAAO,CAAC,CAAC,MAAM,EAAE;gBACf,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU;oBACtB,CAAC,CAAC,KAAK,CAAC,CAAC,iBAAiB,KAAK,CAAC,CAAC,UAAU,GAAG;oBAC9C,CAAC,CAAC,EAAE,CAAC,CACV,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,IAAI,EAAE;KACH,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAClC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export type { ImageRef, ImageResult } from "./types.js";
2
2
  export { parseCompose, parseImageRef } from "./composeParser.js";
3
3
  export { resolveImage } from "./resolver.js";
4
- export { formatJson, formatTable } from "./output.js";
4
+ export { formatJson, formatText } from "./output.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { parseCompose, parseImageRef } from "./composeParser.js";
2
2
  export { resolveImage } from "./resolver.js";
3
- export { formatJson, formatTable } from "./output.js";
3
+ export { formatJson, formatText } from "./output.js";
4
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
package/dist/output.d.ts CHANGED
@@ -1,9 +1,3 @@
1
1
  import type { ImageResult } from "./types.js";
2
- /**
3
- * Format results as a JSON array.
4
- */
5
2
  export declare function formatJson(results: ImageResult[]): string;
6
- /**
7
- * Format results as a box-drawing table.
8
- */
9
- export declare function formatTable(results: ImageResult[]): string;
3
+ export declare function formatText(results: ImageResult[]): string;
package/dist/output.js CHANGED
@@ -1,41 +1,19 @@
1
- /**
2
- * Format results as a JSON array.
3
- */
4
1
  export function formatJson(results) {
5
2
  return JSON.stringify(results, null, 2);
6
3
  }
7
- /**
8
- * Format results as a box-drawing table.
9
- */
10
- export function formatTable(results) {
11
- const columns = ["SERVICE", "IMAGE", "REPO", "COMMIT", "STATUS", "CONFIDENCE"];
12
- const MAX_COL_WIDTH = 50;
13
- const truncate = (s, max) => s.length > max ? s.slice(0, max - 1) + "…" : s;
14
- // Build rows
15
- const rows = results.map((r) => [
16
- r.service,
17
- truncate(r.image, MAX_COL_WIDTH),
18
- r.repo ? truncate(r.repo.replace("https://", ""), MAX_COL_WIDTH) : "-",
19
- r.commit ? r.commit.slice(0, 12) : "-",
20
- r.status,
21
- r.confidence || "-",
22
- ]);
23
- // Calculate column widths
24
- const widths = columns.map((col, i) => {
25
- const dataMax = rows.reduce((max, row) => Math.max(max, row[i].length), 0);
26
- return Math.max(col.length, dataMax);
27
- });
28
- const pad = (s, w) => s + " ".repeat(w - s.length);
29
- // Build lines
30
- const topBorder = "┌" + widths.map((w) => "─".repeat(w + 2)).join("┬") + "┐";
31
- const headerSep = "├" + widths.map((w) => "─".repeat(w + 2)).join("┼") + "┤";
32
- const bottomBorder = "└" + widths.map((w) => "─".repeat(w + 2)).join("┴") + "┘";
33
- const headerRow = "│" +
34
- columns.map((col, i) => " " + pad(col, widths[i]) + " ").join("│") +
35
- "│";
36
- const dataRows = rows.map((row) => "│" +
37
- row.map((cell, i) => " " + pad(cell, widths[i]) + " ").join("│") +
38
- "│");
39
- return [topBorder, headerRow, headerSep, ...dataRows, bottomBorder].join("\n");
4
+ export function formatText(results) {
5
+ return results
6
+ .map((r) => {
7
+ const commit = r.commit ? r.commit.slice(0, 12) : "-";
8
+ const repo = r.repo?.replace("https://", "") ?? "-";
9
+ const confidence = r.confidence ?? "-";
10
+ return (`${r.service}: ${r.image}\n` +
11
+ ` repo: ${repo}\n` +
12
+ ` commit: ${commit}\n` +
13
+ ` status: ${r.status}\n` +
14
+ ` confidence: ${confidence}` +
15
+ (r.commit_url ? `\n url: ${r.commit_url}` : ""));
16
+ })
17
+ .join("\n\n");
40
18
  }
41
19
  //# sourceMappingURL=output.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,OAAsB;IAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAsB;IAC/C,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACtD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;QACpD,MAAM,UAAU,GAAG,CAAC,CAAC,UAAU,IAAI,GAAG,CAAC;QACvC,OAAO,CACL,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI;YAC5B,iBAAiB,IAAI,IAAI;YACzB,iBAAiB,MAAM,IAAI;YAC3B,iBAAiB,CAAC,CAAC,MAAM,IAAI;YAC7B,iBAAiB,UAAU,EAAE;YAC7B,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACxD,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-provenance",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Resolve Docker images to their source code commits on GitHub",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/cli.ts CHANGED
@@ -4,7 +4,7 @@ import { readFileSync } from "node:fs";
4
4
  import { existsSync } from "node:fs";
5
5
  import { parseCompose, parseImageRef } from "./composeParser.js";
6
6
  import { resolveImage } from "./resolver.js";
7
- import { formatJson, formatTable } from "./output.js";
7
+ import { formatJson, formatText } from "./output.js";
8
8
 
9
9
  function printHelp(): void {
10
10
  console.log(`usage: code-provenance [-h] [--json] [compose_file]
@@ -47,11 +47,18 @@ async function main(): Promise<number> {
47
47
  }
48
48
 
49
49
  const yamlContent = readFileSync(composeFile, "utf-8");
50
- const services = parseCompose(yamlContent);
50
+
51
+ let services: Array<[string, string]>;
52
+ try {
53
+ services = parseCompose(yamlContent);
54
+ } catch (err) {
55
+ console.error(`Error: failed to parse ${composeFile} — ${err instanceof Error ? err.message : err}`);
56
+ return 1;
57
+ }
51
58
 
52
59
  if (services.length === 0) {
53
- console.error("No services with images found.");
54
- return 0;
60
+ console.error("No services with images found. Is this a valid docker-compose file?");
61
+ return 1;
55
62
  }
56
63
 
57
64
  // Resolve all images in parallel
@@ -81,7 +88,7 @@ async function main(): Promise<number> {
81
88
  if (jsonOutput) {
82
89
  console.log(formatJson(results));
83
90
  } else {
84
- console.log(formatTable(results));
91
+ console.log(formatText(results));
85
92
  }
86
93
 
87
94
  return 0;
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export type { ImageRef, ImageResult } from "./types.js";
2
2
  export { parseCompose, parseImageRef } from "./composeParser.js";
3
3
  export { resolveImage } from "./resolver.js";
4
- export { formatJson, formatTable } from "./output.js";
4
+ export { formatJson, formatText } from "./output.js";
package/src/output.ts CHANGED
@@ -1,62 +1,23 @@
1
1
  import type { ImageResult } from "./types.js";
2
2
 
3
- /**
4
- * Format results as a JSON array.
5
- */
6
3
  export function formatJson(results: ImageResult[]): string {
7
4
  return JSON.stringify(results, null, 2);
8
5
  }
9
6
 
10
- /**
11
- * Format results as a box-drawing table.
12
- */
13
- export function formatTable(results: ImageResult[]): string {
14
- const columns = ["SERVICE", "IMAGE", "REPO", "COMMIT", "STATUS", "CONFIDENCE"];
15
-
16
- const MAX_COL_WIDTH = 50;
17
-
18
- const truncate = (s: string, max: number) =>
19
- s.length > max ? s.slice(0, max - 1) + "…" : s;
20
-
21
- // Build rows
22
- const rows: string[][] = results.map((r) => [
23
- r.service,
24
- truncate(r.image, MAX_COL_WIDTH),
25
- r.repo ? truncate(r.repo.replace("https://", ""), MAX_COL_WIDTH) : "-",
26
- r.commit ? r.commit.slice(0, 12) : "-",
27
- r.status,
28
- r.confidence || "-",
29
- ]);
30
-
31
- // Calculate column widths
32
- const widths = columns.map((col, i) => {
33
- const dataMax = rows.reduce((max, row) => Math.max(max, row[i].length), 0);
34
- return Math.max(col.length, dataMax);
35
- });
36
-
37
- const pad = (s: string, w: number) => s + " ".repeat(w - s.length);
38
-
39
- // Build lines
40
- const topBorder =
41
- "┌" + widths.map((w) => "─".repeat(w + 2)).join("┬") + "┐";
42
- const headerSep =
43
- "├" + widths.map((w) => "─".repeat(w + 2)).join("┼") + "┤";
44
- const bottomBorder =
45
- "└" + widths.map((w) => "─".repeat(w + 2)).join("┴") + "┘";
46
-
47
- const headerRow =
48
- "│" +
49
- columns.map((col, i) => " " + pad(col, widths[i]) + " ").join("│") +
50
- "│";
51
-
52
- const dataRows = rows.map(
53
- (row) =>
54
- "│" +
55
- row.map((cell, i) => " " + pad(cell, widths[i]) + " ").join("│") +
56
- "│"
57
- );
58
-
59
- return [topBorder, headerRow, headerSep, ...dataRows, bottomBorder].join(
60
- "\n"
61
- );
7
+ export function formatText(results: ImageResult[]): string {
8
+ return results
9
+ .map((r) => {
10
+ const commit = r.commit ? r.commit.slice(0, 12) : "-";
11
+ const repo = r.repo?.replace("https://", "") ?? "-";
12
+ const confidence = r.confidence ?? "-";
13
+ return (
14
+ `${r.service}: ${r.image}\n` +
15
+ ` repo: ${repo}\n` +
16
+ ` commit: ${commit}\n` +
17
+ ` status: ${r.status}\n` +
18
+ ` confidence: ${confidence}` +
19
+ (r.commit_url ? `\n url: ${r.commit_url}` : "")
20
+ );
21
+ })
22
+ .join("\n\n");
62
23
  }