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.
@@ -26568,7 +26568,7 @@ ${facts.stderr}`))
26568
26568
  return null;
26569
26569
  }
26570
26570
  function isCommandUnavailable(facts, countsRead) {
26571
- if (facts.exitCode === 127 || facts.exitCode === 126)
26571
+ if (facts.exitCode === 127 || facts.exitCode === 126 || facts.exitCode === 125)
26572
26572
  return true;
26573
26573
  if (countsRead)
26574
26574
  return false;
@@ -26791,6 +26791,79 @@ var init_classify2 = __esm({
26791
26791
  const p = int(passed);
26792
26792
  return { tests_passed: p, tests_failed: Math.max(0, t - p) };
26793
26793
  }
26794
+ },
26795
+ {
26796
+ /**
26797
+ * BARE TAP — assertion lines with no plan and no summary comment (TERM-1138).
26798
+ *
26799
+ * LAST ON PURPOSE. It is the loosest reader here, so anything that a more specific
26800
+ * one can read must reach that one first: `node --test` and node-tap both emit `ok`
26801
+ * lines AND a closing summary, and their readers are ordered above for that reason.
26802
+ * Moving this up would have it answer for both.
26803
+ *
26804
+ * A hand-rolled harness prints neither summary — it emits its assertions and stops.
26805
+ * That is what morebetterltd/wheelhouse does: thirty `ok N - …` lines, exit 0, and
26806
+ * before this every one of those runs reported `counts-unparsed`, which the claim
26807
+ * page renders as "RESULT UNREADABLE — THE SUITE EXITED 0" over a suite that passed.
26808
+ *
26809
+ * ON THE MISSING PLAN LINE. TAP requires `1..N` so a reader can tell a finished
26810
+ * stream from a truncated one, and there is none here, so this cannot prove the
26811
+ * suite reached its end. That is a real limit and it is NOT a reason to refuse,
26812
+ * because it holds this format to a standard no reader in this file meets — the
26813
+ * jest reader greps a line out of stdout that a repository could `echo` without
26814
+ * running anything. These are format adapters, not a trust boundary; the boundary
26815
+ * is that the command is the repository's own or is refused a signature.
26816
+ *
26817
+ * CONTIGUOUS FROM 1, which buys self-consistency rather than security:
26818
+ *
26819
+ * - starting at 1 rejects a TRUNCATION. `testOutputTail` keeps the last lines, so
26820
+ * a stream beginning `ok 47` is the middle of a longer run and counting it would
26821
+ * report three tests for a suite that ran fifty.
26822
+ * - no gaps rejects prose that happens to carry the word, and a stream interleaved
26823
+ * with another's.
26824
+ * - anchored with no leading space rejects TAP SUBTESTS, which indent. Counting
26825
+ * those would double them against their parent.
26826
+ */
26827
+ runner: "bare TAP",
26828
+ read: (out) => {
26829
+ let n = 0;
26830
+ let failed = 0;
26831
+ let passed = 0;
26832
+ let plan = null;
26833
+ for (const line of out.split("\n")) {
26834
+ if (/^Bail out!/.test(line))
26835
+ return null;
26836
+ const p = /^(\d+)\.\.(\d+)\s*$/.exec(line);
26837
+ if (p) {
26838
+ const declared = Number(p[2]) - Number(p[1]) + 1;
26839
+ if (plan !== null && plan !== declared)
26840
+ return null;
26841
+ plan = declared;
26842
+ continue;
26843
+ }
26844
+ const m = /^(not )?ok (\d+)(?:\s|$)/.exec(line);
26845
+ if (!m)
26846
+ continue;
26847
+ if (Number(m[2]) !== n + 1)
26848
+ return null;
26849
+ n += 1;
26850
+ const directive = /#\s*(skip|todo)\b/i.exec(line);
26851
+ const kind = directive?.[1]?.toLowerCase();
26852
+ if (kind === "skip")
26853
+ continue;
26854
+ if (m[1] !== void 0) {
26855
+ if (kind !== "todo")
26856
+ failed += 1;
26857
+ continue;
26858
+ }
26859
+ passed += 1;
26860
+ }
26861
+ if (n === 0)
26862
+ return null;
26863
+ if (plan !== null && plan !== n)
26864
+ return null;
26865
+ return { tests_passed: passed, tests_failed: failed };
26866
+ }
26794
26867
  }
26795
26868
  ];
26796
26869
  SUPPORTED_RUNNERS = READERS.map((r) => r.runner);
@@ -26877,6 +26950,10 @@ function scrubEnv(source, opts) {
26877
26950
  env["GOCACHE"] = join20(jailHome, ".cache", "go-build");
26878
26951
  env["GOFLAGS"] = "-modcacherw";
26879
26952
  env["CARGO_HOME"] = join20(jailHome, ".cargo");
26953
+ const bundle = join20(jailHome, ".bundle");
26954
+ env["GEM_HOME"] = bundle;
26955
+ env["BUNDLE_PATH"] = bundle;
26956
+ env["BUNDLE_APP_CONFIG"] = bundle;
26880
26957
  const proxy = opts.proxyUrl ?? DEAD_PROXY;
26881
26958
  env["HTTP_PROXY"] = proxy;
26882
26959
  env["HTTPS_PROXY"] = proxy;
@@ -27177,6 +27254,19 @@ var init_egressProxy = __esm({
27177
27254
  "static.crates.io",
27178
27255
  "index.crates.io",
27179
27256
  "crates.io",
27257
+ // TERM-1139. `ruby` has had an image since the mapping existed and `bundle install`
27258
+ // as its derived command, and this host was missing — so every ruby repo could start
27259
+ // and could never install. Install is the ONLY step with a network grant at all, so a
27260
+ // denial here is terminal, not a slow path.
27261
+ //
27262
+ // One entry, not two: `hostAllowed` is dot-anchored SUFFIX matching, so this covers
27263
+ // `index.rubygems.org` as well. Listing that separately would advertise the grant as
27264
+ // narrower than it is, which the `github.com` note below rejects for the same reason.
27265
+ "rubygems.org",
27266
+ // TERM-1139, added with the `dotnet` image mapping. `dotnet restore` fetches from
27267
+ // NuGet; the coupling test refuses a mapped runtime whose registry is unreachable, and
27268
+ // it caught this one the moment the image landed.
27269
+ "api.nuget.org",
27180
27270
  // Git dependencies. Approved by Eric 2026-07-22 after a live run measured the
27181
27271
  // chokepoint working under load (20 events, 16 allowed / 4 denied by host).
27182
27272
  //
@@ -28558,7 +28648,7 @@ function imageForRuntime(runtime, override, version2) {
28558
28648
  return override;
28559
28649
  const shape = RUNTIME_IMAGES[runtime];
28560
28650
  if (!shape) {
28561
- 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.`);
28651
+ 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.`);
28562
28652
  }
28563
28653
  if (version2 === void 0 || version2 === null)
28564
28654
  return unversionedImage(shape);
@@ -28809,7 +28899,37 @@ var init_execute = __esm({
28809
28899
  },
28810
28900
  go: { repository: "golang", suffix: "-bookworm", defaultVersion: "1.23", declaredIsFloor: true },
28811
28901
  ruby: { repository: "ruby", suffix: "-bookworm", defaultVersion: "3.3", declaredIsFloor: false },
28812
- rust: { repository: "rust", suffix: "-bookworm", defaultVersion: "1", declaredIsFloor: true }
28902
+ rust: { repository: "rust", suffix: "-bookworm", defaultVersion: "1", declaredIsFloor: true },
28903
+ /**
28904
+ * TERM-1139. `dotnet` was unmapped alongside `jvm`, and the recorded reason was that
28905
+ * neither had "a single obvious base image (gradle vs maven, sdk vs runtime)". That
28906
+ * reason holds for jvm and it does NOT hold here, which is why only this half moved.
28907
+ *
28908
+ * "sdk vs runtime" answers itself: the derived commands are `dotnet restore` and
28909
+ * `dotnet test`, and neither exists on the runtime image. There is no second build
28910
+ * tool competing for the slot the way maven and gradle compete for jvm's — and since
28911
+ * no official image carries both of those, jvm genuinely cannot be served by one key.
28912
+ *
28913
+ * MEASURED, not chosen by tag: `mcr.microsoft.com/dotnet/sdk:8.0` carries `git` and
28914
+ * `dotnet` (881MB). `git` is the property the whole `image-tooling-live` test exists
28915
+ * for, and `eclipse-temurin:21-jdk` was rejected here for lacking it.
28916
+ *
28917
+ * The tag shape fits without touching the builder: the SDK publishes a tag per
28918
+ * version, so `repository:VERSION` is a real image at every version envspec can
28919
+ * derive, with no suffix. That is NOT true of the maven images, where the leading
28920
+ * tag component is maven's version and Java's sits in the suffix.
28921
+ *
28922
+ * `declaredIsFloor` is true on the same reasoning as go and rust: an SDK builds
28923
+ * older target frameworks, so booting 8.0 for a repo asking 6.0 is the supported
28924
+ * case rather than a substitution. A repo asking for something NEWER than our
28925
+ * default still refuses, which is where TERM-643 put that line.
28926
+ */
28927
+ dotnet: {
28928
+ repository: "mcr.microsoft.com/dotnet/sdk",
28929
+ suffix: "",
28930
+ defaultVersion: "8.0",
28931
+ declaredIsFloor: true
28932
+ }
28813
28933
  };
28814
28934
  unversionedImage = (shape) => `${shape.repository}:${shape.defaultVersion}${shape.suffix}`;
28815
28935
  TAG_VERSION = /^\d+(?:\.\d+){0,2}$/;
@@ -29503,14 +29623,24 @@ function answerDidItPass(r) {
29503
29623
  const passed = r.status === "verified" && r.outcome !== null && isGreen(r.outcome);
29504
29624
  return { passed, summary: renderVerdictLine(r), lookAt: r.preview?.url ?? null };
29505
29625
  }
29506
- var RUN_TEST_COMMAND_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS;
29626
+ var RUN_TEST_COMMAND_SOURCES, RUN_IMAGE_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS;
29507
29627
  var init_result = __esm({
29508
29628
  "../../packages/envrun/dist/result.js"() {
29509
29629
  "use strict";
29510
29630
  init_dist2();
29511
29631
  init_classify2();
29512
29632
  init_venueDescriptor();
29513
- RUN_TEST_COMMAND_SOURCES = [...TEST_COMMAND_SOURCES, "developer-declared"];
29633
+ RUN_TEST_COMMAND_SOURCES = [
29634
+ ...TEST_COMMAND_SOURCES,
29635
+ "developer-declared",
29636
+ "operator-declared"
29637
+ ];
29638
+ RUN_IMAGE_SOURCES = [
29639
+ "detected",
29640
+ "none",
29641
+ "operator-declared",
29642
+ "developer-declared"
29643
+ ];
29514
29644
  RUN_RESULT_SCHEMA = "terminalhire.verification-run/1";
29515
29645
  RUN_RESULT_FIELDS = [
29516
29646
  "schema",
@@ -29535,6 +29665,7 @@ var init_result = __esm({
29535
29665
  "preview",
29536
29666
  "containerImage",
29537
29667
  "containerImageDigest",
29668
+ "imageSource",
29538
29669
  "leaksClean",
29539
29670
  "venue"
29540
29671
  ];
@@ -29567,6 +29698,9 @@ var init_result = __esm({
29567
29698
  preview: (r) => r.preview === null ? null : `preview ${r.preview.url}`,
29568
29699
  containerImage: (r) => r.containerImage === null ? null : `image ${r.containerImage}`,
29569
29700
  containerImageDigest: (r) => r.containerImageDigest === null ? null : `image digest ${r.containerImageDigest}`,
29701
+ // Shown only when a human chose the environment. `detected` is the ordinary case and
29702
+ // saying so on every run would train the reader to skip the line that matters.
29703
+ imageSource: (r) => r.imageSource === "detected" || r.imageSource === "none" ? null : `image source ${r.imageSource} (not signed)`,
29570
29704
  leaksClean: (r) => r.leaksClean === null ? null : r.leaksClean ? null : "WARNING labelled Docker objects survived teardown",
29571
29705
  // Absent on most runs, so it prints only when there is something to say. Silence
29572
29706
  // here is the honest rendering of "no venue answered": a placeholder line would
@@ -29693,12 +29827,23 @@ function toAcceptancePredicate(pair, opts = {}) {
29693
29827
  if (why !== null)
29694
29828
  return refuse3("test-command-origin-unattested", `the ${side} run ${why}`);
29695
29829
  }
29696
- if (patched.testCommandSource === "developer-declared") {
29697
- return refuse3("test-command-origin-unattested", "the developer supplied the test command (unreachable \u2014 the source rules above cover it)");
29830
+ if (patched.testCommandSource === "developer-declared" || patched.testCommandSource === "operator-declared") {
29831
+ 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)`);
29698
29832
  }
