Skip to content

Commit 9ca67d2

Browse files
fengmk2claude
andcommitted
refactor: use scoped registry config and env vars for GitHub auth
- Configure @voidzero-dev scoped registry for GitHub Package Registry - Use environment variables for auth token instead of writing to .npmrc - Prevents token theft by subsequent scripts - Switch all imports from namespace to named imports - Remove unused NPM_REGISTRY constant Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 61a6d97 commit 9ca67d2

10 files changed

Lines changed: 171 additions & 170 deletions

File tree

dist/index.mjs

Lines changed: 63 additions & 63 deletions
Large diffs are not rendered by default.

src/cache-restore.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as cache from '@actions/cache'
2-
import * as glob from '@actions/glob'
3-
import * as core from '@actions/core'
4-
import * as os from 'node:os'
1+
import { restoreCache as restoreCacheAction } from '@actions/cache'
2+
import { hashFiles } from '@actions/glob'
3+
import { warning, info, debug, saveState, setOutput } from '@actions/core'
4+
import { arch, platform } from 'node:os'
55
import type { Inputs } from './types.js'
66
import { State, Outputs } from './types.js'
77
import { detectLockFile, getCacheDirectories } from './utils.js'
@@ -10,57 +10,57 @@ export async function restoreCache(inputs: Inputs): Promise<void> {
1010
// Detect lock file
1111
const lockFile = detectLockFile(inputs.cacheDependencyPath)
1212
if (!lockFile) {
13-
core.warning('No lock file found. Skipping cache restore.')
14-
core.setOutput(Outputs.CacheHit, false)
13+
warning('No lock file found. Skipping cache restore.')
14+
setOutput(Outputs.CacheHit, false)
1515
return
1616
}
1717

18-
core.info(`Using lock file: ${lockFile.path}`)
18+
info(`Using lock file: ${lockFile.path}`)
1919

2020
// Get cache directories based on lock file type
2121
const cachePaths = await getCacheDirectories(lockFile.type)
2222
if (!cachePaths.length) {
23-
core.warning('No cache directories found. Skipping cache restore.')
24-
core.setOutput(Outputs.CacheHit, false)
23+
warning('No cache directories found. Skipping cache restore.')
24+
setOutput(Outputs.CacheHit, false)
2525
return
2626
}
2727

28-
core.debug(`Cache paths: ${cachePaths.join(', ')}`)
29-
core.saveState(State.CachePaths, JSON.stringify(cachePaths))
28+
debug(`Cache paths: ${cachePaths.join(', ')}`)
29+
saveState(State.CachePaths, JSON.stringify(cachePaths))
3030

3131
// Generate cache key: vite-plus-{platform}-{arch}-{lockfile-type}-{hash}
32-
const platform = process.env.RUNNER_OS || os.platform()
33-
const arch = os.arch()
34-
const fileHash = await glob.hashFiles(lockFile.path)
32+
const runnerOS = process.env.RUNNER_OS || platform()
33+
const runnerArch = arch()
34+
const fileHash = await hashFiles(lockFile.path)
3535

3636
if (!fileHash) {
3737
throw new Error(`Failed to generate hash for lock file: ${lockFile.path}`)
3838
}
3939

40-
const primaryKey = `vite-plus-${platform}-${arch}-${lockFile.type}-${fileHash}`
40+
const primaryKey = `vite-plus-${runnerOS}-${runnerArch}-${lockFile.type}-${fileHash}`
4141
const restoreKeys = [
42-
`vite-plus-${platform}-${arch}-${lockFile.type}-`,
43-
`vite-plus-${platform}-${arch}-`,
42+
`vite-plus-${runnerOS}-${runnerArch}-${lockFile.type}-`,
43+
`vite-plus-${runnerOS}-${runnerArch}-`,
4444
]
4545

46-
core.debug(`Primary key: ${primaryKey}`)
47-
core.debug(`Restore keys: ${restoreKeys.join(', ')}`)
46+
debug(`Primary key: ${primaryKey}`)
47+
debug(`Restore keys: ${restoreKeys.join(', ')}`)
4848

49-
core.saveState(State.CachePrimaryKey, primaryKey)
49+
saveState(State.CachePrimaryKey, primaryKey)
5050

5151
// Attempt to restore cache
52-
const matchedKey = await cache.restoreCache(
52+
const matchedKey = await restoreCacheAction(
5353
cachePaths,
5454
primaryKey,
5555
restoreKeys
5656
)
5757

5858
if (matchedKey) {
59-
core.info(`Cache restored from key: ${matchedKey}`)
60-
core.saveState(State.CacheMatchedKey, matchedKey)
61-
core.setOutput(Outputs.CacheHit, true)
59+
info(`Cache restored from key: ${matchedKey}`)
60+
saveState(State.CacheMatchedKey, matchedKey)
61+
setOutput(Outputs.CacheHit, true)
6262
} else {
63-
core.info('Cache not found')
64-
core.setOutput(Outputs.CacheHit, false)
63+
info('Cache not found')
64+
setOutput(Outputs.CacheHit, false)
6565
}
6666
}

src/cache-save.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,44 @@
1-
import * as cache from '@actions/cache'
2-
import * as core from '@actions/core'
1+
import { saveCache as saveCacheAction } from '@actions/cache'
2+
import { getState, info, warning } from '@actions/core'
33
import { State } from './types.js'
44

55
export async function saveCache(): Promise<void> {
6-
const primaryKey = core.getState(State.CachePrimaryKey)
7-
const matchedKey = core.getState(State.CacheMatchedKey)
8-
const cachePathsJson = core.getState(State.CachePaths)
6+
const primaryKey = getState(State.CachePrimaryKey)
7+
const matchedKey = getState(State.CacheMatchedKey)
8+
const cachePathsJson = getState(State.CachePaths)
99

1010
if (!primaryKey) {
11-
core.info('No cache key found. Skipping cache save.')
11+
info('No cache key found. Skipping cache save.')
1212
return
1313
}
1414

1515
if (!cachePathsJson) {
16-
core.info('No cache paths found. Skipping cache save.')
16+
info('No cache paths found. Skipping cache save.')
1717
return
1818
}
1919

2020
// Skip if cache hit on primary key (no changes)
2121
if (primaryKey === matchedKey) {
22-
core.info(`Cache hit on primary key "${primaryKey}". Skipping save.`)
22+
info(`Cache hit on primary key "${primaryKey}". Skipping save.`)
2323
return
2424
}
2525

2626
const cachePaths: string[] = JSON.parse(cachePathsJson) as string[]
2727

2828
if (!cachePaths.length) {
29-
core.info('Empty cache paths. Skipping cache save.')
29+
info('Empty cache paths. Skipping cache save.')
3030
return
3131
}
3232

3333
try {
34-
const cacheId = await cache.saveCache(cachePaths, primaryKey)
34+
const cacheId = await saveCacheAction(cachePaths, primaryKey)
3535
if (cacheId === -1) {
36-
core.warning('Cache save failed or was skipped.')
36+
warning('Cache save failed or was skipped.')
3737
return
3838
}
39-
core.info(`Cache saved with key: ${primaryKey}`)
39+
info(`Cache saved with key: ${primaryKey}`)
4040
} catch (error) {
4141
// Don't fail the action if cache save fails
42-
core.warning(`Failed to save cache: ${error}`)
42+
warning(`Failed to save cache: ${error}`)
4343
}
4444
}

src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as core from '@actions/core'
1+
import { saveState, getState, setFailed } from '@actions/core'
22
import { getInputs } from './inputs.js'
33
import { installVitePlus } from './install-viteplus.js'
44
import { runViteInstall } from './run-install.js'
@@ -9,7 +9,7 @@ import type { Inputs } from './types.js'
99

1010
async function runMain(inputs: Inputs): Promise<void> {
1111
// Mark that post action should run
12-
core.saveState(State.IsPost, 'true')
12+
saveState(State.IsPost, 'true')
1313

1414
// Step 1: Install @voidzero-dev/global
1515
await installVitePlus(inputs)
@@ -35,7 +35,7 @@ async function runPost(inputs: Inputs): Promise<void> {
3535
async function main(): Promise<void> {
3636
const inputs = getInputs()
3737

38-
if (core.getState(State.IsPost) === 'true') {
38+
if (getState(State.IsPost) === 'true') {
3939
await runPost(inputs)
4040
} else {
4141
await runMain(inputs)
@@ -44,5 +44,5 @@ async function main(): Promise<void> {
4444

4545
main().catch(error => {
4646
console.error(error)
47-
core.setFailed(error instanceof Error ? error.message : String(error))
47+
setFailed(error instanceof Error ? error.message : String(error))
4848
})

src/inputs.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import * as core from '@actions/core'
1+
import { getInput, getBooleanInput } from '@actions/core'
22
import { parse as parseYaml } from 'yaml'
33
import { z } from 'zod'
44
import type { Inputs, Registry, RunInstall } from './types.js'
55
import { RunInstallInputSchema } from './types.js'
66

77
export function getInputs(): Inputs {
88
return {
9-
version: core.getInput('version') || 'latest',
10-
registry: parseRegistry(core.getInput('registry')),
11-
githubToken: core.getInput('github-token') || undefined,
12-
runInstall: parseRunInstall(core.getInput('run-install')),
13-
cache: core.getBooleanInput('cache'),
14-
cacheDependencyPath: core.getInput('cache-dependency-path') || undefined,
9+
version: getInput('version') || 'latest',
10+
registry: parseRegistry(getInput('registry')),
11+
githubToken: getInput('github-token') || undefined,
12+
runInstall: parseRunInstall(getInput('run-install')),
13+
cache: getBooleanInput('cache'),
14+
cacheDependencyPath: getInput('cache-dependency-path') || undefined,
1515
}
1616
}
1717

src/install-viteplus.ts

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import * as core from '@actions/core'
2-
import * as exec from '@actions/exec'
1+
import { info, debug, warning, saveState, setOutput, addPath } from '@actions/core'
2+
import { exec, getExecOutput } from '@actions/exec'
33
import type { Inputs } from './types.js'
44
import {
55
PACKAGE_NAME,
6-
NPM_REGISTRY,
76
GITHUB_REGISTRY,
87
State,
98
Outputs,
@@ -12,7 +11,7 @@ import {
1211
export async function installVitePlus(inputs: Inputs): Promise<void> {
1312
const { version, registry, githubToken } = inputs
1413

15-
core.info(`Installing ${PACKAGE_NAME}@${version} from ${registry} registry...`)
14+
info(`Installing ${PACKAGE_NAME}@${version} from ${registry} registry...`)
1615

1716
// Validate GitHub token if using GitHub registry
1817
if (registry === 'github' && !githubToken) {
@@ -26,30 +25,33 @@ export async function installVitePlus(inputs: Inputs): Promise<void> {
2625
const packageSpec =
2726
version === 'latest' ? PACKAGE_NAME : `${PACKAGE_NAME}@${version}`
2827

29-
const registryUrl = registry === 'github' ? GITHUB_REGISTRY : NPM_REGISTRY
30-
31-
// Run npm install -g
32-
const args = ['install', '-g', packageSpec, `--registry=${registryUrl}`]
33-
34-
core.debug(`Running: npm ${args.join(' ')}`)
28+
const args = ['install', '-g', packageSpec]
3529

3630
// Set up environment for installation
31+
// Use environment variables instead of writing to .npmrc to prevent token theft
3732
const env: Record<string, string> = {}
3833
for (const [key, value] of Object.entries(process.env)) {
3934
if (value !== undefined) {
4035
env[key] = value
4136
}
4237
}
4338

44-
// Configure registry auth for GitHub
39+
// Configure scoped registry for GitHub Package Registry via environment variables
40+
// This allows @voidzero-dev packages from GitHub while other packages use npm
4541
if (registry === 'github' && githubToken) {
46-
env.NODE_AUTH_TOKEN = githubToken
42+
debug('Configuring @voidzero-dev scoped registry for GitHub Package Registry')
43+
44+
// npm reads environment variables in the format: npm_config_<key>
45+
// For scoped registry: @voidzero-dev:registry -> npm_config_@voidzero-dev:registry
46+
env['npm_config_@voidzero-dev:registry'] = GITHUB_REGISTRY
47+
48+
// For auth token: //npm.pkg.github.com/:_authToken -> npm_config_//npm.pkg.github.com/:_authToken
49+
env['npm_config_//npm.pkg.github.com/:_authToken'] = githubToken
4750
}
4851

49-
const exitCode = await exec.exec('npm', args, {
50-
env,
51-
silent: false,
52-
})
52+
debug(`Running: npm ${args.join(' ')}`)
53+
54+
const exitCode = await exec('npm', args, { env })
5355

5456
if (exitCode !== 0) {
5557
throw new Error(
@@ -59,26 +61,26 @@ export async function installVitePlus(inputs: Inputs): Promise<void> {
5961

6062
// Verify installation and get version
6163
const installedVersion = await getInstalledVersion()
62-
core.info(`Successfully installed ${PACKAGE_NAME}@${installedVersion}`)
64+
info(`Successfully installed ${PACKAGE_NAME}@${installedVersion}`)
6365

6466
// Save state for outputs
65-
core.saveState(State.InstalledVersion, installedVersion)
66-
core.setOutput(Outputs.Version, installedVersion)
67+
saveState(State.InstalledVersion, installedVersion)
68+
setOutput(Outputs.Version, installedVersion)
6769

6870
// Ensure global bin is in PATH
6971
await ensureGlobalBinInPath()
7072
}
7173

7274
async function getInstalledVersion(): Promise<string> {
7375
try {
74-
const result = await exec.getExecOutput('vp', ['--version'], {
76+
const result = await getExecOutput('vp', ['--version'], {
7577
silent: true,
7678
})
7779
return result.stdout.trim()
7880
} catch {
7981
// Fallback: check npm list
8082
try {
81-
const result = await exec.getExecOutput(
83+
const result = await getExecOutput(
8284
'npm',
8385
['list', '-g', PACKAGE_NAME, '--depth=0', '--json'],
8486
{ silent: true }
@@ -95,15 +97,15 @@ async function getInstalledVersion(): Promise<string> {
9597

9698
async function ensureGlobalBinInPath(): Promise<void> {
9799
try {
98-
const result = await exec.getExecOutput('npm', ['bin', '-g'], {
100+
const result = await getExecOutput('npm', ['bin', '-g'], {
99101
silent: true,
100102
})
101103
const globalBin = result.stdout.trim()
102104
if (globalBin && !process.env.PATH?.includes(globalBin)) {
103-
core.addPath(globalBin)
104-
core.debug(`Added ${globalBin} to PATH`)
105+
addPath(globalBin)
106+
debug(`Added ${globalBin} to PATH`)
105107
}
106108
} catch (error) {
107-
core.warning(`Could not determine global npm bin path: ${error}`)
109+
warning(`Could not determine global npm bin path: ${error}`)
108110
}
109111
}

src/run-install.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as core from '@actions/core'
2-
import * as exec from '@actions/exec'
1+
import { startGroup, endGroup, setFailed, info } from '@actions/core'
2+
import { exec } from '@actions/exec'
33
import type { Inputs } from './types.js'
44

55
export async function runViteInstall(inputs: Inputs): Promise<void> {
@@ -12,25 +12,25 @@ export async function runViteInstall(inputs: Inputs): Promise<void> {
1212
const cwd = options.cwd || process.env.GITHUB_WORKSPACE || process.cwd()
1313
const cmdStr = `vite ${args.join(' ')}`
1414

15-
core.startGroup(`Running ${cmdStr} in ${cwd}...`)
15+
startGroup(`Running ${cmdStr} in ${cwd}...`)
1616

1717
try {
18-
const exitCode = await exec.exec('vite', args, {
18+
const exitCode = await exec('vite', args, {
1919
cwd,
2020
ignoreReturnCode: true,
2121
})
2222

2323
if (exitCode !== 0) {
24-
core.setFailed(
24+
setFailed(
2525
`Command "${cmdStr}" (cwd: ${cwd}) exited with code ${exitCode}`
2626
)
2727
} else {
28-
core.info(`Successfully ran ${cmdStr}`)
28+
info(`Successfully ran ${cmdStr}`)
2929
}
3030
} catch (error) {
31-
core.setFailed(`Failed to run ${cmdStr}: ${error}`)
31+
setFailed(`Failed to run ${cmdStr}: ${error}`)
3232
} finally {
33-
core.endGroup()
33+
endGroup()
3434
}
3535
}
3636
}

src/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,4 @@ export enum Outputs {
6060

6161
// Package constants
6262
export const PACKAGE_NAME = '@voidzero-dev/global'
63-
export const NPM_REGISTRY = 'https://registry.npmjs.org'
6463
export const GITHUB_REGISTRY = 'https://npm.pkg.github.com'

0 commit comments

Comments
 (0)