@kici-dev/agent 0.6.1 → 0.7.0
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/config.d.ts +38 -38
- package/dist/eval-runner.js +1866 -0
- package/dist/execution/dep-installer.d.ts +28 -7
- package/dist/execution/eval-context.d.ts +114 -0
- package/dist/execution/global-eval-types.d.ts +26 -0
- package/dist/execution/job-runner.d.ts +23 -75
- package/dist/execution/npm-registry-config.d.ts +6 -0
- package/dist/execution/rule-evaluator.d.ts +2 -1
- package/dist/execution/sandbox/bare-metal-sandbox.d.ts +6 -0
- package/dist/execution/sandbox/container-hardening.d.ts +8 -0
- package/dist/execution/sandbox/container-sandbox.d.ts +9 -0
- package/dist/execution/sandbox/eval-dispatch.d.ts +28 -0
- package/dist/execution/sandbox/eval-fork-runner.d.ts +43 -0
- package/dist/execution/sandbox/eval-runner.d.ts +21 -0
- package/dist/execution/sandbox/fork-runner.d.ts +23 -0
- package/dist/execution/sandbox/ipc-protocol.d.ts +82 -8
- package/dist/execution/sandbox/job-network.d.ts +91 -0
- package/dist/execution/sandbox/log-masker.d.ts +38 -0
- package/dist/execution/sandbox/types.d.ts +6 -0
- package/dist/execution/sandbox/workflow-runner.d.ts +1 -1
- package/dist/execution/source-packer.d.ts +4 -4
- package/dist/execution/source-restore.d.ts +28 -13
- package/dist/execution/workflow-loader.d.ts +16 -13
- package/dist/execution/yarnrc-berry-config.d.ts +6 -4
- package/dist/index.js +83 -40
- package/dist/provenance/statement-builder.d.ts +19 -8
- package/dist/server.js +1527 -1665
- package/dist/workflow-runner-bundle.js +1105 -184
- package/dist/workflow-runner.js +395 -149
- package/dist/ws/orchestrator-client.d.ts +4 -0
- package/package.json +6 -5
- package/sbom.spdx.json +66 -66
package/dist/index.js
CHANGED
|
@@ -105,6 +105,10 @@ const configSchema = z.object({
|
|
|
105
105
|
sandboxHardened: z.string().default("true").transform((s) => s !== "false"),
|
|
106
106
|
sandboxReadonlyRootfs: z.string().default("false").transform((s) => s === "true"),
|
|
107
107
|
sandboxUser: z.string().optional(),
|
|
108
|
+
runnerUser: z.string().optional(),
|
|
109
|
+
runnerDebugStdio: z.string().default("false").transform((s) => s === "true"),
|
|
110
|
+
sandboxNetworkIsolation: z.string().default("true").transform((s) => s !== "false"),
|
|
111
|
+
allowInstallScripts: z.string().default("false").transform((s) => s === "true"),
|
|
108
112
|
sandboxPidsLimit: z.coerce.number().int().positive().default(512),
|
|
109
113
|
sandboxMemoryBytes: z.coerce.number().int().positive().default(2147483648),
|
|
110
114
|
sandboxNanoCpus: z.coerce.number().int().positive().default(2e9),
|
|
@@ -159,6 +163,10 @@ const envDef = defineEnv({
|
|
|
159
163
|
sandboxHardened: "KICI_SANDBOX_HARDENED",
|
|
160
164
|
sandboxReadonlyRootfs: "KICI_SANDBOX_READONLY_ROOTFS",
|
|
161
165
|
sandboxUser: "KICI_SANDBOX_USER",
|
|
166
|
+
runnerUser: "KICI_RUNNER_USER",
|
|
167
|
+
runnerDebugStdio: "KICI_RUNNER_DEBUG_STDIO",
|
|
168
|
+
sandboxNetworkIsolation: "KICI_SANDBOX_NETWORK_ISOLATION",
|
|
169
|
+
allowInstallScripts: "KICI_ALLOW_INSTALL_SCRIPTS",
|
|
162
170
|
sandboxPidsLimit: "KICI_SANDBOX_PIDS_LIMIT",
|
|
163
171
|
sandboxMemoryBytes: "KICI_SANDBOX_MEMORY_BYTES",
|
|
164
172
|
sandboxNanoCpus: "KICI_SANDBOX_NANO_CPUS",
|
|
@@ -212,6 +220,10 @@ const envDef = defineEnv({
|
|
|
212
220
|
* - KICI_SCALER_CLAIM_CODE (optional single-use claim code the agent exchanges for its own ephemeral credentials before registering; ignored when KICI_AGENT_TOKEN is set)
|
|
213
221
|
* - KICI_SCALER_IDLE_TIMEOUT (ms, default 5000) — how long a scaler-managed agent waits before shutdown after going idle
|
|
214
222
|
* - KICI_SCALER_PENDING_DISPATCH_TIMEOUT (ms, default 60000) — extended idle window when register.ack signals a queued bound job
|
|
223
|
+
* - KICI_RUNNER_USER (optional, uid | uid:gid | name) — run the bare-metal runner child as a dedicated user instead of the agent's own
|
|
224
|
+
* - KICI_ALLOW_INSTALL_SCRIPTS (default: false) — re-enable package lifecycle scripts during the `.kici/` dependency install
|
|
225
|
+
* - KICI_SANDBOX_NETWORK_ISOLATION (default: true) — RFC1918 + cloud-metadata egress filtering for nested job containers
|
|
226
|
+
* - KICI_RUNNER_DEBUG_STDIO (default: false) — echo the runner child's raw stdio onto the agent's stderr
|
|
215
227
|
* - KICI_EXECUTION_MODE (optional, options: container | bare-metal | firecracker) — override the runner's mode-pick logic
|
|
216
228
|
* - KICI_CONCURRENCY_WAIT_TIMEOUT_MS (default: 3_600_000) — workflow-runner timeout when long-polling for a slot-release follow-up `concurrency.ack`
|
|
217
229
|
* - KICI_AGENT_BETWEEN_JOBS_RESET_COMMAND (optional) — host-reset command run between jobs on a reused agent (fail-open)
|
|
@@ -220,10 +232,23 @@ const envDef = defineEnv({
|
|
|
220
232
|
* - KICI_AGENT_ORPHAN_CLEANUP (default: true) — reap a finished job's leaked process tree (bare-metal); false = only signal the runner child
|
|
221
233
|
* - KICI_AGENT_DRAIN_ON_RESET_FAILURE (default: false) — drain the agent after repeated consecutive reset failures
|
|
222
234
|
*/
|
|
235
|
+
/**
|
|
236
|
+
* Env vars the boot-time unknown-KICI_* validator tolerates **only** under
|
|
237
|
+
* `NODE_ENV=test`. `KICI_SKIP_DB_TESTS` is the vitest Postgres harness's
|
|
238
|
+
* opt-out (`scripts/db-test-postgres.ts`), so a suite run with it set must not
|
|
239
|
+
* fail the agent's own config tests. Mirrors the orchestrator's list, which
|
|
240
|
+
* already carries it. Under any other NODE_ENV the allowance is empty, so a
|
|
241
|
+
* production boot with a stray one still fails the validator.
|
|
242
|
+
*/
|
|
243
|
+
const TEST_ONLY_ENV_VARS = ["KICI_SKIP_DB_TESTS"];
|
|
223
244
|
function loadConfig() {
|
|
224
245
|
const data = envDef.parse();
|
|
225
246
|
if (!data.scalerManaged && !data.agentToken) validateNoReservedLabels(data.labels, "KICI_LABELS");
|
|
226
|
-
validateUnknownKiciVars([
|
|
247
|
+
validateUnknownKiciVars([
|
|
248
|
+
...envDef.listKnownEnvVars(),
|
|
249
|
+
...LOGGER_ENV_VARS,
|
|
250
|
+
...process.env.NODE_ENV === "test" ? TEST_ONLY_ENV_VARS : []
|
|
251
|
+
]);
|
|
227
252
|
return {
|
|
228
253
|
...data,
|
|
229
254
|
agentId: data.agentId ?? `${hostname()}-${randomUUID().slice(0, 8)}`
|
|
@@ -390,10 +415,12 @@ function redactNpmOutput(input, tokens) {
|
|
|
390
415
|
*
|
|
391
416
|
* `nodeLinker: node-modules` makes berry lay down a real `node_modules` tree
|
|
392
417
|
* (no PnP `.pnp.cjs`), so the agent's packer / restore / sibling-walk /
|
|
393
|
-
* workflow-loader work unchanged. `enableScripts: false`
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* `--ignore-scripts`.
|
|
418
|
+
* workflow-loader work unchanged. `enableScripts: false` keeps dependency
|
|
419
|
+
* lifecycle scripts from running at all — for every install, not only one
|
|
420
|
+
* against a private registry — the same security model as npm/pnpm/classic
|
|
421
|
+
* `--ignore-scripts`. An operator opts back in with
|
|
422
|
+
* `KICI_ALLOW_INSTALL_SCRIPTS=true`, which arrives here as
|
|
423
|
+
* `ignoreScripts: false`.
|
|
397
424
|
*
|
|
398
425
|
* Reuses the same `ApplyNpmRegistryConfigArgs` / `ApplyNpmRegistryConfigResult`
|
|
399
426
|
* shapes as the npm overlay so `dep-installer` can pick either by flavor.
|
|
@@ -440,8 +467,8 @@ async function applyYarnrcBerryConfig(args) {
|
|
|
440
467
|
};
|
|
441
468
|
const tokenEnv = {};
|
|
442
469
|
const tokensForRedaction = [];
|
|
470
|
+
if (args.ignoreScripts !== false) merged.enableScripts = false;
|
|
443
471
|
if (hasPrivateRegistry) {
|
|
444
|
-
merged.enableScripts = false;
|
|
445
472
|
const npmScopes = { ...doc.npmScopes ?? {} };
|
|
446
473
|
for (let i = 0; i < registries.length; i++) {
|
|
447
474
|
const reg = registries[i];
|
|
@@ -787,9 +814,11 @@ function isAbsoluteRel(rel) {
|
|
|
787
814
|
* Security: the install runs with an isolated per-invocation cache/store
|
|
788
815
|
* directory to prevent cache poisoning across build jobs — a malicious
|
|
789
816
|
* package.json in one repo cannot taint the cache used by subsequent builds.
|
|
790
|
-
* The
|
|
791
|
-
*
|
|
792
|
-
*
|
|
817
|
+
* The install runs with `--ignore-scripts` for every package manager. A
|
|
818
|
+
* lifecycle script in a committed `package.json` is customer code the agent
|
|
819
|
+
* never agreed to execute: it would run wherever the install runs, which for a
|
|
820
|
+
* step-child install is the process holding the job's secrets. Operators who
|
|
821
|
+
* genuinely need it set `KICI_ALLOW_INSTALL_SCRIPTS=true` on the agent.
|
|
793
822
|
*/
|
|
794
823
|
const logger$3 = createLogger({ prefix: "dep-installer" });
|
|
795
824
|
const execFileAsync = promisify(execFile);
|
|
@@ -825,9 +854,11 @@ async function detectKiciYarnFlavor(repoRoot, kiciDir) {
|
|
|
825
854
|
* between build jobs; the directory is removed after installation.
|
|
826
855
|
*
|
|
827
856
|
* If `opts.npmRegistries` / `opts.installEnvSecrets` is provided, a job-scoped
|
|
828
|
-
* `.kici/.npmrc` overlay is synthesized for the install
|
|
829
|
-
*
|
|
830
|
-
*
|
|
857
|
+
* `.kici/.npmrc` overlay is synthesized for the install and restored in
|
|
858
|
+
* `finally`.
|
|
859
|
+
*
|
|
860
|
+
* Lifecycle scripts are disabled for every package manager unless the operator
|
|
861
|
+
* set `opts.allowInstallScripts`.
|
|
831
862
|
*
|
|
832
863
|
* @param kiciDir - Path to the `.kici/` directory containing package.json.
|
|
833
864
|
* @param opts - Optional registry / installEnv / repoRoot configuration.
|
|
@@ -849,13 +880,15 @@ async function installDeps(kiciDir, opts = {}) {
|
|
|
849
880
|
yarnFlavor
|
|
850
881
|
});
|
|
851
882
|
const startTime = Date.now();
|
|
852
|
-
const
|
|
883
|
+
const ignoreScripts = opts.allowInstallScripts !== true;
|
|
884
|
+
const baseEnv = opts.baseEnv ?? process.env;
|
|
853
885
|
const isBerry = packageManager === PackageManager.Yarn && yarnFlavor === YarnFlavor.Berry;
|
|
854
886
|
const registryConfig = isBerry ? await applyYarnrcBerryConfig({
|
|
855
887
|
kiciDir,
|
|
856
888
|
npmRegistries: opts.npmRegistries,
|
|
857
889
|
installEnvSecrets: opts.installEnvSecrets,
|
|
858
|
-
jobIdShort: opts.jobIdShort ?? "00000000"
|
|
890
|
+
jobIdShort: opts.jobIdShort ?? "00000000",
|
|
891
|
+
ignoreScripts
|
|
859
892
|
}) : await applyNpmRegistryConfig({
|
|
860
893
|
kiciDir,
|
|
861
894
|
npmRegistries: opts.npmRegistries,
|
|
@@ -865,22 +898,26 @@ async function installDeps(kiciDir, opts = {}) {
|
|
|
865
898
|
try {
|
|
866
899
|
if (packageManager === PackageManager.Pnpm) await runPnpmInstall({
|
|
867
900
|
kiciDir,
|
|
868
|
-
|
|
869
|
-
registryConfig
|
|
901
|
+
ignoreScripts,
|
|
902
|
+
registryConfig,
|
|
903
|
+
baseEnv
|
|
870
904
|
});
|
|
871
905
|
else if (isBerry) await runYarnBerryInstall({
|
|
872
906
|
kiciDir,
|
|
873
|
-
registryConfig
|
|
907
|
+
registryConfig,
|
|
908
|
+
baseEnv
|
|
874
909
|
});
|
|
875
910
|
else if (packageManager === PackageManager.Yarn) await runYarnInstall({
|
|
876
911
|
kiciDir,
|
|
877
|
-
|
|
878
|
-
registryConfig
|
|
912
|
+
ignoreScripts,
|
|
913
|
+
registryConfig,
|
|
914
|
+
baseEnv
|
|
879
915
|
});
|
|
880
916
|
else await runNpmInstall({
|
|
881
917
|
kiciDir,
|
|
882
|
-
|
|
883
|
-
registryConfig
|
|
918
|
+
ignoreScripts,
|
|
919
|
+
registryConfig,
|
|
920
|
+
baseEnv
|
|
884
921
|
});
|
|
885
922
|
} catch (e) {
|
|
886
923
|
const tokens = registryConfig.tokensForRedaction;
|
|
@@ -890,8 +927,8 @@ async function installDeps(kiciDir, opts = {}) {
|
|
|
890
927
|
} finally {
|
|
891
928
|
await registryConfig.cleanup();
|
|
892
929
|
}
|
|
893
|
-
if (packageManager === PackageManager.Pnpm && await kiciHasLocalProtocolDeps(kiciDir)) await buildWorkspaceClosure(repoRoot);
|
|
894
|
-
if (packageManager === PackageManager.Yarn) await buildYarnWorkspaceClosure(repoRoot, kiciDir, yarnFlavor);
|
|
930
|
+
if (packageManager === PackageManager.Pnpm && await kiciHasLocalProtocolDeps(kiciDir)) await buildWorkspaceClosure(repoRoot, baseEnv);
|
|
931
|
+
if (packageManager === PackageManager.Yarn) await buildYarnWorkspaceClosure(repoRoot, kiciDir, yarnFlavor, baseEnv);
|
|
895
932
|
const durationMs = Date.now() - startTime;
|
|
896
933
|
process.stderr.write(`[dep-installer:trace] install complete: ${durationMs}ms\n`);
|
|
897
934
|
logger$3.info("Deps installed inline", {
|
|
@@ -899,20 +936,26 @@ async function installDeps(kiciDir, opts = {}) {
|
|
|
899
936
|
durationMs
|
|
900
937
|
});
|
|
901
938
|
}
|
|
902
|
-
/**
|
|
903
|
-
|
|
904
|
-
|
|
939
|
+
/**
|
|
940
|
+
* Build the Node binary directory onto PATH so spawned tools find `node`.
|
|
941
|
+
*
|
|
942
|
+
* `baseEnv` is the caller's declared environment for the subprocess. It
|
|
943
|
+
* defaults to `process.env` because inside the runner child that IS the
|
|
944
|
+
* sanitized job environment; an agent-process caller passes a sanitized base.
|
|
945
|
+
*/
|
|
946
|
+
function envWithNodeOnPath(extraEnv, nodeDir, baseEnv = process.env) {
|
|
947
|
+
const { NODE_ENV: _NODE_ENV, ...restEnv } = baseEnv;
|
|
905
948
|
return {
|
|
906
949
|
...restEnv,
|
|
907
950
|
...extraEnv,
|
|
908
|
-
PATH: `${nodeDir}${process.platform === "win32" ? ";" : ":"}${
|
|
951
|
+
PATH: `${nodeDir}${process.platform === "win32" ? ";" : ":"}${restEnv.PATH ?? ""}`
|
|
909
952
|
};
|
|
910
953
|
}
|
|
911
954
|
/** Run `npm install` in `.kici/` with an isolated cache directory. */
|
|
912
955
|
async function runNpmInstall(args) {
|
|
913
956
|
const { npmCliPath, nodeExe, nodeDir } = resolveNpm();
|
|
914
957
|
const { path: cacheDir, cleanup } = await makeTempDir("npm-cache");
|
|
915
|
-
const env = envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir);
|
|
958
|
+
const env = envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir, args.baseEnv);
|
|
916
959
|
const buildArgs = (...prefix) => {
|
|
917
960
|
const a = [
|
|
918
961
|
...prefix,
|
|
@@ -922,7 +965,7 @@ async function runNpmInstall(args) {
|
|
|
922
965
|
"--no-audit",
|
|
923
966
|
"--no-fund"
|
|
924
967
|
];
|
|
925
|
-
if (args.
|
|
968
|
+
if (args.ignoreScripts) a.push("--ignore-scripts");
|
|
926
969
|
return a;
|
|
927
970
|
};
|
|
928
971
|
try {
|
|
@@ -951,7 +994,7 @@ async function runPnpmInstall(args) {
|
|
|
951
994
|
await assertPnpmAvailable();
|
|
952
995
|
const { nodeDir } = resolveNpm();
|
|
953
996
|
const { path: storeDir, cleanup } = await makeTempDir("pnpm-store");
|
|
954
|
-
const env = envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir);
|
|
997
|
+
const env = envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir, args.baseEnv);
|
|
955
998
|
const argv = [
|
|
956
999
|
"install",
|
|
957
1000
|
`--config.store-dir=${storeDir}`,
|
|
@@ -960,7 +1003,7 @@ async function runPnpmInstall(args) {
|
|
|
960
1003
|
"--config.side-effects-cache=false",
|
|
961
1004
|
PNPM_IGNORE_BUILD_GATE_ARG
|
|
962
1005
|
];
|
|
963
|
-
if (args.
|
|
1006
|
+
if (args.ignoreScripts) argv.push("--ignore-scripts");
|
|
964
1007
|
try {
|
|
965
1008
|
process.stderr.write(`[dep-installer:trace] running: pnpm ${argv.join(" ")}\n`);
|
|
966
1009
|
await execFileAsync("pnpm", argv, {
|
|
@@ -974,7 +1017,7 @@ async function runPnpmInstall(args) {
|
|
|
974
1017
|
}
|
|
975
1018
|
}
|
|
976
1019
|
/** Pure: argv for `yarn install` with an isolated cache folder. */
|
|
977
|
-
function buildYarnInstallArgs(cacheDir,
|
|
1020
|
+
function buildYarnInstallArgs(cacheDir, ignoreScripts) {
|
|
978
1021
|
const a = [
|
|
979
1022
|
"install",
|
|
980
1023
|
"--cache-folder",
|
|
@@ -982,7 +1025,7 @@ function buildYarnInstallArgs(cacheDir, hasPrivateRegistry) {
|
|
|
982
1025
|
"--non-interactive",
|
|
983
1026
|
"--no-progress"
|
|
984
1027
|
];
|
|
985
|
-
if (
|
|
1028
|
+
if (ignoreScripts) a.push("--ignore-scripts");
|
|
986
1029
|
return a;
|
|
987
1030
|
}
|
|
988
1031
|
/**
|
|
@@ -997,8 +1040,8 @@ async function runYarnInstall(args) {
|
|
|
997
1040
|
await assertYarnAvailable();
|
|
998
1041
|
const { nodeDir } = resolveNpm();
|
|
999
1042
|
const { path: cacheDir, cleanup } = await makeTempDir("yarn-cache");
|
|
1000
|
-
const env = envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir);
|
|
1001
|
-
const argv = buildYarnInstallArgs(cacheDir, args.
|
|
1043
|
+
const env = envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir, args.baseEnv);
|
|
1044
|
+
const argv = buildYarnInstallArgs(cacheDir, args.ignoreScripts);
|
|
1002
1045
|
try {
|
|
1003
1046
|
process.stderr.write(`[dep-installer:trace] running: yarn ${argv.join(" ")}\n`);
|
|
1004
1047
|
await execFileAsync("yarn", argv, {
|
|
@@ -1028,7 +1071,7 @@ async function runYarnBerryInstall(args) {
|
|
|
1028
1071
|
await assertYarnAvailable();
|
|
1029
1072
|
const { nodeDir } = resolveNpm();
|
|
1030
1073
|
const env = {
|
|
1031
|
-
...envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir),
|
|
1074
|
+
...envWithNodeOnPath(args.registryConfig.extraEnv, nodeDir, args.baseEnv),
|
|
1032
1075
|
COREPACK_ENABLE_DOWNLOAD_PROMPT: "0"
|
|
1033
1076
|
};
|
|
1034
1077
|
const argv = buildYarnBerryInstallArgs();
|
|
@@ -1059,11 +1102,11 @@ async function assertYarnAvailable() {
|
|
|
1059
1102
|
* Deep cross-sibling build chains may build out of strict topological order —
|
|
1060
1103
|
* real `.kici` closures are shallow.
|
|
1061
1104
|
*/
|
|
1062
|
-
async function buildYarnWorkspaceClosure(repoRoot, kiciDir, yarnFlavor) {
|
|
1105
|
+
async function buildYarnWorkspaceClosure(repoRoot, kiciDir, yarnFlavor, baseEnv) {
|
|
1063
1106
|
const siblings = await collectInRepoSiblings(repoRoot, kiciDir, resolveYarnNodeModulesRoot(repoRoot, kiciDir));
|
|
1064
1107
|
if (siblings.length === 0) return;
|
|
1065
1108
|
const { nodeDir } = resolveNpm();
|
|
1066
|
-
const env = envWithNodeOnPath({}, nodeDir);
|
|
1109
|
+
const env = envWithNodeOnPath({}, nodeDir, baseEnv);
|
|
1067
1110
|
for (const rel of [...siblings].reverse()) {
|
|
1068
1111
|
const sibDir = join(repoRoot, rel);
|
|
1069
1112
|
if (!await siblingHasBuildScript(sibDir)) continue;
|
|
@@ -1107,9 +1150,9 @@ async function siblingHasBuildScript(sibDir) {
|
|
|
1107
1150
|
* the subprocess stderr/stdout is folded into the thrown error so the job's
|
|
1108
1151
|
* failure message names the real cause instead of a bare "Command failed".
|
|
1109
1152
|
*/
|
|
1110
|
-
async function buildWorkspaceClosure(repoRoot) {
|
|
1153
|
+
async function buildWorkspaceClosure(repoRoot, baseEnv) {
|
|
1111
1154
|
const { nodeDir } = resolveNpm();
|
|
1112
|
-
const env = envWithNodeOnPath({}, nodeDir);
|
|
1155
|
+
const env = envWithNodeOnPath({}, nodeDir, baseEnv);
|
|
1113
1156
|
const argv = [
|
|
1114
1157
|
"--filter",
|
|
1115
1158
|
"{.kici}^...",
|
|
@@ -52,27 +52,38 @@ export interface LocalBuildContext {
|
|
|
52
52
|
repository: string;
|
|
53
53
|
ref: string;
|
|
54
54
|
sha: string | null;
|
|
55
|
+
/**
|
|
56
|
+
* The token's `workflow_ref` claim (`<name>@<sha>`) when the orchestrator
|
|
57
|
+
* supplied one. NOT a global workflow's clone ref — those are never equal,
|
|
58
|
+
* and comparing them is what a cross-check would have failed on.
|
|
59
|
+
*/
|
|
55
60
|
workflowRef: string;
|
|
56
61
|
runId: string;
|
|
57
62
|
jobId: string;
|
|
58
63
|
orgId?: string;
|
|
59
64
|
sourceOrigin?: SourceOrigin;
|
|
65
|
+
/** Informational source provider, mirroring the live builder's `provider`. */
|
|
66
|
+
provider?: string;
|
|
67
|
+
/** The orchestrator's provenance issuer, for the `builder.id`. */
|
|
68
|
+
issuer: string;
|
|
60
69
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* the
|
|
64
|
-
* `/orchestrator/unknown` builder id. This field is not verification
|
|
65
|
-
* load-bearing for a deferred bundle: the later token binds to the frozen
|
|
66
|
-
* statement by hash, not by field-for-field cross-check.
|
|
70
|
+
* The orchestrator instance id, for the `builder.id`. Absent when the
|
|
71
|
+
* orchestrator sent no provenance context, which yields the honest
|
|
72
|
+
* `/orchestrator/unknown` the local guess has always produced.
|
|
67
73
|
*/
|
|
68
|
-
|
|
74
|
+
orchestratorId?: string;
|
|
69
75
|
}
|
|
70
76
|
/**
|
|
71
77
|
* Build a frozen SLSA v1.0 provenance statement from agent-local job context,
|
|
72
78
|
* for a deferred attestation (no minted identity token yet). Marks
|
|
73
79
|
* `attestationOrigin: 'deferred'` in the internal parameters. The caller
|
|
74
80
|
* DSSE-signs the returned statement immediately and computes its statement hash
|
|
75
|
-
* — the
|
|
81
|
+
* — one of the two bindings the later OIDC mint commits to.
|
|
82
|
+
*
|
|
83
|
+
* Emits the same fields `buildProvenanceStatement` emits, so a statement frozen
|
|
84
|
+
* from an orchestrator-supplied context is field-for-field what a live mint
|
|
85
|
+
* would have produced. That is what lets the orchestrator cross-check the
|
|
86
|
+
* statement against its own run row before signing anything that commits to it.
|
|
76
87
|
*/
|
|
77
88
|
export declare function buildLocalProvenanceStatement(input: {
|
|
78
89
|
context: LocalBuildContext;
|