diff --git a/packages/targets/sdk-pypi/src/index.test.ts b/packages/targets/sdk-pypi/src/index.test.ts index 5bd3603e..fa78e43e 100644 --- a/packages/targets/sdk-pypi/src/index.test.ts +++ b/packages/targets/sdk-pypi/src/index.test.ts @@ -31,4 +31,22 @@ describe('sdk-pypi target adapter', () => { expect(secret).not.toHaveBeenCalled(); expect(execMock).not.toHaveBeenCalled(); }); + + it('passes PyPI credentials through the child environment, not argv', async () => { + execMock.mockResolvedValue({ exitCode: 0, stdout: 'uploaded', stderr: '' }); + + await adapter.ship(fakeShipContext({ + dryRun: false, + secret: (key: string) => key === 'PYPI_TOKEN' ? 'pypi-secret-token' : undefined, + }) as any, {}); + + const [bin, args, options] = execMock.mock.calls[0] ?? []; + expect(bin).toBe('twine'); + expect(args).not.toContain('pypi-secret-token'); + expect(args).not.toContain('--password'); + expect(options.env).toMatchObject({ + TWINE_USERNAME: '__token__', + TWINE_PASSWORD: 'pypi-secret-token', + }); + }); }); diff --git a/packages/targets/sdk-pypi/src/index.ts b/packages/targets/sdk-pypi/src/index.ts index 277d3101..5f254d6f 100644 --- a/packages/targets/sdk-pypi/src/index.ts +++ b/packages/targets/sdk-pypi/src/index.ts @@ -55,12 +55,18 @@ export default defineTarget({ [ 'upload', ...repoFlag, - '--username', '__token__', - '--password', token, '--non-interactive', `${ctx.artifact}/*`, ], - { log: ctx.log, throwOnNonZero: true } + { + env: { + ...ctx.env, + TWINE_USERNAME: '__token__', + TWINE_PASSWORD: token, + }, + log: ctx.log, + throwOnNonZero: true, + } ); return {