@kici-dev/engine 0.1.16 → 0.1.18
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/approval/types.js +1 -1
- package/dist/audit/access-log-policy.js +3 -1
- package/dist/audit/activity.js +1 -1
- package/dist/audit/retention-policy.js +5 -1
- package/dist/bundler/index.js +1 -1
- package/dist/bundler/rolldown-config.js +1 -1
- package/dist/env/environment-allowlist.d.ts +1 -1
- package/dist/env/environment-allowlist.js +13 -2
- package/dist/environment/index.js +1 -1
- package/dist/environment/scope-resolver.js +1 -1
- package/dist/environment/types.js +1 -1
- package/dist/fanout/materialize.d.ts +123 -0
- package/dist/fanout/materialize.js +176 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +9 -7
- package/dist/labels/compile.d.ts +40 -0
- package/dist/labels/compile.js +91 -0
- package/dist/labels-match.d.ts +32 -0
- package/dist/labels-match.js +55 -0
- package/dist/labels.js +1 -1
- package/dist/matrix/expand.d.ts +48 -0
- package/dist/matrix/expand.js +72 -0
- package/dist/matrix/format.d.ts +10 -0
- package/dist/matrix/format.js +20 -0
- package/dist/metrics/catalog-policy.js +8 -3
- package/dist/metrics/metric-catalog.generated.d.ts +11 -1
- package/dist/metrics/metric-catalog.generated.js +14 -2
- package/dist/protocol/analytics-events.js +1 -1
- package/dist/protocol/cluster-name.js +1 -1
- package/dist/protocol/dashboard-global-workflows.js +1 -1
- package/dist/protocol/dashboard-write-operations.js +1 -1
- package/dist/protocol/event-log-payload.js +1 -1
- package/dist/protocol/messages/access-log.d.ts +15 -5
- package/dist/protocol/messages/access-log.js +3 -1
- package/dist/protocol/messages/actor.js +1 -1
- package/dist/protocol/messages/auth.d.ts +1 -0
- package/dist/protocol/messages/auth.js +11 -2
- package/dist/protocol/messages/browser.js +1 -1
- package/dist/protocol/messages/capabilities.js +1 -1
- package/dist/protocol/messages/common.js +1 -1
- package/dist/protocol/messages/dashboard-global-workflows.js +1 -1
- package/dist/protocol/messages/dashboard.d.ts +985 -57
- package/dist/protocol/messages/dashboard.js +368 -13
- package/dist/protocol/messages/event-log.js +1 -1
- package/dist/protocol/messages/execution-status.d.ts +13 -1
- package/dist/protocol/messages/execution-status.js +13 -3
- package/dist/protocol/messages/join.js +1 -1
- package/dist/protocol/messages/log-pull.js +1 -1
- package/dist/protocol/messages/observe.d.ts +1 -0
- package/dist/protocol/messages/oidc-token-relay.d.ts +31 -0
- package/dist/protocol/messages/oidc-token-relay.js +34 -0
- package/dist/protocol/messages/orchestrator-agent.d.ts +56 -0
- package/dist/protocol/messages/orchestrator-agent.js +47 -2
- package/dist/protocol/messages/peer.d.ts +48 -0
- package/dist/protocol/messages/peer.js +12 -1
- package/dist/protocol/messages/platform-orchestrator.d.ts +171 -4
- package/dist/protocol/messages/platform-orchestrator.js +1 -1
- package/dist/protocol/messages/run-events.js +1 -1
- package/dist/protocol/messages/scaler-event.js +1 -1
- package/dist/protocol/messages/source-registration.d.ts +7 -6
- package/dist/protocol/messages/source-registration.js +7 -6
- package/dist/protocol/version.js +1 -1
- package/dist/provenance/bundle.d.ts +54 -0
- package/dist/provenance/bundle.js +53 -0
- package/dist/provenance/dsse.d.ts +39 -0
- package/dist/provenance/dsse.js +53 -0
- package/dist/provenance/schema.js +1 -1
- package/dist/provenance/verify.d.ts +71 -0
- package/dist/provenance/verify.js +135 -0
- package/dist/provider/changed-files-fetcher.js +1 -1
- package/dist/provider/check-run-conclusion.js +1 -1
- package/dist/provider/check-status-poster.js +1 -1
- package/dist/provider/clone-token-provider.js +1 -1
- package/dist/provider/contributor-resolver.js +1 -1
- package/dist/provider/index.js +1 -1
- package/dist/provider/lock-file-fetcher.js +1 -1
- package/dist/provider/lock-file-parse-error.js +3 -1
- package/dist/provider/repo-url-builder.js +1 -1
- package/dist/provider/types.d.ts +2 -2
- package/dist/provider/types.js +1 -1
- package/dist/provider/webhook-normalizer.js +1 -1
- package/dist/registration/registerable-trigger-type.js +1 -1
- package/dist/scaler/resource-types.js +1 -1
- package/dist/scaler/scaler-backend-type.js +1 -1
- package/dist/secrets/index.js +1 -1
- package/dist/secrets/types.js +1 -1
- package/dist/state-machine/index.js +1 -1
- package/dist/state-machine/machine.js +1 -1
- package/dist/state-machine/types.js +1 -1
- package/dist/trigger/decision-trace.js +1 -1
- package/dist/trigger/jsonpath-matcher.js +1 -1
- package/dist/trigger/matcher.js +1 -1
- package/dist/trigger/trigger-event-type.js +1 -1
- package/dist/trigger/types.d.ts +76 -3
- package/dist/trigger/types.js +33 -5
- package/dist/webhook/signature.js +1 -1
- package/dist/ws/close-codes.js +1 -1
- package/dist/ws/rate-limiter.js +3 -1
- package/dist/ws/ws-like.js +1 -1
- package/package.json +26 -3
- package/sbom.spdx.json +85 -10
- package/dist/protocol/messages/observe.js +0 -70
- package/dist/protocol/messages/test-run.js +0 -52
- /package/dist/{chunk-gOLHoazu.js → chunk-BTugEXQM.js} +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KiCI provenance bundle: the Mode-A (KiCI-signed) attestation package.
|
|
3
|
+
*
|
|
4
|
+
* A KiCI bundle is the Sigstore model with the KiCI identity JWT standing in
|
|
5
|
+
* for the Fulcio certificate and no transparency log: it carries the DSSE
|
|
6
|
+
* envelope over the in-toto statement, the ephemeral public key that signed it,
|
|
7
|
+
* and the identity JWT that anchors the statement's build context to a
|
|
8
|
+
* KiCI-minted identity (verified offline against the Platform JWKS).
|
|
9
|
+
*
|
|
10
|
+
* Pure schema + constants, browser-safe — the agent producer and the verifier
|
|
11
|
+
* both import it. Exported at `@kici-dev/engine/provenance/bundle`.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
/** Versioned media type for the KiCI-custom Mode-A bundle (verifier dispatches on it). */
|
|
15
|
+
export declare const KICI_PROVENANCE_BUNDLE_MEDIA_TYPE = "application/vnd.kici.provenance.bundle+json;version=0.1";
|
|
16
|
+
/** OIDC audience the agent requests for the identity token bound into a bundle. */
|
|
17
|
+
export declare const KICI_PROVENANCE_AUDIENCE = "kici-provenance";
|
|
18
|
+
/** in-toto DSSE payload type for the signed statement. */
|
|
19
|
+
export declare const IN_TOTO_PAYLOAD_TYPE = "application/vnd.in-toto+json";
|
|
20
|
+
/** Signing mode of a stored attestation. Mode A = KiCI-signed (the only mode today). */
|
|
21
|
+
export declare const AttestationMode: z.ZodEnum<{
|
|
22
|
+
kici: "kici";
|
|
23
|
+
}>;
|
|
24
|
+
export type AttestationMode = z.infer<typeof AttestationMode>;
|
|
25
|
+
/** Object-storage prefix for provenance bundles. */
|
|
26
|
+
export declare const PROVENANCE_STORAGE_PREFIX = "provenance";
|
|
27
|
+
/**
|
|
28
|
+
* Storage key for a provenance bundle:
|
|
29
|
+
* `provenance/{runId}/{jobId}/{subjectDigest}.kici.json`. Shared by the agent
|
|
30
|
+
* producer and the orchestrator persistence path so the two never drift.
|
|
31
|
+
*/
|
|
32
|
+
export declare function provenanceStorageKey(runId: string, jobId: string, subjectDigest: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Mode-A (KiCI-signed) bundle: the DSSE envelope over the statement plus the
|
|
35
|
+
* verification material (the ephemeral signing public key as a JWK + the
|
|
36
|
+
* identity JWT).
|
|
37
|
+
*/
|
|
38
|
+
export declare const kiciBundleSchema: z.ZodObject<{
|
|
39
|
+
mediaType: z.ZodLiteral<"application/vnd.kici.provenance.bundle+json;version=0.1">;
|
|
40
|
+
dsseEnvelope: z.ZodObject<{
|
|
41
|
+
payloadType: z.ZodString;
|
|
42
|
+
payload: z.ZodString;
|
|
43
|
+
signatures: z.ZodArray<z.ZodObject<{
|
|
44
|
+
keyid: z.ZodString;
|
|
45
|
+
sig: z.ZodString;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
}, z.core.$strip>;
|
|
48
|
+
verificationMaterial: z.ZodObject<{
|
|
49
|
+
publicKey: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
50
|
+
identityToken: z.ZodString;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export type KiciBundle = z.infer<typeof kiciBundleSchema>;
|
|
54
|
+
//# sourceMappingURL=bundle.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { dsseEnvelopeSchema } from "./dsse.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/provenance/bundle.ts
|
|
5
|
+
/**
|
|
6
|
+
* KiCI provenance bundle: the Mode-A (KiCI-signed) attestation package.
|
|
7
|
+
*
|
|
8
|
+
* A KiCI bundle is the Sigstore model with the KiCI identity JWT standing in
|
|
9
|
+
* for the Fulcio certificate and no transparency log: it carries the DSSE
|
|
10
|
+
* envelope over the in-toto statement, the ephemeral public key that signed it,
|
|
11
|
+
* and the identity JWT that anchors the statement's build context to a
|
|
12
|
+
* KiCI-minted identity (verified offline against the Platform JWKS).
|
|
13
|
+
*
|
|
14
|
+
* Pure schema + constants, browser-safe — the agent producer and the verifier
|
|
15
|
+
* both import it. Exported at `@kici-dev/engine/provenance/bundle`.
|
|
16
|
+
*/
|
|
17
|
+
/** Versioned media type for the KiCI-custom Mode-A bundle (verifier dispatches on it). */
|
|
18
|
+
const KICI_PROVENANCE_BUNDLE_MEDIA_TYPE = "application/vnd.kici.provenance.bundle+json;version=0.1";
|
|
19
|
+
/** OIDC audience the agent requests for the identity token bound into a bundle. */
|
|
20
|
+
const KICI_PROVENANCE_AUDIENCE = "kici-provenance";
|
|
21
|
+
/** in-toto DSSE payload type for the signed statement. */
|
|
22
|
+
const IN_TOTO_PAYLOAD_TYPE = "application/vnd.in-toto+json";
|
|
23
|
+
/** Signing mode of a stored attestation. Mode A = KiCI-signed (the only mode today). */
|
|
24
|
+
const AttestationMode = z.enum(["kici"]);
|
|
25
|
+
/** Object-storage prefix for provenance bundles. */
|
|
26
|
+
const PROVENANCE_STORAGE_PREFIX = "provenance";
|
|
27
|
+
/**
|
|
28
|
+
* Storage key for a provenance bundle:
|
|
29
|
+
* `provenance/{runId}/{jobId}/{subjectDigest}.kici.json`. Shared by the agent
|
|
30
|
+
* producer and the orchestrator persistence path so the two never drift.
|
|
31
|
+
*/
|
|
32
|
+
function provenanceStorageKey(runId, jobId, subjectDigest) {
|
|
33
|
+
return `${PROVENANCE_STORAGE_PREFIX}/${runId}/${jobId}/${subjectDigest}.kici.json`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Mode-A (KiCI-signed) bundle: the DSSE envelope over the statement plus the
|
|
37
|
+
* verification material (the ephemeral signing public key as a JWK + the
|
|
38
|
+
* identity JWT).
|
|
39
|
+
*/
|
|
40
|
+
const kiciBundleSchema = z.object({
|
|
41
|
+
mediaType: z.literal(KICI_PROVENANCE_BUNDLE_MEDIA_TYPE),
|
|
42
|
+
dsseEnvelope: dsseEnvelopeSchema,
|
|
43
|
+
verificationMaterial: z.object({
|
|
44
|
+
/** JWK of the ephemeral ES256 key that signed the DSSE envelope. */
|
|
45
|
+
publicKey: z.record(z.string(), z.unknown()),
|
|
46
|
+
/** The KiCI ID token (verified against the Platform JWKS). */
|
|
47
|
+
identityToken: z.string()
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
//#endregion
|
|
51
|
+
export { AttestationMode, IN_TOTO_PAYLOAD_TYPE, KICI_PROVENANCE_AUDIENCE, KICI_PROVENANCE_BUNDLE_MEDIA_TYPE, PROVENANCE_STORAGE_PREFIX, kiciBundleSchema, provenanceStorageKey };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSSE (Dead Simple Signing Envelope) helpers for KiCI provenance.
|
|
3
|
+
*
|
|
4
|
+
* Provides the in-toto pre-authentication encoding (PAE) and the envelope
|
|
5
|
+
* assembly used by the agent producer and the verifier. Pure byte / base64
|
|
6
|
+
* assembly with no Node-only crypto, so this module stays browser-safe and is
|
|
7
|
+
* exported at the subpath `@kici-dev/engine/provenance/dsse`.
|
|
8
|
+
*
|
|
9
|
+
* Spec reference: https://github.com/secure-systems-lab/dsse/blob/master/protocol.md
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
/** A single DSSE signature: a key id plus the base64 signature bytes. */
|
|
13
|
+
export declare const dsseSignatureSchema: z.ZodObject<{
|
|
14
|
+
keyid: z.ZodString;
|
|
15
|
+
sig: z.ZodString;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type DsseSignature = z.infer<typeof dsseSignatureSchema>;
|
|
18
|
+
/** A DSSE envelope: the payload type, the base64 payload, and ≥1 signature. */
|
|
19
|
+
export declare const dsseEnvelopeSchema: z.ZodObject<{
|
|
20
|
+
payloadType: z.ZodString;
|
|
21
|
+
payload: z.ZodString;
|
|
22
|
+
signatures: z.ZodArray<z.ZodObject<{
|
|
23
|
+
keyid: z.ZodString;
|
|
24
|
+
sig: z.ZodString;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export type DsseEnvelope = z.infer<typeof dsseEnvelopeSchema>;
|
|
28
|
+
/**
|
|
29
|
+
* DSSE pre-authentication encoding: `"DSSEv1 <lenType> <type> <lenBody> <body>"`.
|
|
30
|
+
* The length fields count bytes (UTF-8 for the type, raw bytes for the payload).
|
|
31
|
+
* This is the exact byte sequence that gets signed and verified.
|
|
32
|
+
*/
|
|
33
|
+
export declare function dssePae(payloadType: string, payload: Uint8Array): Uint8Array;
|
|
34
|
+
/** Assemble a {@link DsseEnvelope} from the payload bytes + raw signature bytes. */
|
|
35
|
+
export declare function buildDsseEnvelope(payloadType: string, payloadBytes: Uint8Array, signatures: {
|
|
36
|
+
keyid: string;
|
|
37
|
+
sig: Uint8Array;
|
|
38
|
+
}[]): DsseEnvelope;
|
|
39
|
+
//# sourceMappingURL=dsse.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/provenance/dsse.ts
|
|
4
|
+
/**
|
|
5
|
+
* DSSE (Dead Simple Signing Envelope) helpers for KiCI provenance.
|
|
6
|
+
*
|
|
7
|
+
* Provides the in-toto pre-authentication encoding (PAE) and the envelope
|
|
8
|
+
* assembly used by the agent producer and the verifier. Pure byte / base64
|
|
9
|
+
* assembly with no Node-only crypto, so this module stays browser-safe and is
|
|
10
|
+
* exported at the subpath `@kici-dev/engine/provenance/dsse`.
|
|
11
|
+
*
|
|
12
|
+
* Spec reference: https://github.com/secure-systems-lab/dsse/blob/master/protocol.md
|
|
13
|
+
*/
|
|
14
|
+
/** A single DSSE signature: a key id plus the base64 signature bytes. */
|
|
15
|
+
const dsseSignatureSchema = z.object({
|
|
16
|
+
keyid: z.string(),
|
|
17
|
+
sig: z.string()
|
|
18
|
+
});
|
|
19
|
+
/** A DSSE envelope: the payload type, the base64 payload, and ≥1 signature. */
|
|
20
|
+
const dsseEnvelopeSchema = z.object({
|
|
21
|
+
payloadType: z.string(),
|
|
22
|
+
payload: z.string(),
|
|
23
|
+
signatures: z.array(dsseSignatureSchema).min(1)
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* DSSE pre-authentication encoding: `"DSSEv1 <lenType> <type> <lenBody> <body>"`.
|
|
27
|
+
* The length fields count bytes (UTF-8 for the type, raw bytes for the payload).
|
|
28
|
+
* This is the exact byte sequence that gets signed and verified.
|
|
29
|
+
*/
|
|
30
|
+
function dssePae(payloadType, payload) {
|
|
31
|
+
const enc = new TextEncoder();
|
|
32
|
+
const typeBytes = enc.encode(payloadType);
|
|
33
|
+
const prefix = enc.encode(`DSSEv1 ${typeBytes.length} ${payloadType} ${payload.length} `);
|
|
34
|
+
const out = new Uint8Array(prefix.length + payload.length);
|
|
35
|
+
out.set(prefix, 0);
|
|
36
|
+
out.set(payload, prefix.length);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/** Assemble a {@link DsseEnvelope} from the payload bytes + raw signature bytes. */
|
|
40
|
+
function buildDsseEnvelope(payloadType, payloadBytes, signatures) {
|
|
41
|
+
return {
|
|
42
|
+
payloadType,
|
|
43
|
+
payload: Buffer.from(payloadBytes).toString("base64"),
|
|
44
|
+
signatures: signatures.map((s) => ({
|
|
45
|
+
keyid: s.keyid,
|
|
46
|
+
sig: Buffer.from(s.sig).toString("base64")
|
|
47
|
+
}))
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { buildDsseEnvelope, dsseEnvelopeSchema, dssePae, dsseSignatureSchema };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=dsse.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared, browser-safe verification core for KiCI provenance bundles (Mode A).
|
|
3
|
+
*
|
|
4
|
+
* Given a KiCI-signed bundle, the Platform JWKS, and an out-of-band trusted
|
|
5
|
+
* issuer, `verifyKiciBundle` establishes the full Mode-A chain offline:
|
|
6
|
+
*
|
|
7
|
+
* - the identity JWT verifies against the supplied JWKS with `iss` PINNED to
|
|
8
|
+
* the caller-supplied `expectedIssuer` (never the token's own `iss`) and the
|
|
9
|
+
* audience checked;
|
|
10
|
+
* - the DSSE envelope verifies against the ephemeral public key carried in the
|
|
11
|
+
* bundle, whose `keyid` must equal its RFC 7638 JWK thumbprint;
|
|
12
|
+
* - the in-toto statement's build context must equal the (server-truth) JWT
|
|
13
|
+
* claims — a mismatch is a HARD FAIL, the check that makes the agent-built
|
|
14
|
+
* statement sound;
|
|
15
|
+
* - when an artifact digest is supplied, a subject digest must match it.
|
|
16
|
+
*
|
|
17
|
+
* The core uses only `jose` (isomorphic) and `crypto.subtle`/`atob`/`TextDecoder`
|
|
18
|
+
* (present in modern browsers and Node 24) — no `node:fs`, no `fetch`, no
|
|
19
|
+
* `Buffer` — so the exact same function runs in the `kici verify-attestation`
|
|
20
|
+
* CLI and the dashboard's verified badge. Exported at the subpath
|
|
21
|
+
* `@kici-dev/engine/provenance/verify`; it is deliberately NOT re-exported from
|
|
22
|
+
* the engine barrel (the barrel must stay free of the `jose` dependency).
|
|
23
|
+
*/
|
|
24
|
+
import { type JSONWebKeySet } from 'jose';
|
|
25
|
+
import { type KiciProvenanceStatement } from './schema.js';
|
|
26
|
+
/** Tri-state outcome of a single verification check. */
|
|
27
|
+
export type CheckStatus = 'pass' | 'fail' | 'skipped';
|
|
28
|
+
/** Per-check verification outcomes. */
|
|
29
|
+
export interface VerifyChecks {
|
|
30
|
+
/** Bundle + statement schema validation. */
|
|
31
|
+
schema: CheckStatus;
|
|
32
|
+
/** Identity-token signature, issuer-pin, and audience. */
|
|
33
|
+
jwt: CheckStatus;
|
|
34
|
+
/** DSSE envelope signature over the statement. */
|
|
35
|
+
dsse: CheckStatus;
|
|
36
|
+
/** Statement build context vs. server-truth JWT claims (hard fail on mismatch). */
|
|
37
|
+
buildContext: CheckStatus;
|
|
38
|
+
/** Subject digest vs. the supplied artifact digest (skipped when none given). */
|
|
39
|
+
digest: CheckStatus;
|
|
40
|
+
}
|
|
41
|
+
/** Structured verification result. Never thrown for a verification failure. */
|
|
42
|
+
export interface VerifyResult {
|
|
43
|
+
verified: boolean;
|
|
44
|
+
mode: 'kici' | 'sigstore' | 'unknown';
|
|
45
|
+
checks: VerifyChecks;
|
|
46
|
+
claims?: Record<string, unknown>;
|
|
47
|
+
statement?: KiciProvenanceStatement;
|
|
48
|
+
failures: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface VerifyKiciBundleOptions {
|
|
51
|
+
/** The bundle to verify (validated against `kiciBundleSchema`). */
|
|
52
|
+
bundle: unknown;
|
|
53
|
+
/** Trusted JWKS (already fetched by the caller). */
|
|
54
|
+
jwks: JSONWebKeySet;
|
|
55
|
+
/** Trusted issuer the token `iss` is pinned to (out-of-band, never the token's own). */
|
|
56
|
+
expectedIssuer: string;
|
|
57
|
+
/** Expected token audience, if any. */
|
|
58
|
+
expectedAudience?: string;
|
|
59
|
+
/** Artifact digest to match against a subject, if any. */
|
|
60
|
+
expectedDigest?: {
|
|
61
|
+
alg: string;
|
|
62
|
+
hex: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Verify a KiCI provenance bundle offline. Returns a structured result; throws
|
|
67
|
+
* only on a programming-level error, never for a verification failure (a failed
|
|
68
|
+
* verification is `verified:false` with populated `failures`).
|
|
69
|
+
*/
|
|
70
|
+
export declare function verifyKiciBundle(opts: VerifyKiciBundleOptions): Promise<VerifyResult>;
|
|
71
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { dssePae } from "./dsse.js";
|
|
3
|
+
import { kiciBundleSchema } from "./bundle.js";
|
|
4
|
+
import { kiciProvenanceStatementSchema } from "./schema.js";
|
|
5
|
+
import { calculateJwkThumbprint, createLocalJWKSet, importJWK, jwtVerify } from "jose";
|
|
6
|
+
//#region src/provenance/verify.ts
|
|
7
|
+
/**
|
|
8
|
+
* Shared, browser-safe verification core for KiCI provenance bundles (Mode A).
|
|
9
|
+
*
|
|
10
|
+
* Given a KiCI-signed bundle, the Platform JWKS, and an out-of-band trusted
|
|
11
|
+
* issuer, `verifyKiciBundle` establishes the full Mode-A chain offline:
|
|
12
|
+
*
|
|
13
|
+
* - the identity JWT verifies against the supplied JWKS with `iss` PINNED to
|
|
14
|
+
* the caller-supplied `expectedIssuer` (never the token's own `iss`) and the
|
|
15
|
+
* audience checked;
|
|
16
|
+
* - the DSSE envelope verifies against the ephemeral public key carried in the
|
|
17
|
+
* bundle, whose `keyid` must equal its RFC 7638 JWK thumbprint;
|
|
18
|
+
* - the in-toto statement's build context must equal the (server-truth) JWT
|
|
19
|
+
* claims — a mismatch is a HARD FAIL, the check that makes the agent-built
|
|
20
|
+
* statement sound;
|
|
21
|
+
* - when an artifact digest is supplied, a subject digest must match it.
|
|
22
|
+
*
|
|
23
|
+
* The core uses only `jose` (isomorphic) and `crypto.subtle`/`atob`/`TextDecoder`
|
|
24
|
+
* (present in modern browsers and Node 24) — no `node:fs`, no `fetch`, no
|
|
25
|
+
* `Buffer` — so the exact same function runs in the `kici verify-attestation`
|
|
26
|
+
* CLI and the dashboard's verified badge. Exported at the subpath
|
|
27
|
+
* `@kici-dev/engine/provenance/verify`; it is deliberately NOT re-exported from
|
|
28
|
+
* the engine barrel (the barrel must stay free of the `jose` dependency).
|
|
29
|
+
*/
|
|
30
|
+
/** Browser-safe base64 → bytes (no Buffer — this module is imported by the dashboard). */
|
|
31
|
+
function b64ToBytes(b64) {
|
|
32
|
+
return Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Verify a KiCI provenance bundle offline. Returns a structured result; throws
|
|
36
|
+
* only on a programming-level error, never for a verification failure (a failed
|
|
37
|
+
* verification is `verified:false` with populated `failures`).
|
|
38
|
+
*/
|
|
39
|
+
async function verifyKiciBundle(opts) {
|
|
40
|
+
const checks = {
|
|
41
|
+
schema: "skipped",
|
|
42
|
+
jwt: "skipped",
|
|
43
|
+
dsse: "skipped",
|
|
44
|
+
buildContext: "skipped",
|
|
45
|
+
digest: "skipped"
|
|
46
|
+
};
|
|
47
|
+
const failures = [];
|
|
48
|
+
if (opts.bundle?.mediaType !== "application/vnd.kici.provenance.bundle+json;version=0.1") return {
|
|
49
|
+
verified: false,
|
|
50
|
+
mode: "sigstore",
|
|
51
|
+
checks,
|
|
52
|
+
failures: ["mode_b_unsupported"]
|
|
53
|
+
};
|
|
54
|
+
const parsed = kiciBundleSchema.safeParse(opts.bundle);
|
|
55
|
+
if (!parsed.success) {
|
|
56
|
+
checks.schema = "fail";
|
|
57
|
+
return {
|
|
58
|
+
verified: false,
|
|
59
|
+
mode: "kici",
|
|
60
|
+
checks,
|
|
61
|
+
failures: ["bundle_schema_invalid"]
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const bundle = parsed.data;
|
|
65
|
+
checks.schema = "pass";
|
|
66
|
+
const statementBytes = b64ToBytes(bundle.dsseEnvelope.payload);
|
|
67
|
+
let statement;
|
|
68
|
+
const stmt = kiciProvenanceStatementSchema.safeParse(JSON.parse(new TextDecoder().decode(statementBytes)));
|
|
69
|
+
if (!stmt.success) {
|
|
70
|
+
checks.schema = "fail";
|
|
71
|
+
failures.push("statement_schema_invalid");
|
|
72
|
+
} else statement = stmt.data;
|
|
73
|
+
let claims;
|
|
74
|
+
try {
|
|
75
|
+
const { payload } = await jwtVerify(bundle.verificationMaterial.identityToken, createLocalJWKSet(opts.jwks), {
|
|
76
|
+
issuer: opts.expectedIssuer,
|
|
77
|
+
audience: opts.expectedAudience
|
|
78
|
+
});
|
|
79
|
+
claims = payload;
|
|
80
|
+
checks.jwt = "pass";
|
|
81
|
+
} catch {
|
|
82
|
+
checks.jwt = "fail";
|
|
83
|
+
failures.push("identity_token_invalid");
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const pubJwk = bundle.verificationMaterial.publicKey;
|
|
87
|
+
const thumbprint = await calculateJwkThumbprint(pubJwk, "sha256");
|
|
88
|
+
if (bundle.dsseEnvelope.signatures[0].keyid !== thumbprint) throw new Error("keyid does not match public-key thumbprint");
|
|
89
|
+
const key = await importJWK(pubJwk, "ES256");
|
|
90
|
+
if (!await crypto.subtle.verify({
|
|
91
|
+
name: "ECDSA",
|
|
92
|
+
hash: "SHA-256"
|
|
93
|
+
}, key, b64ToBytes(bundle.dsseEnvelope.signatures[0].sig), dssePae(bundle.dsseEnvelope.payloadType, statementBytes))) throw new Error("bad signature");
|
|
94
|
+
checks.dsse = "pass";
|
|
95
|
+
} catch {
|
|
96
|
+
checks.dsse = "fail";
|
|
97
|
+
failures.push("dsse_signature_invalid");
|
|
98
|
+
}
|
|
99
|
+
if (statement && claims) {
|
|
100
|
+
const ok = crossCheckBuildContext(statement, claims);
|
|
101
|
+
checks.buildContext = ok ? "pass" : "fail";
|
|
102
|
+
if (!ok) failures.push("build_context_mismatch");
|
|
103
|
+
} else {
|
|
104
|
+
checks.buildContext = "fail";
|
|
105
|
+
failures.push("build_context_uncheckable");
|
|
106
|
+
}
|
|
107
|
+
if (opts.expectedDigest && statement) {
|
|
108
|
+
const ok = checkSubjectDigest(statement, opts.expectedDigest);
|
|
109
|
+
checks.digest = ok ? "pass" : "fail";
|
|
110
|
+
if (!ok) failures.push("subject_digest_mismatch");
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
verified: checks.schema === "pass" && checks.jwt === "pass" && checks.dsse === "pass" && checks.buildContext === "pass" && checks.digest !== "fail",
|
|
114
|
+
mode: "kici",
|
|
115
|
+
checks,
|
|
116
|
+
claims,
|
|
117
|
+
statement,
|
|
118
|
+
failures
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** The statement's build context must equal the (server-truth) JWT claims. */
|
|
122
|
+
function crossCheckBuildContext(statement, claims) {
|
|
123
|
+
const bd = statement.predicate.buildDefinition;
|
|
124
|
+
const wf = bd.externalParameters.workflow;
|
|
125
|
+
const ip = bd.internalParameters ?? {};
|
|
126
|
+
return wf.repository === claims.repository && wf.ref === claims.ref && wf.path === claims.workflow_ref && ip.commit === claims.sha && ip.runId === claims.kici_run_id && ip.jobId === claims.kici_job_id;
|
|
127
|
+
}
|
|
128
|
+
/** At least one subject must carry a digest matching the supplied artifact digest. */
|
|
129
|
+
function checkSubjectDigest(statement, expected) {
|
|
130
|
+
return statement.subject.some((s) => s.digest[expected.alg] === expected.hex);
|
|
131
|
+
}
|
|
132
|
+
//#endregion
|
|
133
|
+
export { verifyKiciBundle };
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
package/dist/provider/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
//#region src/provider/lock-file-parse-error.ts
|
|
3
3
|
/**
|
|
4
4
|
* Thrown by a LockFileFetcher when a lock file is present at the repo ref but
|
|
@@ -8,6 +8,8 @@ import "../chunk-gOLHoazu.js";
|
|
|
8
8
|
* `lock_resolution` init-failure run.
|
|
9
9
|
*/
|
|
10
10
|
var LockFileParseError = class LockFileParseError extends Error {
|
|
11
|
+
repoIdentifier;
|
|
12
|
+
ref;
|
|
11
13
|
name = "LockFileParseError";
|
|
12
14
|
constructor(repoIdentifier, ref, message) {
|
|
13
15
|
super(message);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
package/dist/provider/types.d.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* These types are the foundation for all provider interfaces.
|
|
5
5
|
* Keep this minimal -- only types needed by multiple interfaces belong here.
|
|
6
6
|
*/
|
|
7
|
-
/** Identifies a git hosting provider, generic webhook source, or
|
|
8
|
-
export type ProviderType = 'github' | 'gitlab' | 'bitbucket' | 'generic' | '
|
|
7
|
+
/** Identifies a git hosting provider, generic webhook source, or local filesystem (`file://`) source. */
|
|
8
|
+
export type ProviderType = 'github' | 'gitlab' | 'bitbucket' | 'generic' | 'local';
|
|
9
9
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/provider/types.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
package/dist/secrets/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
package/dist/secrets/types.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
export {};
|
package/dist/trigger/matcher.js
CHANGED