Skip to content

Commit ba9da3b

Browse files
committed
imp(sdk/js): typing for AppCompose
1 parent c35b479 commit ba9da3b

File tree

2 files changed

+241
-2
lines changed

2 files changed

+241
-2
lines changed

sdk/js/src/__tests__/get-compose-hash.test.ts

Lines changed: 213 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,10 @@ describe('Deterministic JSON Serialization', () => {
296296

297297
describe('Edge Cases', () => {
298298
it('should handle empty objects', () => {
299+
// @ts-expect-error - empty object is valid
299300
const compose: AppCompose = {}
300301
const hash = getComposeHash(compose)
301-
302+
302303
expect(hash).toHaveLength(64)
303304
expect(hash).toMatch(/^[a-f0-9]{64}$/)
304305
})
@@ -376,4 +377,215 @@ describe('Deterministic JSON Serialization', () => {
376377
expect(getComposeHash(compose1)).not.toBe(getComposeHash(compose2))
377378
})
378379
})
380+
381+
describe('New AppCompose Fields', () => {
382+
it('should handle manifest_version and name fields', () => {
383+
const compose: AppCompose = {
384+
manifest_version: 1,
385+
name: "my-app",
386+
runner: "docker-compose",
387+
docker_compose_file: "docker-compose.yml"
388+
}
389+
390+
const hash = getComposeHash(compose)
391+
expect(hash).toBeDefined()
392+
expect(hash).toHaveLength(64)
393+
})
394+
395+
it('should handle docker_config field', () => {
396+
const compose: AppCompose = {
397+
manifest_version: 1,
398+
name: "my-app",
399+
runner: "docker-compose",
400+
docker_compose_file: "docker-compose.yml",
401+
docker_config: {
402+
registry: "docker.io",
403+
username: "myuser",
404+
token_key: "token123"
405+
}
406+
}
407+
408+
const hash = getComposeHash(compose)
409+
expect(hash).toBeDefined()
410+
expect(hash).toHaveLength(64)
411+
})
412+
413+
it('should handle boolean flags', () => {
414+
const compose: AppCompose = {
415+
manifest_version: 1,
416+
name: "my-app",
417+
runner: "docker-compose",
418+
docker_compose_file: "docker-compose.yml",
419+
public_logs: true,
420+
public_sysinfo: false,
421+
public_tcbinfo: true,
422+
kms_enabled: true,
423+
gateway_enabled: false,
424+
local_key_provider_enabled: true,
425+
no_instance_id: false,
426+
secure_time: true
427+
}
428+
429+
const hash = getComposeHash(compose)
430+
expect(hash).toBeDefined()
431+
expect(hash).toHaveLength(64)
432+
})
433+
434+
it('should handle key_provider and key_provider_id fields', () => {
435+
const compose: AppCompose = {
436+
manifest_version: 1,
437+
name: "my-app",
438+
runner: "docker-compose",
439+
docker_compose_file: "docker-compose.yml",
440+
key_provider: "kms",
441+
key_provider_id: "abcd1234"
442+
}
443+
444+
const hash = getComposeHash(compose)
445+
expect(hash).toBeDefined()
446+
expect(hash).toHaveLength(64)
447+
})
448+
449+
it('should handle allowed_envs array', () => {
450+
const compose: AppCompose = {
451+
manifest_version: 1,
452+
name: "my-app",
453+
runner: "docker-compose",
454+
docker_compose_file: "docker-compose.yml",
455+
allowed_envs: ["NODE_ENV", "PORT", "DATABASE_URL"]
456+
}
457+
458+
const hash = getComposeHash(compose)
459+
expect(hash).toBeDefined()
460+
expect(hash).toHaveLength(64)
461+
})
462+
463+
it('should handle features array (deprecated)', () => {
464+
const compose: AppCompose = {
465+
manifest_version: 1,
466+
name: "my-app",
467+
runner: "docker-compose",
468+
docker_compose_file: "docker-compose.yml",
469+
features: ["feature1", "feature2"]
470+
}
471+
472+
const hash = getComposeHash(compose)
473+
expect(hash).toBeDefined()
474+
expect(hash).toHaveLength(64)
475+
})
476+
})
477+
478+
describe('Default Values Processing', () => {
479+
it('should set default values for undefined fields', () => {
480+
const compose: AppCompose = {
481+
runner: "docker-compose",
482+
docker_compose_file: "docker-compose.yml"
483+
}
484+
485+
const hash1 = getComposeHash(compose)
486+
487+
// Should be the same as explicitly setting defaults (but empty arrays/objects are removed)
488+
const compose2: AppCompose = {
489+
manifest_version: 1,
490+
runner: "docker-compose",
491+
docker_compose_file: "docker-compose.yml",
492+
public_logs: false,
493+
public_sysinfo: false,
494+
public_tcbinfo: true,
495+
kms_enabled: false,
496+
gateway_enabled: false,
497+
local_key_provider_enabled: false,
498+
no_instance_id: false,
499+
secure_time: true
500+
// Empty arrays and objects are removed: features, docker_config, key_provider_id, allowed_envs, name
501+
}
502+
503+
expect(hash1).toBe(getComposeHash(compose2))
504+
})
505+
})
506+
507+
describe('Gateway/Tproxy Enabled Logic', () => {
508+
it('should handle tproxy_enabled conversion to gateway_enabled', () => {
509+
const compose1: AppCompose = {
510+
runner: "docker-compose",
511+
docker_compose_file: "docker-compose.yml",
512+
tproxy_enabled: true
513+
}
514+
515+
const compose2: AppCompose = {
516+
manifest_version: 1,
517+
runner: "docker-compose",
518+
docker_compose_file: "docker-compose.yml",
519+
gateway_enabled: true,
520+
public_logs: false,
521+
public_sysinfo: false,
522+
public_tcbinfo: true,
523+
kms_enabled: false,
524+
local_key_provider_enabled: false,
525+
no_instance_id: false,
526+
secure_time: true
527+
}
528+
529+
expect(getComposeHash(compose1)).toBe(getComposeHash(compose2))
530+
})
531+
532+
it('should prioritize gateway_enabled over tproxy_enabled', () => {
533+
const compose1: AppCompose = {
534+
runner: "docker-compose",
535+
docker_compose_file: "docker-compose.yml",
536+
gateway_enabled: false,
537+
tproxy_enabled: true
538+
}
539+
540+
// Should result in gateway_enabled: true because tproxy_enabled is true
541+
const compose2: AppCompose = {
542+
manifest_version: 1,
543+
runner: "docker-compose",
544+
docker_compose_file: "docker-compose.yml",
545+
gateway_enabled: true,
546+
public_logs: false,
547+
public_sysinfo: false,
548+
public_tcbinfo: true,
549+
kms_enabled: false,
550+
local_key_provider_enabled: false,
551+
no_instance_id: false,
552+
secure_time: true
553+
}
554+
555+
expect(getComposeHash(compose1)).toBe(getComposeHash(compose2))
556+
})
557+
})
558+
559+
describe('Backward Compatibility', () => {
560+
it('should still work with legacy bash_script and pre_launch_script', () => {
561+
const compose: AppCompose = {
562+
runner: "bash",
563+
bash_script: "start.sh",
564+
pre_launch_script: "echo 'Starting...'"
565+
}
566+
567+
const hash = getComposeHash(compose)
568+
expect(hash).toBeDefined()
569+
expect(hash).toHaveLength(64)
570+
})
571+
572+
it('should maintain deterministic behavior across versions', () => {
573+
// A compose with both old and new fields
574+
const compose: AppCompose = {
575+
runner: "docker-compose",
576+
docker_compose_file: "docker-compose.yml",
577+
bash_script: "start.sh", // Should be removed by preprocessing
578+
features: ["legacy-feature"],
579+
public_logs: true,
580+
kms_enabled: false,
581+
gateway_enabled: true,
582+
allowed_envs: ["NODE_ENV"],
583+
secure_time: false
584+
}
585+
586+
const hash = getComposeHash(compose)
587+
expect(hash).toBeDefined()
588+
expect(hash).toHaveLength(64)
589+
})
590+
})
379591
})

