terminalhire 0.42.21 → 0.42.22

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.
@@ -26050,7 +26050,7 @@ ${facts.stderr}`))
26050
26050
  return null;
26051
26051
  }
26052
26052
  function isCommandUnavailable(facts, countsRead) {
26053
- if (facts.exitCode === 127 || facts.exitCode === 126)
26053
+ if (facts.exitCode === 127 || facts.exitCode === 126 || facts.exitCode === 125)
26054
26054
  return true;
26055
26055
  if (countsRead)
26056
26056
  return false;
@@ -26273,6 +26273,79 @@ var init_classify2 = __esm({
26273
26273
  const p = int(passed);
26274
26274
  return { tests_passed: p, tests_failed: Math.max(0, t - p) };
26275
26275
  }
26276
+ },
26277
+ {
26278
+ /**
26279
+ * BARE TAP — assertion lines with no plan and no summary comment (TERM-1138).
26280
+ *
26281
+ * LAST ON PURPOSE. It is the loosest reader here, so anything that a more specific
26282
+ * one can read must reach that one first: `node --test` and node-tap both emit `ok`
26283
+ * lines AND a closing summary, and their readers are ordered above for that reason.
26284
+ * Moving this up would have it answer for both.
26285
+ *
26286
+ * A hand-rolled harness prints neither summary — it emits its assertions and stops.
26287
+ * That is what morebetterltd/wheelhouse does: thirty `ok N - …` lines, exit 0, and
26288
+ * before this every one of those runs reported `counts-unparsed`, which the claim
26289
+ * page renders as "RESULT UNREADABLE — THE SUITE EXITED 0" over a suite that passed.
26290
+ *
26291
+ * ON THE MISSING PLAN LINE. TAP requires `1..N` so a reader can tell a finished
26292
+ * stream from a truncated one, and there is none here, so this cannot prove the
26293
+ * suite reached its end. That is a real limit and it is NOT a reason to refuse,
26294
+ * because it holds this format to a standard no reader in this file meets — the
26295
+ * jest reader greps a line out of stdout that a repository could `echo` without
26296
+ * running anything. These are format adapters, not a trust boundary; the boundary
26297
+ * is that the command is the repository's own or is refused a signature.
26298
+ *
26299
+ * CONTIGUOUS FROM 1, which buys self-consistency rather than security:
26300
+ *
26301
+ * - starting at 1 rejects a TRUNCATION. `testOutputTail` keeps the last lines, so
26302
+ * a stream beginning `ok 47` is the middle of a longer run and counting it would
26303
+ * report three tests for a suite that ran fifty.
26304
+ * - no gaps rejects prose that happens to carry the word, and a stream interleaved
26305
+ * with another's.
26306
+ * - anchored with no leading space rejects TAP SUBTESTS, which indent. Counting
26307
+ * those would double them against their parent.
26308
+ */
26309
+ runner: "bare TAP",
26310
+ read: (out) => {
26311
+ let n = 0;
26312
+ let failed = 0;
26313
+ let passed = 0;
26314
+ let plan = null;
26315
+ for (const line of out.split("\n")) {
26316
+ if (/^Bail out!/.test(line))
26317
+ return null;
26318
+ const p = /^(\d+)\.\.(\d+)\s*$/.exec(line);
26319
+ if (p) {
26320
+ const declared = Number(p[2]) - Number(p[1]) + 1;
26321
+ if (plan !== null && plan !== declared)
26322
+ return null;
26323
+ plan = declared;
26324
+ continue;
26325
+ }
26326
+ const m = /^(not )?ok (\d+)(?:\s|$)/.exec(line);
26327
+ if (!m)
26328
+ continue;
26329
+ if (Number(m[2]) !== n + 1)
26330
+ return null;
26331
+ n += 1;
26332
+ const directive = /#\s*(skip|todo)\b/i.exec(line);
26333
+ const kind = directive?.[1]?.toLowerCase();
26334
+ if (kind === "skip")
26335
+ continue;
26336
+ if (m[1] !== void 0) {
26337
+ if (kind !== "todo")
26338
+ failed += 1;
26339
+ continue;
26340
+ }
26341
+ passed += 1;
26342
+ }
26343
+ if (n === 0)
26344
+ return null;
26345
+ if (plan !== null && plan !== n)
26346
+ return null;
26347
+ return { tests_passed: passed, tests_failed: failed };
26348
+ }
26276
26349
  }
26277
26350
  ];
26278
26351
  SUPPORTED_RUNNERS = READERS.map((r) => r.runner);
@@ -26359,6 +26432,10 @@ function scrubEnv(source, opts) {
26359
26432
  env["GOCACHE"] = join18(jailHome, ".cache", "go-build");
26360
26433
  env["GOFLAGS"] = "-modcacherw";
26361
26434
  env["CARGO_HOME"] = join18(jailHome, ".cargo");
26435
+ const bundle = join18(jailHome, ".bundle");
26436
+ env["GEM_HOME"] = bundle;
26437
+ env["BUNDLE_PATH"] = bundle;
26438
+ env["BUNDLE_APP_CONFIG"] = bundle;
26362
26439
  const proxy = opts.proxyUrl ?? DEAD_PROXY;
26363
26440
  env["HTTP_PROXY"] = proxy;
26364
26441
  env["HTTPS_PROXY"] = proxy;
@@ -26659,6 +26736,19 @@ var init_egressProxy = __esm({
26659
26736
  "static.crates.io",
26660
26737
  "index.crates.io",
26661
26738
  "crates.io",
26739
+ // TERM-1139. `ruby` has had an image since the mapping existed and `bundle install`
26740
+ // as its derived command, and this host was missing — so every ruby repo could start
26741
+ // and could never install. Install is the ONLY step with a network grant at all, so a
26742
+ // denial here is terminal, not a slow path.
26743
+ //
26744
+ // One entry, not two: `hostAllowed` is dot-anchored SUFFIX matching, so this covers
26745
+ // `index.rubygems.org` as well. Listing that separately would advertise the grant as
26746
+ // narrower than it is, which the `github.com` note below rejects for the same reason.
26747
+ "rubygems.org",
26748
+ // TERM-1139, added with the `dotnet` image mapping. `dotnet restore` fetches from
26749
+ // NuGet; the coupling test refuses a mapped runtime whose registry is unreachable, and
26750
+ // it caught this one the moment the image landed.
26751
+ "api.nuget.org",
26662
26752
  // Git dependencies. Approved by Eric 2026-07-22 after a live run measured the
26663
26753
  // chokepoint working under load (20 events, 16 allowed / 4 denied by host).
26664
26754
  //
@@ -28040,7 +28130,7 @@ function imageForRuntime(runtime, override, version) {
28040
28130
  return override;
28041
28131
  const shape = RUNTIME_IMAGES[runtime];
28042
28132
  if (!shape) {
28043
- throw new RunRefusalError(`no container image is mapped for runtime ${JSON.stringify(runtime)}. Refusing to run it in the Node image: a missing interpreter surfaces as "command not found", which the classifier reads as tests-failed \u2014 a false red blamed on the repo.`);
28133
+ throw new RunRefusalError(`no container image is mapped for runtime ${JSON.stringify(runtime)}. Refusing to run it in the Node image: a bare "command not found" exits 127, which classifyVerification already owns as ours \u2014 but a test script that RUNS and fails inside on the missing tool exits with its own status and prints to stdout, and that falls through to tests-failed \u2014 a false red blamed on the repo.`);
28044
28134
  }
28045
28135
  if (version === void 0 || version === null)
28046
28136
  return unversionedImage(shape);
@@ -28291,7 +28381,37 @@ var init_execute = __esm({
28291
28381
  },
28292
28382
  go: { repository: "golang", suffix: "-bookworm", defaultVersion: "1.23", declaredIsFloor: true },
28293
28383
  ruby: { repository: "ruby", suffix: "-bookworm", defaultVersion: "3.3", declaredIsFloor: false },
28294
- rust: { repository: "rust", suffix: "-bookworm", defaultVersion: "1", declaredIsFloor: true }
28384
+ rust: { repository: "rust", suffix: "-bookworm", defaultVersion: "1", declaredIsFloor: true },
28385
+ /**
28386
+ * TERM-1139. `dotnet` was unmapped alongside `jvm`, and the recorded reason was that
28387
+ * neither had "a single obvious base image (gradle vs maven, sdk vs runtime)". That
28388
+ * reason holds for jvm and it does NOT hold here, which is why only this half moved.
28389
+ *
28390
+ * "sdk vs runtime" answers itself: the derived commands are `dotnet restore` and
28391
+ * `dotnet test`, and neither exists on the runtime image. There is no second build
28392
+ * tool competing for the slot the way maven and gradle compete for jvm's — and since
28393
+ * no official image carries both of those, jvm genuinely cannot be served by one key.
28394
+ *
28395
+ * MEASURED, not chosen by tag: `mcr.microsoft.com/dotnet/sdk:8.0` carries `git` and
28396
+ * `dotnet` (881MB). `git` is the property the whole `image-tooling-live` test exists
28397
+ * for, and `eclipse-temurin:21-jdk` was rejected here for lacking it.
28398
+ *
28399
+ * The tag shape fits without touching the builder: the SDK publishes a tag per
28400
+ * version, so `repository:VERSION` is a real image at every version envspec can
28401
+ * derive, with no suffix. That is NOT true of the maven images, where the leading
28402
+ * tag component is maven's version and Java's sits in the suffix.
28403
+ *
28404
+ * `declaredIsFloor` is true on the same reasoning as go and rust: an SDK builds
28405
+ * older target frameworks, so booting 8.0 for a repo asking 6.0 is the supported
28406
+ * case rather than a substitution. A repo asking for something NEWER than our
28407
+ * default still refuses, which is where TERM-643 put that line.
28408
+ */
28409
+ dotnet: {
28410
+ repository: "mcr.microsoft.com/dotnet/sdk",
28411
+ suffix: "",
28412
+ defaultVersion: "8.0",
28413
+ declaredIsFloor: true
28414
+ }
28295
28415
  };
28296
28416
  unversionedImage = (shape) => `${shape.repository}:${shape.defaultVersion}${shape.suffix}`;
28297
28417
  TAG_VERSION = /^\d+(?:\.\d+){0,2}$/;
@@ -28985,14 +29105,24 @@ function answerDidItPass(r) {
28985
29105
  const passed = r.status === "verified" && r.outcome !== null && isGreen(r.outcome);
28986
29106
  return { passed, summary: renderVerdictLine(r), lookAt: r.preview?.url ?? null };
28987
29107
  }
28988
- var RUN_TEST_COMMAND_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS;
29108
+ var RUN_TEST_COMMAND_SOURCES, RUN_IMAGE_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS;
28989
29109
  var init_result = __esm({
28990
29110
  "../../packages/envrun/dist/result.js"() {
28991
29111
  "use strict";
28992
29112
  init_dist2();
28993
29113
  init_classify2();
28994
29114
  init_venueDescriptor();
28995
- RUN_TEST_COMMAND_SOURCES = [...TEST_COMMAND_SOURCES, "developer-declared"];
29115
+ RUN_TEST_COMMAND_SOURCES = [
29116
+ ...TEST_COMMAND_SOURCES,
29117
+ "developer-declared",
29118
+ "operator-declared"
29119
+ ];
29120
+ RUN_IMAGE_SOURCES = [
29121
+ "detected",
29122
+ "none",
29123
+ "operator-declared",
29124
+ "developer-declared"
29125
+ ];
28996
29126
  RUN_RESULT_SCHEMA = "terminalhire.verification-run/1";
28997
29127
  RUN_RESULT_FIELDS = [
28998
29128
  "schema",
@@ -29017,6 +29147,7 @@ var init_result = __esm({
29017
29147
  "preview",
29018
29148
  "containerImage",
29019
29149
  "containerImageDigest",
29150
+ "imageSource",
29020
29151
  "leaksClean",
29021
29152
  "venue"
29022
29153
  ];
@@ -29049,6 +29180,9 @@ var init_result = __esm({
29049
29180
  preview: (r) => r.preview === null ? null : `preview ${r.preview.url}`,
29050
29181
  containerImage: (r) => r.containerImage === null ? null : `image ${r.containerImage}`,
29051
29182
  containerImageDigest: (r) => r.containerImageDigest === null ? null : `image digest ${r.containerImageDigest}`,
29183
+ // Shown only when a human chose the environment. `detected` is the ordinary case and
29184
+ // saying so on every run would train the reader to skip the line that matters.
29185
+ imageSource: (r) => r.imageSource === "detected" || r.imageSource === "none" ? null : `image source ${r.imageSource} (not signed)`,
29052
29186
  leaksClean: (r) => r.leaksClean === null ? null : r.leaksClean ? null : "WARNING labelled Docker objects survived teardown",
29053
29187
  // Absent on most runs, so it prints only when there is something to say. Silence
29054
29188
  // here is the honest rendering of "no venue answered": a placeholder line would
@@ -29175,12 +29309,23 @@ function toAcceptancePredicate(pair, opts = {}) {
29175
29309
  if (why !== null)
29176
29310
  return refuse3("test-command-origin-unattested", `the ${side} run ${why}`);
29177
29311
  }
29178
- if (patched.testCommandSource === "developer-declared") {
29179
- return refuse3("test-command-origin-unattested", "the developer supplied the test command (unreachable \u2014 the source rules above cover it)");
29312
+ if (patched.testCommandSource === "developer-declared" || patched.testCommandSource === "operator-declared") {
29313
+ return refuse3("test-command-origin-unattested", `${patched.testCommandSource === "developer-declared" ? "the developer" : "an operator"} supplied the test command (unreachable \u2014 the source rules above cover it)`);
29180
29314
  }
29181
29315
  if (baseline.testCommandSource !== patched.testCommandSource) {
29182
29316
  return refuse3("test-command-origin-unattested", `the pair disagrees on where the command came from: baseline ${baseline.testCommandSource}, patched ${patched.testCommandSource}. One signed value cannot describe both.`);
29183
29317
  }
29318
+ for (const [side, source, image] of [
29319
+ ["patched", patched.imageSource, patched.containerImage],
29320
+ ["baseline", baseline.imageSource, baseline.containerImage]
29321
+ ]) {
29322
+ const why = IMAGE_SOURCE_IS_SIGNABLE[source](image);
29323
+ if (why !== null)
29324
+ return refuse3("image-origin-unattested", `the ${side} run ${why}`);
29325
+ }
29326
+ if (baseline.imageSource !== patched.imageSource) {
29327
+ return refuse3("image-origin-unattested", `the pair disagrees on where the image came from: baseline ${baseline.imageSource}, patched ${patched.imageSource}. The environment is part of what the statement says was held constant.`);
29328
+ }
29184
29329
  if (baseline.containerImage !== patched.containerImage) {
29185
29330
  return refuse3("pair-disagrees-on-image", `baseline ran in ${String(baseline.containerImage)} and patched in ${String(patched.containerImage)}. The signed measurement names one image, so a pair from two environments would attribute to the patch whatever the image changed.`);
29186
29331
  }
@@ -29237,7 +29382,7 @@ function signRunStatement(predicate, privateKey, keyid) {
29237
29382
  const statement = createAcceptanceStatement(predicate);
29238
29383
  return { statement, envelope: signStatement(statement, privateKey, keyid) };
29239
29384
  }
29240
- var OUTCOME_TO_BUDGET, BASELINE_IS_A_VERDICT, CONTRADICTS_COUNTS, SOURCE_IS_SIGNABLE, ATTEST_REFUSAL_REASONS, refuse3, LOCAL_MEASUREMENT_PREFIX, REFERENCE_DOMAIN_COMPONENT, REFERENCE_DOMAIN_NAME, REFERENCE_IPV6, REFERENCE_DOMAIN, REFERENCE_PATH_COMPONENT, REPO_DIGEST_RE;
29385
+ var OUTCOME_TO_BUDGET, BASELINE_IS_A_VERDICT, CONTRADICTS_COUNTS, SOURCE_IS_SIGNABLE, IMAGE_SOURCE_IS_SIGNABLE, ATTEST_REFUSAL_REASONS, refuse3, LOCAL_MEASUREMENT_PREFIX, REFERENCE_DOMAIN_COMPONENT, REFERENCE_DOMAIN_NAME, REFERENCE_IPV6, REFERENCE_DOMAIN, REFERENCE_PATH_COMPONENT, REPO_DIGEST_RE;
29241
29386
  var init_attestation2 = __esm({
29242
29387
  "../../packages/envrun/dist/attestation.js"() {
29243
29388
  "use strict";
@@ -29293,11 +29438,25 @@ var init_attestation2 = __esm({
29293
29438
  // The party under verification chose it, and no signed member can say so. Per ADR-005
29294
29439
  // Decision 2, emit nothing rather than pick the closest word.
29295
29440
  "developer-declared": () => "had its test command supplied by the developer whose work is under verification, and the signed vocabulary has no member for that. `founder-declared` would attribute the choice to the other party; `detected` would claim the repo chose it. Both are false.",
29441
+ // US, out of band, per posting — the twin of `IMAGE_SOURCE_IS_SIGNABLE['operator-declared']`
29442
+ // and refusing for the same reason. `founder-declared` is the nearest signed member and it
29443
+ // is still false: the poster did not choose this, we did, and signing our own choice under
29444
+ // the counterparty's name is the specific false attribution the `developer-declared` entry
29445
+ // above exists to refuse. Decision 2 — emit nothing rather than pick the closest word.
29446
+ "operator-declared": () => "had its test command chosen by an operator out of band, and the signed vocabulary has no member for that. Signing it would present a hand-picked command as one the repository chose for itself.",
29296
29447
  // `none` means nobody chose a command, so a command beside it is a contradiction. Shadowed
29297
29448
  // today — `thrun.ts` sets `none` only when the derived command is null, and `no-test-command`
29298
29449
  // fires first — but that coupling runs through `runEnvironmentSpec` and lives in no type.
29299
29450
  none: (command) => command === null ? null : `records its command source as \`none\` \u2014 nobody chose one \u2014 beside the command ${JSON.stringify(command)}`
