@xemahq/biome-supply-chain 0.1.1 → 0.1.3
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/LICENSE +1 -1
- package/README.md +7 -1
- package/dist/lib/verdicts.d.ts.map +1 -1
- package/dist/lib/verdicts.js.map +1 -1
- package/package.json +10 -13
- package/src/index.ts +0 -2
- package/src/lib/cosign-exec.ts +0 -188
- package/src/lib/verdicts.ts +0 -52
package/LICENSE
CHANGED
|
@@ -9,7 +9,7 @@ Parameters
|
|
|
9
9
|
|
|
10
10
|
Licensor: Neuralchowder Inc.
|
|
11
11
|
|
|
12
|
-
Licensed Work: Xema. The Licensed Work is (c) 2026 Neuralchowder Inc
|
|
12
|
+
Licensed Work: Xema. The Licensed Work is (c) 2026 Neuralchowder Inc.
|
|
13
13
|
|
|
14
14
|
The Licensed Work includes, without limitation, Xema Core, Xema Runtime,
|
|
15
15
|
Xema Kernel, Xema control plane, Xema application runtime, Xema biome
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ This package belongs to Layer 1 — a framework-free runtime SDK utility.
|
|
|
4
4
|
|
|
5
5
|
Shared cosign supply-chain verification for Xema biomes. It centralizes the two
|
|
6
6
|
things that were previously copy-pasted between `biome-fetcher-api` (OCI bundle
|
|
7
|
-
verification) and
|
|
7
|
+
verification) and `xema-store-api`:
|
|
8
8
|
|
|
9
9
|
- the single cosign CLI invocation (`ensureCosignAvailable`,
|
|
10
10
|
`verifyCosignSignature`, `verifyCosignAttestation`, `verifyCosignBlob`), and
|
|
@@ -49,3 +49,9 @@ if (outcome === CosignVerifyOutcome.Verified) {
|
|
|
49
49
|
Artifact resolution (resolving an OCI ref, or fetching + writing a blob to a
|
|
50
50
|
temp file) stays with each consumer; this package owns only the cosign exec and
|
|
51
51
|
the verdict enums.
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
Business Source License 1.1 (BSL-1.1) — source-available; converts to MPL-2.0
|
|
56
|
+
four years after each release. © Xema — [xema.dev](https://xema.dev). See
|
|
57
|
+
the [repository LICENSE](../../../LICENSE).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verdicts.d.ts","sourceRoot":"","sources":["../../src/lib/verdicts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verdicts.d.ts","sourceRoot":"","sources":["../../src/lib/verdicts.ts"],"names":[],"mappings":"AAqBA,oBAAY,gBAAgB;IAC1B,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAGD,oBAAY,iBAAiB;IAC3B,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAGD,oBAAY,eAAe;IACzB,gBAAgB,4BAA4B;IAC5C,gBAAgB,4BAA4B;IAC5C,kBAAkB,yCAAyC;IAC3D,iBAAiB,6BAA6B;IAC9C,iBAAiB,6BAA6B;IAC9C,iBAAiB,6BAA6B;CAC/C;AAOD,oBAAY,mBAAmB;IAC7B,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAGD,eAAO,MAAM,8BAA8B,EACzC,gCAAyC,CAAC"}
|
package/dist/lib/verdicts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verdicts.js","sourceRoot":"","sources":["../../src/lib/verdicts.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"verdicts.js","sourceRoot":"","sources":["../../src/lib/verdicts.ts"],"names":[],"mappings":";;;AAqBA,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,mCAAe,CAAA;IACf,uCAAmB,CAAA;IACnB,yCAAqB,CAAA;AACvB,CAAC,EAJW,gBAAgB,gCAAhB,gBAAgB,QAI3B;AAGD,IAAY,iBAIX;AAJD,WAAY,iBAAiB;IAC3B,oCAAe,CAAA;IACf,wCAAmB,CAAA;IACnB,wCAAmB,CAAA;AACrB,CAAC,EAJW,iBAAiB,iCAAjB,iBAAiB,QAI5B;AAGD,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,+DAA4C,CAAA;IAC5C,+DAA4C,CAAA;IAC5C,8EAA2D,CAAA;IAC3D,iEAA8C,CAAA;IAC9C,iEAA8C,CAAA;IAC9C,iEAA8C,CAAA;AAChD,CAAC,EAPW,eAAe,+BAAf,eAAe,QAO1B;AAOD,IAAY,mBAGX;AAHD,WAAY,mBAAmB;IAC7B,4CAAqB,CAAA;IACrB,wCAAiB,CAAA;AACnB,CAAC,EAHW,mBAAmB,mCAAnB,mBAAmB,QAG9B;AAGY,QAAA,8BAA8B,GACzC,gCAAyC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/biome-supply-chain",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Shared cosign supply-chain verification for Xema biomes: the single cosign CLI exec + the signature/provenance verdict enums used by biome-fetcher-api (OCI
|
|
5
|
-
"license": "
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Shared cosign supply-chain verification for Xema biomes: the single cosign CLI exec + the signature/provenance verdict enums used by biome-fetcher-api (OCI bundle verification) and xema-store-api. Node-builtins only.",
|
|
5
|
+
"license": "LicenseRef-Xema-BSL-1.1",
|
|
6
6
|
"author": "Neuralchowder Inc. <developer@xema.dev> (https://xema.dev)",
|
|
7
7
|
"homepage": "https://xema.dev",
|
|
8
8
|
"repository": {
|
|
@@ -29,14 +29,11 @@
|
|
|
29
29
|
"main": "./dist/index.js",
|
|
30
30
|
"types": "./dist/index.d.ts",
|
|
31
31
|
"files": [
|
|
32
|
-
"dist"
|
|
33
|
-
"src"
|
|
32
|
+
"dist"
|
|
34
33
|
],
|
|
35
34
|
"devDependencies": {
|
|
36
|
-
"@types/node": "
|
|
37
|
-
"
|
|
38
|
-
"ts-jest": "^29.0.0",
|
|
39
|
-
"typescript": "^5.0.0"
|
|
35
|
+
"@types/node": "25.2.3",
|
|
36
|
+
"typescript": "5.9.3"
|
|
40
37
|
},
|
|
41
38
|
"keywords": [
|
|
42
39
|
"xema",
|
|
@@ -48,9 +45,9 @@
|
|
|
48
45
|
"signature-verification"
|
|
49
46
|
],
|
|
50
47
|
"scripts": {
|
|
51
|
-
"build": "tsc",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
48
|
+
"build": "tsc -p tsconfig.build.json",
|
|
49
|
+
"test": "tsc -p tsconfig.json && node --test \"dist-test/test/**/*.test.js\"",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
51
|
+
"clean": "rm -rf dist dist-test"
|
|
55
52
|
}
|
|
56
53
|
}
|
package/src/index.ts
DELETED
package/src/lib/cosign-exec.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
import { CosignVerifyOutcome } from './verdicts';
|
|
4
|
-
|
|
5
|
-
/** Default cosign binary name (overridable per call). */
|
|
6
|
-
const DEFAULT_COSIGN_BIN = 'cosign';
|
|
7
|
-
|
|
8
|
-
interface CosignRunResult {
|
|
9
|
-
readonly code: number;
|
|
10
|
-
readonly stderr: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* The single canonical cosign invocation. Spawns the binary, captures stderr,
|
|
15
|
-
* and resolves with the exit code (never rejects on a non-zero exit — the
|
|
16
|
-
* caller decides whether a non-zero code is an error or a "failed" verdict).
|
|
17
|
-
* Rejects only when the process cannot be spawned at all.
|
|
18
|
-
*/
|
|
19
|
-
function runCosign(
|
|
20
|
-
bin: string,
|
|
21
|
-
args: readonly string[],
|
|
22
|
-
): Promise<CosignRunResult> {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
const child = spawn(bin, [...args], {
|
|
25
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
26
|
-
});
|
|
27
|
-
let stderr = '';
|
|
28
|
-
child.stderr?.on('data', (chunk: Buffer) => {
|
|
29
|
-
stderr += chunk.toString();
|
|
30
|
-
});
|
|
31
|
-
child.on('error', reject);
|
|
32
|
-
child.on('close', (code) => {
|
|
33
|
-
resolve({ code: code ?? 1, stderr });
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Throws if the cosign CLI is not available on PATH. */
|
|
39
|
-
export async function ensureCosignAvailable(
|
|
40
|
-
bin: string = DEFAULT_COSIGN_BIN,
|
|
41
|
-
): Promise<void> {
|
|
42
|
-
try {
|
|
43
|
-
const { code, stderr } = await runCosign(bin, ['version']);
|
|
44
|
-
if (code !== 0) {
|
|
45
|
-
throw new Error(`\`${bin} version\` exited ${code}: ${stderr.slice(-200)}`);
|
|
46
|
-
}
|
|
47
|
-
} catch (cause) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
`cosign CLI is not on PATH — install from https://github.com/sigstore/cosign ` +
|
|
50
|
-
`(${cause instanceof Error ? cause.message : String(cause)})`,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface VerifyCosignSignatureInput {
|
|
56
|
-
readonly ociRef: string;
|
|
57
|
-
/** Exact keyless certificate-identity URIs (any one may match). */
|
|
58
|
-
readonly trustedIdentities: readonly string[];
|
|
59
|
-
readonly oidcIssuer?: string | undefined;
|
|
60
|
-
/** Keyed verification: path to the public key (mutually exclusive w/ keyless). */
|
|
61
|
-
readonly keyPath?: string | undefined;
|
|
62
|
-
readonly bin?: string | undefined;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Verify a signature on an OCI ref (keyless identity allowlist OR keyed).
|
|
67
|
-
* Throws on non-verification; resolves on success. Mirrors the fetcher's
|
|
68
|
-
* former inline behaviour.
|
|
69
|
-
*/
|
|
70
|
-
export async function verifyCosignSignature(
|
|
71
|
-
input: VerifyCosignSignatureInput,
|
|
72
|
-
): Promise<void> {
|
|
73
|
-
const bin = input.bin ?? DEFAULT_COSIGN_BIN;
|
|
74
|
-
const args: string[] = ['verify'];
|
|
75
|
-
if (input.keyPath) {
|
|
76
|
-
args.push('--key', input.keyPath);
|
|
77
|
-
} else {
|
|
78
|
-
if (input.trustedIdentities.length === 0) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
'verifyCosignSignature: keyless mode requires at least one trusted identity',
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
for (const id of input.trustedIdentities) {
|
|
84
|
-
args.push('--certificate-identity', id);
|
|
85
|
-
}
|
|
86
|
-
if (input.oidcIssuer) {
|
|
87
|
-
args.push('--certificate-oidc-issuer', input.oidcIssuer);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
args.push(input.ociRef);
|
|
91
|
-
const { code, stderr } = await runCosign(bin, args);
|
|
92
|
-
if (code !== 0) {
|
|
93
|
-
throw new Error(`${bin} verify failed (code=${code}): ${stderr.slice(-200)}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export interface VerifyCosignAttestationInput {
|
|
98
|
-
readonly ociRef: string;
|
|
99
|
-
readonly predicateType: string;
|
|
100
|
-
readonly trustedIdentities: readonly string[];
|
|
101
|
-
readonly oidcIssuer?: string | undefined;
|
|
102
|
-
readonly keyPath?: string | undefined;
|
|
103
|
-
readonly bin?: string | undefined;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Verify an in-toto/SLSA attestation on an OCI ref. Throws on
|
|
108
|
-
* non-verification; resolves on success.
|
|
109
|
-
*/
|
|
110
|
-
export async function verifyCosignAttestation(
|
|
111
|
-
input: VerifyCosignAttestationInput,
|
|
112
|
-
): Promise<void> {
|
|
113
|
-
const bin = input.bin ?? DEFAULT_COSIGN_BIN;
|
|
114
|
-
const args: string[] = ['verify-attestation', '--type', input.predicateType];
|
|
115
|
-
if (input.keyPath) {
|
|
116
|
-
args.push('--key', input.keyPath);
|
|
117
|
-
} else {
|
|
118
|
-
if (input.trustedIdentities.length === 0) {
|
|
119
|
-
throw new Error(
|
|
120
|
-
'verifyCosignAttestation: keyless mode requires at least one trusted identity',
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
for (const id of input.trustedIdentities) {
|
|
124
|
-
args.push('--certificate-identity', id);
|
|
125
|
-
}
|
|
126
|
-
if (input.oidcIssuer) {
|
|
127
|
-
args.push('--certificate-oidc-issuer', input.oidcIssuer);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
args.push(input.ociRef);
|
|
131
|
-
const { code, stderr } = await runCosign(bin, args);
|
|
132
|
-
if (code !== 0) {
|
|
133
|
-
throw new Error(
|
|
134
|
-
`${bin} verify-attestation failed (code=${code}): ${stderr.slice(-200)}`,
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export interface VerifyCosignBlobInput {
|
|
140
|
-
/** Path to the artifact bytes on disk (caller owns fetch/temp-file lifecycle). */
|
|
141
|
-
readonly artifactPath: string;
|
|
142
|
-
/** Path to the detached signature bundle on disk. */
|
|
143
|
-
readonly bundlePath: string;
|
|
144
|
-
/** Keyless certificate-identity REGEXPS (any one may match). */
|
|
145
|
-
readonly trustedIdentityRegexps: readonly string[];
|
|
146
|
-
readonly oidcIssuer?: string | undefined;
|
|
147
|
-
readonly bin?: string | undefined;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export interface VerifyCosignBlobResult {
|
|
151
|
-
readonly outcome: CosignVerifyOutcome;
|
|
152
|
-
/** The identity regexp that matched, when Verified. */
|
|
153
|
-
readonly matchedIdentity?: string | undefined;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Verify a detached signature over a blob (`cosign verify-blob --bundle`).
|
|
158
|
-
* Tries each trusted identity regexp; the first that verifies wins. Returns a
|
|
159
|
-
* neutral {@link CosignVerifyOutcome} (never throws on a failed verification —
|
|
160
|
-
* an empty trust list or all-mismatch resolves to `Failed`). The caller owns
|
|
161
|
-
* artifact/bundle materialisation on disk.
|
|
162
|
-
*/
|
|
163
|
-
export async function verifyCosignBlob(
|
|
164
|
-
input: VerifyCosignBlobInput,
|
|
165
|
-
): Promise<VerifyCosignBlobResult> {
|
|
166
|
-
const bin = input.bin ?? DEFAULT_COSIGN_BIN;
|
|
167
|
-
if (input.trustedIdentityRegexps.length === 0) {
|
|
168
|
-
return { outcome: CosignVerifyOutcome.Failed };
|
|
169
|
-
}
|
|
170
|
-
for (const identity of input.trustedIdentityRegexps) {
|
|
171
|
-
const args: string[] = [
|
|
172
|
-
'verify-blob',
|
|
173
|
-
'--bundle',
|
|
174
|
-
input.bundlePath,
|
|
175
|
-
'--certificate-identity-regexp',
|
|
176
|
-
identity,
|
|
177
|
-
];
|
|
178
|
-
if (input.oidcIssuer) {
|
|
179
|
-
args.push('--certificate-oidc-issuer', input.oidcIssuer);
|
|
180
|
-
}
|
|
181
|
-
args.push(input.artifactPath);
|
|
182
|
-
const { code } = await runCosign(bin, args);
|
|
183
|
-
if (code === 0) {
|
|
184
|
-
return { outcome: CosignVerifyOutcome.Verified, matchedIdentity: identity };
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return { outcome: CosignVerifyOutcome.Failed };
|
|
188
|
-
}
|
package/src/lib/verdicts.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared cosign supply-chain verdict vocabulary.
|
|
3
|
-
*
|
|
4
|
-
* This is the single source of truth for the lowercase verdict/error enums
|
|
5
|
-
* that `biome-fetcher-api` (OCI bundle verification) and `@xemahq/biome-package`
|
|
6
|
-
* (the packaging CLI) previously duplicated locally. They are value-identical
|
|
7
|
-
* to those former copies, so adopting this package is a pure de-duplication
|
|
8
|
-
* with no wire/behaviour change.
|
|
9
|
-
*
|
|
10
|
-
* NOTE: `xema-store-api` keeps its OWN UPPERCASE `SignatureVerdict` /
|
|
11
|
-
* `ProvenanceVerdict` (persisted + OpenAPI + cross-service event wire); it
|
|
12
|
-
* consumes only the cosign EXEC + {@link CosignVerifyOutcome} from this
|
|
13
|
-
* package, mapping the neutral outcome to its own wire enum.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/** Signature verification verdict. */
|
|
17
|
-
export enum SignatureVerdict {
|
|
18
|
-
Valid = 'valid',
|
|
19
|
-
Invalid = 'invalid',
|
|
20
|
-
Unsigned = 'unsigned',
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** SLSA attestation / provenance verdict. */
|
|
24
|
-
export enum ProvenanceVerdict {
|
|
25
|
-
Valid = 'valid',
|
|
26
|
-
Invalid = 'invalid',
|
|
27
|
-
Missing = 'missing',
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Stable, typed reasons a cosign verification may reject an artifact. */
|
|
31
|
-
export enum CosignErrorCode {
|
|
32
|
-
SignatureMissing = 'BIOME_SIGNATURE_MISSING',
|
|
33
|
-
SignatureInvalid = 'BIOME_SIGNATURE_INVALID',
|
|
34
|
-
IdentityNotTrusted = 'BIOME_SIGNATURE_IDENTITY_NOT_TRUSTED',
|
|
35
|
-
ProvenanceMissing = 'BIOME_PROVENANCE_MISSING',
|
|
36
|
-
ProvenanceInvalid = 'BIOME_PROVENANCE_INVALID',
|
|
37
|
-
CosignUnavailable = 'BIOME_COSIGN_UNAVAILABLE',
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Casing-neutral internal outcome of a detached-blob verification. The blob
|
|
42
|
-
* path (store) maps this to its own UPPERCASE wire verdict; it deliberately
|
|
43
|
-
* does not leak the wire casing into the shared exec layer.
|
|
44
|
-
*/
|
|
45
|
-
export enum CosignVerifyOutcome {
|
|
46
|
-
Verified = 'verified',
|
|
47
|
-
Failed = 'failed',
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Canonical SLSA provenance predicate type. */
|
|
51
|
-
export const SLSA_PROVENANCE_PREDICATE_TYPE =
|
|
52
|
-
'https://slsa.dev/provenance/v1' as const;
|