Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions .claude/hooks/setup-security-tools/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import process from 'node:process'
import { fileURLToPath } from 'node:url'

import { PackageURL } from '@socketregistry/packageurl-js'
import { Type } from '@sinclair/typebox'

import { whichSync } from '@socketsecurity/lib/bin'
import { downloadBinary } from '@socketsecurity/lib/dlx/binary'
import { downloadPackage } from '@socketsecurity/lib/dlx/package'
Expand All @@ -25,37 +27,37 @@ import { getDefaultLogger } from '@socketsecurity/lib/logger'
import { normalizePath } from '@socketsecurity/lib/paths/normalize'
import { getSocketHomePath } from '@socketsecurity/lib/paths/socket'
import { spawn } from '@socketsecurity/lib/spawn'
import { z } from 'zod'
import { parseSchema } from '@socketsecurity/lib/validation/validate-schema'

const logger = getDefaultLogger()

// ── Tool config loaded from external-tools.json (self-contained) ──

const checksumEntrySchema = z.object({
asset: z.string(),
sha256: z.string(),
const checksumEntrySchema = Type.Object({
asset: Type.String(),
sha256: Type.String(),
})

const toolSchema = z.object({
description: z.string().optional(),
version: z.string().optional(),
purl: z.string().optional(),
integrity: z.string().optional(),
repository: z.string().optional(),
release: z.string().optional(),
checksums: z.record(z.string(), checksumEntrySchema).optional(),
ecosystems: z.array(z.string()).optional(),
const toolSchema = Type.Object({
description: Type.Optional(Type.String()),
version: Type.Optional(Type.String()),
purl: Type.Optional(Type.String()),
integrity: Type.Optional(Type.String()),
repository: Type.Optional(Type.String()),
release: Type.Optional(Type.String()),
checksums: Type.Optional(Type.Record(Type.String(), checksumEntrySchema)),
ecosystems: Type.Optional(Type.Array(Type.String())),
})

const configSchema = z.object({
description: z.string().optional(),
tools: z.record(z.string(), toolSchema),
const configSchema = Type.Object({
description: Type.Optional(Type.String()),
tools: Type.Record(Type.String(), toolSchema),
})

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const configPath = path.join(__dirname, 'external-tools.json')
const rawConfig = JSON.parse(readFileSync(configPath, 'utf8'))
const config = configSchema.parse(rawConfig)
const config = parseSchema(configSchema, rawConfig)

const AGENTSHIELD = config.tools['agentshield']!
const ZIZMOR = config.tools['zizmor']!
Expand Down
4 changes: 2 additions & 2 deletions .claude/hooks/setup-security-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "module",
"main": "./index.mts",
"dependencies": {
"@socketsecurity/lib": "catalog:",
"zod": "4.1.12"
"@sinclair/typebox": "catalog:",
"@socketsecurity/lib": "catalog:"
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"@mdn/browser-compat-data": "catalog:",
"@npmcli/package-json": "catalog:",
"@npmcli/promise-spawn": "catalog:",
"@sinclair/typebox": "catalog:",
"@socketregistry/is-unicode-supported": "workspace:*",
"@socketregistry/packageurl-js": "catalog:",
"@socketsecurity/lib": "catalog:",
Expand Down Expand Up @@ -129,8 +130,7 @@
"vitest": "catalog:",
"which": "catalog:",
"yargs-parser": "catalog:",
"yoctocolors-cjs": "catalog:",
"zod": "catalog:"
"yoctocolors-cjs": "catalog:"
},
"typeCoverage": {
"cache": true,
Expand Down
33 changes: 14 additions & 19 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ catalog:
'@mdn/browser-compat-data': 7.1.5
'@npmcli/package-json': 7.0.0
'@npmcli/promise-spawn': 8.0.3
'@sinclair/typebox': 0.34.49
'@socketregistry/packageurl-js': 1.4.2
'@socketsecurity/lib': 5.20.1
'@types/fs-extra': 11.0.4
Expand Down Expand Up @@ -100,7 +101,6 @@ catalog:
which: 5.0.0
yargs-parser: 22.0.0
yoctocolors-cjs: 2.1.3
zod: 4.3.6

# Wait 7 days (10080 minutes) before installing newly published packages.
minimumReleaseAge: 10080
Expand Down
23 changes: 10 additions & 13 deletions scripts/xport-emit-schema.mts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
/**
* @fileoverview Emit `xport.schema.json` from the zod schema.
* @fileoverview Emit `xport.schema.json` from the TypeBox schema.
*
* The zod schema in `scripts/xport-schema.mts` is the source of truth. This
* script writes the draft-2020-12 JSON Schema that consumers without zod
* (editors, external validators) consume via the `$schema` reference in
* `xport.json`.
* The TypeBox schema in `scripts/xport-schema.mts` is the source of truth.
* TypeBox schemas are JSON Schema natively — no conversion library needed,
* just serialize the schema object and add the draft-2020-12 meta headers.
*
* Run via `pnpm run xport:emit-schema` when the zod schema changes.
* Run via `pnpm run xport:emit-schema` when the schema changes.
*/

import { writeFileSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

import { z } from 'zod'
import { getDefaultLogger } from '@socketsecurity/lib/logger'

import { XportManifestSchema } from './xport-schema.mts'
Expand All @@ -24,16 +22,15 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
const rootDir = path.resolve(__dirname, '..')
const outPath = path.join(rootDir, 'xport.schema.json')

const json = z.toJSONSchema(XportManifestSchema, {
target: 'draft-2020-12',
})

// Add the canonical $id for portability across Socket repos.
// TypeBox schemas carry JSON Schema shape directly, plus a Symbol-keyed
// [Kind] marker that JSON.stringify drops. Spreading the schema first
// then layering the canonical $schema / $id / title on top gives a clean
// draft-2020-12 document with the Socket-specific headers.
const enriched = {
$schema: 'https://json-schema.org/draft/2020-12/schema',
$id: 'https://github.com/SocketDev/xport.schema.json',
title: 'xport lock-step manifest',
...json,
...XportManifestSchema,
}

writeFileSync(outPath, JSON.stringify(enriched, null, 2) + '\n', 'utf8')
Expand Down
Loading