29300
29451
  };
29452
+ IMAGE_SOURCE_IS_SIGNABLE = {
29453
+ detected: () => null,
29454
+ "operator-declared": () => "had its container image chosen by an operator out of band, and the signed vocabulary has no member for that. Signing it would present a hand-picked environment as the one the runtime mapping selected.",
29455
+ "developer-declared": () => "had its container image supplied by the developer whose work is under verification. A chosen interpreter turns a red suite green as surely as a chosen test command.",
29456
+ // `none` means no image was booted, so an image name beside it is a contradiction — the
29457
+ // `SOURCE_IS_SIGNABLE.none` argument, applied to the other field.
29458
+ none: (image) => image === null ? null : `records its image source as \`none\` \u2014 nothing was booted \u2014 beside the image ${JSON.stringify(image)}`
29459
+ };
29301
29460
  ATTEST_REFUSAL_REASONS = [
29302
29461
  "our-environment-failed",
29303
29462
  "run-was-refused",
@@ -29339,7 +29498,11 @@ var init_attestation2 = __esm({
29339
29498
  // The signed triple must be reproducible from what it names — see the guard.
29340
29499
  "patch-binding-incomplete",
29341
29500
  "outcome-contradicts-counts",
29342
- "test-command-origin-unattested"
29501
+ "test-command-origin-unattested",
29502
+ // The environment half of the pair above. `pair-disagrees-on-image` compares image NAMES;
29503
+ // this one asks who CHOSE the name, which no comparison of the two halves can reveal when
29504
+ // both were handed the same override.
29505
+ "image-origin-unattested"
29343
29506
  ];
29344
29507
  refuse3 = (reason, detail) => ({
29345
29508
  ok: false,
@@ -29843,13 +30006,20 @@ function gcpBootArgv(p) {
29843
30006
  // steal". Attaching an account removes that, so the safety now rests on two things,
29844
30007
  // and this change MUST land together with proof #2 — never ahead of it:
29845
30008
  //
29846
- // 1. `--no-scopes` + ZERO project roles bound the BLAST RADIUS of a lifted token.
29847
- // No scopes → the OAuth access-token endpoint serves nothing (measured,
29848
- // TERM-706); zero roles → the token authorizes no GCP API. But it is NOT
29849
- // valueless: it is the attestation evidence itself, so a lifted token still
29850
- // authorizes a false claim about WHERE a run happened (the steal-a-true-token
29851
- // attack in the item-2 spike). `--no-scopes` stays because it removes lateral
29852
- // GCP access; it does not make losing the identity token cheap.
30009
+ // 1. `--no-scopes` and a NARROW grant set bound the BLAST RADIUS of a lifted
30010
+ // token. No scopes → the OAuth access-token endpoint serves nothing
30011
+ // (measured, TERM-706). This said "ZERO project roles" until 2026-09-18, and
30012
+ // that was never true of the account we ship: measured live, `venue-identity@`
30013
+ // holds `roles/confidentialcomputing.workloadUser` on the project and
30014
+ // `roles/artifactregistry.reader` on the `venue-images` repository alone —
30015
+ // the same two grants the Confidential Space note below already named, so this
30016
+ // file contradicted itself. Neither reaches a second repository, a bucket or
30017
+ // another VM, which is the property "zero roles" was reaching for. But the
30018
+ // token is NOT valueless: it is the attestation evidence itself, so a lifted
30019
+ // token still authorizes a false claim about WHERE a run happened (the
30020
+ // steal-a-true-token attack in the item-2 spike). `--no-scopes` stays because
30021
+ // it removes lateral GCP access; it does not make losing the identity token
30022
+ // cheap.
29853
30023
  // 2. The untrusted code cannot reach the metadata server to lift the token at all.
29854
30024
  // The test step runs `--network=none`; the install step runs on an `--internal`
29855
30025
  // network whose only egress is a CONNECT-only, registry-allowlisted proxy that
@@ -33539,6 +33709,9 @@ function refusedRun(fields) {
33539
33709
  treeDigest: null,
33540
33710
  baselinePatchSha256: null,
33541
33711
  testCommandSource: "none",
33712
+ // Nothing was booted, so nobody chose an image. Same reasoning as `containerImage: null`
33713
+ // below: it must not read as an image we picked and cannot name.
33714
+ imageSource: "none",
33542
33715
  boundaryRefusals: fields.boundaryRefusals,
33543
33716
  touchedPaths: fields.touchedPaths,
33544
33717
  preview: null,
@@ -33887,7 +34060,7 @@ async function runVerification(req, ctx) {
33887
34060
  // that `founder-declared` (as this did for one review round) signs the counterparty's
33888
34061
  // name onto the developer's choice, which is worse than laundering it as `detected`:
33889
34062
  // it is a specific false attribution inside a field a reviewer trusts.
33890
- testCommandSource: req.testCommandOverride !== void 0 ? req.testCommandOverrideOrigin === "founder" ? "founder-declared" : "developer-declared" : derived.testCommand === null ? "none" : "detected",
34063
+ testCommandSource: req.testCommandOverride !== void 0 ? req.testCommandOverrideOrigin === "founder" ? "founder-declared" : req.testCommandOverrideOrigin === "operator" ? "operator-declared" : "developer-declared" : derived.testCommand === null ? "none" : "detected",
33891
34064
  boundaryRefusals: [],
33892
34065
  touchedPaths: pre.touchedPaths,
33893
34066
  preview: null,
@@ -33897,6 +34070,12 @@ async function runVerification(req, ctx) {
33897
34070
  // that measures one; a run without it is recordable but not attestable —
33898
34071
  // `toAcceptancePredicate` refuses `missing-image-digest` (TERM-893).
33899
34072
  containerImageDigest: null,
34073
+ // The image half of the provenance pair above. `detected` means the runtime mapping
34074
+ // chose the environment; an override names the human. Defaulting an unstated origin to
34075
+ // `developer-declared` is deliberate and matches `testCommandSource`: `th run --image`
34076
+ // runs on the developer's machine, judging the developer's work, so attributing it to
34077
+ // the operator would sign our name onto their choice.
34078
+ imageSource: req.image === void 0 ? "detected" : req.imageOrigin === "operator" ? "operator-declared" : "developer-declared",
33900
34079
  leaksClean: verdict.leaks.clean,
33901
34080
  // Built from the LEASE, over the client that ran the steps — never from
33902
34081
  // `req.placement`, which is a request. `venueDescriptor.ts` carries the
@@ -34852,6 +35031,7 @@ __export(dist_exports, {
34852
35031
  REDACTED_TARGET_SHA: () => REDACTED_TARGET_SHA,
34853
35032
  RELEASED_LEASE_CENSUS_REASON: () => RELEASED_LEASE_CENSUS_REASON,
34854
35033
  REPO_DIGEST_RE: () => REPO_DIGEST_RE,
35034
+ RUN_IMAGE_SOURCES: () => RUN_IMAGE_SOURCES,
34855
35035
  RUN_LABEL_KEY: () => RUN_LABEL_KEY,
34856
35036
  RUN_RESULT_FIELDS: () => RUN_RESULT_FIELDS,
34857
35037
  RUN_RESULT_SCHEMA: () => RUN_RESULT_SCHEMA,