@@ -70,6 +70,18 @@ function sanitizeForGCP(str: string): string {
7070 return str . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 - ] / g, "-" ) ;
7171}
7272
73+ // Generate a random alphanumeric password
74+ function generateRandomPassword ( length : number ) : string {
75+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ;
76+ let result = '' ;
77+ const randomBytes = new Uint8Array ( length ) ;
78+ crypto . getRandomValues ( randomBytes ) ;
79+ for ( let i = 0 ; i < length ; i ++ ) {
80+ result += chars [ randomBytes [ i ] % chars . length ] ;
81+ }
82+ return result ;
83+ }
84+
7385function getInstanceName ( username : string , instanceId : string = DEFAULT_INSTANCE_ID ) : string {
7486 const sanitizedUser = sanitizeForGCP ( username ) ;
7587 const sanitizedId = sanitizeForGCP ( instanceId ) ;
@@ -229,6 +241,9 @@ export async function createDevEnvironment(
229241
230242 const now = new Date ( ) . toISOString ( ) ;
231243 const hasSnap = await snapshotExists ( username ) ;
244+
245+ // Generate ttyd password upfront (metadata API is read-only, so we can't set it from startup script)
246+ const ttydPassword = generateRandomPassword ( 16 ) ;
232247
233248 // Determine which machine configs to try
234249 // If user specified a machine type, use only that one
@@ -315,9 +330,13 @@ export async function createDevEnvironment(
315330 key : "instance-id" ,
316331 value : instanceId ,
317332 } ,
333+ {
334+ key : "ttyd-password" ,
335+ value : ttydPassword ,
336+ } ,
318337 {
319338 key : "startup-script" ,
320- value : getStartupScript ( username , hasSnap , token ) ,
339+ value : getStartupScript ( username , hasSnap , token , ttydPassword ) ,
321340 } ,
322341 ] ,
323342 } ,
@@ -749,7 +768,7 @@ async function waitForOperation(operationName: string): Promise<void> {
749768 throw new Error ( "Operation timed out" ) ;
750769}
751770
752- function getStartupScript ( username : string , isRestore : boolean = false , githubToken ?: string ) : string {
771+ function getStartupScript ( username : string , isRestore : boolean = false , githubToken ?: string , ttydPassword ?: string ) : string {
753772 // GitHub token credential setup for developer user
754773 const devTokenSetup = githubToken
755774 ? `
@@ -1010,13 +1029,9 @@ echo "✓ Frontend service started on port 3000" >> /var/log/startup.log
10101029# Start ttyd web terminal service
10111030echo "Starting ttyd web terminal..." >> /var/log/startup.log
10121031
1013- # Generate a random password for ttyd authentication (use more bytes to ensure 16 chars after filtering)
1014- TTYD_PASSWORD=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 16)
1015-
1016- # Store the password in VM metadata for the dashboard to retrieve
1017- curl -X PUT "http://metadata.google.internal/computeMetadata/v1/instance/attributes/ttyd-password" \\
1018- -H "Metadata-Flavor: Google" \\
1019- -d "\$TTYD_PASSWORD" 2>/dev/null || true
1032+ # Get ttyd password from metadata (set during VM creation)
1033+ TTYD_PASSWORD=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/attributes/ttyd-password 2>/dev/null || echo "defaultpass")
1034+ echo "ttyd password retrieved from metadata" >> /var/log/startup.log
10201035
10211036# Start ttyd on port 7681 with authentication
10221037# -W: Writable (allow input)
0 commit comments