33 *
44 * These tests verify edge cases, security features, and error handling
55 * for the --enable-chroot feature.
6+ *
7+ * NOTE: stdout may contain entrypoint debug logs in addition to command output.
8+ * Use toContain() instead of exact matches, or check the last line of output.
69 */
710
811/// <reference path="../jest-custom-matchers.d.ts" />
@@ -11,6 +14,14 @@ import { describe, test, expect, beforeAll, afterAll } from '@jest/globals';
1114import { createRunner , AwfRunner } from '../fixtures/awf-runner' ;
1215import { cleanup } from '../fixtures/cleanup' ;
1316
17+ /**
18+ * Helper to get the last non-empty line from stdout (skips debug logs)
19+ */
20+ function getLastLine ( output : string ) : string {
21+ const lines = output . trim ( ) . split ( '\n' ) . filter ( line => line . trim ( ) !== '' ) ;
22+ return lines [ lines . length - 1 ] || '' ;
23+ }
24+
1425describe ( 'Chroot Edge Cases' , ( ) => {
1526 let runner : AwfRunner ;
1627
@@ -34,10 +45,11 @@ describe('Chroot Edge Cases', () => {
3445 } ) ;
3546
3647 expect ( result ) . toSucceed ( ) ;
37- expect ( result . stdout . trim ( ) ) . toBe ( '/tmp' ) ;
48+ // The last line should be /tmp (after all the debug output)
49+ expect ( getLastLine ( result . stdout ) ) . toBe ( '/tmp' ) ;
3850 } , 120000 ) ;
3951
40- test ( 'should fall back to / if workdir does not exist' , async ( ) => {
52+ test ( 'should fall back to home directory if workdir does not exist' , async ( ) => {
4153 const result = await runner . runWithSudo ( 'pwd' , {
4254 allowDomains : [ 'localhost' ] ,
4355 logLevel : 'debug' ,
@@ -47,8 +59,9 @@ describe('Chroot Edge Cases', () => {
4759 } ) ;
4860
4961 expect ( result ) . toSucceed ( ) ;
50- // Should fall back to / or home directory
51- expect ( result . stdout . trim ( ) ) . toMatch ( / ^ \/ / ) ;
62+ // Should fall back to home directory (starts with /)
63+ const lastLine = getLastLine ( result . stdout ) ;
64+ expect ( lastLine ) . toMatch ( / ^ \/ / ) ;
5265 } , 120000 ) ;
5366 } ) ;
5467
@@ -76,7 +89,9 @@ describe('Chroot Edge Cases', () => {
7689 } ) ;
7790
7891 expect ( result ) . toSucceed ( ) ;
79- expect ( result . stdout . trim ( ) ) . toMatch ( / ^ \/ / ) ;
92+ // HOME should be a path starting with /
93+ const lastLine = getLastLine ( result . stdout ) ;
94+ expect ( lastLine ) . toMatch ( / ^ \/ / ) ;
8095 } , 120000 ) ;
8196
8297 test ( 'should pass custom environment variables' , async ( ) => {
@@ -108,14 +123,17 @@ describe('Chroot Edge Cases', () => {
108123 } , 120000 ) ;
109124
110125 test ( 'should have read access to /etc' , async ( ) => {
111- const result = await runner . runWithSudo ( 'cat /etc/hostname' , {
126+ // /etc/hostname might not exist in all environments, check /etc/passwd instead
127+ const result = await runner . runWithSudo ( 'cat /etc/passwd | head -1' , {
112128 allowDomains : [ 'localhost' ] ,
113129 logLevel : 'debug' ,
114130 timeout : 60000 ,
115131 enableChroot : true ,
116132 } ) ;
117133
118134 expect ( result ) . toSucceed ( ) ;
135+ // passwd file should have root entry
136+ expect ( result . stdout ) . toContain ( 'root' ) ;
119137 } , 120000 ) ;
120138
121139 test ( 'should have write access to /tmp' , async ( ) => {
@@ -133,27 +151,21 @@ describe('Chroot Edge Cases', () => {
133151 expect ( result . stdout ) . toContain ( 'test' ) ;
134152 } , 120000 ) ;
135153
136- test ( 'should not have access to Docker socket' , async ( ) => {
137- // Docker socket should be hidden (mounted to /dev/null)
138- const result = await runner . runWithSudo ( 'ls -la /var/run/docker.sock 2>&1' , {
139- allowDomains : [ 'localhost' ] ,
140- logLevel : 'debug' ,
141- timeout : 60000 ,
142- enableChroot : true ,
143- } ) ;
144-
145- // Should either not exist or be /dev/null
146- if ( result . success ) {
147- // If it exists, it should be empty (pointing to /dev/null)
148- const checkResult = await runner . runWithSudo ( 'test -S /var/run/docker.sock && echo "is_socket"' , {
154+ test ( 'should have Docker socket hidden or inaccessible' , async ( ) => {
155+ // Docker socket should be hidden (mounted to /dev/null) or not exist
156+ const result = await runner . runWithSudo (
157+ 'test -S /var/run/docker.sock && echo "has_socket" || echo "no_socket"' ,
158+ {
149159 allowDomains : [ 'localhost' ] ,
150160 logLevel : 'debug' ,
151161 timeout : 60000 ,
152162 enableChroot : true ,
153- } ) ;
154- // Should not be a socket (it's /dev/null)
155- expect ( checkResult . stdout ) . not . toContain ( 'is_socket' ) ;
156- }
163+ }
164+ ) ;
165+
166+ expect ( result ) . toSucceed ( ) ;
167+ // The docker socket should NOT be a socket (it's /dev/null or doesn't exist)
168+ expect ( result . stdout ) . toContain ( 'no_socket' ) ;
157169 } , 120000 ) ;
158170 } ) ;
159171
@@ -335,8 +347,9 @@ describe('Chroot Edge Cases', () => {
335347 } ) ;
336348
337349 expect ( result ) . toSucceed ( ) ;
338- // Should not be root (uid 0)
339- const uid = parseInt ( result . stdout . trim ( ) ) ;
350+ // Should not be root (uid 0) - check last line of output
351+ const lastLine = getLastLine ( result . stdout ) ;
352+ const uid = parseInt ( lastLine ) ;
340353 expect ( uid ) . not . toBe ( 0 ) ;
341354 } , 120000 ) ;
342355
@@ -349,7 +362,9 @@ describe('Chroot Edge Cases', () => {
349362 } ) ;
350363
351364 expect ( result ) . toSucceed ( ) ;
352- expect ( result . stdout . trim ( ) ) . not . toBe ( 'root' ) ;
365+ // The last line should be the username, which should not be 'root'
366+ const lastLine = getLastLine ( result . stdout ) ;
367+ expect ( lastLine ) . not . toBe ( 'root' ) ;
353368 } , 120000 ) ;
354369 } ) ;
355370} ) ;
0 commit comments