29699
29833
  if (baseline.testCommandSource !== patched.testCommandSource) {
29700
29834
  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.`);
29701
29835
  }
29836
+ for (const [side, source, image] of [
29837
+ ["patched", patched.imageSource, patched.containerImage],
29838
+ ["baseline", baseline.imageSource, baseline.containerImage]
29839
+ ]) {
29840
+ const why = IMAGE_SOURCE_IS_SIGNABLE[source](image);
29841
+ if (why !== null)
29842
+ return refuse3("image-origin-unattested", `the ${side} run ${why}`);
29843
+ }
29844
+ if (baseline.imageSource !== patched.imageSource) {
29845
+ 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.`);
29846
+ }
29702
29847
  if (baseline.containerImage !== patched.containerImage) {
29703
29848
  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.`);
29704
29849
  }
@@ -29755,7 +29900,7 @@ function signRunStatement(predicate, privateKey, keyid) {
29755
29900
  const statement = createAcceptanceStatement(predicate);
29756
29901
  return { statement, envelope: signStatement(statement, privateKey, keyid) };
29757
29902
  }
29758
- 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;
29903
+ 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;
29759
29904
  var init_attestation2 = __esm({
29760
29905
  "../../packages/envrun/dist/attestation.js"() {
29761
29906
  "use strict";
@@ -29811,11 +29956,25 @@ var init_attestation2 = __esm({
29811
29956
  // The party under verification chose it, and no signed member can say so. Per ADR-005
29812
29957
  // Decision 2, emit nothing rather than pick the closest word.
29813
29958
  "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.",
29959
+ // US, out of band, per posting — the twin of `IMAGE_SOURCE_IS_SIGNABLE['operator-declared']`
29960
+ // and refusing for the same reason. `founder-declared` is the nearest signed member and it
29961
+ // is still false: the poster did not choose this, we did, and signing our own choice under
29962
+ // the counterparty's name is the specific false attribution the `developer-declared` entry
29963
+ // above exists to refuse. Decision 2 — emit nothing rather than pick the closest word.
29964
+ "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.",
29814
29965
  // `none` means nobody chose a command, so a command beside it is a contradiction. Shadowed
29815
29966
  // today — `thrun.ts` sets `none` only when the derived command is null, and `no-test-command`
29816
29967
  // fires first — but that coupling runs through `runEnvironmentSpec` and lives in no type.
29817
29968
  none: (command) => command === null ? null : `records its command source as \`none\` \u2014 nobody chose one \u2014 beside the command ${JSON.stringify(command)}`
29818
29969
  };
