mirror of
https://github.com/step-security/harden-runner.git
synced 2026-06-05 21:17:06 +00:00
121 lines
No EOL
3.5 KiB
TypeScript
121 lines
No EOL
3.5 KiB
TypeScript
import * as core from "@actions/core";
|
|
import { HttpClient } from "@actions/http-client";
|
|
import { RequestOptions } from "@actions/http-client/lib/interfaces";
|
|
import { BearerCredentialHandler } from "@actions/http-client/lib/auth";
|
|
import * as crypto from "crypto";
|
|
|
|
const versionSalt = "1.0";
|
|
export const cacheKey = "harden-runner-cacheKey";
|
|
export const cacheFile = "/home/agent/cache.txt";
|
|
|
|
function getCacheApiUrl(resource: string): string {
|
|
const baseUrl: string = process.env["ACTIONS_CACHE_URL"] || "";
|
|
if (!baseUrl) {
|
|
throw new Error("Cache Service Url not found, unable to restore cache.");
|
|
}
|
|
|
|
const url = `${baseUrl}_apis/artifactcache/${resource}`;
|
|
core.debug(`Resource Url: ${url}`);
|
|
return url;
|
|
}
|
|
|
|
function createAcceptHeader(type: string, apiVersion: string): string {
|
|
return `${type};api-version=${apiVersion}`;
|
|
}
|
|
|
|
function getRequestOptions(): RequestOptions {
|
|
const token = process.env["ACTIONS_RUNTIME_TOKEN"] || "";
|
|
|
|
const requestOptions: RequestOptions = {
|
|
headers: {
|
|
Accept: createAcceptHeader("application/json", "6.0-preview.1"),
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
};
|
|
|
|
return requestOptions;
|
|
}
|
|
|
|
function createHttpClient(): HttpClient {
|
|
const token = process.env["ACTIONS_RUNTIME_TOKEN"] || "";
|
|
const bhandler = new BearerCredentialHandler(token);
|
|
return new HttpClient("actions/cache", [bhandler], getRequestOptions());
|
|
}
|
|
|
|
export function getCacheVersion(
|
|
paths: string[],
|
|
compressionMethod?: CompressionMethod
|
|
): string {
|
|
const components = paths.concat(
|
|
!compressionMethod || compressionMethod === CompressionMethod.Gzip
|
|
? []
|
|
: [compressionMethod]
|
|
);
|
|
|
|
// Add salt to cache version to support breaking changes in cache entry
|
|
components.push(versionSalt);
|
|
|
|
return crypto.createHash("sha256").update(components.join("|")).digest("hex");
|
|
}
|
|
|
|
export async function getCacheEntry(
|
|
keys: string[],
|
|
paths: string[],
|
|
options?: InternalCacheOptions
|
|
): Promise<ArtifactCacheEntry | null> {
|
|
const httpClient = createHttpClient();
|
|
const version = getCacheVersion(paths, options?.compressionMethod);
|
|
const resource = `cache?keys=${encodeURIComponent(
|
|
keys.join(",")
|
|
)}&version=${version}`;
|
|
|
|
const response = await httpClient.getJson<ArtifactCacheEntry>(
|
|
getCacheApiUrl(resource)
|
|
);
|
|
if (response.statusCode === 204) {
|
|
throw new Error("Request returned 204 status");
|
|
}
|
|
if (!isSuccessStatusCode(response.statusCode)) {
|
|
throw new Error(`Cache service responded with ${response.statusCode}`);
|
|
}
|
|
|
|
const cacheResult = response.result;
|
|
const cacheDownloadUrl = cacheResult?.archiveLocation;
|
|
if (!cacheDownloadUrl) {
|
|
throw new Error("Cache still be done, but not found.");
|
|
}
|
|
|
|
return cacheResult;
|
|
}
|
|
|
|
export interface InternalCacheOptions {
|
|
compressionMethod?: CompressionMethod;
|
|
cacheSize?: number;
|
|
}
|
|
|
|
export interface ArtifactCacheEntry {
|
|
cacheKey?: string;
|
|
scope?: string;
|
|
creationTime?: string;
|
|
archiveLocation?: string;
|
|
}
|
|
|
|
function isSuccessStatusCode(statusCode?: number): boolean {
|
|
if (!statusCode) {
|
|
return false;
|
|
}
|
|
return statusCode >= 200 && statusCode < 300;
|
|
}
|
|
|
|
export enum CompressionMethod {
|
|
Gzip = "gzip",
|
|
// Long range mode was added to zstd in v1.3.2.
|
|
// This enum is for earlier version of zstd that does not have --long support
|
|
ZstdWithoutLong = "zstd-without-long",
|
|
Zstd = "zstd",
|
|
}
|
|
// Refer: https://github.com/actions/cache/blob/12681847c623a9274356751fdf0a63576ff3f846/src/utils/actionUtils.ts#L53
|
|
const RefKey = "GITHUB_REF";
|
|
export function isValidEvent(): boolean {
|
|
return RefKey in process.env && Boolean(process.env[RefKey]);
|
|
} |