Skip to content

Commit ec3cf27

Browse files
committed
fix(publish): remove dangerous --skip-checks flag and add comprehensive validation
BREAKING: CI publish workflow now runs full test suite before publishing ## Critical Security Fix The publish:ci script was using --skip-checks which bypassed: - Test suite validation - Lint/type checking - Code quality checks This created a dangerous path where broken code could be published to npm, potentially costing thousands in incident response and reputation damage. ## Changes **publish:ci script**: - Changed from --skip-checks to --skip-git - Now only skips git-specific checks (safe in CI) - Still runs full test + lint validation **provenance.yml workflow**: - setup-script now runs: test && check && build - Ensures full validation before publish step - Build artifacts validated before npm publish **scripts/publish.mjs**: - Removed CI restriction on --skip-build - Added validateBuildArtifacts() function - Validates dist/index.js, dist/index.d.ts, types/ exist - Updated help text to clarify validation behavior - Removed unused CI constant ## Safety Guarantees CI publish will now FAIL if: - ✗ Any test fails - ✗ Lint/type errors exist - ✗ Build artifacts missing - ✗ Version already published The --skip-build flag is safe because: - setup-script builds first - Artifact validation ensures build succeeded - Fails immediately with clear error if missing ## What We Skip (and Why It's Safe) --skip-git: Safe because CI runs on clean checkouts with branch protection --skip-build: Safe because setup-script already built, we validate artifacts
1 parent bc0af62 commit ec3cf27

File tree

3 files changed

+42
-11
lines changed

3 files changed

+42
-11
lines changed

.github/workflows/provenance.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ jobs:
2929
dist-tag: ${{ inputs.dist-tag }}
3030
package-name: '@socketsecurity/sdk'
3131
publish-script: 'publish:ci'
32-
setup-script: 'pnpm run build'
32+
setup-script: 'pnpm test --all && pnpm check --all && pnpm build'
3333
use-trusted-publishing: true

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"prepare": "husky",
4949
"prepublishOnly": "echo 'ERROR: Use GitHub Actions workflow for publishing' && exit 1",
5050
"publish": "node scripts/publish.mjs",
51-
"publish:ci": "node scripts/publish.mjs --skip-checks --skip-build --tag ${DIST_TAG:-latest}",
51+
"publish:ci": "node scripts/publish.mjs --skip-git --skip-build --tag ${DIST_TAG:-latest}",
5252
"claude": "node scripts/claude.mjs",
5353
"test": "node scripts/test.mjs",
5454
"type": "tsgo --noEmit -p .config/tsconfig.check.json",

scripts/publish.mjs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const logger = getDefaultLogger()
1818
const __dirname = path.dirname(fileURLToPath(import.meta.url))
1919
const rootPath = path.join(__dirname, '..')
2020
const WIN32 = process.platform === 'win32'
21-
const CI = !!process.env.CI
2221

2322
// Simple inline logger.
2423
const log = {
@@ -236,6 +235,37 @@ async function runPrePublishChecks(options = {}) {
236235
return true
237236
}
238237

238+
/**
239+
* Validate that build artifacts exist.
240+
*/
241+
async function validateBuildArtifacts() {
242+
log.step('Validating build artifacts')
243+
244+
// Check for main entry point.
245+
const distIndex = path.join(rootPath, 'dist', 'index.js')
246+
if (!existsSync(distIndex)) {
247+
log.error('Missing dist/index.js')
248+
return false
249+
}
250+
251+
// Check for type definitions.
252+
const distIndexDts = path.join(rootPath, 'dist', 'index.d.ts')
253+
if (!existsSync(distIndexDts)) {
254+
log.error('Missing dist/index.d.ts')
255+
return false
256+
}
257+
258+
// Check for types directory.
259+
const typesDir = path.join(rootPath, 'types')
260+
if (!existsSync(typesDir)) {
261+
log.error('Missing types/ directory')
262+
return false
263+
}
264+
265+
log.success('Build artifacts validated')
266+
return true
267+
}
268+
239269
/**
240270
* Build the project.
241271
*/
@@ -464,7 +494,7 @@ async function main() {
464494
logger.log(' --dry-run Perform a dry-run without publishing')
465495
logger.log(' --force Force publish even with warnings')
466496
logger.log(' --skip-checks Skip pre-publish checks')
467-
logger.log(' --skip-build Skip build step (not allowed in CI)')
497+
logger.log(' --skip-build Skip build step (validates artifacts exist)')
468498
logger.log(' --skip-git Skip git status checks')
469499
logger.log(' --skip-tag Skip git tag push')
470500
logger.log(' --complex Use complex multi-package flow')
@@ -480,13 +510,6 @@ async function main() {
480510
return
481511
}
482512

483-
// Check CI restrictions.
484-
if (CI && values['skip-build']) {
485-
log.error('--skip-build is not allowed in CI')
486-
process.exitCode = 1
487-
return
488-
}
489-
490513
printHeader('Publish Runner')
491514

492515
// Get current version.
@@ -515,6 +538,14 @@ async function main() {
515538
process.exitCode = 1
516539
return
517540
}
541+
} else {
542+
// Validate that build artifacts exist when skipping build.
543+
const artifactsExist = await validateBuildArtifacts()
544+
if (!artifactsExist && !values.force) {
545+
log.error('Build artifacts missing - run pnpm build first')
546+
process.exitCode = 1
547+
return
548+
}
518549
}
519550

520551
// Publish.

0 commit comments

Comments
 (0)