29970
+ IMAGE_SOURCE_IS_SIGNABLE = {
29971
+ detected: () => null,
29972
+ "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.",
29973
+ "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.",
29974
+ // `none` means no image was booted, so an image name beside it is a contradiction — the
29975
+ // `SOURCE_IS_SIGNABLE.none` argument, applied to the other field.
29976
+ none: (image) => image === null ? null : `records its image source as \`none\` \u2014 nothing was booted \u2014 beside the image ${JSON.stringify(image)}`
29977
+ };
29819
29978
  ATTEST_REFUSAL_REASONS = [
29820
29979
  "our-environment-failed",
29821
29980
  "run-was-refused",
@@ -29857,7 +30016,11 @@ var init_attestation2 = __esm({
29857
30016
  // The signed triple must be reproducible from what it names — see the guard.
29858
30017
  "patch-binding-incomplete",
29859
30018
  "outcome-contradicts-counts",
29860
- "test-command-origin-unattested"
30019
+ "test-command-origin-unattested",
30020
+ // The environment half of the pair above. `pair-disagrees-on-image` compares image NAMES;
30021
+ // this one asks who CHOSE the name, which no comparison of the two halves can reveal when
30022
+ // both were handed the same override.
30023
+ "image-origin-unattested"
29861
30024
  ];
29862
30025
  refuse3 = (reason, detail) => ({
29863
30026
  ok: false,
@@ -30361,13 +30524,20 @@ function gcpBootArgv(p) {
30361
30524
  // steal". Attaching an account removes that, so the safety now rests on two things,
30362
30525
  // and this change MUST land together with proof #2 — never ahead of it:
30363
30526
  //
30364
- // 1. `--no-scopes` + ZERO project roles bound the BLAST RADIUS of a lifted token.
30365
- // No scopes → the OAuth access-token endpoint serves nothing (measured,
30366
- // TERM-706); zero roles → the token authorizes no GCP API. But it is NOT
30367
- // valueless: it is the attestation evidence itself, so a lifted token still
30368
- // authorizes a false claim about WHERE a run happened (the steal-a-true-token
30369
- // attack in the item-2 spike). `--no-scopes` stays because it removes lateral
30370
- // GCP access; it does not make losing the identity token cheap.
30527
+ // 1. `--no-scopes` and a NARROW grant set bound the BLAST RADIUS of a lifted
30528
+ // token. No scopes → the OAuth access-token endpoint serves nothing
30529
+ // (measured, TERM-706). This said "ZERO project roles" until 2026-09-18, and
30530
+ // that was never true of the account we ship: measured live, `venue-identity@`
30531
+ // holds `roles/confidentialcomputing.workloadUser` on the project and
30532
+ // `roles/artifactregistry.reader` on the `venue-images` repository alone —
30533
+ // the same two grants the Confidential Space note below already named, so this
30534
+ // file contradicted itself. Neither reaches a second repository, a bucket or
30535
+ // another VM, which is the property "zero roles" was reaching for. But the
30536
+ // token is NOT valueless: it is the attestation evidence itself, so a lifted
30537
+ // token still authorizes a false claim about WHERE a run happened (the
30538
+ // steal-a-true-token attack in the item-2 spike). `--no-scopes` stays because
30539
+ // it removes lateral GCP access; it does not make losing the identity token
30540
+ // cheap.
30371
30541
  // 2. The untrusted code cannot reach the metadata server to lift the token at all.
30372
30542
  // The test step runs `--network=none`; the install step runs on an `--internal`
30373
30543
  // network whose only egress is a CONNECT-only, registry-allowlisted proxy that
@@ -34057,6 +34227,9 @@ function refusedRun(fields) {
34057
34227
  treeDigest: null,
34058
34228
  baselinePatchSha256: null,
34059
34229
  testCommandSource: "none",
34230
+ // Nothing was booted, so nobody chose an image. Same reasoning as `containerImage: null`
34231
+ // below: it must not read as an image we picked and cannot name.
34232
+ imageSource: "none",
34060
34233
  boundaryRefusals: fields.boundaryRefusals,
34061
34234
  touchedPaths: fields.touchedPaths,
34062
34235
  preview: null,
@@ -34405,7 +34578,7 @@ async function runVerification(req, ctx) {
34405
34578
  // that `founder-declared` (as this did for one review round) signs the counterparty's
34406
34579
  // name onto the developer's choice, which is worse than laundering it as `detected`:
34407
34580
  // it is a specific false attribution inside a field a reviewer trusts.
34408
- testCommandSource: req.testCommandOverride !== void 0 ? req.testCommandOverrideOrigin === "founder" ? "founder-declared" : "developer-declared" : derived.testCommand === null ? "none" : "detected",
34581
+ testCommandSource: req.testCommandOverride !== void 0 ? req.testCommandOverrideOrigin === "founder" ? "founder-declared" : req.testCommandOverrideOrigin === "operator" ? "operator-declared" : "developer-declared" : derived.testCommand === null ? "none" : "detected",
34409
34582
  boundaryRefusals: [],
34410
34583
  touchedPaths: pre.touchedPaths,
34411
34584
  preview: null,
@@ -34415,6 +34588,12 @@ async function runVerification(req, ctx) {
34415
34588
  // that measures one; a run without it is recordable but not attestable —
34416
34589
  // `toAcceptancePredicate` refuses `missing-image-digest` (TERM-893).
34417
34590
  containerImageDigest: null,
34591
+ // The image half of the provenance pair above. `detected` means the runtime mapping
34592
+ // chose the environment; an override names the human. Defaulting an unstated origin to
34593
+ // `developer-declared` is deliberate and matches `testCommandSource`: `th run --image`
34594
+ // runs on the developer's machine, judging the developer's work, so attributing it to
34595
+ // the operator would sign our name onto their choice.
34596
+ imageSource: req.image === void 0 ? "detected" : req.imageOrigin === "operator" ? "operator-declared" : "developer-declared",
34418
34597
  leaksClean: verdict.leaks.clean,
34419
34598
  // Built from the LEASE, over the client that ran the steps — never from
34420
34599
  // `req.placement`, which is a request. `venueDescriptor.ts` carries the
@@ -35370,6 +35549,7 @@ __export(dist_exports, {
35370
35549
  REDACTED_TARGET_SHA: () => REDACTED_TARGET_SHA,
35371
35550
  RELEASED_LEASE_CENSUS_REASON: () => RELEASED_LEASE_CENSUS_REASON,
35372
35551
  REPO_DIGEST_RE: () => REPO_DIGEST_RE,
35552
+ RUN_IMAGE_SOURCES: () => RUN_IMAGE_SOURCES,
35373
35553
  RUN_LABEL_KEY: () => RUN_LABEL_KEY,
35374
35554
  RUN_RESULT_FIELDS: () => RUN_RESULT_FIELDS,
35375
35555
  RUN_RESULT_SCHEMA: () => RUN_RESULT_SCHEMA,