Files
Samuel AttardandClaude 8d424eb34d build: run the TypeScript scripts under script/ with plain node (#54168)
ts-node was used as a CLI for a handful of TypeScript scripts under
script/. Those now rely on the type stripping built into Node.js instead:

- script/gen-filenames, check-patch-diff, run-clang-tidy and the release
  helpers (find-github-release, upload-to-github, github-token, types)
  are renamed to .mts and invoked with `node`. They use
  import.meta.dirname and explicit .mts / .js specifiers, and
  tsconfig.script.json moves to nodenext with verbatimModuleSyntax so
  tsc checks them the way Node runs them.
- The documented minimum Node.js for building goes from 22.12 to 22.18,
  the first 22.x release with type stripping on by default.
- script/codesign/gen-trust.ts and its trust.xml template are deleted;
  nothing has invoked them since generate-identity.sh switched to a
  user-scoped keychain in #50058.
- oxfmt, oxlint, lint-staged and .gitattributes learn about .mts.

ts-node itself stays for now because the spec runner still loads specs
through its require hook.

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-21 13:09:47 -07:00

84 lines
2.7 KiB
TypeScript

import { createTokenAuth } from '@octokit/auth-token';
import type { ElectronReleaseRepo } from './types.mts';
const cachedTokens = Object.create(null);
const SUDOWOODO_OIDC_AUDIENCE = 'sudowoodo-broker';
async function getActionsIdToken(): Promise<string> {
const { ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN } = process.env;
if (!ACTIONS_ID_TOKEN_REQUEST_URL || !ACTIONS_ID_TOKEN_REQUEST_TOKEN) {
throw new Error(
'ACTIONS_ID_TOKEN_REQUEST_URL/_TOKEN not set — the job needs `permissions: id-token: write` to mint an OIDC token for the sudowoodo exchange'
);
}
const resp = await fetch(ACTIONS_ID_TOKEN_REQUEST_URL + '&audience=' + SUDOWOODO_OIDC_AUDIENCE, {
headers: {
authorization: 'Bearer ' + ACTIONS_ID_TOKEN_REQUEST_TOKEN
}
});
if (!resp.ok) {
throw new Error(`Failed to request an Actions OIDC token, got status: ${resp.status}`);
}
const { value } = (await resp.json()) as { value: string };
return value;
}
async function ensureToken(repo: ElectronReleaseRepo) {
if (!cachedTokens[repo]) {
cachedTokens[repo] = await (async () => {
const { ELECTRON_GITHUB_TOKEN, SUDOWOODO_EXCHANGE_URL } = process.env;
if (ELECTRON_GITHUB_TOKEN) {
return ELECTRON_GITHUB_TOKEN;
}
if (SUDOWOODO_EXCHANGE_URL) {
const idToken = await getActionsIdToken();
const resp = await fetch(SUDOWOODO_EXCHANGE_URL + '?repo=' + repo, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + idToken
}
});
if (resp.status !== 200) {
console.error('bad sudowoodo exchange response code:', resp.status);
throw new Error('non-200 status code received from sudowoodo exchange function');
}
try {
return JSON.parse(await resp.text()).token;
} catch {
// Swallow as the error could include the token
throw new Error('Unexpected error parsing sudowoodo exchange response');
}
}
throw new Error('Could not find or fetch a valid GitHub Auth Token');
})();
}
}
export const createGitHubTokenStrategy = (repo: ElectronReleaseRepo) => () => {
let tokenAuth: ReturnType<typeof createTokenAuth> | null = null;
async function ensureTokenAuth(): Promise<ReturnType<typeof createTokenAuth>> {
if (!tokenAuth) {
await ensureToken(repo);
tokenAuth = createTokenAuth(cachedTokens[repo]);
}
return tokenAuth;
}
async function auth() {
return await (
await ensureTokenAuth()
)();
}
const hook: ReturnType<typeof createTokenAuth>['hook'] = async (...args) => {
const a = await ensureTokenAuth();
return (a as any).hook(...args);
};
auth.hook = hook;
return auth;
};