sdk/js/src/get-compose-hash.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,36 @@ function sortObject(obj: SortableValue): SortableValue {
3030
return obj;
3131
}
3232

33+
export type KeyProviderKind = "none" | "kms" | "local";
34+
35+
export interface DockerConfig extends SortableObject {
36+
registry?: string;
37+
username?: string;
38+
token_key?: string;
39+
}
40+
3341
export interface AppCompose extends SortableObject {
34-
runner?: string;
42+
manifest_version?: number;
43+
name?: string;
44+
// Deprecated
45+
features?: string[];
46+
runner: string;
3547
docker_compose_file?: string;
48+
docker_config?: DockerConfig;
49+
public_logs?: boolean;
50+
public_sysinfo?: boolean;
51+
public_tcbinfo?: boolean;
52+
kms_enabled?: boolean;
53+
gateway_enabled?: boolean;
54+
// For backward compatibility with tproxy_enabled
55+
tproxy_enabled?: boolean;
56+
local_key_provider_enabled?: boolean;
57+
key_provider?: KeyProviderKind;
58+
key_provider_id?: string; // hex string
59+
allowed_envs?: string[];
60+
no_instance_id?: boolean;
61+
secure_time?: boolean;
62+
// Legacy fields for backward compatibility
3663
bash_script?: string;
3764
pre_launch_script?: string;
3865
}

0 commit comments

Comments
 (0)