@@ -3,12 +3,44 @@ import { Architecture, Runtime } from 'aws-cdk-lib/aws-lambda';
33import { Bundling , DEFAULT_UV_VERSION } from '../src/bundling' ;
44import type { ICommandHooks } from '../src/types' ;
55
6+ type BundlingModule = typeof import ( '../src/bundling' ) ;
7+
68function decodeCommands ( value : string ) {
79 return JSON . parse ( Buffer . from ( value , 'base64' ) . toString ( 'utf8' ) ) as string [ ] ;
810}
911
12+ function getExpectedDockerUserArg ( ) {
13+ if (
14+ typeof process . getuid !== 'function' ||
15+ typeof process . getgid !== 'function'
16+ ) {
17+ throw new Error ( 'process.getuid() and process.getgid() are required' ) ;
18+ }
19+
20+ return `${ process . getuid ( ) } :${ process . getgid ( ) } ` ;
21+ }
22+
23+ function loadBundlingModule ( ensureBuilderContainerMock : jest . Mock ) {
24+ let loadedModule : BundlingModule | undefined ;
25+
26+ jest . isolateModules ( ( ) => {
27+ jest . doMock ( '../src/build-container' , ( ) => ( {
28+ BUILDER_LABEL : 'com.fourtheorem.uv-python-lambda.builder' ,
29+ ensureBuilderContainer : ensureBuilderContainerMock ,
30+ } ) ) ;
31+ loadedModule = require ( '../src/bundling' ) as BundlingModule ;
32+ } ) ;
33+
34+ if ( ! loadedModule ) {
35+ throw new Error ( 'Failed to load bundling module' ) ;
36+ }
37+
38+ return loadedModule ;
39+ }
40+
1041describe ( 'Bundling' , ( ) => {
1142 afterEach ( ( ) => {
43+ jest . resetModules ( ) ;
1244 jest . restoreAllMocks ( ) ;
1345 } ) ;
1446
@@ -104,6 +136,23 @@ describe('Bundling', () => {
104136 expect ( command ) . toContain ( 'UV_PYTHON_LAMBDA_NOFILE_LIMIT=1048576' ) ;
105137 } ) ;
106138
139+ test ( 'runs export commands as the host user when uid and gid are available' , ( ) => {
140+ const bundling = new Bundling ( {
141+ rootDir : '/tmp/project-user' ,
142+ runtime : Runtime . PYTHON_3_12 ,
143+ architecture : Architecture . X86_64 ,
144+ workspacePackage : 'app' ,
145+ } ) ;
146+
147+ const command = Reflect . get ( bundling , 'createBundlingCommand' ) . call (
148+ bundling ,
149+ ) as string [ ] ;
150+
151+ expect ( command ) . toContain ( '--user' ) ;
152+ expect ( command ) . toContain ( getExpectedDockerUserArg ( ) ) ;
153+ expect ( command ) . toContain ( '/opt/uv-python-lambda/export.sh' ) ;
154+ } ) ;
155+
107156 test ( 'builds the builder image with the default uv version' , ( ) => {
108157 const fromBuildSpy = jest
109158 . spyOn ( DockerImage , 'fromBuild' )
@@ -188,4 +237,34 @@ describe('Bundling', () => {
188237 Reflect . get ( overriddenBundling , 'containerBuilderKey' ) ,
189238 ) ;
190239 } ) ;
240+
241+ test ( 'starts the builder container as the host user when uid and gid are available' , ( ) => {
242+ const ensureBuilderContainerMock = jest . fn ( ) ;
243+ const bundlingModule = loadBundlingModule ( ensureBuilderContainerMock ) ;
244+ const fromBuildSpy = jest
245+ . spyOn ( DockerImage , 'fromBuild' )
246+ . mockReturnValue ( { image : 'mock-image' } as DockerImage ) ;
247+
248+ const bundling = new bundlingModule . Bundling ( {
249+ rootDir : '/tmp/project-run-user' ,
250+ runtime : Runtime . PYTHON_3_12 ,
251+ architecture : Architecture . X86_64 ,
252+ } ) ;
253+
254+ Reflect . get ( bundling , 'ensureBuilderReady' ) . call (
255+ bundling ,
256+ '/tmp/cdk-run-user' ,
257+ ) ;
258+
259+ expect ( fromBuildSpy ) . toHaveBeenCalled ( ) ;
260+ expect ( ensureBuilderContainerMock ) . toHaveBeenCalledWith (
261+ expect . objectContaining ( {
262+ args : expect . arrayContaining ( [
263+ '--user' ,
264+ getExpectedDockerUserArg ( ) ,
265+ 'mock-image' ,
266+ ] ) ,
267+ } ) ,
268+ ) ;
269+ } ) ;
191270} ) ;
0 commit comments