@aipt/idp-deploy 0.1.2

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.
Files changed (52) hide show
  1. package/README.md +471 -0
  2. package/bin/idpctl.mjs +8 -0
  3. package/compose/edge.yaml +61 -0
  4. package/compose/flow.yaml +34 -0
  5. package/compose/portal.yaml +38 -0
  6. package/compose/postgresql.yaml +62 -0
  7. package/compose/registry.yaml +35 -0
  8. package/compose/smartgo.yaml +271 -0
  9. package/compose/tech.yaml +64 -0
  10. package/contracts/active-profile.schema.json +19 -0
  11. package/contracts/asset-lifecycle.schema.json +49 -0
  12. package/contracts/backup-generation.schema.json +60 -0
  13. package/contracts/component-runtime.schema.json +32 -0
  14. package/contracts/config-release.schema.json +33 -0
  15. package/contracts/deployment-evidence.schema.json +43 -0
  16. package/contracts/deployment-plan.schema.json +67 -0
  17. package/contracts/release-candidate.schema.json +33 -0
  18. package/contracts/release-defaults.schema.json +56 -0
  19. package/contracts/restore-candidate.schema.json +63 -0
  20. package/contracts/smartgo-component-config.schema.json +79 -0
  21. package/contracts/tech-backup-boundary.schema.json +61 -0
  22. package/contracts/tech-source-credentials.schema.json +17 -0
  23. package/deploy.sh +5 -0
  24. package/docs/restore-runbook.md +56 -0
  25. package/governance/asset-lifecycle.v1.json +79 -0
  26. package/package.json +42 -0
  27. package/release/defaults.v1.json +64 -0
  28. package/src/acceptance.mjs +127 -0
  29. package/src/bindings.mjs +518 -0
  30. package/src/cli.mjs +360 -0
  31. package/src/compose.mjs +19 -0
  32. package/src/config.mjs +903 -0
  33. package/src/delivery.mjs +123 -0
  34. package/src/errors.mjs +12 -0
  35. package/src/foundation-contracts.mjs +128 -0
  36. package/src/foundation.mjs +107 -0
  37. package/src/gitops.mjs +285 -0
  38. package/src/hash.mjs +47 -0
  39. package/src/image-lock.mjs +160 -0
  40. package/src/images.mjs +215 -0
  41. package/src/lifecycle.mjs +58 -0
  42. package/src/local-source.mjs +354 -0
  43. package/src/oci-mirror.mjs +10 -0
  44. package/src/operations.mjs +1484 -0
  45. package/src/process.mjs +46 -0
  46. package/src/profiles.mjs +41 -0
  47. package/src/release.mjs +1760 -0
  48. package/src/render.mjs +330 -0
  49. package/src/security.mjs +156 -0
  50. package/src/source-contracts.mjs +106 -0
  51. package/src/sources.mjs +78 -0
  52. package/src/workbench-projects.mjs +118 -0
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.internal/contracts/deployment-evidence.v1.schema.json",
4
+ "title": "IDP Deployment Evidence v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "planDigest", "releaseCandidateDigest", "runtime", "environmentRef", "repositoryState", "rollout", "resources", "checks", "observedAt", "digest"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "idp.deployment-evidence/v1" },
10
+ "planDigest": { "$ref": "#/$defs/digest" },
11
+ "releaseCandidateDigest": { "$ref": "#/$defs/digest" },
12
+ "runtime": { "enum": ["compose", "kubernetes-gitops"] },
13
+ "environmentRef": { "$ref": "#/$defs/environmentRef" },
14
+ "repositoryState": {
15
+ "oneOf": [
16
+ { "type": "null" },
17
+ { "type": "object", "additionalProperties": false, "required": ["repository", "commit"], "properties": { "repository": { "type": "string", "minLength": 1 }, "commit": { "type": "string", "pattern": "^[0-9a-f]{40}$" } } }
18
+ ]
19
+ },
20
+ "rollout": {
21
+ "type": "object", "additionalProperties": false, "required": ["strategy", "status", "stableImageDigest"],
22
+ "properties": { "strategy": { "enum": ["rolling", "canary", "blue-green"] }, "status": { "enum": ["healthy", "degraded", "aborted"] }, "stableImageDigest": { "$ref": "#/$defs/digest" } }
23
+ },
24
+ "resources": {
25
+ "type": "array",
26
+ "items": {
27
+ "type": "object", "additionalProperties": false, "required": ["apiVersion", "kind", "namespace", "name", "uid", "imageDigest"],
28
+ "properties": { "apiVersion": { "type": "string", "minLength": 1 }, "kind": { "type": "string", "minLength": 1 }, "namespace": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1 }, "uid": { "type": "string", "minLength": 1 }, "imageDigest": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/digest" }] } }
29
+ }
30
+ },
31
+ "checks": {
32
+ "type": "array", "minItems": 1,
33
+ "items": { "type": "object", "additionalProperties": false, "required": ["name", "status", "evidenceDigest"], "properties": { "name": { "$ref": "#/$defs/name" }, "status": { "enum": ["passed", "failed"] }, "evidenceDigest": { "$ref": "#/$defs/digest" } } }
34
+ },
35
+ "observedAt": { "type": "string", "format": "date-time" },
36
+ "digest": { "$ref": "#/$defs/digest" }
37
+ },
38
+ "$defs": {
39
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
40
+ "name": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,62}$" },
41
+ "environmentRef": { "type": "string", "pattern": "^environment:[a-z][a-z0-9-]*(?:\\.[a-z0-9-]+)*@v[1-9][0-9]*$" }
42
+ }
43
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.company.invalid/contracts/deployment-plan-v1.schema.json",
4
+ "title": "IDP Kubernetes GitOps DeploymentPlan v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "operation", "application", "environment", "inputs", "repository", "renderedFiles", "createdAt", "digest"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "idp.deployment-plan/v1" },
10
+ "operation": { "enum": ["create", "update", "remove"] },
11
+ "application": { "$ref": "#/$defs/name" },
12
+ "environment": { "$ref": "#/$defs/name" },
13
+ "inputs": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "required": ["component", "environmentBinding", "releaseCandidate"],
17
+ "properties": {
18
+ "component": { "$ref": "#/$defs/input" },
19
+ "environmentBinding": { "$ref": "#/$defs/input" },
20
+ "releaseCandidate": {
21
+ "allOf": [
22
+ { "$ref": "#/$defs/input" },
23
+ { "type": "object", "required": ["contractDigest"], "properties": { "contractDigest": { "$ref": "#/$defs/digest" } } }
24
+ ]
25
+ }
26
+ }
27
+ },
28
+ "repository": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["root", "expectedHead", "applicationPath", "preimageDigest"],
32
+ "properties": {
33
+ "root": { "type": "string", "pattern": "^/" },
34
+ "expectedHead": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
35
+ "applicationPath": { "type": "string", "pattern": "^applications/[a-z][a-z0-9-]+$" },
36
+ "preimageDigest": { "$ref": "#/$defs/digest" }
37
+ }
38
+ },
39
+ "renderedFiles": {
40
+ "type": "array",
41
+ "items": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["path", "digest", "content"],
45
+ "properties": {
46
+ "path": { "type": "string", "pattern": "^applications/[a-z][a-z0-9-]+/" },
47
+ "digest": { "$ref": "#/$defs/digest" },
48
+ "content": { "type": "string", "minLength": 1 }
49
+ }
50
+ }
51
+ },
52
+ "createdAt": { "type": "string", "format": "date-time" },
53
+ "digest": { "$ref": "#/$defs/digest" }
54
+ },
55
+ "$defs": {
56
+ "name": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,62}$" },
57
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
58
+ "input": {
59
+ "type": "object",
60
+ "required": ["path", "digest"],
61
+ "properties": {
62
+ "path": { "type": "string", "pattern": "^/" },
63
+ "digest": { "$ref": "#/$defs/digest" }
64
+ }
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.internal/contracts/release-candidate.v1.schema.json",
4
+ "title": "IDP Release Candidate v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "application", "version", "source", "componentContractDigest", "image", "configReleaseDigest", "acceptanceEvidenceDigests", "targetEnvironmentRef", "rolloutStrategy", "createdAt", "digest"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "idp.release-candidate/v1" },
10
+ "application": { "$ref": "#/$defs/name" },
11
+ "version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$" },
12
+ "source": {
13
+ "type": "object", "additionalProperties": false, "required": ["repository", "commit", "digest"],
14
+ "properties": { "repository": { "type": "string", "minLength": 1 }, "commit": { "type": "string", "pattern": "^[0-9a-f]{40}$" }, "digest": { "$ref": "#/$defs/digest" } }
15
+ },
16
+ "componentContractDigest": { "$ref": "#/$defs/digest" },
17
+ "image": {
18
+ "type": "object", "additionalProperties": false, "required": ["ref", "digest", "platforms"],
19
+ "properties": { "ref": { "type": "string", "pattern": "^\\S+@sha256:[0-9a-f]{64}$" }, "digest": { "$ref": "#/$defs/digest" }, "platforms": { "const": ["linux/amd64", "linux/arm64"] } }
20
+ },
21
+ "configReleaseDigest": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/digest" }] },
22
+ "acceptanceEvidenceDigests": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/digest" } },
23
+ "targetEnvironmentRef": { "$ref": "#/$defs/environmentRef" },
24
+ "rolloutStrategy": { "enum": ["rolling", "canary", "blue-green"] },
25
+ "createdAt": { "type": "string", "format": "date-time" },
26
+ "digest": { "$ref": "#/$defs/digest" }
27
+ },
28
+ "$defs": {
29
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
30
+ "name": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,62}$" },
31
+ "environmentRef": { "type": "string", "pattern": "^environment:[a-z][a-z0-9-]*(?:\\.[a-z0-9-]+)*@v[1-9][0-9]*$" }
32
+ }
33
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.internal/contracts/release-defaults.v1.schema.json",
4
+ "title": "IDP Release Defaults v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "releaseVersion", "ociRepositoryRoot", "platforms", "thirdPartyImages", "buildImages"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 1 },
10
+ "releaseVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-z0-9][a-z0-9.-]*)?$" },
11
+ "ociRepositoryRoot": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[1-9][0-9]{0,4})?(?:/[a-z0-9]+(?:[._-][a-z0-9]+)*)+$" },
12
+ "platforms": {
13
+ "const": ["linux/amd64", "linux/arm64"]
14
+ },
15
+ "thirdPartyImages": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": ["IDP_POSTGRES_IMAGE", "IDP_CADDY_IMAGE", "IDP_REGISTRY_IMAGE"],
19
+ "properties": {
20
+ "IDP_POSTGRES_IMAGE": { "$ref": "#/$defs/pinnedImage" },
21
+ "IDP_CADDY_IMAGE": { "$ref": "#/$defs/pinnedImage" },
22
+ "IDP_REGISTRY_IMAGE": { "$ref": "#/$defs/pinnedImage" }
23
+ }
24
+ },
25
+ "buildImages": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": ["tech", "flow", "portal"],
29
+ "properties": {
30
+ "tech": { "$ref": "#/$defs/buildImage" },
31
+ "flow": { "$ref": "#/$defs/buildImage" },
32
+ "portal": { "$ref": "#/$defs/buildImage" }
33
+ }
34
+ }
35
+ },
36
+ "$defs": {
37
+ "pinnedImage": { "type": "string", "pattern": "^\\S+@sha256:[0-9a-f]{64}$" },
38
+ "buildImage": {
39
+ "type": "object",
40
+ "additionalProperties": false,
41
+ "required": ["environmentKey", "sourceDirectory", "context", "dockerfile", "repositorySuffix", "buildArgs", "prebuildContract"],
42
+ "properties": {
43
+ "environmentKey": { "enum": ["IDP_TECH_IMAGE", "IDP_FLOW_IMAGE", "IDP_PORTAL_IMAGE"] },
44
+ "sourceDirectory": { "enum": ["tech", "flow", "portal"] },
45
+ "context": { "const": "." },
46
+ "dockerfile": { "type": "string", "pattern": "^[A-Za-z0-9._/-]+$" },
47
+ "repositorySuffix": { "enum": ["", "/flow", "/portal"] },
48
+ "buildArgs": {
49
+ "type": "object",
50
+ "additionalProperties": { "type": "string", "minLength": 1 }
51
+ },
52
+ "prebuildContract": { "enum": ["none", "portal-backstage-v1"] }
53
+ }
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.internal/contracts/restore-candidate.v1.schema.json",
4
+ "title": "IDP Restore Candidate v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "candidateId", "generationId", "profile", "status", "preimage", "creationEvidenceDigest", "configDigest", "dataDigest", "results", "createdAt", "digest"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 1 },
10
+ "candidateId": { "type": "string", "minLength": 1 },
11
+ "generationId": { "type": "string", "pattern": "^[0-9TZ-]+-[0-9a-f]{12}$" },
12
+ "profile": { "enum": ["tech-only", "foundation", "core", "portal", "flow", "registry", "full"] },
13
+ "status": { "const": "ready-for-cutover" },
14
+ "preimage": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "required": ["targetExisted", "productionDataUntouched"],
18
+ "properties": {
19
+ "targetExisted": { "const": false },
20
+ "productionDataUntouched": { "const": true }
21
+ }
22
+ },
23
+ "creationEvidenceDigest": { "$ref": "#/$defs/digest" },
24
+ "configDigest": { "$ref": "#/$defs/digest" },
25
+ "dataDigest": { "$ref": "#/$defs/digest" },
26
+ "results": {
27
+ "type": "array",
28
+ "minItems": 1,
29
+ "items": {
30
+ "oneOf": [
31
+ {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["dataset", "database", "tableCount", "ownedCount", "canConnect", "status"],
35
+ "properties": {
36
+ "dataset": { "enum": ["postgresql:tech", "postgresql:backstage"] },
37
+ "database": { "enum": ["tech", "backstage"] },
38
+ "tableCount": { "type": "integer", "minimum": 1 },
39
+ "ownedCount": { "type": "integer", "minimum": 1 },
40
+ "canConnect": { "const": true },
41
+ "status": { "const": "restored" }
42
+ }
43
+ },
44
+ {
45
+ "type": "object",
46
+ "additionalProperties": false,
47
+ "required": ["dataset", "entries", "status"],
48
+ "properties": {
49
+ "dataset": { "const": "registry:packages" },
50
+ "entries": { "type": "integer", "minimum": 1 },
51
+ "status": { "const": "restored" }
52
+ }
53
+ }
54
+ ]
55
+ }
56
+ },
57
+ "createdAt": { "type": "string", "format": "date-time" },
58
+ "digest": { "$ref": "#/$defs/digest" }
59
+ },
60
+ "$defs": {
61
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }
62
+ }
63
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.example.internal/contracts/smartgo-component-config.schema.json",
4
+ "title": "SmartGo idp-managed component configuration",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "NODE_ENV",
9
+ "SMARTGO_DEPLOYMENT_MODE",
10
+ "SMARTGO_AUTH_MODE",
11
+ "SMARTGO_BIND_HOST",
12
+ "SMARTGO_STUDIO_STATE_MODE",
13
+ "SMARTGO_STUDIO_DATA_DIRECTORY",
14
+ "MEDIA_ASSET_REPOSITORY",
15
+ "GOTOLOGY_PUBLIC_URL",
16
+ "OPERATIONS_PUBLIC_URL",
17
+ "STUDIO_PUBLIC_URL",
18
+ "SMARTGO_ARTIFACT_STORE_PROVIDER",
19
+ "SMARTGO_MINIO_BUCKET",
20
+ "SMARTGO_MINIO_INTERNAL_ENDPOINT",
21
+ "SMARTGO_MINIO_PUBLIC_ENDPOINT",
22
+ "SIGNED_OBJECT_URL_TTL_SECONDS",
23
+ "DATABASE_URL_FILE",
24
+ "DIRECT_DATABASE_URL_FILE",
25
+ "SMARTGO_OPERATOR_TOKEN_FILE",
26
+ "PLATFORM_IDENTITY_SERVICE_TOKEN_FILE",
27
+ "PLATFORM_IDENTITY_ACTIVATION_TOKEN_FILE",
28
+ "PLATFORM_IDENTITY_CLIENT_SECRET_FILE",
29
+ "ARTIFACT_RENDERER_CALLBACK_TOKEN_FILE",
30
+ "ALIYUN_OSS_ACCESS_KEY_ID_FILE",
31
+ "ALIYUN_OSS_ACCESS_KEY_SECRET_FILE",
32
+ "ARTIFACT_DELIVERY_S3_ACCESS_KEY_ID_FILE",
33
+ "ARTIFACT_DELIVERY_S3_ACCESS_KEY_SECRET_FILE",
34
+ "WORKER_ARTIFACT_S3_ACCESS_KEY_ID_FILE",
35
+ "WORKER_ARTIFACT_S3_ACCESS_KEY_SECRET_FILE",
36
+ "SMARTGO_MINIO_ROOT_USER_FILE",
37
+ "SMARTGO_MINIO_ROOT_PASSWORD_FILE",
38
+ "SMARTGO_NPMRC_FILE"
39
+ ],
40
+ "properties": {
41
+ "NODE_ENV": { "const": "development" },
42
+ "SMARTGO_DEPLOYMENT_MODE": { "const": "idp-managed" },
43
+ "SMARTGO_AUTH_MODE": { "const": "local-open" },
44
+ "SMARTGO_BIND_HOST": { "enum": ["127.0.0.1", "::1"] },
45
+ "SMARTGO_STUDIO_STATE_MODE": { "const": "ephemeral-fixture" },
46
+ "SMARTGO_STUDIO_DATA_DIRECTORY": { "const": "/run/smartgo/studio" },
47
+ "MEDIA_ASSET_REPOSITORY": { "const": "minio" },
48
+ "GOTOLOGY_PUBLIC_URL": { "type": "string", "format": "uri", "pattern": "^https?://" },
49
+ "OPERATIONS_PUBLIC_URL": { "type": "string", "format": "uri", "pattern": "^https?://" },
50
+ "STUDIO_PUBLIC_URL": { "type": "string", "format": "uri", "pattern": "^https?://" },
51
+ "SMARTGO_ARTIFACT_STORE_PROVIDER": { "const": "s3" },
52
+ "SMARTGO_MINIO_BUCKET": { "const": "smartgo-artifacts" },
53
+ "SMARTGO_MINIO_INTERNAL_ENDPOINT": { "type": "string", "format": "uri", "pattern": "^http://smartgo-object-store:9000/?$" },
54
+ "SMARTGO_MINIO_PUBLIC_ENDPOINT": { "type": "string", "format": "uri", "pattern": "^https?://" },
55
+ "SIGNED_OBJECT_URL_TTL_SECONDS": { "type": "string", "pattern": "^[1-9][0-9]{0,4}$" },
56
+ "DATABASE_URL_FILE": { "$ref": "#/$defs/secretFile" },
57
+ "DIRECT_DATABASE_URL_FILE": { "$ref": "#/$defs/secretFile" },
58
+ "SMARTGO_OPERATOR_TOKEN_FILE": { "$ref": "#/$defs/secretFile" },
59
+ "PLATFORM_IDENTITY_SERVICE_TOKEN_FILE": { "$ref": "#/$defs/secretFile" },
60
+ "PLATFORM_IDENTITY_ACTIVATION_TOKEN_FILE": { "$ref": "#/$defs/secretFile" },
61
+ "PLATFORM_IDENTITY_CLIENT_SECRET_FILE": { "$ref": "#/$defs/secretFile" },
62
+ "ARTIFACT_RENDERER_CALLBACK_TOKEN_FILE": { "$ref": "#/$defs/secretFile" },
63
+ "ALIYUN_OSS_ACCESS_KEY_ID_FILE": { "$ref": "#/$defs/secretFile" },
64
+ "ALIYUN_OSS_ACCESS_KEY_SECRET_FILE": { "$ref": "#/$defs/secretFile" },
65
+ "ARTIFACT_DELIVERY_S3_ACCESS_KEY_ID_FILE": { "$ref": "#/$defs/secretFile" },
66
+ "ARTIFACT_DELIVERY_S3_ACCESS_KEY_SECRET_FILE": { "$ref": "#/$defs/secretFile" },
67
+ "WORKER_ARTIFACT_S3_ACCESS_KEY_ID_FILE": { "$ref": "#/$defs/secretFile" },
68
+ "WORKER_ARTIFACT_S3_ACCESS_KEY_SECRET_FILE": { "$ref": "#/$defs/secretFile" },
69
+ "SMARTGO_MINIO_ROOT_USER_FILE": { "$ref": "#/$defs/secretFile" },
70
+ "SMARTGO_MINIO_ROOT_PASSWORD_FILE": { "$ref": "#/$defs/secretFile" },
71
+ "SMARTGO_NPMRC_FILE": { "$ref": "#/$defs/secretFile" }
72
+ },
73
+ "$defs": {
74
+ "secretFile": {
75
+ "type": "string",
76
+ "pattern": "^secrets/[A-Za-z0-9][A-Za-z0-9._/-]{0,199}$"
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.internal/contracts/tech-backup-boundary.v1.schema.json",
4
+ "title": "Tech Backup Boundary v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "generatedAt", "digest", "database", "knowledge", "objectStorage", "restoreVerification"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "tech.backup-boundary.v1" },
10
+ "generatedAt": { "type": "string", "format": "date-time" },
11
+ "digest": { "$ref": "#/$defs/digest" },
12
+ "database": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "required": ["engine", "requiredFormat", "migrations", "counts"],
16
+ "properties": {
17
+ "engine": { "const": "postgresql" },
18
+ "requiredFormat": { "const": "pg_dump-custom" },
19
+ "migrations": {
20
+ "type": "array", "minItems": 1, "maxItems": 10000,
21
+ "items": {
22
+ "type": "object", "additionalProperties": false, "required": ["version", "checksum"],
23
+ "properties": { "version": { "type": "string", "minLength": 1, "maxLength": 256 }, "checksum": { "$ref": "#/$defs/digest" } }
24
+ }
25
+ },
26
+ "counts": {
27
+ "type": "object", "additionalProperties": false, "required": ["spaces", "sources", "references", "snapshots"],
28
+ "properties": {
29
+ "spaces": { "type": "integer", "minimum": 0 }, "sources": { "type": "integer", "minimum": 0 },
30
+ "references": { "type": "integer", "minimum": 0 }, "snapshots": { "type": "integer", "minimum": 0 }
31
+ }
32
+ }
33
+ }
34
+ },
35
+ "knowledge": {
36
+ "type": "object", "additionalProperties": false, "required": ["activeIndexRevision", "sourceRevisions"],
37
+ "properties": {
38
+ "activeIndexRevision": { "type": "string", "minLength": 1, "maxLength": 256 },
39
+ "sourceRevisions": {
40
+ "type": "array", "maxItems": 10000,
41
+ "items": {
42
+ "type": "object", "additionalProperties": false,
43
+ "required": ["sourceId", "identity", "repositoryUrl", "commit", "treeDigest"],
44
+ "properties": {
45
+ "sourceId": { "type": "string", "minLength": 1, "maxLength": 256 },
46
+ "identity": { "type": "string", "minLength": 1, "maxLength": 256 },
47
+ "repositoryUrl": { "type": "string", "minLength": 1, "maxLength": 4096 },
48
+ "commit": { "type": ["string", "null"] }, "treeDigest": { "oneOf": [{ "$ref": "#/$defs/digest" }, { "type": "null" }] }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "objectStorage": {
55
+ "type": "object", "additionalProperties": false, "required": ["mode", "ownedObjects"],
56
+ "properties": { "mode": { "const": "none" }, "ownedObjects": { "const": false } }
57
+ },
58
+ "restoreVerification": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 512 } }
59
+ },
60
+ "$defs": { "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" } }
61
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://idp.internal/contracts/tech-source-credentials.v1.schema.json",
4
+ "title": "Tech Source Credentials Manifest v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "files"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 1 },
10
+ "files": {
11
+ "type": "array",
12
+ "maxItems": 200,
13
+ "uniqueItems": true,
14
+ "items": { "type": "string", "minLength": 1, "maxLength": 200, "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" }
15
+ }
16
+ }
17
+ }
package/deploy.sh ADDED
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
5
+ exec node "$SCRIPT_DIR/bin/idpctl.mjs" release deploy "$@"
@@ -0,0 +1,56 @@
1
+ # IDP 灾难恢复与回切 Runbook
2
+
3
+ 本 Runbook 只操作 `idp-deploy` 拥有的 PostgreSQL 与私有 npm Registry。Tech 当前 P0 的完整可恢复边界还包括 Git Knowledge Release pins 和外部 Secret Manager,必须分别按其事实所有者恢复;不得拿数据库备份冒充完整知识资产备份。Tech 尚未启用对象正文/附件存储,未来启用 OSS/S3 前必须先增加版本化 Binding、对象清单与恢复适配器,本 Runbook 不会伪造该能力。
4
+
5
+ ## 进入条件
6
+
7
+ 1. `IDP_CONFIG_DIR` 可用,Secret 已从加密备份或 Secret Manager 恢复,权限仍为 `0700/0600`。
8
+ 2. `.env` 与 `images.lock.json` 已回到目标代次兼容版本,`doctor <profile> --require-configured` 通过;`restore apply` 后不得再修改该 Profile 配置,否则候选会因配置摘要漂移被拒绝,必须重新生成。
9
+ 3. 备份 generation 已复制到配置声明的 `IDP_BACKUP_DIR/generations`,运行回执摘要链可用。
10
+ 4. 操作窗口内不得并行执行 `images lock`、Compose、备份或恢复命令;`idpctl` 的实例锁会二次拒绝并发。
11
+
12
+ ## 验证备份并生成恢复候选
13
+
14
+ ```bash
15
+ export IDP_CONFIG_DIR=/absolute/outside-git/idp-config
16
+ node bin/idpctl.mjs backup verify <generation-id>
17
+ node bin/idpctl.mjs restore test <generation-id>
18
+ node bin/idpctl.mjs restore apply <generation-id>
19
+ node bin/idpctl.mjs restore verify <candidate-id>
20
+ ```
21
+
22
+ `restore apply` 只写全新的候选目录。任何摘要不一致、未声明文件、空数据集、不安全 tar 路径、数据库 Owner/权限错误或镜像证据漂移都会停止;失败候选移动到 `IDP_RESTORE_DIR/failed`,生产数据保持不变。包含 Tech 的 generation 还必须同时带有经过摘要绑定的 `tech-backup-boundary.json`;`restore test` 会由 Tech 镜像连接隔离恢复库,逐项重算 migration checksum、业务计数、active index 与 Source commit/treeDigest,事实摘要不相等即失败。
23
+
24
+ `portal` 与 `tech-only` 生成的单数据库候选不会物理替换共享 PostgreSQL 集群。它们在 `promote` 时使用逻辑数据库恢复、验收和重命名切换,另一个数据库保持不变。需要整体物理切换 PostgreSQL 时必须选择同时包含 `tech` 与 `backstage` 的 `core`/`full` generation;`registry` generation 可以独立切换。
25
+
26
+ 活动 Profile 为 `foundation` 时,日常应分别执行 `backup create tech-only` 与 `backup create registry`,得到两个可实际切换的故障域。Tech 单库候选会借用当前活动 `foundation` 的 Compose 上下文停启 Tech/Edge,不会误停 Registry。`foundation` 联合 generation 只承诺验证与隔离恢复演练,不承诺跨数据库/目录的伪原子生产切换。
27
+
28
+ ## 生产切换
29
+
30
+ 在变更窗口中记录候选 ID,然后运行:
31
+
32
+ ```bash
33
+ node bin/idpctl.mjs restore promote <candidate-id> --confirm <candidate-id>
34
+ node bin/idpctl.mjs verify <profile>
35
+ ```
36
+
37
+ `core/full/registry` 的物理顺序固定为:验证候选清单、创建回执与物理数据摘要及当前配置摘要 → 保存不可变 Plan → Compose down → 同盘复制完整生产数据并仅覆盖候选声明的数据目录 → 再验暂存摘要 → 原子重命名生产数据为 Preimage → 原子安装暂存副本 → 先启动 PostgreSQL + Tech 并复核 Tech 备份边界 → 再启动其余服务并等待健康。准备暂存副本失败会先重启原服务;安装后任何健康或边界失败都会停掉失败版本、恢复原生产目录并重新启动。
38
+
39
+ `portal/tech-only` 的逻辑顺序固定为:把已验证 Dump 流式恢复到新数据库 → 验证非空表、Owner 和应用角色连接权限 → Tech 候选先复核备份边界 → 短暂停止对应应用及其本机消费者/Edge → 终止目标库连接 → 把原库重命名为 `idp_preimage_*` → 把新库重命名为正式库名 → Tech 先行启动并再次复核边界 → 恢复其他服务并等待健康。健康或边界失败时新库改名为 `idp_failed_*`,Preimage 自动改回正式库名并重启原服务。若回滚本身失败,命令输出 `IDP_LOGICAL_RESTORE_ROLLBACK_FAILED` 和准确数据库 Preimage,禁止继续手工覆盖。
40
+
41
+ ## 人工验收
42
+
43
+ 1. `verify` 中运行服务集合必须与活动 Profile 严格相等,且全部为 `running/healthy`;多余 Orphan 同样失败。
44
+ 2. Edge、Flow、Portal、Tech `/live`、Tech `/ready`(当前 Profile 包含时)和 Registry 端到端探针全部通过。
45
+ 3. 用只读开发者流程安装一个已知 npm 包;用发布账号完成一次临时包发布与撤销。
46
+ 4. 对 Portal/Flow 做一条只读查询和一条可回滚写入,确认应用角色权限。
47
+ 5. 核对恢复回执的 `candidateDigest`、`planDigest`、`preimage` 和 `status=promoted-and-healthy`。
48
+ 6. Tech 回执必须带有与 generation 相同的 `techBoundaryDigest`。`gitReleaseRefetch=external-evidence-required` 不是成功证明:还需在企业 Git 网络内按清单逐个重取 commit 并重算 treeDigest,证据归档后才算完整知识恢复演练。
49
+
50
+ ## 清理与保留
51
+
52
+ - 成功切换后至少跨过一个完整备份周期并再次执行恢复演练,才能清理生产 Preimage。
53
+ - 单数据库逻辑切换的 `idp_preimage_*` 与 `idp_failed_*` 也属于恢复证据,不得在同一次变更中自动删除。
54
+ - 清理是独立的破坏性变更,本工具不会自动删除 Preimage、generation 或失败候选。
55
+ - generation 必须继续复制到与数据盘故障域不同的位置;只有本机备份不满足灾难恢复要求。
56
+ - 初始建议目标:每日备份(RPO 24 小时),演练恢复在 2 小时内完成(RTO 2 小时);有更严格业务要求时应缩短周期并引入 PostgreSQL PITR。
@@ -0,0 +1,79 @@
1
+ {
2
+ "schemaVersion": "idp-deploy.asset-lifecycle/v1",
3
+ "planId": "idp-deploy.bench-deployment-ownership-reception@1",
4
+ "version": 1,
5
+ "approvedAt": "2026-08-31",
6
+ "immutable": true,
7
+ "archiveRoot": "archive",
8
+ "activeComponents": ["postgresql", "registry", "tech", "flow", "portal", "edge"],
9
+ "receipts": [
10
+ {
11
+ "sourceProject": "bench",
12
+ "sourceAsset": "packages/ops",
13
+ "sourceEvidence": "sha256:b38d9c08a03a58d60aba0b2350efa478018e3c4852afb2c331318ec1d95f21af",
14
+ "decision": "accepted",
15
+ "targetCapability": "controlled-deployment-kernel",
16
+ "targetPaths": ["src/operations.mjs", "contracts/active-profile.schema.json", "contracts/backup-generation.schema.json", "contracts/restore-candidate.schema.json"],
17
+ "evidence": ["tests/operations.test.mjs", "tests/integration/runtime.test.mjs"],
18
+ "remainingGates": ["Bench 消费者全部停止导入 @acme/ops", "Bench 生成 packages/ops 的 ARCHIVE.json"]
19
+ },
20
+ {
21
+ "sourceProject": "bench",
22
+ "sourceAsset": "scripts/ops-agent.mjs",
23
+ "sourceEvidence": "sha256:b1d50c927cdfb41535dbcfe67e541ee8902ae284cbba4584fd57e788bdfc6920",
24
+ "decision": "replaced",
25
+ "targetCapability": "single-kernel-cli-ai-operations",
26
+ "targetPaths": ["bin/idpctl.mjs", "src/cli.mjs", "src/operations.mjs"],
27
+ "evidence": ["tests/cli.test.mjs", "tests/operations.test.mjs"],
28
+ "remainingGates": ["Portal 保持只读且不调用旧 Unix Socket", "Bench 生成 ops-agent ARCHIVE.json"]
29
+ },
30
+ {
31
+ "sourceProject": "bench",
32
+ "sourceAsset": "docker-compose.yml",
33
+ "sourceEvidence": "sha256:a2f2b5b16c78b3c968b08d8cfe9f02caf2de373893a0551efd89de6d010b5286",
34
+ "decision": "selectively-received",
35
+ "targetCapability": "independent-compose-fragments-and-minimal-profiles",
36
+ "targetPaths": ["src/profiles.mjs", "src/compose.mjs", "compose/postgresql.yaml", "compose/registry.yaml", "compose/tech.yaml", "compose/flow.yaml", "compose/portal.yaml", "compose/edge.yaml"],
37
+ "evidence": ["tests/compose.test.mjs", "tests/integration/runtime.test.mjs"],
38
+ "remainingGates": ["Bench 确认没有消费者调用旧 local:up", "未接收中间件逐项完成 Binding 与恢复评审", "Bench 生成 legacy Compose ARCHIVE.json"]
39
+ },
40
+ {
41
+ "sourceProject": "bench",
42
+ "sourceAsset": "local",
43
+ "sourceEvidence": "sha256:b38d9c08a03a58d60aba0b2350efa478018e3c4852afb2c331318ec1d95f21af",
44
+ "decision": "selectively-received",
45
+ "targetCapability": "verdaccio-and-postgresql-bootstrap-only",
46
+ "targetPaths": ["compose/registry.yaml", "compose/postgresql.yaml", "scripts/postgresql/010-create-databases.sh", "src/render.mjs"],
47
+ "evidence": ["tests/config.test.mjs", "tests/compose.test.mjs", "tests/render.test.mjs"],
48
+ "remainingGates": ["ClickHouse、Kafka/RocketMQ、Nacos、可观测栈分别出现真实 Binding", "每个新增服务具备独立 Profile、健康检查和备份恢复边界", "Bench 生成 local runtime ARCHIVE.json"]
49
+ },
50
+ {
51
+ "sourceProject": "bench",
52
+ "sourceAsset": "gitops",
53
+ "sourceEvidence": "sha256:b38d9c08a03a58d60aba0b2350efa478018e3c4852afb2c331318ec1d95f21af",
54
+ "decision": "deferred",
55
+ "targetCapability": "future-approved-gitops-environment",
56
+ "targetPaths": [],
57
+ "evidence": ["docs/features/bench-deployment-ownership-reception/DESIGN.md"],
58
+ "remainingGates": ["批准 Kubernetes 与 Argo CD 目标环境", "通过 server-side dry-run、回滚与 Secret 投影验证", "证明当前 Mac 单机部署不依赖该路径"]
59
+ },
60
+ {
61
+ "sourceProject": "bench",
62
+ "sourceAsset": "infra/terraform",
63
+ "sourceEvidence": "sha256:b38d9c08a03a58d60aba0b2350efa478018e3c4852afb2c331318ec1d95f21af",
64
+ "decision": "deferred",
65
+ "targetCapability": "future-approved-iac-environment",
66
+ "targetPaths": [],
67
+ "evidence": ["docs/features/bench-deployment-ownership-reception/DESIGN.md"],
68
+ "remainingGates": ["批准云 Provider、账户与状态后端", "完成 plan/apply/destroy 与外部资源 Preimage", "定义 Secret、成本和灾备合同"]
69
+ }
70
+ ],
71
+ "policy": {
72
+ "runtimeCrossRepositorySourceReads": false,
73
+ "archiveIncludedInRuntime": false,
74
+ "secretsOnlyFromExternalConfigDir": true,
75
+ "unapprovedRemoteResources": false,
76
+ "portalWriteProxy": false
77
+ },
78
+ "digest": "sha256:589462d761b7cfe3cacfbbf327fdd76e01aed01be82104dd82bcd62479a2b72e"
79
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@aipt/idp-deploy",
3
+ "version": "0.1.2",
4
+ "description": "IDP 私有化部署、外部配置、备份恢复与交付编排 CLI。",
5
+ "type": "module",
6
+ "bin": {
7
+ "idpctl": "./bin/idpctl.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "compose",
13
+ "contracts",
14
+ "release",
15
+ "governance",
16
+ "docs/restore-runbook.md",
17
+ "README.md",
18
+ "deploy.sh"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "dependencies": {
24
+ "yaml": "2.9.0"
25
+ },
26
+ "engines": {
27
+ "node": ">=20"
28
+ },
29
+ "scripts": {
30
+ "idpctl": "node bin/idpctl.mjs",
31
+ "deploy": "./deploy.sh",
32
+ "test": "node --test tests/*.test.mjs",
33
+ "test:integration": "node --test --test-timeout=240000 tests/integration/*.test.mjs",
34
+ "lifecycle:check": "node bin/idpctl.mjs lifecycle check",
35
+ "smoke:local": "node scripts/smoke-local.mjs",
36
+ "smoke:smartgo": "node scripts/smoke-smartgo.mjs",
37
+ "smoke:smartgo:object-store": "node scripts/smoke-smartgo.mjs --object-store-runtime",
38
+ "check": "node scripts/check-syntax.mjs && node bin/idpctl.mjs lifecycle check && node --test tests/*.test.mjs",
39
+ "example": "node examples/private-mac-m4/run.mjs",
40
+ "example:no-cluster": "node examples/no-cluster-delivery/run.mjs"
41
+ }
42
+ }