Skip to content

Commit 260bca0

Browse files
committed
Merge branch 'dev' into docs/v4
2 parents 1dab537 + ef023cc commit 260bca0

File tree

7 files changed

+56
-24
lines changed

7 files changed

+56
-24
lines changed

lib/db/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,16 @@ export interface UploadPartsTable {
3030
e_tag: string | null
3131
}
3232

33+
export interface MetaTable {
34+
key: 'version'
35+
value: string
36+
}
37+
3338
export interface Database {
3439
cache_keys: CacheKeysTable
3540
uploads: UploadsTable
3641
upload_parts: UploadPartsTable
42+
meta: MetaTable
3743
}
3844

3945
let _db: Kysely<Database>

lib/db/migrations.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { DatabaseDriverName } from '~/lib/db/drivers'
44

55
export function migrations(dbType: DatabaseDriverName) {
66
return {
7-
cache_keys_table: {
7+
$0_cache_keys_table: {
88
async up(db) {
99
let query = db.schema
1010
.createTable('cache_keys')
@@ -22,7 +22,7 @@ export function migrations(dbType: DatabaseDriverName) {
2222
await db.schema.dropTable('cache_keys').ifExists().execute()
2323
},
2424
},
25-
uploads_and_upload_parts_tables: {
25+
$1_uploads_and_upload_parts_tables: {
2626
async up(db) {
2727
await db.schema
2828
.createTable('uploads')
@@ -56,5 +56,18 @@ export function migrations(dbType: DatabaseDriverName) {
5656
await db.schema.dropTable('upload_parts').ifExists().execute()
5757
},
5858
},
59+
$2_meta_table: {
60+
async up(db) {
61+
await db.schema
62+
.createTable('meta')
63+
.addColumn('key', dbType === 'mysql' ? 'varchar(255)' : 'text', (c) => c.primaryKey())
64+
.addColumn('value', 'text')
65+
.ifNotExists()
66+
.execute()
67+
},
68+
async down(db) {
69+
await db.schema.dropTable('meta').ifExists().execute()
70+
},
71+
},
5972
} satisfies Record<string, Migration>
6073
}

lib/env.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const booleanSchema = z.string().transform((v) => v.toLowerCase() === 'true')
44

55
const envSchema = z.object({
66
ENABLE_DIRECT_DOWNLOADS: booleanSchema.default('false'),
7-
DOWNLOAD_SECRET_KEY: z.string(),
87
URL_ACCESS_TOKEN: z.string().min(1),
98
CLEANUP_OLDER_THAN_DAYS: z.coerce.number().int().min(0).default(90),
109
API_BASE_URL: z.string().url(),

lib/storage/index.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createHash, randomInt } from 'node:crypto'
1+
import { randomBytes, randomInt } from 'node:crypto'
22

33
import consola from 'consola'
44

@@ -226,6 +226,11 @@ export async function initializeStorage() {
226226
})
227227

228228
const keys = await findStaleKeys(db, { olderThanDays })
229+
if (keys.length === 0) {
230+
logger.debug('Prune: No caches to prune')
231+
return
232+
}
233+
229234
await driver.delete({
230235
objectNames: keys.map((key) => getObjectNameFromKey(key.key, key.version)),
231236
})
@@ -266,11 +271,7 @@ export async function initializeStorage() {
266271
}
267272

268273
function createLocalDownloadUrl(objectName: string) {
269-
const hashedKey = createHash('sha256')
270-
.update(objectName + ENV.DOWNLOAD_SECRET_KEY)
271-
.digest('base64url')
272-
273-
return `${ENV.API_BASE_URL}/download/${hashedKey}/${objectName}`
274+
return `${ENV.API_BASE_URL}/download/${randomBytes(64).toString('hex')}/${objectName}`
274275
}
275276

276277
export function useStorageAdapter() {

plugins/setup.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { H3Error } from 'h3'
22

3-
import { initializeDatabase } from '~/lib/db'
3+
import { initializeDatabase, useDB } from '~/lib/db'
44
import { ENV } from '~/lib/env'
55
import { logger } from '~/lib/logger'
6-
import { initializeStorage } from '~/lib/storage'
6+
import { initializeStorage, useStorageAdapter } from '~/lib/storage'
77

88
export default defineNitroPlugin(async (nitro) => {
9-
logger.info(`🚀 Starting GitHub Actions Cache Server (${useRuntimeConfig().version})`)
9+
const version = useRuntimeConfig().version
10+
logger.info(`🚀 Starting GitHub Actions Cache Server (${version})`)
1011

1112
await initializeDatabase()
1213
await initializeStorage()
@@ -34,6 +35,28 @@ export default defineNitroPlugin(async (nitro) => {
3435
})
3536
}
3637

38+
if (!version) throw new Error('No version found in runtime config')
39+
40+
const db = useDB()
41+
const existing = await db
42+
.selectFrom('meta')
43+
.where('key', '=', 'version')
44+
.select('value')
45+
.executeTakeFirst()
46+
47+
if (!existing || existing.value !== version) {
48+
logger.info(
49+
`Version changed from ${existing?.value ?? '[no version, first install]'} to ${version}. Pruning cache...`,
50+
)
51+
await useStorageAdapter().pruneCaches()
52+
}
53+
54+
if (existing) {
55+
await db.updateTable('meta').set('value', version).where('key', '=', 'version').execute()
56+
} else {
57+
await db.insertInto('meta').values({ key: 'version', value: version }).execute()
58+
}
59+
3760
if (process.send) process.send('nitro:ready')
3861
})
3962

routes/download/[hash]/[objectName].ts renamed to routes/download/[random]/[objectName].ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
import { createHash } from 'node:crypto'
2-
31
import { z } from 'zod'
42

5-
import { ENV } from '~/lib/env'
63
import { useStorageAdapter } from '~/lib/storage'
74

85
const pathParamsSchema = z.object({
96
objectName: z.string(),
10-
hash: z.string(),
117
})
128

139
export default defineEventHandler(async (event) => {
@@ -18,12 +14,7 @@ export default defineEventHandler(async (event) => {
1814
statusMessage: `Invalid path parameters: ${parsedPathParams.error.message}`,
1915
})
2016

21-
const { objectName, hash } = parsedPathParams.data
22-
23-
const hashedCacheId = createHash('sha256')
24-
.update(objectName + ENV.DOWNLOAD_SECRET_KEY)
25-
.digest('base64url')
26-
if (hashedCacheId !== hash) throw createError({ statusCode: 403, statusMessage: 'Forbidden' })
17+
const { objectName } = parsedPathParams.data
2718

2819
const stream = await useStorageAdapter().download(objectName)
2920

tests/.env.base

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ URL_ACCESS_TOKEN=test_token
22
API_BASE_URL=http://localhost:3000
33
NODE_ENV=development
44
RUNNER_TEMP=tests/temp/runner
5-
ACTIONS_CACHE_URL=http://localhost:3000/test_token/
6-
DOWNLOAD_SECRET_KEY=test_key
5+
ACTIONS_CACHE_URL=http://localhost:3000/test_token/

0 commit comments

Comments
 (0)