iec-builder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +111 -0
- package/.iec.yaml +5 -0
- package/CLAUDE.md +174 -0
- package/Dockerfile +34 -0
- package/README.md +84 -0
- package/catalog-info.yaml +11 -0
- package/dist/config/env.d.ts +219 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +89 -0
- package/dist/config/env.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth.d.ts +43 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +217 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/org-access.d.ts +28 -0
- package/dist/middleware/org-access.d.ts.map +1 -0
- package/dist/middleware/org-access.js +102 -0
- package/dist/middleware/org-access.js.map +1 -0
- package/dist/models/types.d.ts +254 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +2 -0
- package/dist/models/types.js.map +1 -0
- package/dist/routes/ai.d.ts +2 -0
- package/dist/routes/ai.d.ts.map +1 -0
- package/dist/routes/ai.js +77 -0
- package/dist/routes/ai.js.map +1 -0
- package/dist/routes/audit.d.ts +2 -0
- package/dist/routes/audit.d.ts.map +1 -0
- package/dist/routes/audit.js +102 -0
- package/dist/routes/audit.js.map +1 -0
- package/dist/routes/builds.d.ts +2 -0
- package/dist/routes/builds.d.ts.map +1 -0
- package/dist/routes/builds.js +262 -0
- package/dist/routes/builds.js.map +1 -0
- package/dist/routes/cluster.d.ts +2 -0
- package/dist/routes/cluster.d.ts.map +1 -0
- package/dist/routes/cluster.js +181 -0
- package/dist/routes/cluster.js.map +1 -0
- package/dist/routes/config.d.ts +2 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +291 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/databases.d.ts +2 -0
- package/dist/routes/databases.d.ts.map +1 -0
- package/dist/routes/databases.js +161 -0
- package/dist/routes/databases.js.map +1 -0
- package/dist/routes/db-whitelist.d.ts +2 -0
- package/dist/routes/db-whitelist.d.ts.map +1 -0
- package/dist/routes/db-whitelist.js +148 -0
- package/dist/routes/db-whitelist.js.map +1 -0
- package/dist/routes/domains.d.ts +2 -0
- package/dist/routes/domains.d.ts.map +1 -0
- package/dist/routes/domains.js +449 -0
- package/dist/routes/domains.js.map +1 -0
- package/dist/routes/oauth.d.ts +2 -0
- package/dist/routes/oauth.d.ts.map +1 -0
- package/dist/routes/oauth.js +180 -0
- package/dist/routes/oauth.js.map +1 -0
- package/dist/routes/observability.d.ts +2 -0
- package/dist/routes/observability.d.ts.map +1 -0
- package/dist/routes/observability.js +167 -0
- package/dist/routes/observability.js.map +1 -0
- package/dist/routes/orgs.d.ts +2 -0
- package/dist/routes/orgs.d.ts.map +1 -0
- package/dist/routes/orgs.js +270 -0
- package/dist/routes/orgs.js.map +1 -0
- package/dist/routes/platform.d.ts +2 -0
- package/dist/routes/platform.d.ts.map +1 -0
- package/dist/routes/platform.js +107 -0
- package/dist/routes/platform.js.map +1 -0
- package/dist/routes/push.d.ts +2 -0
- package/dist/routes/push.d.ts.map +1 -0
- package/dist/routes/push.js +233 -0
- package/dist/routes/push.js.map +1 -0
- package/dist/routes/rotation.d.ts +3 -0
- package/dist/routes/rotation.d.ts.map +1 -0
- package/dist/routes/rotation.js +154 -0
- package/dist/routes/rotation.js.map +1 -0
- package/dist/routes/services.d.ts +2 -0
- package/dist/routes/services.d.ts.map +1 -0
- package/dist/routes/services.js +246 -0
- package/dist/routes/services.js.map +1 -0
- package/dist/routes/storage.d.ts +2 -0
- package/dist/routes/storage.d.ts.map +1 -0
- package/dist/routes/storage.js +118 -0
- package/dist/routes/storage.js.map +1 -0
- package/dist/routes/users.d.ts +2 -0
- package/dist/routes/users.d.ts.map +1 -0
- package/dist/routes/users.js +183 -0
- package/dist/routes/users.js.map +1 -0
- package/dist/routes/versions.d.ts +2 -0
- package/dist/routes/versions.d.ts.map +1 -0
- package/dist/routes/versions.js +195 -0
- package/dist/routes/versions.js.map +1 -0
- package/dist/routes/webhooks.d.ts +2 -0
- package/dist/routes/webhooks.d.ts.map +1 -0
- package/dist/routes/webhooks.js +334 -0
- package/dist/routes/webhooks.js.map +1 -0
- package/dist/services/__tests__/deploy-pipeline.integration.test.d.ts +2 -0
- package/dist/services/__tests__/deploy-pipeline.integration.test.d.ts.map +1 -0
- package/dist/services/__tests__/deploy-pipeline.integration.test.js +482 -0
- package/dist/services/__tests__/deploy-pipeline.integration.test.js.map +1 -0
- package/dist/services/bio-client.d.ts +68 -0
- package/dist/services/bio-client.d.ts.map +1 -0
- package/dist/services/bio-client.js +110 -0
- package/dist/services/bio-client.js.map +1 -0
- package/dist/services/build-queue.d.ts +7 -0
- package/dist/services/build-queue.d.ts.map +1 -0
- package/dist/services/build-queue.js +114 -0
- package/dist/services/build-queue.js.map +1 -0
- package/dist/services/builder.d.ts +7 -0
- package/dist/services/builder.d.ts.map +1 -0
- package/dist/services/builder.js +1384 -0
- package/dist/services/builder.js.map +1 -0
- package/dist/services/catalog.d.ts +177 -0
- package/dist/services/catalog.d.ts.map +1 -0
- package/dist/services/catalog.js +805 -0
- package/dist/services/catalog.js.map +1 -0
- package/dist/services/catalog.test.d.ts +2 -0
- package/dist/services/catalog.test.d.ts.map +1 -0
- package/dist/services/catalog.test.js +467 -0
- package/dist/services/catalog.test.js.map +1 -0
- package/dist/services/cloudflare.d.ts +43 -0
- package/dist/services/cloudflare.d.ts.map +1 -0
- package/dist/services/cloudflare.js +182 -0
- package/dist/services/cloudflare.js.map +1 -0
- package/dist/services/config-validator.d.ts +28 -0
- package/dist/services/config-validator.d.ts.map +1 -0
- package/dist/services/config-validator.js +68 -0
- package/dist/services/config-validator.js.map +1 -0
- package/dist/services/config-validator.test.d.ts +2 -0
- package/dist/services/config-validator.test.d.ts.map +1 -0
- package/dist/services/config-validator.test.js +151 -0
- package/dist/services/config-validator.test.js.map +1 -0
- package/dist/services/crypto.d.ts +19 -0
- package/dist/services/crypto.d.ts.map +1 -0
- package/dist/services/crypto.js +63 -0
- package/dist/services/crypto.js.map +1 -0
- package/dist/services/database.d.ts +26 -0
- package/dist/services/database.d.ts.map +1 -0
- package/dist/services/database.js +100 -0
- package/dist/services/database.js.map +1 -0
- package/dist/services/db-credential-manager.d.ts +73 -0
- package/dist/services/db-credential-manager.d.ts.map +1 -0
- package/dist/services/db-credential-manager.js +342 -0
- package/dist/services/db-credential-manager.js.map +1 -0
- package/dist/services/db-provisioner.d.ts +57 -0
- package/dist/services/db-provisioner.d.ts.map +1 -0
- package/dist/services/db-provisioner.js +400 -0
- package/dist/services/db-provisioner.js.map +1 -0
- package/dist/services/db-provisioner.test.d.ts +2 -0
- package/dist/services/db-provisioner.test.d.ts.map +1 -0
- package/dist/services/db-provisioner.test.js +141 -0
- package/dist/services/db-provisioner.test.js.map +1 -0
- package/dist/services/db-whitelist.d.ts +58 -0
- package/dist/services/db-whitelist.d.ts.map +1 -0
- package/dist/services/db-whitelist.js +379 -0
- package/dist/services/db-whitelist.js.map +1 -0
- package/dist/services/dependency-resolver.d.ts +58 -0
- package/dist/services/dependency-resolver.d.ts.map +1 -0
- package/dist/services/dependency-resolver.js +180 -0
- package/dist/services/dependency-resolver.js.map +1 -0
- package/dist/services/dependency-resolver.test.d.ts +2 -0
- package/dist/services/dependency-resolver.test.d.ts.map +1 -0
- package/dist/services/dependency-resolver.test.js +195 -0
- package/dist/services/dependency-resolver.test.js.map +1 -0
- package/dist/services/deploy-gate.d.ts +19 -0
- package/dist/services/deploy-gate.d.ts.map +1 -0
- package/dist/services/deploy-gate.js +56 -0
- package/dist/services/deploy-gate.js.map +1 -0
- package/dist/services/deploy-gate.test.d.ts +2 -0
- package/dist/services/deploy-gate.test.d.ts.map +1 -0
- package/dist/services/deploy-gate.test.js +199 -0
- package/dist/services/deploy-gate.test.js.map +1 -0
- package/dist/services/dockerfile-generator.d.ts +31 -0
- package/dist/services/dockerfile-generator.d.ts.map +1 -0
- package/dist/services/dockerfile-generator.js +544 -0
- package/dist/services/dockerfile-generator.js.map +1 -0
- package/dist/services/dockerfile-generator.test.d.ts +2 -0
- package/dist/services/dockerfile-generator.test.d.ts.map +1 -0
- package/dist/services/dockerfile-generator.test.js +144 -0
- package/dist/services/dockerfile-generator.test.js.map +1 -0
- package/dist/services/forgejo.d.ts +58 -0
- package/dist/services/forgejo.d.ts.map +1 -0
- package/dist/services/forgejo.js +131 -0
- package/dist/services/forgejo.js.map +1 -0
- package/dist/services/koko.d.ts +153 -0
- package/dist/services/koko.d.ts.map +1 -0
- package/dist/services/koko.js +260 -0
- package/dist/services/koko.js.map +1 -0
- package/dist/services/kubernetes.d.ts +16 -0
- package/dist/services/kubernetes.d.ts.map +1 -0
- package/dist/services/kubernetes.js +102 -0
- package/dist/services/kubernetes.js.map +1 -0
- package/dist/services/oauth-provisioner.d.ts +30 -0
- package/dist/services/oauth-provisioner.d.ts.map +1 -0
- package/dist/services/oauth-provisioner.js +182 -0
- package/dist/services/oauth-provisioner.js.map +1 -0
- package/dist/services/oauth-provisioner.test.d.ts +2 -0
- package/dist/services/oauth-provisioner.test.d.ts.map +1 -0
- package/dist/services/oauth-provisioner.test.js +349 -0
- package/dist/services/oauth-provisioner.test.js.map +1 -0
- package/dist/services/pod-diagnostics.d.ts +11 -0
- package/dist/services/pod-diagnostics.d.ts.map +1 -0
- package/dist/services/pod-diagnostics.js +201 -0
- package/dist/services/pod-diagnostics.js.map +1 -0
- package/dist/services/rotation-scheduler.d.ts +2 -0
- package/dist/services/rotation-scheduler.d.ts.map +1 -0
- package/dist/services/rotation-scheduler.js +215 -0
- package/dist/services/rotation-scheduler.js.map +1 -0
- package/dist/services/storage-credential-manager.d.ts +43 -0
- package/dist/services/storage-credential-manager.d.ts.map +1 -0
- package/dist/services/storage-credential-manager.js +159 -0
- package/dist/services/storage-credential-manager.js.map +1 -0
- package/dist/services/storage-provisioner.d.ts +32 -0
- package/dist/services/storage-provisioner.d.ts.map +1 -0
- package/dist/services/storage-provisioner.js +136 -0
- package/dist/services/storage-provisioner.js.map +1 -0
- package/dist/services/storage.d.ts +65 -0
- package/dist/services/storage.d.ts.map +1 -0
- package/dist/services/storage.js +204 -0
- package/dist/services/storage.js.map +1 -0
- package/dist/services/troubleshooter.d.ts +22 -0
- package/dist/services/troubleshooter.d.ts.map +1 -0
- package/dist/services/troubleshooter.js +168 -0
- package/dist/services/troubleshooter.js.map +1 -0
- package/dist/services/vault-client.d.ts +114 -0
- package/dist/services/vault-client.d.ts.map +1 -0
- package/dist/services/vault-client.js +411 -0
- package/dist/services/vault-client.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +6 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/response.d.ts +13 -0
- package/dist/utils/response.d.ts.map +1 -0
- package/dist/utils/response.js +12 -0
- package/dist/utils/response.js.map +1 -0
- package/docs/registry-migration.md +301 -0
- package/docs/registry-quickstart.md +169 -0
- package/ecosystem.config.cjs +14 -0
- package/findings.md +168 -0
- package/helm/default-service/Chart.yaml +6 -0
- package/helm/default-service/templates/deployment.yaml +97 -0
- package/helm/default-service/templates/ingress.yaml +43 -0
- package/helm/default-service/templates/service.yaml +17 -0
- package/helm/default-service/values.yaml +82 -0
- package/helm/services/iec-builder/Chart.yaml +6 -0
- package/helm/services/iec-builder/templates/_helpers.tpl +61 -0
- package/helm/services/iec-builder/templates/deployment.yaml +73 -0
- package/helm/services/iec-builder/templates/service.yaml +15 -0
- package/helm/services/iec-builder/templates/serviceaccount.yaml +12 -0
- package/helm/services/iec-builder/values.yaml +56 -0
- package/helm/vault-values.yaml +127 -0
- package/package.json +45 -0
- package/progress.md +156 -0
- package/scripts/.vault-init-keys.json +23 -0
- package/scripts/backfill-ownership.ts +113 -0
- package/scripts/finalize-mongo-auth.sh +212 -0
- package/scripts/setup-ipset.sh +107 -0
- package/scripts/setup-mongo-auth.sh +163 -0
- package/scripts/setup-neo4j-auth.sh +62 -0
- package/scripts/setup-redis-auth.sh +55 -0
- package/scripts/setup-registry-secret.sh +71 -0
- package/scripts/setup-vault.sh +308 -0
- package/src/config/env.ts +117 -0
- package/src/index.ts +153 -0
- package/src/middleware/auth.ts +294 -0
- package/src/middleware/org-access.ts +126 -0
- package/src/models/types.ts +288 -0
- package/src/routes/ai.ts +115 -0
- package/src/routes/audit.ts +121 -0
- package/src/routes/builds.ts +320 -0
- package/src/routes/cluster.ts +235 -0
- package/src/routes/config.ts +369 -0
- package/src/routes/databases.ts +201 -0
- package/src/routes/db-whitelist.ts +204 -0
- package/src/routes/domains.ts +547 -0
- package/src/routes/oauth.ts +195 -0
- package/src/routes/observability.ts +205 -0
- package/src/routes/orgs.ts +330 -0
- package/src/routes/platform.ts +134 -0
- package/src/routes/rotation.ts +191 -0
- package/src/routes/services.ts +290 -0
- package/src/routes/storage.ts +153 -0
- package/src/routes/users.ts +235 -0
- package/src/routes/webhooks.ts +384 -0
- package/src/services/__tests__/catalog-storage.test.ts +186 -0
- package/src/services/__tests__/deploy-pipeline.integration.test.ts +624 -0
- package/src/services/__tests__/pod-diagnostics.test.ts +332 -0
- package/src/services/__tests__/storage-credential-manager.test.ts +129 -0
- package/src/services/__tests__/storage-provisioner.test.ts +166 -0
- package/src/services/__tests__/troubleshooter.test.ts +329 -0
- package/src/services/bio-client.ts +189 -0
- package/src/services/build-queue.ts +137 -0
- package/src/services/builder.ts +1800 -0
- package/src/services/catalog.test.ts +1389 -0
- package/src/services/catalog.ts +1187 -0
- package/src/services/cloudflare.ts +259 -0
- package/src/services/config-validator.test.ts +190 -0
- package/src/services/config-validator.ts +108 -0
- package/src/services/crypto.ts +78 -0
- package/src/services/database.ts +122 -0
- package/src/services/db-credential-manager.test.ts +101 -0
- package/src/services/db-credential-manager.ts +447 -0
- package/src/services/db-provisioner.test.ts +602 -0
- package/src/services/db-provisioner.ts +589 -0
- package/src/services/db-whitelist.test.ts +671 -0
- package/src/services/db-whitelist.ts +496 -0
- package/src/services/dependency-resolver.test.ts +677 -0
- package/src/services/dependency-resolver.ts +319 -0
- package/src/services/deploy-gate.test.ts +247 -0
- package/src/services/deploy-gate.ts +75 -0
- package/src/services/dockerfile-generator.test.ts +401 -0
- package/src/services/dockerfile-generator.ts +606 -0
- package/src/services/forgejo.ts +212 -0
- package/src/services/koko.ts +492 -0
- package/src/services/kubernetes.ts +141 -0
- package/src/services/oauth-provisioner.test.ts +477 -0
- package/src/services/oauth-provisioner.ts +286 -0
- package/src/services/pod-diagnostics.ts +261 -0
- package/src/services/rotation-scheduler.ts +293 -0
- package/src/services/storage-credential-manager.ts +223 -0
- package/src/services/storage-provisioner.ts +216 -0
- package/src/services/storage.ts +274 -0
- package/src/services/troubleshooter.ts +208 -0
- package/src/services/vault-client.test.ts +272 -0
- package/src/services/vault-client.ts +587 -0
- package/src/utils/logger.ts +6 -0
- package/src/utils/response.ts +23 -0
- package/task_plan.md +171 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +19 -0
|
@@ -0,0 +1,1389 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach, beforeAll } from 'vitest'
|
|
2
|
+
import { mkdir, writeFile, rm } from 'fs/promises'
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import { tmpdir } from 'os'
|
|
5
|
+
import { randomUUID } from 'crypto'
|
|
6
|
+
|
|
7
|
+
vi.mock('../utils/logger.js', () => ({
|
|
8
|
+
logger: {
|
|
9
|
+
info: vi.fn(),
|
|
10
|
+
warn: vi.fn(),
|
|
11
|
+
error: vi.fn(),
|
|
12
|
+
},
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
const mockEnv = vi.hoisted(() => ({
|
|
16
|
+
ENFORCE_MINIMUM_CATALOG_VERSION: 'false',
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
vi.mock('../config/env.js', () => ({
|
|
20
|
+
env: mockEnv,
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
import { parseCatalogInfo } from './catalog.js'
|
|
24
|
+
|
|
25
|
+
async function createFixture(catalogYaml: string): Promise<string> {
|
|
26
|
+
const dir = join(tmpdir(), `iec-catalog-test-${randomUUID()}`)
|
|
27
|
+
await mkdir(dir, { recursive: true })
|
|
28
|
+
await writeFile(join(dir, 'catalog-info.yaml'), catalogYaml, 'utf-8')
|
|
29
|
+
return dir
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('catalog defaults', () => {
|
|
33
|
+
const tempDirs: string[] = []
|
|
34
|
+
|
|
35
|
+
afterEach(async () => {
|
|
36
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
37
|
+
tempDirs.splice(0, tempDirs.length)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should apply correct static framework defaults', async () => {
|
|
41
|
+
const dir = await createFixture(`
|
|
42
|
+
apiVersion: backstage.io/v1alpha1
|
|
43
|
+
kind: Component
|
|
44
|
+
metadata:
|
|
45
|
+
name: my-static-site
|
|
46
|
+
description: A simple static site
|
|
47
|
+
annotations:
|
|
48
|
+
insureco.io/catalog-version: "1"
|
|
49
|
+
insureco.io/framework: static
|
|
50
|
+
spec:
|
|
51
|
+
type: service
|
|
52
|
+
lifecycle: production
|
|
53
|
+
owner: test-org
|
|
54
|
+
`)
|
|
55
|
+
tempDirs.push(dir)
|
|
56
|
+
|
|
57
|
+
const result = await parseCatalogInfo(dir)
|
|
58
|
+
expect(result).not.toBeNull()
|
|
59
|
+
expect(result!.framework).toBe('static')
|
|
60
|
+
expect(result!.buildCommand).toBe('true')
|
|
61
|
+
expect(result!.outputDir).toBe('.')
|
|
62
|
+
expect(result!.port).toBe(80)
|
|
63
|
+
expect(result!.healthEndpoint).toBe('/health')
|
|
64
|
+
// startCommand falls back to 'npm start' because '' is falsy in the || chain
|
|
65
|
+
expect(result!.startCommand).toBe('npm start')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should allow annotation overrides for static framework', async () => {
|
|
69
|
+
const dir = await createFixture(`
|
|
70
|
+
apiVersion: backstage.io/v1alpha1
|
|
71
|
+
kind: Component
|
|
72
|
+
metadata:
|
|
73
|
+
name: my-static-site
|
|
74
|
+
annotations:
|
|
75
|
+
insureco.io/catalog-version: "1"
|
|
76
|
+
insureco.io/framework: static
|
|
77
|
+
insureco.io/build-command: "npm run build"
|
|
78
|
+
insureco.io/output-dir: "dist"
|
|
79
|
+
insureco.io/port: "8080"
|
|
80
|
+
spec:
|
|
81
|
+
type: service
|
|
82
|
+
lifecycle: production
|
|
83
|
+
owner: test-org
|
|
84
|
+
`)
|
|
85
|
+
tempDirs.push(dir)
|
|
86
|
+
|
|
87
|
+
const result = await parseCatalogInfo(dir)
|
|
88
|
+
expect(result).not.toBeNull()
|
|
89
|
+
expect(result!.framework).toBe('static')
|
|
90
|
+
expect(result!.buildCommand).toBe('npm run build')
|
|
91
|
+
expect(result!.outputDir).toBe('dist')
|
|
92
|
+
expect(result!.port).toBe(8080)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should return null when no catalog-info.yaml exists', async () => {
|
|
96
|
+
const dir = join(tmpdir(), `iec-catalog-test-${randomUUID()}`)
|
|
97
|
+
await mkdir(dir, { recursive: true })
|
|
98
|
+
tempDirs.push(dir)
|
|
99
|
+
|
|
100
|
+
const result = await parseCatalogInfo(dir)
|
|
101
|
+
expect(result).toBeNull()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should apply express framework defaults', async () => {
|
|
105
|
+
const dir = await createFixture(`
|
|
106
|
+
apiVersion: backstage.io/v1alpha1
|
|
107
|
+
kind: Component
|
|
108
|
+
metadata:
|
|
109
|
+
name: my-api
|
|
110
|
+
annotations:
|
|
111
|
+
insureco.io/catalog-version: "1"
|
|
112
|
+
insureco.io/framework: express
|
|
113
|
+
spec:
|
|
114
|
+
type: service
|
|
115
|
+
lifecycle: production
|
|
116
|
+
owner: test-org
|
|
117
|
+
`)
|
|
118
|
+
tempDirs.push(dir)
|
|
119
|
+
|
|
120
|
+
const result = await parseCatalogInfo(dir)
|
|
121
|
+
expect(result).not.toBeNull()
|
|
122
|
+
expect(result!.framework).toBe('express')
|
|
123
|
+
expect(result!.buildCommand).toBe('npm run build')
|
|
124
|
+
expect(result!.outputDir).toBe('dist')
|
|
125
|
+
expect(result!.port).toBe(3000)
|
|
126
|
+
expect(result!.healthEndpoint).toBe('/health')
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
describe('catalog version validation', () => {
|
|
131
|
+
const tempDirs: string[] = []
|
|
132
|
+
|
|
133
|
+
afterEach(async () => {
|
|
134
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
135
|
+
tempDirs.splice(0, tempDirs.length)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('should reject catalog with missing version annotation', async () => {
|
|
139
|
+
const dir = await createFixture(`
|
|
140
|
+
apiVersion: backstage.io/v1alpha1
|
|
141
|
+
kind: Component
|
|
142
|
+
metadata:
|
|
143
|
+
name: my-api
|
|
144
|
+
annotations:
|
|
145
|
+
insureco.io/framework: express
|
|
146
|
+
spec:
|
|
147
|
+
type: service
|
|
148
|
+
lifecycle: production
|
|
149
|
+
owner: test-org
|
|
150
|
+
`)
|
|
151
|
+
tempDirs.push(dir)
|
|
152
|
+
|
|
153
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
154
|
+
'missing the required "insureco.io/catalog-version" annotation'
|
|
155
|
+
)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('should reject catalog with invalid semver format', async () => {
|
|
159
|
+
const dir = await createFixture(`
|
|
160
|
+
apiVersion: backstage.io/v1alpha1
|
|
161
|
+
kind: Component
|
|
162
|
+
metadata:
|
|
163
|
+
name: my-api
|
|
164
|
+
annotations:
|
|
165
|
+
insureco.io/catalog-version: "0"
|
|
166
|
+
insureco.io/framework: express
|
|
167
|
+
spec:
|
|
168
|
+
type: service
|
|
169
|
+
lifecycle: production
|
|
170
|
+
owner: test-org
|
|
171
|
+
`)
|
|
172
|
+
tempDirs.push(dir)
|
|
173
|
+
|
|
174
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
175
|
+
'Invalid catalog version format'
|
|
176
|
+
)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('should include docs URL in missing version error', async () => {
|
|
180
|
+
const dir = await createFixture(`
|
|
181
|
+
apiVersion: backstage.io/v1alpha1
|
|
182
|
+
kind: Component
|
|
183
|
+
metadata:
|
|
184
|
+
name: my-api
|
|
185
|
+
annotations:
|
|
186
|
+
insureco.io/framework: express
|
|
187
|
+
spec:
|
|
188
|
+
type: service
|
|
189
|
+
lifecycle: production
|
|
190
|
+
owner: test-org
|
|
191
|
+
`)
|
|
192
|
+
tempDirs.push(dir)
|
|
193
|
+
|
|
194
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
195
|
+
'https://tawa.insureco.io/docs/catalog-reference'
|
|
196
|
+
)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('should reject catalog with incompatible major version', async () => {
|
|
200
|
+
const dir = await createFixture(`
|
|
201
|
+
apiVersion: backstage.io/v1alpha1
|
|
202
|
+
kind: Component
|
|
203
|
+
metadata:
|
|
204
|
+
name: my-api
|
|
205
|
+
annotations:
|
|
206
|
+
insureco.io/catalog-version: "1.0.0"
|
|
207
|
+
insureco.io/framework: express
|
|
208
|
+
spec:
|
|
209
|
+
type: service
|
|
210
|
+
lifecycle: production
|
|
211
|
+
owner: test-org
|
|
212
|
+
`)
|
|
213
|
+
tempDirs.push(dir)
|
|
214
|
+
|
|
215
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
216
|
+
'not compatible with this builder'
|
|
217
|
+
)
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('should reject catalog version ahead of builder', async () => {
|
|
221
|
+
const dir = await createFixture(`
|
|
222
|
+
apiVersion: backstage.io/v1alpha1
|
|
223
|
+
kind: Component
|
|
224
|
+
metadata:
|
|
225
|
+
name: my-api
|
|
226
|
+
annotations:
|
|
227
|
+
insureco.io/catalog-version: "0.9.0"
|
|
228
|
+
insureco.io/framework: express
|
|
229
|
+
insureco.io/health-endpoint: /health
|
|
230
|
+
spec:
|
|
231
|
+
type: service
|
|
232
|
+
lifecycle: production
|
|
233
|
+
owner: test-org
|
|
234
|
+
`)
|
|
235
|
+
tempDirs.push(dir)
|
|
236
|
+
|
|
237
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
238
|
+
'not supported by this builder'
|
|
239
|
+
)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
it('should warn but accept catalog with lower minor version', async () => {
|
|
243
|
+
const dir = await createFixture(`
|
|
244
|
+
apiVersion: backstage.io/v1alpha1
|
|
245
|
+
kind: Component
|
|
246
|
+
metadata:
|
|
247
|
+
name: my-api
|
|
248
|
+
annotations:
|
|
249
|
+
insureco.io/catalog-version: "0.1.0"
|
|
250
|
+
insureco.io/framework: express
|
|
251
|
+
spec:
|
|
252
|
+
type: service
|
|
253
|
+
lifecycle: production
|
|
254
|
+
owner: test-org
|
|
255
|
+
`)
|
|
256
|
+
tempDirs.push(dir)
|
|
257
|
+
|
|
258
|
+
const result = await parseCatalogInfo(dir)
|
|
259
|
+
expect(result).not.toBeNull()
|
|
260
|
+
expect(result!.catalogVersion).toBe('0.1.0')
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it('should accept legacy version "1" as "0.1.0"', async () => {
|
|
264
|
+
const dir = await createFixture(`
|
|
265
|
+
apiVersion: backstage.io/v1alpha1
|
|
266
|
+
kind: Component
|
|
267
|
+
metadata:
|
|
268
|
+
name: my-api
|
|
269
|
+
annotations:
|
|
270
|
+
insureco.io/catalog-version: "1"
|
|
271
|
+
insureco.io/framework: express
|
|
272
|
+
spec:
|
|
273
|
+
type: service
|
|
274
|
+
lifecycle: production
|
|
275
|
+
owner: test-org
|
|
276
|
+
`)
|
|
277
|
+
tempDirs.push(dir)
|
|
278
|
+
|
|
279
|
+
const result = await parseCatalogInfo(dir)
|
|
280
|
+
expect(result).not.toBeNull()
|
|
281
|
+
expect(result!.catalogVersion).toBe('0.1.0')
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('should accept catalog with current version 0.2.0', async () => {
|
|
285
|
+
const dir = await createFixture(`
|
|
286
|
+
apiVersion: backstage.io/v1alpha1
|
|
287
|
+
kind: Component
|
|
288
|
+
metadata:
|
|
289
|
+
name: my-api
|
|
290
|
+
annotations:
|
|
291
|
+
insureco.io/catalog-version: "0.2.0"
|
|
292
|
+
insureco.io/framework: express
|
|
293
|
+
insureco.io/health-endpoint: /health
|
|
294
|
+
spec:
|
|
295
|
+
type: service
|
|
296
|
+
lifecycle: production
|
|
297
|
+
owner: test-org
|
|
298
|
+
`)
|
|
299
|
+
tempDirs.push(dir)
|
|
300
|
+
|
|
301
|
+
const result = await parseCatalogInfo(dir)
|
|
302
|
+
expect(result).not.toBeNull()
|
|
303
|
+
expect(result!.catalogVersion).toBe('0.2.0')
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should reject 0.2.0 catalog missing required framework annotation', async () => {
|
|
307
|
+
const dir = await createFixture(`
|
|
308
|
+
apiVersion: backstage.io/v1alpha1
|
|
309
|
+
kind: Component
|
|
310
|
+
metadata:
|
|
311
|
+
name: my-api
|
|
312
|
+
annotations:
|
|
313
|
+
insureco.io/catalog-version: "0.2.0"
|
|
314
|
+
insureco.io/health-endpoint: /health
|
|
315
|
+
spec:
|
|
316
|
+
type: service
|
|
317
|
+
lifecycle: production
|
|
318
|
+
owner: test-org
|
|
319
|
+
`)
|
|
320
|
+
tempDirs.push(dir)
|
|
321
|
+
|
|
322
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
323
|
+
'requires the "insureco.io/framework" annotation'
|
|
324
|
+
)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
it('should reject 0.2.0 catalog missing required health-endpoint annotation', async () => {
|
|
328
|
+
const dir = await createFixture(`
|
|
329
|
+
apiVersion: backstage.io/v1alpha1
|
|
330
|
+
kind: Component
|
|
331
|
+
metadata:
|
|
332
|
+
name: my-api
|
|
333
|
+
annotations:
|
|
334
|
+
insureco.io/catalog-version: "0.2.0"
|
|
335
|
+
insureco.io/framework: express
|
|
336
|
+
spec:
|
|
337
|
+
type: service
|
|
338
|
+
lifecycle: production
|
|
339
|
+
owner: test-org
|
|
340
|
+
`)
|
|
341
|
+
tempDirs.push(dir)
|
|
342
|
+
|
|
343
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
344
|
+
'requires the "insureco.io/health-endpoint" annotation'
|
|
345
|
+
)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
it('should accept catalog with current version', async () => {
|
|
349
|
+
const dir = await createFixture(`
|
|
350
|
+
apiVersion: backstage.io/v1alpha1
|
|
351
|
+
kind: Component
|
|
352
|
+
metadata:
|
|
353
|
+
name: my-api
|
|
354
|
+
annotations:
|
|
355
|
+
insureco.io/catalog-version: "1"
|
|
356
|
+
insureco.io/framework: express
|
|
357
|
+
spec:
|
|
358
|
+
type: service
|
|
359
|
+
lifecycle: production
|
|
360
|
+
owner: test-org
|
|
361
|
+
`)
|
|
362
|
+
tempDirs.push(dir)
|
|
363
|
+
|
|
364
|
+
const result = await parseCatalogInfo(dir)
|
|
365
|
+
expect(result).not.toBeNull()
|
|
366
|
+
expect(result!.name).toBe('my-api')
|
|
367
|
+
expect(result!.framework).toBe('express')
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('should reject catalog with no annotations at all', async () => {
|
|
371
|
+
const dir = await createFixture(`
|
|
372
|
+
apiVersion: backstage.io/v1alpha1
|
|
373
|
+
kind: Component
|
|
374
|
+
metadata:
|
|
375
|
+
name: my-api
|
|
376
|
+
spec:
|
|
377
|
+
type: service
|
|
378
|
+
lifecycle: production
|
|
379
|
+
owner: test-org
|
|
380
|
+
`)
|
|
381
|
+
tempDirs.push(dir)
|
|
382
|
+
|
|
383
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
384
|
+
'missing the required "insureco.io/catalog-version" annotation'
|
|
385
|
+
)
|
|
386
|
+
})
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
describe('catalog config declarations', () => {
|
|
390
|
+
const tempDirs: string[] = []
|
|
391
|
+
|
|
392
|
+
afterEach(async () => {
|
|
393
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
394
|
+
tempDirs.splice(0, tempDirs.length)
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
it('should parse spec.config declarations with all fields', async () => {
|
|
398
|
+
const dir = await createFixture(`
|
|
399
|
+
apiVersion: backstage.io/v1alpha1
|
|
400
|
+
kind: Component
|
|
401
|
+
metadata:
|
|
402
|
+
name: my-api
|
|
403
|
+
annotations:
|
|
404
|
+
insureco.io/catalog-version: "1"
|
|
405
|
+
insureco.io/framework: express
|
|
406
|
+
spec:
|
|
407
|
+
type: service
|
|
408
|
+
lifecycle: production
|
|
409
|
+
owner: test-org
|
|
410
|
+
config:
|
|
411
|
+
- key: NEXTAUTH_SECRET
|
|
412
|
+
secret: true
|
|
413
|
+
required: true
|
|
414
|
+
- key: LOG_LEVEL
|
|
415
|
+
default: "info"
|
|
416
|
+
- key: STRIPE_API_KEY
|
|
417
|
+
secret: true
|
|
418
|
+
required: true
|
|
419
|
+
`)
|
|
420
|
+
tempDirs.push(dir)
|
|
421
|
+
|
|
422
|
+
const result = await parseCatalogInfo(dir)
|
|
423
|
+
expect(result).not.toBeNull()
|
|
424
|
+
expect(result!.configDeclarations).toEqual([
|
|
425
|
+
{ key: 'NEXTAUTH_SECRET', secret: true, required: true },
|
|
426
|
+
{ key: 'LOG_LEVEL', default: 'info' },
|
|
427
|
+
{ key: 'STRIPE_API_KEY', secret: true, required: true },
|
|
428
|
+
])
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
it('should default to empty array when spec.config is missing', async () => {
|
|
432
|
+
const dir = await createFixture(`
|
|
433
|
+
apiVersion: backstage.io/v1alpha1
|
|
434
|
+
kind: Component
|
|
435
|
+
metadata:
|
|
436
|
+
name: my-api
|
|
437
|
+
annotations:
|
|
438
|
+
insureco.io/catalog-version: "1"
|
|
439
|
+
insureco.io/framework: express
|
|
440
|
+
spec:
|
|
441
|
+
type: service
|
|
442
|
+
lifecycle: production
|
|
443
|
+
owner: test-org
|
|
444
|
+
`)
|
|
445
|
+
tempDirs.push(dir)
|
|
446
|
+
|
|
447
|
+
const result = await parseCatalogInfo(dir)
|
|
448
|
+
expect(result).not.toBeNull()
|
|
449
|
+
expect(result!.configDeclarations).toEqual([])
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('should reject declarations with invalid key names', async () => {
|
|
453
|
+
const dir = await createFixture(`
|
|
454
|
+
apiVersion: backstage.io/v1alpha1
|
|
455
|
+
kind: Component
|
|
456
|
+
metadata:
|
|
457
|
+
name: my-api
|
|
458
|
+
annotations:
|
|
459
|
+
insureco.io/catalog-version: "1"
|
|
460
|
+
insureco.io/framework: express
|
|
461
|
+
spec:
|
|
462
|
+
type: service
|
|
463
|
+
lifecycle: production
|
|
464
|
+
owner: test-org
|
|
465
|
+
config:
|
|
466
|
+
- key: "INVALID KEY WITH SPACES"
|
|
467
|
+
`)
|
|
468
|
+
tempDirs.push(dir)
|
|
469
|
+
|
|
470
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow('Invalid config declaration key')
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
it('should reject duplicate declaration keys', async () => {
|
|
474
|
+
const dir = await createFixture(`
|
|
475
|
+
apiVersion: backstage.io/v1alpha1
|
|
476
|
+
kind: Component
|
|
477
|
+
metadata:
|
|
478
|
+
name: my-api
|
|
479
|
+
annotations:
|
|
480
|
+
insureco.io/catalog-version: "1"
|
|
481
|
+
insureco.io/framework: express
|
|
482
|
+
spec:
|
|
483
|
+
type: service
|
|
484
|
+
lifecycle: production
|
|
485
|
+
owner: test-org
|
|
486
|
+
config:
|
|
487
|
+
- key: STRIPE_KEY
|
|
488
|
+
secret: true
|
|
489
|
+
- key: STRIPE_KEY
|
|
490
|
+
`)
|
|
491
|
+
tempDirs.push(dir)
|
|
492
|
+
|
|
493
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow('Duplicate config declaration key: "STRIPE_KEY"')
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
it('should skip non-object entries in config array', async () => {
|
|
497
|
+
const dir = await createFixture(`
|
|
498
|
+
apiVersion: backstage.io/v1alpha1
|
|
499
|
+
kind: Component
|
|
500
|
+
metadata:
|
|
501
|
+
name: my-api
|
|
502
|
+
annotations:
|
|
503
|
+
insureco.io/catalog-version: "1"
|
|
504
|
+
insureco.io/framework: express
|
|
505
|
+
spec:
|
|
506
|
+
type: service
|
|
507
|
+
lifecycle: production
|
|
508
|
+
owner: test-org
|
|
509
|
+
config:
|
|
510
|
+
- key: VALID_KEY
|
|
511
|
+
- "just a string"
|
|
512
|
+
- 42
|
|
513
|
+
`)
|
|
514
|
+
tempDirs.push(dir)
|
|
515
|
+
|
|
516
|
+
const result = await parseCatalogInfo(dir)
|
|
517
|
+
expect(result).not.toBeNull()
|
|
518
|
+
expect(result!.configDeclarations).toEqual([{ key: 'VALID_KEY' }])
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
it('should parse minimal declarations with only key', async () => {
|
|
522
|
+
const dir = await createFixture(`
|
|
523
|
+
apiVersion: backstage.io/v1alpha1
|
|
524
|
+
kind: Component
|
|
525
|
+
metadata:
|
|
526
|
+
name: my-api
|
|
527
|
+
annotations:
|
|
528
|
+
insureco.io/catalog-version: "1"
|
|
529
|
+
insureco.io/framework: express
|
|
530
|
+
spec:
|
|
531
|
+
type: service
|
|
532
|
+
lifecycle: production
|
|
533
|
+
owner: test-org
|
|
534
|
+
config:
|
|
535
|
+
- key: APP_NAME
|
|
536
|
+
`)
|
|
537
|
+
tempDirs.push(dir)
|
|
538
|
+
|
|
539
|
+
const result = await parseCatalogInfo(dir)
|
|
540
|
+
expect(result).not.toBeNull()
|
|
541
|
+
expect(result!.configDeclarations).toEqual([
|
|
542
|
+
{ key: 'APP_NAME' },
|
|
543
|
+
])
|
|
544
|
+
})
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
describe('catalog auth parsing', () => {
|
|
548
|
+
const tempDirs: string[] = []
|
|
549
|
+
|
|
550
|
+
afterEach(async () => {
|
|
551
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
552
|
+
tempDirs.splice(0, tempDirs.length)
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
it('should parse auth mode sso', async () => {
|
|
556
|
+
const dir = await createFixture(`
|
|
557
|
+
apiVersion: backstage.io/v1alpha1
|
|
558
|
+
kind: Component
|
|
559
|
+
metadata:
|
|
560
|
+
name: my-api
|
|
561
|
+
annotations:
|
|
562
|
+
insureco.io/catalog-version: "1"
|
|
563
|
+
insureco.io/framework: express
|
|
564
|
+
spec:
|
|
565
|
+
type: service
|
|
566
|
+
lifecycle: production
|
|
567
|
+
owner: test-org
|
|
568
|
+
auth:
|
|
569
|
+
mode: sso
|
|
570
|
+
`)
|
|
571
|
+
tempDirs.push(dir)
|
|
572
|
+
|
|
573
|
+
const result = await parseCatalogInfo(dir)
|
|
574
|
+
expect(result).not.toBeNull()
|
|
575
|
+
expect(result!.authMode).toBe('sso')
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
it('should parse auth mode service-only', async () => {
|
|
579
|
+
const dir = await createFixture(`
|
|
580
|
+
apiVersion: backstage.io/v1alpha1
|
|
581
|
+
kind: Component
|
|
582
|
+
metadata:
|
|
583
|
+
name: worker-svc
|
|
584
|
+
annotations:
|
|
585
|
+
insureco.io/catalog-version: "1"
|
|
586
|
+
insureco.io/framework: express
|
|
587
|
+
spec:
|
|
588
|
+
type: service
|
|
589
|
+
lifecycle: production
|
|
590
|
+
owner: test-org
|
|
591
|
+
auth:
|
|
592
|
+
mode: service-only
|
|
593
|
+
`)
|
|
594
|
+
tempDirs.push(dir)
|
|
595
|
+
|
|
596
|
+
const result = await parseCatalogInfo(dir)
|
|
597
|
+
expect(result).not.toBeNull()
|
|
598
|
+
expect(result!.authMode).toBe('service-only')
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
it('should parse auth mode none', async () => {
|
|
602
|
+
const dir = await createFixture(`
|
|
603
|
+
apiVersion: backstage.io/v1alpha1
|
|
604
|
+
kind: Component
|
|
605
|
+
metadata:
|
|
606
|
+
name: public-api
|
|
607
|
+
annotations:
|
|
608
|
+
insureco.io/catalog-version: "1"
|
|
609
|
+
insureco.io/framework: express
|
|
610
|
+
spec:
|
|
611
|
+
type: service
|
|
612
|
+
lifecycle: production
|
|
613
|
+
owner: test-org
|
|
614
|
+
auth:
|
|
615
|
+
mode: none
|
|
616
|
+
`)
|
|
617
|
+
tempDirs.push(dir)
|
|
618
|
+
|
|
619
|
+
const result = await parseCatalogInfo(dir)
|
|
620
|
+
expect(result).not.toBeNull()
|
|
621
|
+
expect(result!.authMode).toBe('none')
|
|
622
|
+
})
|
|
623
|
+
|
|
624
|
+
it('should return undefined authMode when spec.auth is not specified', async () => {
|
|
625
|
+
const dir = await createFixture(`
|
|
626
|
+
apiVersion: backstage.io/v1alpha1
|
|
627
|
+
kind: Component
|
|
628
|
+
metadata:
|
|
629
|
+
name: my-api
|
|
630
|
+
annotations:
|
|
631
|
+
insureco.io/catalog-version: "1"
|
|
632
|
+
insureco.io/framework: express
|
|
633
|
+
spec:
|
|
634
|
+
type: service
|
|
635
|
+
lifecycle: production
|
|
636
|
+
owner: test-org
|
|
637
|
+
`)
|
|
638
|
+
tempDirs.push(dir)
|
|
639
|
+
|
|
640
|
+
const result = await parseCatalogInfo(dir)
|
|
641
|
+
expect(result).not.toBeNull()
|
|
642
|
+
expect(result!.authMode).toBeUndefined()
|
|
643
|
+
})
|
|
644
|
+
|
|
645
|
+
it('should throw for invalid auth mode value', async () => {
|
|
646
|
+
const dir = await createFixture(`
|
|
647
|
+
apiVersion: backstage.io/v1alpha1
|
|
648
|
+
kind: Component
|
|
649
|
+
metadata:
|
|
650
|
+
name: my-api
|
|
651
|
+
annotations:
|
|
652
|
+
insureco.io/catalog-version: "1"
|
|
653
|
+
insureco.io/framework: express
|
|
654
|
+
spec:
|
|
655
|
+
type: service
|
|
656
|
+
lifecycle: production
|
|
657
|
+
owner: test-org
|
|
658
|
+
auth:
|
|
659
|
+
mode: invalid-mode
|
|
660
|
+
`)
|
|
661
|
+
tempDirs.push(dir)
|
|
662
|
+
|
|
663
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow('Invalid spec.auth.mode: "invalid-mode"')
|
|
664
|
+
})
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
describe('catalog consumesDatabase parsing', () => {
|
|
668
|
+
const tempDirs: string[] = []
|
|
669
|
+
|
|
670
|
+
afterEach(async () => {
|
|
671
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
672
|
+
tempDirs.splice(0, tempDirs.length)
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
it('should parse consumesDatabase with envVar override in 0.2.0 catalog', async () => {
|
|
676
|
+
const dir = await createFixture(`
|
|
677
|
+
apiVersion: backstage.io/v1alpha1
|
|
678
|
+
kind: Component
|
|
679
|
+
metadata:
|
|
680
|
+
name: portal
|
|
681
|
+
annotations:
|
|
682
|
+
insureco.io/catalog-version: "0.2.0"
|
|
683
|
+
insureco.io/framework: nextjs
|
|
684
|
+
insureco.io/health-endpoint: /api/health
|
|
685
|
+
spec:
|
|
686
|
+
type: service
|
|
687
|
+
lifecycle: production
|
|
688
|
+
owner: test-org
|
|
689
|
+
consumesDatabase:
|
|
690
|
+
- service: bio
|
|
691
|
+
type: mongodb
|
|
692
|
+
envVar: MONGODB_URI
|
|
693
|
+
`)
|
|
694
|
+
tempDirs.push(dir)
|
|
695
|
+
|
|
696
|
+
const result = await parseCatalogInfo(dir)
|
|
697
|
+
expect(result).not.toBeNull()
|
|
698
|
+
expect(result!.consumesDatabase).toEqual([
|
|
699
|
+
{ service: 'bio', type: 'mongodb', envVar: 'MONGODB_URI' },
|
|
700
|
+
])
|
|
701
|
+
})
|
|
702
|
+
|
|
703
|
+
it('should ignore consumesDatabase in 0.1.0 catalog', async () => {
|
|
704
|
+
const dir = await createFixture(`
|
|
705
|
+
apiVersion: backstage.io/v1alpha1
|
|
706
|
+
kind: Component
|
|
707
|
+
metadata:
|
|
708
|
+
name: portal
|
|
709
|
+
annotations:
|
|
710
|
+
insureco.io/catalog-version: "0.1.0"
|
|
711
|
+
insureco.io/framework: nextjs
|
|
712
|
+
spec:
|
|
713
|
+
type: service
|
|
714
|
+
lifecycle: production
|
|
715
|
+
owner: test-org
|
|
716
|
+
consumesDatabase:
|
|
717
|
+
- service: bio
|
|
718
|
+
type: mongodb
|
|
719
|
+
`)
|
|
720
|
+
tempDirs.push(dir)
|
|
721
|
+
|
|
722
|
+
const result = await parseCatalogInfo(dir)
|
|
723
|
+
expect(result).not.toBeNull()
|
|
724
|
+
expect(result!.consumesDatabase).toEqual([])
|
|
725
|
+
})
|
|
726
|
+
|
|
727
|
+
it('should parse databases with sharedWith in 0.2.0 catalog', async () => {
|
|
728
|
+
const dir = await createFixture(`
|
|
729
|
+
apiVersion: backstage.io/v1alpha1
|
|
730
|
+
kind: Component
|
|
731
|
+
metadata:
|
|
732
|
+
name: bio
|
|
733
|
+
annotations:
|
|
734
|
+
insureco.io/catalog-version: "0.2.0"
|
|
735
|
+
insureco.io/framework: express
|
|
736
|
+
insureco.io/health-endpoint: /health
|
|
737
|
+
spec:
|
|
738
|
+
type: service
|
|
739
|
+
lifecycle: production
|
|
740
|
+
owner: test-org
|
|
741
|
+
databases:
|
|
742
|
+
- type: mongodb
|
|
743
|
+
name: bio
|
|
744
|
+
sharedWith:
|
|
745
|
+
- service: portal
|
|
746
|
+
access: readWrite
|
|
747
|
+
`)
|
|
748
|
+
tempDirs.push(dir)
|
|
749
|
+
|
|
750
|
+
const result = await parseCatalogInfo(dir)
|
|
751
|
+
expect(result).not.toBeNull()
|
|
752
|
+
expect(result!.databases).toHaveLength(1)
|
|
753
|
+
expect(result!.databases[0].sharedWith).toEqual([
|
|
754
|
+
{ service: 'portal', access: 'readWrite' },
|
|
755
|
+
])
|
|
756
|
+
})
|
|
757
|
+
})
|
|
758
|
+
|
|
759
|
+
describe('checkCatalogVersion', () => {
|
|
760
|
+
// Import the exported function directly
|
|
761
|
+
let checkCatalogVersion: typeof import('./catalog.js').checkCatalogVersion
|
|
762
|
+
|
|
763
|
+
beforeAll(async () => {
|
|
764
|
+
const mod = await import('./catalog.js')
|
|
765
|
+
checkCatalogVersion = mod.checkCatalogVersion
|
|
766
|
+
})
|
|
767
|
+
|
|
768
|
+
it('should return ok for matching version', () => {
|
|
769
|
+
expect(checkCatalogVersion('0.4.0').result).toBe('ok')
|
|
770
|
+
})
|
|
771
|
+
|
|
772
|
+
it('should return warn for lower minor version', () => {
|
|
773
|
+
const result = checkCatalogVersion('0.1.0')
|
|
774
|
+
expect(result.result).toBe('warn')
|
|
775
|
+
expect(result.message).toContain('behind')
|
|
776
|
+
})
|
|
777
|
+
|
|
778
|
+
it('should return reject for higher minor version', () => {
|
|
779
|
+
const result = checkCatalogVersion('0.9.0')
|
|
780
|
+
expect(result.result).toBe('reject')
|
|
781
|
+
expect(result.message).toContain('not supported')
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
it('should return reject for different major version', () => {
|
|
785
|
+
const result = checkCatalogVersion('1.0.0')
|
|
786
|
+
expect(result.result).toBe('reject')
|
|
787
|
+
expect(result.message).toContain('not compatible')
|
|
788
|
+
})
|
|
789
|
+
|
|
790
|
+
it('should return reject for invalid format', () => {
|
|
791
|
+
const result = checkCatalogVersion('abc')
|
|
792
|
+
expect(result.result).toBe('reject')
|
|
793
|
+
expect(result.message).toContain('Invalid catalog version format')
|
|
794
|
+
})
|
|
795
|
+
})
|
|
796
|
+
|
|
797
|
+
describe('catalog minimum version enforcement', () => {
|
|
798
|
+
const tempDirs: string[] = []
|
|
799
|
+
|
|
800
|
+
afterEach(async () => {
|
|
801
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
802
|
+
tempDirs.splice(0, tempDirs.length)
|
|
803
|
+
mockEnv.ENFORCE_MINIMUM_CATALOG_VERSION = 'false'
|
|
804
|
+
})
|
|
805
|
+
|
|
806
|
+
it('should reject legacy version "1" when enforcement is enabled', async () => {
|
|
807
|
+
mockEnv.ENFORCE_MINIMUM_CATALOG_VERSION = 'true'
|
|
808
|
+
|
|
809
|
+
const dir = await createFixture(`
|
|
810
|
+
apiVersion: backstage.io/v1alpha1
|
|
811
|
+
kind: Component
|
|
812
|
+
metadata:
|
|
813
|
+
name: my-api
|
|
814
|
+
annotations:
|
|
815
|
+
insureco.io/catalog-version: "1"
|
|
816
|
+
insureco.io/framework: express
|
|
817
|
+
spec:
|
|
818
|
+
type: service
|
|
819
|
+
lifecycle: production
|
|
820
|
+
owner: test-org
|
|
821
|
+
`)
|
|
822
|
+
tempDirs.push(dir)
|
|
823
|
+
|
|
824
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
825
|
+
'below the minimum supported version'
|
|
826
|
+
)
|
|
827
|
+
})
|
|
828
|
+
|
|
829
|
+
it('should warn but accept legacy version "1" when enforcement is off', async () => {
|
|
830
|
+
const dir = await createFixture(`
|
|
831
|
+
apiVersion: backstage.io/v1alpha1
|
|
832
|
+
kind: Component
|
|
833
|
+
metadata:
|
|
834
|
+
name: my-api
|
|
835
|
+
annotations:
|
|
836
|
+
insureco.io/catalog-version: "1"
|
|
837
|
+
insureco.io/framework: express
|
|
838
|
+
spec:
|
|
839
|
+
type: service
|
|
840
|
+
lifecycle: production
|
|
841
|
+
owner: test-org
|
|
842
|
+
`)
|
|
843
|
+
tempDirs.push(dir)
|
|
844
|
+
|
|
845
|
+
const result = await parseCatalogInfo(dir)
|
|
846
|
+
expect(result).not.toBeNull()
|
|
847
|
+
expect(result!.catalogVersion).toBe('0.1.0')
|
|
848
|
+
})
|
|
849
|
+
|
|
850
|
+
it('should reject version 0.1.0 when enforcement is enabled', async () => {
|
|
851
|
+
mockEnv.ENFORCE_MINIMUM_CATALOG_VERSION = 'true'
|
|
852
|
+
|
|
853
|
+
const dir = await createFixture(`
|
|
854
|
+
apiVersion: backstage.io/v1alpha1
|
|
855
|
+
kind: Component
|
|
856
|
+
metadata:
|
|
857
|
+
name: my-api
|
|
858
|
+
annotations:
|
|
859
|
+
insureco.io/catalog-version: "0.1.0"
|
|
860
|
+
insureco.io/framework: express
|
|
861
|
+
spec:
|
|
862
|
+
type: service
|
|
863
|
+
lifecycle: production
|
|
864
|
+
owner: test-org
|
|
865
|
+
`)
|
|
866
|
+
tempDirs.push(dir)
|
|
867
|
+
|
|
868
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
869
|
+
'below the minimum supported version'
|
|
870
|
+
)
|
|
871
|
+
})
|
|
872
|
+
|
|
873
|
+
it('should include upgrade instructions in minimum version error', async () => {
|
|
874
|
+
mockEnv.ENFORCE_MINIMUM_CATALOG_VERSION = 'true'
|
|
875
|
+
|
|
876
|
+
const dir = await createFixture(`
|
|
877
|
+
apiVersion: backstage.io/v1alpha1
|
|
878
|
+
kind: Component
|
|
879
|
+
metadata:
|
|
880
|
+
name: my-api
|
|
881
|
+
annotations:
|
|
882
|
+
insureco.io/catalog-version: "1"
|
|
883
|
+
insureco.io/framework: express
|
|
884
|
+
spec:
|
|
885
|
+
type: service
|
|
886
|
+
lifecycle: production
|
|
887
|
+
owner: test-org
|
|
888
|
+
`)
|
|
889
|
+
tempDirs.push(dir)
|
|
890
|
+
|
|
891
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
892
|
+
'tawa.insureco.io/docs/catalog-reference'
|
|
893
|
+
)
|
|
894
|
+
})
|
|
895
|
+
})
|
|
896
|
+
|
|
897
|
+
describe('catalog spec field validation', () => {
|
|
898
|
+
const tempDirs: string[] = []
|
|
899
|
+
|
|
900
|
+
afterEach(async () => {
|
|
901
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
902
|
+
tempDirs.splice(0, tempDirs.length)
|
|
903
|
+
})
|
|
904
|
+
|
|
905
|
+
it('should reject 0.2.0 catalog with missing owner', async () => {
|
|
906
|
+
const dir = await createFixture(`
|
|
907
|
+
apiVersion: backstage.io/v1alpha1
|
|
908
|
+
kind: Component
|
|
909
|
+
metadata:
|
|
910
|
+
name: my-api
|
|
911
|
+
annotations:
|
|
912
|
+
insureco.io/catalog-version: "0.2.0"
|
|
913
|
+
insureco.io/framework: express
|
|
914
|
+
insureco.io/health-endpoint: /health
|
|
915
|
+
spec:
|
|
916
|
+
type: service
|
|
917
|
+
lifecycle: production
|
|
918
|
+
`)
|
|
919
|
+
tempDirs.push(dir)
|
|
920
|
+
|
|
921
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
922
|
+
'spec.owner is required'
|
|
923
|
+
)
|
|
924
|
+
})
|
|
925
|
+
|
|
926
|
+
it('should reject 0.2.0 catalog with owner set to unknown', async () => {
|
|
927
|
+
const dir = await createFixture(`
|
|
928
|
+
apiVersion: backstage.io/v1alpha1
|
|
929
|
+
kind: Component
|
|
930
|
+
metadata:
|
|
931
|
+
name: my-api
|
|
932
|
+
annotations:
|
|
933
|
+
insureco.io/catalog-version: "0.2.0"
|
|
934
|
+
insureco.io/framework: express
|
|
935
|
+
insureco.io/health-endpoint: /health
|
|
936
|
+
spec:
|
|
937
|
+
type: service
|
|
938
|
+
lifecycle: production
|
|
939
|
+
owner: unknown
|
|
940
|
+
`)
|
|
941
|
+
tempDirs.push(dir)
|
|
942
|
+
|
|
943
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
944
|
+
'spec.owner is required'
|
|
945
|
+
)
|
|
946
|
+
})
|
|
947
|
+
|
|
948
|
+
it('should reject 0.2.0 catalog with missing lifecycle', async () => {
|
|
949
|
+
const dir = await createFixture(`
|
|
950
|
+
apiVersion: backstage.io/v1alpha1
|
|
951
|
+
kind: Component
|
|
952
|
+
metadata:
|
|
953
|
+
name: my-api
|
|
954
|
+
annotations:
|
|
955
|
+
insureco.io/catalog-version: "0.2.0"
|
|
956
|
+
insureco.io/framework: express
|
|
957
|
+
insureco.io/health-endpoint: /health
|
|
958
|
+
spec:
|
|
959
|
+
type: service
|
|
960
|
+
owner: test-org
|
|
961
|
+
`)
|
|
962
|
+
tempDirs.push(dir)
|
|
963
|
+
|
|
964
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
965
|
+
'spec.lifecycle is required'
|
|
966
|
+
)
|
|
967
|
+
})
|
|
968
|
+
|
|
969
|
+
it('should reject 0.2.0 catalog with missing type', async () => {
|
|
970
|
+
const dir = await createFixture(`
|
|
971
|
+
apiVersion: backstage.io/v1alpha1
|
|
972
|
+
kind: Component
|
|
973
|
+
metadata:
|
|
974
|
+
name: my-api
|
|
975
|
+
annotations:
|
|
976
|
+
insureco.io/catalog-version: "0.2.0"
|
|
977
|
+
insureco.io/framework: express
|
|
978
|
+
insureco.io/health-endpoint: /health
|
|
979
|
+
spec:
|
|
980
|
+
lifecycle: production
|
|
981
|
+
owner: test-org
|
|
982
|
+
`)
|
|
983
|
+
tempDirs.push(dir)
|
|
984
|
+
|
|
985
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
986
|
+
'spec.type is required'
|
|
987
|
+
)
|
|
988
|
+
})
|
|
989
|
+
|
|
990
|
+
it('should accept 0.2.0 catalog with all required fields', async () => {
|
|
991
|
+
const dir = await createFixture(`
|
|
992
|
+
apiVersion: backstage.io/v1alpha1
|
|
993
|
+
kind: Component
|
|
994
|
+
metadata:
|
|
995
|
+
name: my-api
|
|
996
|
+
annotations:
|
|
997
|
+
insureco.io/catalog-version: "0.2.0"
|
|
998
|
+
insureco.io/framework: express
|
|
999
|
+
insureco.io/health-endpoint: /health
|
|
1000
|
+
spec:
|
|
1001
|
+
type: service
|
|
1002
|
+
lifecycle: production
|
|
1003
|
+
owner: test-org
|
|
1004
|
+
`)
|
|
1005
|
+
tempDirs.push(dir)
|
|
1006
|
+
|
|
1007
|
+
const result = await parseCatalogInfo(dir)
|
|
1008
|
+
expect(result).not.toBeNull()
|
|
1009
|
+
expect(result!.catalogVersion).toBe('0.2.0')
|
|
1010
|
+
expect(result!.owner).toBe('test-org')
|
|
1011
|
+
expect(result!.framework).toBe('express')
|
|
1012
|
+
})
|
|
1013
|
+
|
|
1014
|
+
it('should NOT validate spec fields for legacy 0.1.0 catalogs', async () => {
|
|
1015
|
+
const dir = await createFixture(`
|
|
1016
|
+
apiVersion: backstage.io/v1alpha1
|
|
1017
|
+
kind: Component
|
|
1018
|
+
metadata:
|
|
1019
|
+
name: my-api
|
|
1020
|
+
annotations:
|
|
1021
|
+
insureco.io/catalog-version: "0.1.0"
|
|
1022
|
+
insureco.io/framework: express
|
|
1023
|
+
spec:
|
|
1024
|
+
type: service
|
|
1025
|
+
lifecycle: production
|
|
1026
|
+
`)
|
|
1027
|
+
tempDirs.push(dir)
|
|
1028
|
+
|
|
1029
|
+
const result = await parseCatalogInfo(dir)
|
|
1030
|
+
expect(result).not.toBeNull()
|
|
1031
|
+
expect(result!.owner).toBe('unknown')
|
|
1032
|
+
})
|
|
1033
|
+
|
|
1034
|
+
it('should include field name and example in spec validation error', async () => {
|
|
1035
|
+
const dir = await createFixture(`
|
|
1036
|
+
apiVersion: backstage.io/v1alpha1
|
|
1037
|
+
kind: Component
|
|
1038
|
+
metadata:
|
|
1039
|
+
name: my-api
|
|
1040
|
+
annotations:
|
|
1041
|
+
insureco.io/catalog-version: "0.2.0"
|
|
1042
|
+
insureco.io/framework: express
|
|
1043
|
+
insureco.io/health-endpoint: /health
|
|
1044
|
+
spec:
|
|
1045
|
+
type: service
|
|
1046
|
+
lifecycle: production
|
|
1047
|
+
`)
|
|
1048
|
+
tempDirs.push(dir)
|
|
1049
|
+
|
|
1050
|
+
try {
|
|
1051
|
+
await parseCatalogInfo(dir)
|
|
1052
|
+
expect.fail('Should have thrown')
|
|
1053
|
+
} catch (error) {
|
|
1054
|
+
const message = (error as Error).message
|
|
1055
|
+
expect(message).toContain('spec.owner')
|
|
1056
|
+
expect(message).toContain('owner: my-org')
|
|
1057
|
+
expect(message).toContain('tawa.insureco.io/docs/catalog-reference')
|
|
1058
|
+
}
|
|
1059
|
+
})
|
|
1060
|
+
})
|
|
1061
|
+
|
|
1062
|
+
describe('catalog unified dependencies parsing', () => {
|
|
1063
|
+
const tempDirs: string[] = []
|
|
1064
|
+
|
|
1065
|
+
afterEach(async () => {
|
|
1066
|
+
await Promise.all(tempDirs.map(d => rm(d, { recursive: true, force: true })))
|
|
1067
|
+
tempDirs.splice(0, tempDirs.length)
|
|
1068
|
+
})
|
|
1069
|
+
|
|
1070
|
+
it('should parse spec.dependencies with transport direct in 0.4.0 catalog', async () => {
|
|
1071
|
+
const dir = await createFixture(`
|
|
1072
|
+
apiVersion: backstage.io/v1alpha1
|
|
1073
|
+
kind: Component
|
|
1074
|
+
metadata:
|
|
1075
|
+
name: my-api
|
|
1076
|
+
annotations:
|
|
1077
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1078
|
+
insureco.io/framework: express
|
|
1079
|
+
insureco.io/health-endpoint: /health
|
|
1080
|
+
spec:
|
|
1081
|
+
type: service
|
|
1082
|
+
lifecycle: production
|
|
1083
|
+
owner: test-org
|
|
1084
|
+
dependencies:
|
|
1085
|
+
- service: relay
|
|
1086
|
+
scopes: [relay:send]
|
|
1087
|
+
transport: direct
|
|
1088
|
+
`)
|
|
1089
|
+
tempDirs.push(dir)
|
|
1090
|
+
|
|
1091
|
+
const result = await parseCatalogInfo(dir)
|
|
1092
|
+
expect(result).not.toBeNull()
|
|
1093
|
+
expect(result!.dependencies).toEqual([
|
|
1094
|
+
{ service: 'relay', scopes: ['relay:send'], transport: 'direct' },
|
|
1095
|
+
])
|
|
1096
|
+
})
|
|
1097
|
+
|
|
1098
|
+
it('should parse spec.dependencies with transport gateway', async () => {
|
|
1099
|
+
const dir = await createFixture(`
|
|
1100
|
+
apiVersion: backstage.io/v1alpha1
|
|
1101
|
+
kind: Component
|
|
1102
|
+
metadata:
|
|
1103
|
+
name: my-api
|
|
1104
|
+
annotations:
|
|
1105
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1106
|
+
insureco.io/framework: express
|
|
1107
|
+
insureco.io/health-endpoint: /health
|
|
1108
|
+
spec:
|
|
1109
|
+
type: service
|
|
1110
|
+
lifecycle: production
|
|
1111
|
+
owner: test-org
|
|
1112
|
+
dependencies:
|
|
1113
|
+
- service: raterspot
|
|
1114
|
+
scopes: [raterspot:rate, raterspot:quote]
|
|
1115
|
+
transport: gateway
|
|
1116
|
+
`)
|
|
1117
|
+
tempDirs.push(dir)
|
|
1118
|
+
|
|
1119
|
+
const result = await parseCatalogInfo(dir)
|
|
1120
|
+
expect(result).not.toBeNull()
|
|
1121
|
+
expect(result!.dependencies).toEqual([
|
|
1122
|
+
{ service: 'raterspot', scopes: ['raterspot:rate', 'raterspot:quote'], transport: 'gateway' },
|
|
1123
|
+
])
|
|
1124
|
+
})
|
|
1125
|
+
|
|
1126
|
+
it('should reject invalid transport value', async () => {
|
|
1127
|
+
const dir = await createFixture(`
|
|
1128
|
+
apiVersion: backstage.io/v1alpha1
|
|
1129
|
+
kind: Component
|
|
1130
|
+
metadata:
|
|
1131
|
+
name: my-api
|
|
1132
|
+
annotations:
|
|
1133
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1134
|
+
insureco.io/framework: express
|
|
1135
|
+
insureco.io/health-endpoint: /health
|
|
1136
|
+
spec:
|
|
1137
|
+
type: service
|
|
1138
|
+
lifecycle: production
|
|
1139
|
+
owner: test-org
|
|
1140
|
+
dependencies:
|
|
1141
|
+
- service: relay
|
|
1142
|
+
scopes: [relay:send]
|
|
1143
|
+
transport: invalid
|
|
1144
|
+
`)
|
|
1145
|
+
tempDirs.push(dir)
|
|
1146
|
+
|
|
1147
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
1148
|
+
'Invalid transport "invalid"'
|
|
1149
|
+
)
|
|
1150
|
+
})
|
|
1151
|
+
|
|
1152
|
+
it('should reject dependency with missing service name', async () => {
|
|
1153
|
+
const dir = await createFixture(`
|
|
1154
|
+
apiVersion: backstage.io/v1alpha1
|
|
1155
|
+
kind: Component
|
|
1156
|
+
metadata:
|
|
1157
|
+
name: my-api
|
|
1158
|
+
annotations:
|
|
1159
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1160
|
+
insureco.io/framework: express
|
|
1161
|
+
insureco.io/health-endpoint: /health
|
|
1162
|
+
spec:
|
|
1163
|
+
type: service
|
|
1164
|
+
lifecycle: production
|
|
1165
|
+
owner: test-org
|
|
1166
|
+
dependencies:
|
|
1167
|
+
- scopes: [relay:send]
|
|
1168
|
+
transport: direct
|
|
1169
|
+
`)
|
|
1170
|
+
tempDirs.push(dir)
|
|
1171
|
+
|
|
1172
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
1173
|
+
'service is required'
|
|
1174
|
+
)
|
|
1175
|
+
})
|
|
1176
|
+
|
|
1177
|
+
it('should reject dependency with empty scopes', async () => {
|
|
1178
|
+
const dir = await createFixture(`
|
|
1179
|
+
apiVersion: backstage.io/v1alpha1
|
|
1180
|
+
kind: Component
|
|
1181
|
+
metadata:
|
|
1182
|
+
name: my-api
|
|
1183
|
+
annotations:
|
|
1184
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1185
|
+
insureco.io/framework: express
|
|
1186
|
+
insureco.io/health-endpoint: /health
|
|
1187
|
+
spec:
|
|
1188
|
+
type: service
|
|
1189
|
+
lifecycle: production
|
|
1190
|
+
owner: test-org
|
|
1191
|
+
dependencies:
|
|
1192
|
+
- service: relay
|
|
1193
|
+
scopes: []
|
|
1194
|
+
transport: direct
|
|
1195
|
+
`)
|
|
1196
|
+
tempDirs.push(dir)
|
|
1197
|
+
|
|
1198
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
1199
|
+
'at least one scope is required'
|
|
1200
|
+
)
|
|
1201
|
+
})
|
|
1202
|
+
|
|
1203
|
+
it('should reject duplicate service dependencies', async () => {
|
|
1204
|
+
const dir = await createFixture(`
|
|
1205
|
+
apiVersion: backstage.io/v1alpha1
|
|
1206
|
+
kind: Component
|
|
1207
|
+
metadata:
|
|
1208
|
+
name: my-api
|
|
1209
|
+
annotations:
|
|
1210
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1211
|
+
insureco.io/framework: express
|
|
1212
|
+
insureco.io/health-endpoint: /health
|
|
1213
|
+
spec:
|
|
1214
|
+
type: service
|
|
1215
|
+
lifecycle: production
|
|
1216
|
+
owner: test-org
|
|
1217
|
+
dependencies:
|
|
1218
|
+
- service: relay
|
|
1219
|
+
scopes: [relay:send]
|
|
1220
|
+
transport: direct
|
|
1221
|
+
- service: relay
|
|
1222
|
+
scopes: [relay:receive]
|
|
1223
|
+
transport: direct
|
|
1224
|
+
`)
|
|
1225
|
+
tempDirs.push(dir)
|
|
1226
|
+
|
|
1227
|
+
await expect(parseCatalogInfo(dir)).rejects.toThrow(
|
|
1228
|
+
'Duplicate dependency on service "relay"'
|
|
1229
|
+
)
|
|
1230
|
+
})
|
|
1231
|
+
|
|
1232
|
+
it('should default transport to direct when omitted', async () => {
|
|
1233
|
+
const dir = await createFixture(`
|
|
1234
|
+
apiVersion: backstage.io/v1alpha1
|
|
1235
|
+
kind: Component
|
|
1236
|
+
metadata:
|
|
1237
|
+
name: my-api
|
|
1238
|
+
annotations:
|
|
1239
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1240
|
+
insureco.io/framework: express
|
|
1241
|
+
insureco.io/health-endpoint: /health
|
|
1242
|
+
spec:
|
|
1243
|
+
type: service
|
|
1244
|
+
lifecycle: production
|
|
1245
|
+
owner: test-org
|
|
1246
|
+
dependencies:
|
|
1247
|
+
- service: relay
|
|
1248
|
+
scopes: [relay:send]
|
|
1249
|
+
`)
|
|
1250
|
+
tempDirs.push(dir)
|
|
1251
|
+
|
|
1252
|
+
const result = await parseCatalogInfo(dir)
|
|
1253
|
+
expect(result).not.toBeNull()
|
|
1254
|
+
expect(result!.dependencies[0].transport).toBe('direct')
|
|
1255
|
+
})
|
|
1256
|
+
|
|
1257
|
+
it('should ignore spec.dependencies in pre-0.4.0 catalogs', async () => {
|
|
1258
|
+
const dir = await createFixture(`
|
|
1259
|
+
apiVersion: backstage.io/v1alpha1
|
|
1260
|
+
kind: Component
|
|
1261
|
+
metadata:
|
|
1262
|
+
name: my-api
|
|
1263
|
+
annotations:
|
|
1264
|
+
insureco.io/catalog-version: "0.3.0"
|
|
1265
|
+
insureco.io/framework: express
|
|
1266
|
+
insureco.io/health-endpoint: /health
|
|
1267
|
+
spec:
|
|
1268
|
+
type: service
|
|
1269
|
+
lifecycle: production
|
|
1270
|
+
owner: test-org
|
|
1271
|
+
dependencies:
|
|
1272
|
+
- service: relay
|
|
1273
|
+
scopes: [relay:send]
|
|
1274
|
+
transport: direct
|
|
1275
|
+
`)
|
|
1276
|
+
tempDirs.push(dir)
|
|
1277
|
+
|
|
1278
|
+
const result = await parseCatalogInfo(dir)
|
|
1279
|
+
expect(result).not.toBeNull()
|
|
1280
|
+
expect(result!.dependencies).toEqual([])
|
|
1281
|
+
})
|
|
1282
|
+
|
|
1283
|
+
it('should map legacy internalDependencies to transport:direct with empty scopes', async () => {
|
|
1284
|
+
const dir = await createFixture(`
|
|
1285
|
+
apiVersion: backstage.io/v1alpha1
|
|
1286
|
+
kind: Component
|
|
1287
|
+
metadata:
|
|
1288
|
+
name: my-api
|
|
1289
|
+
annotations:
|
|
1290
|
+
insureco.io/catalog-version: "0.3.0"
|
|
1291
|
+
insureco.io/framework: express
|
|
1292
|
+
insureco.io/health-endpoint: /health
|
|
1293
|
+
spec:
|
|
1294
|
+
type: service
|
|
1295
|
+
lifecycle: production
|
|
1296
|
+
owner: test-org
|
|
1297
|
+
internalDependencies:
|
|
1298
|
+
- service: iec-wallet
|
|
1299
|
+
port: 3000
|
|
1300
|
+
`)
|
|
1301
|
+
tempDirs.push(dir)
|
|
1302
|
+
|
|
1303
|
+
const result = await parseCatalogInfo(dir)
|
|
1304
|
+
expect(result).not.toBeNull()
|
|
1305
|
+
expect(result!.dependencies).toEqual([
|
|
1306
|
+
{ service: 'iec-wallet', scopes: [], transport: 'direct', port: 3000 },
|
|
1307
|
+
])
|
|
1308
|
+
})
|
|
1309
|
+
|
|
1310
|
+
it('should map legacy externalDependencies to transport:gateway', async () => {
|
|
1311
|
+
const dir = await createFixture(`
|
|
1312
|
+
apiVersion: backstage.io/v1alpha1
|
|
1313
|
+
kind: Component
|
|
1314
|
+
metadata:
|
|
1315
|
+
name: my-api
|
|
1316
|
+
annotations:
|
|
1317
|
+
insureco.io/catalog-version: "0.3.0"
|
|
1318
|
+
insureco.io/framework: express
|
|
1319
|
+
insureco.io/health-endpoint: /health
|
|
1320
|
+
spec:
|
|
1321
|
+
type: service
|
|
1322
|
+
lifecycle: production
|
|
1323
|
+
owner: test-org
|
|
1324
|
+
externalDependencies:
|
|
1325
|
+
- service: raterspot
|
|
1326
|
+
scopes: [raterspot:rate]
|
|
1327
|
+
reason: Rating engine
|
|
1328
|
+
`)
|
|
1329
|
+
tempDirs.push(dir)
|
|
1330
|
+
|
|
1331
|
+
const result = await parseCatalogInfo(dir)
|
|
1332
|
+
expect(result).not.toBeNull()
|
|
1333
|
+
expect(result!.dependencies).toEqual([
|
|
1334
|
+
{ service: 'raterspot', scopes: ['raterspot:rate'], transport: 'gateway' },
|
|
1335
|
+
])
|
|
1336
|
+
})
|
|
1337
|
+
|
|
1338
|
+
it('should merge both legacy fields into dependencies', async () => {
|
|
1339
|
+
const dir = await createFixture(`
|
|
1340
|
+
apiVersion: backstage.io/v1alpha1
|
|
1341
|
+
kind: Component
|
|
1342
|
+
metadata:
|
|
1343
|
+
name: my-api
|
|
1344
|
+
annotations:
|
|
1345
|
+
insureco.io/catalog-version: "0.3.0"
|
|
1346
|
+
insureco.io/framework: express
|
|
1347
|
+
insureco.io/health-endpoint: /health
|
|
1348
|
+
spec:
|
|
1349
|
+
type: service
|
|
1350
|
+
lifecycle: production
|
|
1351
|
+
owner: test-org
|
|
1352
|
+
internalDependencies:
|
|
1353
|
+
- service: iec-wallet
|
|
1354
|
+
port: 3000
|
|
1355
|
+
externalDependencies:
|
|
1356
|
+
- service: raterspot
|
|
1357
|
+
scopes: [raterspot:rate]
|
|
1358
|
+
`)
|
|
1359
|
+
tempDirs.push(dir)
|
|
1360
|
+
|
|
1361
|
+
const result = await parseCatalogInfo(dir)
|
|
1362
|
+
expect(result).not.toBeNull()
|
|
1363
|
+
expect(result!.dependencies).toHaveLength(2)
|
|
1364
|
+
expect(result!.dependencies[0]).toEqual({ service: 'iec-wallet', scopes: [], transport: 'direct', port: 3000 })
|
|
1365
|
+
expect(result!.dependencies[1]).toEqual({ service: 'raterspot', scopes: ['raterspot:rate'], transport: 'gateway' })
|
|
1366
|
+
})
|
|
1367
|
+
|
|
1368
|
+
it('should return empty dependencies when no deps declared', async () => {
|
|
1369
|
+
const dir = await createFixture(`
|
|
1370
|
+
apiVersion: backstage.io/v1alpha1
|
|
1371
|
+
kind: Component
|
|
1372
|
+
metadata:
|
|
1373
|
+
name: my-api
|
|
1374
|
+
annotations:
|
|
1375
|
+
insureco.io/catalog-version: "0.4.0"
|
|
1376
|
+
insureco.io/framework: express
|
|
1377
|
+
insureco.io/health-endpoint: /health
|
|
1378
|
+
spec:
|
|
1379
|
+
type: service
|
|
1380
|
+
lifecycle: production
|
|
1381
|
+
owner: test-org
|
|
1382
|
+
`)
|
|
1383
|
+
tempDirs.push(dir)
|
|
1384
|
+
|
|
1385
|
+
const result = await parseCatalogInfo(dir)
|
|
1386
|
+
expect(result).not.toBeNull()
|
|
1387
|
+
expect(result!.dependencies).toEqual([])
|
|
1388
|
+
})
|
|
1389
|
+
})
|