Distinguish GitHub-hosted runners from ones that look hosted

`isHostedRunner` infers hostedness from the runner name and the toolcache path, so it also matches self-hosted runners that are configured to resemble hosted ones. Rename it to `looksLikeHostedRunner` so callers can see they are getting a heuristic, and add `isGitHubHostedRunner`, which reads the `RUNNER_ENVIRONMENT` value the Actions service reports. The existing callers keep the heuristic, so there is no behaviour change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Henry Mercer
2026-09-04 10:03:11 +01:00
parent 5914b031b1
commit ceb85f25b5
5 changed files with 26 additions and 10 deletions

View File

@@ -283,6 +283,19 @@ export function isSelfHostedRunner(env: Env = getEnv()) {
return env.getOptional(ActionsEnvVars.RUNNER_ENVIRONMENT) === "self-hosted";
}
/**
* Whether the job is running on a runner that GitHub hosts, and whose toolcache is therefore thrown
* away once the job has finished.
*
* Unlike `looksLikeHostedRunner`, this is based on what the service reports for the job rather than
* on how the runner's filesystem happens to be laid out, so it does not match self-hosted runners
* that are configured to resemble hosted ones, such as those that mount a persistent volume at
* `/opt/hostedtoolcache`.
*/
export function isGitHubHostedRunner(env: Env = getEnv()) {
return env.getOptional(ActionsEnvVars.RUNNER_ENVIRONMENT) === "github-hosted";
}
/** Determines whether the workflow trigger is `dynamic`. */
export function isDynamicWorkflow(env: Env = getEnv()): boolean {
return getWorkflowEventName(env) === "dynamic";

View File

@@ -5,7 +5,7 @@ import * as core from "@actions/core";
import { getOptionalInput, isDefaultSetup } from "./actions-util";
import { EnvVar } from "./environment";
import { Logger } from "./logging";
import { isHostedRunner, tryGetFolderBytes } from "./util";
import { looksLikeHostedRunner, tryGetFolderBytes } from "./util";
/**
* Returns the total size of all the specified paths.
@@ -109,7 +109,7 @@ export function getDependencyCachingEnabled(): CachingKind {
if (dependencyCaching !== undefined) return getCachingKind(dependencyCaching);
// On self-hosted runners which may have dependencies installed centrally, disable caching by default
if (!isHostedRunner()) return CachingKind.None;
if (!looksLikeHostedRunner()) return CachingKind.None;
// Disable in advanced workflows by default.
if (!isDefaultSetup()) return CachingKind.None;

View File

@@ -90,9 +90,8 @@ import {
Result,
Success,
Failure,
isHostedRunner,
looksLikeHostedRunner,
} from "./util";
export { type Config } from "./config/action-config";
/**
@@ -938,7 +937,7 @@ export async function isTrapCachingEnabled(
if (trapCaching !== undefined) return trapCaching === "true";
// On self-hosted runners which may have slow network access, disable TRAP caching by default.
if (!isHostedRunner()) return false;
if (!looksLikeHostedRunner()) return false;
// If overlay analysis is enabled, then disable TRAP caching since overlay analysis supersedes it.
// This change is gated behind a feature flag.

View File

@@ -842,9 +842,13 @@ export async function checkForTimeout() {
* directory with the name hostedtoolcache which is present on
* GitHub-hosted runners.
*
* @returns true iff the runner is hosted by GitHub
* Since this is a heuristic over how the runner happens to be named and laid out, it also matches
* self-hosted runners that are configured to resemble hosted ones. Prefer
* `isGitHubHostedRunner` when you need the answer the Actions service reports.
*
* @returns true iff the runner looks like it is hosted by GitHub
*/
export function isHostedRunner() {
export function looksLikeHostedRunner() {
return (
// Name of the runner on hosted Windows runners
process.env["RUNNER_NAME"]?.includes("Hosted Agent") ||