-
Notifications
You must be signed in to change notification settings - Fork 25
fix(release): make tag workflow the single npm publisher #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import fs from 'node:fs'; | ||
| import path from 'node:path'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { describe, expect, it } from 'vitest'; | ||
|
|
||
| const configPath = path.resolve(__dirname, '../../../release.config.js'); | ||
| const workflowsPath = path.resolve(__dirname, '../../../../../.github/workflows'); | ||
|
|
||
| async function loadReleaseConfig(cacheKey: string) { | ||
| return (await import(`${pathToFileURL(configPath).href}?${cacheKey}`)).default as { | ||
| publish: { npm: boolean; git: boolean }; | ||
| notifications: { discord: { webhookUrl?: string } }; | ||
| }; | ||
| } | ||
|
|
||
| describe('release ownership contract', () => { | ||
| it('publishes npm only from the tag workflow', async () => { | ||
| const releaseConfig = await loadReleaseConfig('publish-owner'); | ||
| const workflowFiles = fs | ||
| .readdirSync(workflowsPath) | ||
| .filter((file) => /\.ya?ml$/.test(file)); | ||
| const npmPublishers = workflowFiles.filter((file) => | ||
| fs.readFileSync(path.join(workflowsPath, file), 'utf8').includes('npm publish') | ||
| ); | ||
| const publishWorkflow = fs.readFileSync( | ||
| path.join(workflowsPath, 'publish.yml'), | ||
| 'utf8' | ||
| ); | ||
|
|
||
| expect(releaseConfig.publish.npm).toBe(false); | ||
| expect(releaseConfig.publish.git).toBe(true); | ||
| expect(npmPublishers).toEqual(['publish.yml']); | ||
| expect(publishWorkflow).toContain("- 'v*.*.*'"); | ||
| expect(publishWorkflow).toContain('npm publish --access public'); | ||
| }); | ||
|
|
||
| it('loads notification credentials only from the environment', async () => { | ||
| const previousWebhook = process.env.DISCORD_WEBHOOK_URL; | ||
| process.env.DISCORD_WEBHOOK_URL = 'https://example.invalid/test-webhook'; | ||
|
|
||
| try { | ||
| const releaseConfig = await loadReleaseConfig('notification-env'); | ||
| const configSource = fs.readFileSync(configPath, 'utf8'); | ||
|
|
||
| expect(releaseConfig.notifications.discord.webhookUrl).toBe( | ||
| 'https://example.invalid/test-webhook' | ||
| ); | ||
| expect(/https:\/\/discord\.com\/api\/webhooks\//.test(configSource)).toBe(false); | ||
|
Comment on lines
+37
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Assert behavior when The test verifies that an environment value is selected. It does not verify that no fallback credential exists. A hardcoded or constructed fallback can pass the current test. Delete the variable, load the configuration with a distinct cache key, and assert that Proposed test update try {
+ delete process.env.DISCORD_WEBHOOK_URL;
+ const missingCredentialConfig = await loadReleaseConfig(
+ 'notification-no-env'
+ );
+ expect(
+ missingCredentialConfig.notifications.discord.webhookUrl
+ ).toBeUndefined();
+
const releaseConfig = await loadReleaseConfig('notification-env');🧰 Tools🪛 ast-grep (0.45.0)[warning] 42-42: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use. (detect-non-literal-fs-filename-typescript) 🤖 Prompt for AI Agents |
||
| } finally { | ||
| if (previousWebhook === undefined) { | ||
| delete process.env.DISCORD_WEBHOOK_URL; | ||
| } else { | ||
| process.env.DISCORD_WEBHOOK_URL = previousWebhook; | ||
| } | ||
| } | ||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.