@msn-control/liftoff 0.11.3 → 0.12.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/DEVELOPER.md +19 -18
- package/README.md +18 -18
- package/assets/governance/single-maintainer-gitflow/activation-v2-graph.json +1583 -0
- package/dist/adapters/credentials/github-enrollment.d.ts +51 -0
- package/dist/adapters/credentials/github-enrollment.js +226 -0
- package/dist/adapters/credentials/github-enrollment.js.map +1 -0
- package/dist/adapters/credentials/protected-input.d.ts +7 -0
- package/dist/adapters/credentials/protected-input.js +68 -0
- package/dist/adapters/credentials/protected-input.js.map +1 -0
- package/dist/adapters/filesystem/executables.d.ts +2 -0
- package/dist/adapters/filesystem/executables.js +70 -0
- package/dist/adapters/filesystem/executables.js.map +1 -0
- package/dist/adapters/filesystem/update-previews.d.ts +9 -0
- package/dist/adapters/filesystem/update-previews.js +44 -0
- package/dist/adapters/filesystem/update-previews.js.map +1 -1
- package/dist/adapters/filesystem/workstation-attempts.d.ts +13 -0
- package/dist/adapters/filesystem/workstation-attempts.js +78 -0
- package/dist/adapters/filesystem/workstation-attempts.js.map +1 -0
- package/dist/adapters/github/activation-rest.d.ts +40 -0
- package/dist/adapters/github/activation-rest.js +272 -0
- package/dist/adapters/github/activation-rest.js.map +1 -0
- package/dist/adapters/state/azure-blob.d.ts +43 -0
- package/dist/adapters/state/azure-blob.js +335 -0
- package/dist/adapters/state/azure-blob.js.map +1 -0
- package/dist/adapters/state/darwin-capabilities.d.ts +33 -0
- package/dist/adapters/state/darwin-capabilities.js +146 -0
- package/dist/adapters/state/darwin-capabilities.js.map +1 -0
- package/dist/adapters/state/darwin-native-host.d.ts +32 -0
- package/dist/adapters/state/darwin-native-host.js +294 -0
- package/dist/adapters/state/darwin-native-host.js.map +1 -0
- package/dist/adapters/state/darwin-profile.d.ts +6 -0
- package/dist/adapters/state/darwin-profile.js +56 -0
- package/dist/adapters/state/darwin-profile.js.map +1 -0
- package/dist/adapters/state/darwin-system-program.d.ts +1 -0
- package/dist/adapters/state/darwin-system-program.js +94 -0
- package/dist/adapters/state/darwin-system-program.js.map +1 -0
- package/dist/adapters/state/local-qualification.d.ts +16 -0
- package/dist/adapters/state/local-qualification.js +299 -0
- package/dist/adapters/state/local-qualification.js.map +1 -0
- package/dist/adapters/state/local.d.ts +25 -0
- package/dist/adapters/state/local.js +145 -0
- package/dist/adapters/state/local.js.map +1 -0
- package/dist/adapters/state/native-command.d.ts +21 -0
- package/dist/adapters/state/native-command.js +82 -0
- package/dist/adapters/state/native-command.js.map +1 -0
- package/dist/adapters/state/native-files.d.ts +2 -0
- package/dist/adapters/state/native-files.js +47 -0
- package/dist/adapters/state/native-files.js.map +1 -0
- package/dist/adapters/state/native-system.d.ts +38 -0
- package/dist/adapters/state/native-system.js +86 -0
- package/dist/adapters/state/native-system.js.map +1 -0
- package/dist/adapters/state/opentofu.d.ts +35 -0
- package/dist/adapters/state/opentofu.js +350 -0
- package/dist/adapters/state/opentofu.js.map +1 -0
- package/dist/adapters/state/owned-process.d.ts +43 -0
- package/dist/adapters/state/owned-process.js +252 -0
- package/dist/adapters/state/owned-process.js.map +1 -0
- package/dist/adapters/state/posix-lock-program.d.ts +1 -0
- package/dist/adapters/state/posix-lock-program.js +185 -0
- package/dist/adapters/state/posix-lock-program.js.map +1 -0
- package/dist/adapters/state/posix-native-lock.d.ts +15 -0
- package/dist/adapters/state/posix-native-lock.js +145 -0
- package/dist/adapters/state/posix-native-lock.js.map +1 -0
- package/dist/adapters/state/protected-workspace.d.ts +57 -0
- package/dist/adapters/state/protected-workspace.js +412 -0
- package/dist/adapters/state/protected-workspace.js.map +1 -0
- package/dist/application/context.d.ts +3 -0
- package/dist/application/diagnose/doctor.d.ts +5 -0
- package/dist/application/diagnose/doctor.js +21 -5
- package/dist/application/diagnose/doctor.js.map +1 -1
- package/dist/application/diagnose/generated-project.js +2 -7
- package/dist/application/diagnose/generated-project.js.map +1 -1
- package/dist/application/initialize/fixture.js +8 -1
- package/dist/application/initialize/fixture.js.map +1 -1
- package/dist/application/initialize/use-case.js +70 -36
- package/dist/application/initialize/use-case.js.map +1 -1
- package/dist/application/project/manifest.js +5 -4
- package/dist/application/project/manifest.js.map +1 -1
- package/dist/application/state-migration/execution.d.ts +32 -0
- package/dist/application/state-migration/execution.js +440 -0
- package/dist/application/state-migration/execution.js.map +1 -0
- package/dist/application/state-migration/index.d.ts +22 -0
- package/dist/application/state-migration/index.js +17 -0
- package/dist/application/state-migration/index.js.map +1 -0
- package/dist/application/state-migration/lifecycle.d.ts +3 -0
- package/dist/application/state-migration/lifecycle.js +149 -0
- package/dist/application/state-migration/lifecycle.js.map +1 -0
- package/dist/application/state-migration/planning.d.ts +7 -0
- package/dist/application/state-migration/planning.js +150 -0
- package/dist/application/state-migration/planning.js.map +1 -0
- package/dist/application/state-migration/recovery.d.ts +5 -0
- package/dist/application/state-migration/recovery.js +145 -0
- package/dist/application/state-migration/recovery.js.map +1 -0
- package/dist/application/state-migration/runtime.d.ts +32 -0
- package/dist/application/state-migration/runtime.js +188 -0
- package/dist/application/state-migration/runtime.js.map +1 -0
- package/dist/application/state-migration/service.d.ts +2 -0
- package/dist/application/state-migration/service.js +20 -0
- package/dist/application/state-migration/service.js.map +1 -0
- package/dist/application/update/inspection.d.ts +16 -2
- package/dist/application/update/inspection.js +76 -23
- package/dist/application/update/inspection.js.map +1 -1
- package/dist/application/update/migration-runtime.js +24 -11
- package/dist/application/update/migration-runtime.js.map +1 -1
- package/dist/application/update/output.d.ts +2 -0
- package/dist/application/update/output.js +11 -1
- package/dist/application/update/output.js.map +1 -1
- package/dist/application/update/revalidation-plan.d.ts +1 -0
- package/dist/application/update/revalidation-plan.js +25 -12
- package/dist/application/update/revalidation-plan.js.map +1 -1
- package/dist/application/update/revalidation.d.ts +4 -1
- package/dist/application/update/revalidation.js +62 -21
- package/dist/application/update/revalidation.js.map +1 -1
- package/dist/application/update/use-case.js +25 -17
- package/dist/application/update/use-case.js.map +1 -1
- package/dist/cli/args/definitions.js +11 -3
- package/dist/cli/args/definitions.js.map +1 -1
- package/dist/cli/args/parser.js +29 -3
- package/dist/cli/args/parser.js.map +1 -1
- package/dist/domain/governance/activation/approvals.d.ts +264 -7
- package/dist/domain/governance/activation/approvals.js +166 -23
- package/dist/domain/governance/activation/approvals.js.map +1 -1
- package/dist/domain/governance/activation/capabilities.js +5 -2
- package/dist/domain/governance/activation/capabilities.js.map +1 -1
- package/dist/domain/governance/activation/evidence.d.ts +2 -1
- package/dist/domain/governance/activation/evidence.js +64 -11
- package/dist/domain/governance/activation/evidence.js.map +1 -1
- package/dist/domain/governance/activation/graph.d.ts +11 -384
- package/dist/domain/governance/activation/graph.js +424 -379
- package/dist/domain/governance/activation/graph.js.map +1 -1
- package/dist/domain/governance/activation/inputs.d.ts +3 -1
- package/dist/domain/governance/activation/inputs.js +47 -6
- package/dist/domain/governance/activation/inputs.js.map +1 -1
- package/dist/domain/governance/activation/operations.d.ts +4 -1
- package/dist/domain/governance/activation/operations.js +110 -22
- package/dist/domain/governance/activation/operations.js.map +1 -1
- package/dist/domain/governance/activation/readiness.d.ts +10 -0
- package/dist/domain/governance/activation/readiness.js +77 -38
- package/dist/domain/governance/activation/readiness.js.map +1 -1
- package/dist/domain/governance/activation/types.d.ts +151 -9
- package/dist/domain/governance/activation/types.js +23 -1
- package/dist/domain/governance/activation/types.js.map +1 -1
- package/dist/domain/governance/activation/validators.d.ts +4 -1
- package/dist/domain/governance/activation/validators.js +419 -26
- package/dist/domain/governance/activation/validators.js.map +1 -1
- package/dist/domain/governance/policy/identity.d.ts +55 -13
- package/dist/domain/governance/policy/identity.js +28 -8
- package/dist/domain/governance/policy/identity.js.map +1 -1
- package/dist/domain/project/artifact-lifecycle.d.ts +2 -1
- package/dist/domain/project/artifact-lifecycle.js +7 -1
- package/dist/domain/project/artifact-lifecycle.js.map +1 -1
- package/dist/domain/project/catalog.d.ts +50 -1
- package/dist/domain/project/catalog.js +104 -4
- package/dist/domain/project/catalog.js.map +1 -1
- package/dist/domain/project/contracts.d.ts +9 -1
- package/dist/domain/project/infrastructure-layout.d.ts +1 -1
- package/dist/domain/project/infrastructure-layout.js +2 -1
- package/dist/domain/project/infrastructure-layout.js.map +1 -1
- package/dist/domain/project/manifest/governance.d.ts +1 -1
- package/dist/domain/project/manifest/governance.js +9 -10
- package/dist/domain/project/manifest/governance.js.map +1 -1
- package/dist/domain/project/planning.js +4 -5
- package/dist/domain/project/planning.js.map +1 -1
- package/dist/domain/repair/stateful-bounded.d.ts +1 -0
- package/dist/domain/repair/stateful-bounded.js +37 -0
- package/dist/domain/repair/stateful-bounded.js.map +1 -0
- package/dist/domain/repair/stateful-invariants.d.ts +28 -0
- package/dist/domain/repair/stateful-invariants.js +278 -0
- package/dist/domain/repair/stateful-invariants.js.map +1 -0
- package/dist/domain/repair/stateful.d.ts +690 -0
- package/dist/domain/repair/stateful.js +26 -0
- package/dist/domain/repair/stateful.js.map +1 -0
- package/dist/domain/workstation/constraints.d.ts +1 -0
- package/dist/domain/workstation/constraints.js.map +1 -1
- package/dist/domain/workstation/contracts.d.ts +42 -0
- package/dist/domain/workstation/contracts.js +2 -0
- package/dist/domain/workstation/contracts.js.map +1 -0
- package/dist/domain/workstation/executables.d.ts +19 -0
- package/dist/domain/workstation/executables.js +68 -0
- package/dist/domain/workstation/executables.js.map +1 -0
- package/dist/domain/workstation/versions.d.ts +8 -0
- package/dist/domain/workstation/versions.js +145 -0
- package/dist/domain/workstation/versions.js.map +1 -0
- package/dist/framework-adapters.d.ts +2 -0
- package/dist/framework-adapters.js +148 -22
- package/dist/framework-adapters.js.map +1 -1
- package/dist/framework-validation.d.ts +6 -0
- package/dist/framework-validation.js +89 -24
- package/dist/framework-validation.js.map +1 -1
- package/dist/generators/common/base.js +57 -17
- package/dist/generators/common/base.js.map +1 -1
- package/dist/governance-activation/activation-state.js +39 -7
- package/dist/governance-activation/activation-state.js.map +1 -1
- package/dist/governance-activation/authority-records.d.ts +4 -0
- package/dist/governance-activation/authority-records.js +24 -0
- package/dist/governance-activation/authority-records.js.map +1 -0
- package/dist/governance-activation/commands.d.ts +9 -1
- package/dist/governance-activation/commands.js +392 -97
- package/dist/governance-activation/commands.js.map +1 -1
- package/dist/governance-activation/compatibility.d.ts +11 -8
- package/dist/governance-activation/compatibility.js +37 -23
- package/dist/governance-activation/compatibility.js.map +1 -1
- package/dist/governance-activation/doctor.js +40 -16
- package/dist/governance-activation/doctor.js.map +1 -1
- package/dist/governance-activation/github-config.d.ts +17 -0
- package/dist/governance-activation/github-config.js +88 -0
- package/dist/governance-activation/github-config.js.map +1 -0
- package/dist/governance-activation/github-discovery.d.ts +18 -0
- package/dist/governance-activation/github-discovery.js +229 -0
- package/dist/governance-activation/github-discovery.js.map +1 -0
- package/dist/governance-activation/github-ports.d.ts +12 -0
- package/dist/governance-activation/github-ports.js +4 -0
- package/dist/governance-activation/github-ports.js.map +1 -0
- package/dist/governance-activation/github-publication.d.ts +3 -0
- package/dist/governance-activation/github-publication.js +190 -0
- package/dist/governance-activation/github-publication.js.map +1 -0
- package/dist/governance-activation/historical-common.d.ts +98 -0
- package/dist/governance-activation/historical-common.js +269 -0
- package/dist/governance-activation/historical-common.js.map +1 -0
- package/dist/governance-activation/historical-credential-policy.d.ts +3 -0
- package/dist/governance-activation/historical-credential-policy.js +91 -0
- package/dist/governance-activation/historical-credential-policy.js.map +1 -0
- package/dist/governance-activation/historical-inputs.d.ts +6 -0
- package/dist/governance-activation/historical-inputs.js +57 -0
- package/dist/governance-activation/historical-inputs.js.map +1 -0
- package/dist/governance-activation/historical-safety.d.ts +9 -0
- package/dist/governance-activation/historical-safety.js +102 -0
- package/dist/governance-activation/historical-safety.js.map +1 -0
- package/dist/governance-activation/historical-source-metadata.d.ts +31 -0
- package/dist/governance-activation/historical-source-metadata.js +55 -0
- package/dist/governance-activation/historical-source-metadata.js.map +1 -0
- package/dist/governance-activation/historical-state.d.ts +12 -50
- package/dist/governance-activation/historical-state.js +195 -308
- package/dist/governance-activation/historical-state.js.map +1 -1
- package/dist/governance-activation/historical-v1-auxiliary.d.ts +1 -0
- package/dist/governance-activation/historical-v1-auxiliary.js +43 -0
- package/dist/governance-activation/historical-v1-auxiliary.js.map +1 -0
- package/dist/governance-activation/historical-v1-phase-contracts.d.ts +31 -0
- package/dist/governance-activation/historical-v1-phase-contracts.js +46 -0
- package/dist/governance-activation/historical-v1-phase-contracts.js.map +1 -0
- package/dist/governance-activation/historical-v2.d.ts +53 -0
- package/dist/governance-activation/historical-v2.js +313 -0
- package/dist/governance-activation/historical-v2.js.map +1 -0
- package/dist/governance-activation/history-contracts.d.ts +21 -12
- package/dist/governance-activation/history-contracts.js +99 -27
- package/dist/governance-activation/history-contracts.js.map +1 -1
- package/dist/governance-activation/inputs.d.ts +8 -2
- package/dist/governance-activation/inputs.js +41 -6
- package/dist/governance-activation/inputs.js.map +1 -1
- package/dist/governance-activation/migration-history.d.ts +43 -5
- package/dist/governance-activation/migration-history.js +231 -50
- package/dist/governance-activation/migration-history.js.map +1 -1
- package/dist/governance-activation/migration.d.ts +7 -4
- package/dist/governance-activation/migration.js +53 -252
- package/dist/governance-activation/migration.js.map +1 -1
- package/dist/governance-activation/phase-azure.d.ts +3 -0
- package/dist/governance-activation/phase-azure.js +205 -0
- package/dist/governance-activation/phase-azure.js.map +1 -0
- package/dist/governance-activation/phase-bootstrap-state.js +3 -0
- package/dist/governance-activation/phase-bootstrap-state.js.map +1 -1
- package/dist/governance-activation/phase-github.d.ts +3 -0
- package/dist/governance-activation/phase-github.js +192 -0
- package/dist/governance-activation/phase-github.js.map +1 -0
- package/dist/governance-activation/phase-governance.js +8 -2
- package/dist/governance-activation/phase-governance.js.map +1 -1
- package/dist/governance-activation/public-plans.d.ts +36 -0
- package/dist/governance-activation/public-plans.js +100 -0
- package/dist/governance-activation/public-plans.js.map +1 -0
- package/dist/governance-activation/read-only.d.ts +3 -1
- package/dist/governance-activation/read-only.js +7 -3
- package/dist/governance-activation/read-only.js.map +1 -1
- package/dist/governance-activation/reconciliation.js +10 -0
- package/dist/governance-activation/reconciliation.js.map +1 -1
- package/dist/governance-activation/seed-lifecycle.js +14 -25
- package/dist/governance-activation/seed-lifecycle.js.map +1 -1
- package/dist/governance-activation/source-of-truth.d.ts +21 -5
- package/dist/governance-activation/source-of-truth.js +102 -13
- package/dist/governance-activation/source-of-truth.js.map +1 -1
- package/dist/governance-activation/task-projection.d.ts +4 -1
- package/dist/governance-activation/task-projection.js +32 -3
- package/dist/governance-activation/task-projection.js.map +1 -1
- package/dist/governance-activation/task-writes.d.ts +42 -0
- package/dist/governance-activation/task-writes.js +250 -0
- package/dist/governance-activation/task-writes.js.map +1 -0
- package/dist/governance-activation/transition-files.d.ts +12 -0
- package/dist/governance-activation/transition-files.js +109 -0
- package/dist/governance-activation/transition-files.js.map +1 -0
- package/dist/governance-activation/transition-planning.d.ts +3 -1
- package/dist/governance-activation/transition-planning.js +158 -20
- package/dist/governance-activation/transition-planning.js.map +1 -1
- package/dist/governance-activation/transition-ports.d.ts +31 -3
- package/dist/governance-activation/transition-records.d.ts +11 -1
- package/dist/governance-activation/transition-records.js +52 -6
- package/dist/governance-activation/transition-records.js.map +1 -1
- package/dist/governance-activation/transitions.d.ts +5 -0
- package/dist/governance-activation/transitions.js +271 -37
- package/dist/governance-activation/transitions.js.map +1 -1
- package/dist/governance-assessment/engine.js +22 -15
- package/dist/governance-assessment/engine.js.map +1 -1
- package/dist/governance-assessment/project.d.ts +2 -0
- package/dist/governance-assessment/project.js +2 -1
- package/dist/governance-assessment/project.js.map +1 -1
- package/dist/interactive.d.ts +0 -1
- package/dist/interactive.js +3 -22
- package/dist/interactive.js.map +1 -1
- package/dist/openspec-profile.d.ts +2 -1
- package/dist/openspec-profile.js +11 -41
- package/dist/openspec-profile.js.map +1 -1
- package/dist/repository-governance.d.ts +10 -5
- package/dist/repository-governance.js +178 -92
- package/dist/repository-governance.js.map +1 -1
- package/dist/telemetry/contract.d.ts +1 -1
- package/dist/telemetry/contract.js +3 -0
- package/dist/telemetry/contract.js.map +1 -1
- package/dist/workstation-catalog.d.ts +13 -1
- package/dist/workstation-catalog.js +122 -0
- package/dist/workstation-catalog.js.map +1 -1
- package/dist/workstation.d.ts +69 -14
- package/dist/workstation.js +600 -215
- package/dist/workstation.js.map +1 -1
- package/docs/cli-reference.md +59 -21
- package/docs/configuration-and-manifests.md +9 -8
- package/docs/prerequisites.md +93 -18
- package/docs/repository-governance.md +68 -40
- package/docs/spec-workflows-and-agents.md +132 -13
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-command.js","sourceRoot":"","sources":["../../../src/adapters/state/native-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,4CAA4C,CAAC;AACtF,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAMpE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ;IACvD,eAAe,EAAE,eAAe,EAAE,qBAAqB,EAAE,cAAc;IACvE,gBAAgB,EAAE,0BAA0B,EAAE,aAAa;IAC3D,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB;IAC1D,aAAa;IACb,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc;CACzE,CAAC,CAAC;AAEH,MAAM,OAAO,8BAA8B;IAIZ,OAAO;IAH3B,cAAc,CAAS;IAChC,UAAU,CAAiC;IAC3C,WAAW,GAAG,CAAC,CAAC;IAChB,YAA6B,OAO5B;uBAP4B,OAAO;QAQlC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACxH,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,IAAI,8BAA8B,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjF,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;IACjF,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAA4B;QACpC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,WAAW,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QACnD,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC;QAC9I,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC;QACzH,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mFAAmF,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;eACjI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC;QACjI,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC;mBAC9E,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC;QACrI,CAAC;QACD,WAAW,CAAC,WAAW,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAC9G,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5E,WAAW,CAAC,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,QAAQ;eAC9E,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC,4BAA4B,EAAE,0BAA0B,CAAC,CAAC;QACrG,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACzE,MAAM,GAAG,GAA2B,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrD,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,0BAA0B,CAAC,CAAC;YAC7F,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACpB,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;YACjB,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,GAAG;YACzE,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG;YACxD,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC;YACjD,kBAAkB,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,sBAAsB,CAAC;YAClE,gBAAgB,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK;YAC7D,8BAA8B,EAAE,MAAM,EAAE,mCAAmC,EAAE,MAAM;SACpF,CAAC,CAAC;QACH,WAAW,CAAC,UAAU,KAAK,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QACtF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBACvC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG;gBAC3F,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM;gBACzF,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,aAAa,EAAE,KAAK;aACrF,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9D,CAAC;gBAAS,CAAC;YAAC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;YACvC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE;YACzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;SACnD,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;QACrE,IAAI,OAAO,EAAE,MAAM,KAAK,UAAU;YAAE,MAAM,OAAO,CAAC,MAAM,CAAC;IAC3D,CAAC;CACF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { lstat, open, realpath } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { stateAssert } from '../../domain/repair/stateful-invariants.js';
|
|
5
|
+
async function inspectNativeFile(filename) {
|
|
6
|
+
stateAssert(path.isAbsolute(filename) && await realpath(path.dirname(filename)) === path.dirname(filename), 'unsafe-path');
|
|
7
|
+
const existing = await lstat(filename).catch((error) => {
|
|
8
|
+
if (error.code === 'ENOENT')
|
|
9
|
+
return null;
|
|
10
|
+
throw error;
|
|
11
|
+
});
|
|
12
|
+
stateAssert(!existing || (existing.isFile() && !existing.isSymbolicLink() && existing.nlink === 1), 'unsafe-path');
|
|
13
|
+
return existing;
|
|
14
|
+
}
|
|
15
|
+
export async function writePrivateNativeFile(filename, bytes, exclusive = false) {
|
|
16
|
+
const before = await inspectNativeFile(filename);
|
|
17
|
+
stateAssert(!exclusive || !before, 'unsafe-path');
|
|
18
|
+
const file = await open(filename, constants.O_WRONLY | constants.O_CREAT | (constants.O_NOFOLLOW ?? 0)
|
|
19
|
+
| (exclusive ? constants.O_EXCL : 0), 0o600);
|
|
20
|
+
try {
|
|
21
|
+
const current = await file.stat();
|
|
22
|
+
stateAssert(current.isFile() && current.nlink === 1
|
|
23
|
+
&& (!before || (current.ino === before.ino && current.dev === before.dev)), 'unsafe-path');
|
|
24
|
+
await file.chmod(0o600);
|
|
25
|
+
await file.truncate(0);
|
|
26
|
+
await file.writeFile(bytes);
|
|
27
|
+
await file.sync();
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
await file.close();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function readPrivateNativeFile(filename, maximumBytes) {
|
|
34
|
+
const before = await inspectNativeFile(filename);
|
|
35
|
+
stateAssert(before && before.size <= maximumBytes, 'storage-limit');
|
|
36
|
+
const file = await open(filename, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
37
|
+
try {
|
|
38
|
+
const current = await file.stat();
|
|
39
|
+
stateAssert(current.isFile() && current.nlink === 1 && current.ino === before.ino && current.dev === before.dev
|
|
40
|
+
&& current.size === before.size, 'unsafe-path');
|
|
41
|
+
return await file.readFile();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
await file.close();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=native-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-files.js","sourceRoot":"","sources":["../../../src/adapters/state/native-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ChildProcessWithoutNullStreams } from 'node:child_process';
|
|
2
|
+
import { type NativeLocalStateTools, type StateRegisteredExecutable } from '../../domain/repair/stateful.js';
|
|
3
|
+
export declare const nativeLocalStateProtocol: Readonly<{
|
|
4
|
+
version: 'opentofu-1.12.6-posix-fcntl';
|
|
5
|
+
tofuVersion: '1.12.6';
|
|
6
|
+
sourceCommit: "b4305e5a5dd2fb79a27897ae30784a181d3a26cb";
|
|
7
|
+
lockSource: "internal/flock/filesystem_lock_unix.go";
|
|
8
|
+
lockBlob: "c396e445a0eede26b32b97068216fe3691070d9f";
|
|
9
|
+
stateSource: "internal/states/statemgr/filesystem.go";
|
|
10
|
+
stateBlob: "3f01209ea1635c9cad5f499f4f08ce356aef9a4c";
|
|
11
|
+
lockOperation: "F_SETLK/F_WRLCK/start=0/length=0";
|
|
12
|
+
writeOperation: "seek/truncate/write/sync on the same open inode";
|
|
13
|
+
}>;
|
|
14
|
+
export declare function nativeStateHostId(): string;
|
|
15
|
+
export declare function captureStateExecutable(filename: string): Promise<StateRegisteredExecutable>;
|
|
16
|
+
export declare function verifyStateExecutable(executable: StateRegisteredExecutable): Promise<void>;
|
|
17
|
+
export declare function isolatedStateEnvironment(cwd: string): NodeJS.ProcessEnv;
|
|
18
|
+
export declare function startPrivateStateProcess(executable: StateRegisteredExecutable, args: readonly string[], cwd: string, environment?: NodeJS.ProcessEnv, role?: 'command' | 'lease'): Promise<ChildProcessWithoutNullStreams>;
|
|
19
|
+
export declare function runPrivateStateProcess(request: {
|
|
20
|
+
executable: StateRegisteredExecutable;
|
|
21
|
+
args: readonly string[];
|
|
22
|
+
cwd: string;
|
|
23
|
+
stdin?: Uint8Array;
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
maximumBytes?: number;
|
|
26
|
+
environment?: NodeJS.ProcessEnv;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
exitCode: number;
|
|
30
|
+
stdout: Uint8Array;
|
|
31
|
+
stderr: Uint8Array;
|
|
32
|
+
}>;
|
|
33
|
+
export declare function inspectNativeLocalStateTools(request: {
|
|
34
|
+
pythonPath: string;
|
|
35
|
+
tofuPath: string;
|
|
36
|
+
workingDirectory: string;
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
}): Promise<NativeLocalStateTools>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { lstat, readFile, realpath } from 'node:fs/promises';
|
|
2
|
+
import { hostname } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { stateAssert, stateDigest, stateObjectDigest } from '../../domain/repair/stateful-invariants.js';
|
|
5
|
+
import { OwnedPrivateStateProcessRunner, spawnOwnedStateProcess } from './owned-process.js';
|
|
6
|
+
export const nativeLocalStateProtocol = Object.freeze({
|
|
7
|
+
version: 'opentofu-1.12.6-posix-fcntl',
|
|
8
|
+
tofuVersion: '1.12.6',
|
|
9
|
+
sourceCommit: 'b4305e5a5dd2fb79a27897ae30784a181d3a26cb',
|
|
10
|
+
lockSource: 'internal/flock/filesystem_lock_unix.go',
|
|
11
|
+
lockBlob: 'c396e445a0eede26b32b97068216fe3691070d9f',
|
|
12
|
+
stateSource: 'internal/states/statemgr/filesystem.go',
|
|
13
|
+
stateBlob: '3f01209ea1635c9cad5f499f4f08ce356aef9a4c',
|
|
14
|
+
lockOperation: 'F_SETLK/F_WRLCK/start=0/length=0',
|
|
15
|
+
writeOperation: 'seek/truncate/write/sync on the same open inode'
|
|
16
|
+
});
|
|
17
|
+
export function nativeStateHostId() {
|
|
18
|
+
return `native-host:${stateObjectDigest({ platform: process.platform, host: hostname(), uid: process.getuid?.() })}`;
|
|
19
|
+
}
|
|
20
|
+
export async function captureStateExecutable(filename) {
|
|
21
|
+
stateAssert(path.isAbsolute(filename), 'tool-unavailable');
|
|
22
|
+
const resolved = await realpath(filename);
|
|
23
|
+
const info = await lstat(resolved);
|
|
24
|
+
stateAssert(info.isFile() && (info.mode & 0o022) === 0 && (info.mode & 0o111) !== 0, 'tool-unavailable');
|
|
25
|
+
return { path: resolved, sha256: stateDigest(await readFile(resolved)) };
|
|
26
|
+
}
|
|
27
|
+
export async function verifyStateExecutable(executable) {
|
|
28
|
+
stateAssert((await captureStateExecutable(executable.path)).sha256 === executable.sha256, 'tool-unavailable');
|
|
29
|
+
}
|
|
30
|
+
export function isolatedStateEnvironment(cwd) {
|
|
31
|
+
return {
|
|
32
|
+
PATH: '/usr/bin:/bin:/usr/sbin:/sbin', HOME: cwd, USERPROFILE: cwd,
|
|
33
|
+
XDG_CONFIG_HOME: cwd, TMPDIR: cwd, TMP: cwd, TEMP: cwd,
|
|
34
|
+
CHECKPOINT_DISABLE: '1', TF_IN_AUTOMATION: '1', TF_LOG: 'OFF',
|
|
35
|
+
TF_CLI_CONFIG_FILE: path.join(cwd, 'liftoff.private.tfrc'),
|
|
36
|
+
TF_DATA_DIR: path.join(cwd, '.terraform'), LC_ALL: 'C'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function startPrivateStateProcess(executable, args, cwd, environment = isolatedStateEnvironment(cwd), role = 'command') {
|
|
40
|
+
await verifyStateExecutable(executable);
|
|
41
|
+
stateAssert(path.isAbsolute(cwd) && args.every((arg) => !arg.includes('\0')), 'unsafe-path');
|
|
42
|
+
return spawnOwnedStateProcess({ executable: executable.path, args, cwd, environment, role });
|
|
43
|
+
}
|
|
44
|
+
export async function runPrivateStateProcess(request) {
|
|
45
|
+
const timeout = request.timeoutMs ?? 20_000;
|
|
46
|
+
stateAssert(timeout > 0 && timeout <= 300_000, 'invalid-binding');
|
|
47
|
+
await verifyStateExecutable(request.executable);
|
|
48
|
+
return new OwnedPrivateStateProcessRunner().run({
|
|
49
|
+
executable: request.executable.path, args: request.args, cwd: request.cwd,
|
|
50
|
+
environment: request.environment ?? isolatedStateEnvironment(request.cwd), stdin: request.stdin,
|
|
51
|
+
signal: request.signal, timeoutMs: timeout, maximumBytes: request.maximumBytes ?? 2 * 1024 * 1024
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export async function inspectNativeLocalStateTools(request) {
|
|
55
|
+
stateAssert(process.platform === 'darwin', 'unsupported-native-platform');
|
|
56
|
+
const python = await captureStateExecutable(request.pythonPath);
|
|
57
|
+
const tofu = await captureStateExecutable(request.tofuPath);
|
|
58
|
+
const py = await runPrivateStateProcess({
|
|
59
|
+
executable: python, args: ['-I', '-S', '-B', '-c', 'import json,platform,sys; print(json.dumps({"implementation":platform.python_implementation(),"version":".".join(map(str,sys.version_info[:3]))}))'],
|
|
60
|
+
cwd: request.workingDirectory, signal: request.signal
|
|
61
|
+
});
|
|
62
|
+
let pythonVersion;
|
|
63
|
+
try {
|
|
64
|
+
const info = JSON.parse(Buffer.from(py.stdout).toString('utf8'));
|
|
65
|
+
stateAssert(py.exitCode === 0 && info.implementation === 'CPython' && /^3\.14\.\d+$/.test(info.version), 'native-lock-provider-required');
|
|
66
|
+
pythonVersion = info.version;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
py.stdout.fill(0);
|
|
70
|
+
py.stderr.fill(0);
|
|
71
|
+
}
|
|
72
|
+
const tf = await runPrivateStateProcess({
|
|
73
|
+
executable: tofu, args: ['version', '-json'], cwd: request.workingDirectory, signal: request.signal
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
const info = JSON.parse(Buffer.from(tf.stdout).toString('utf8'));
|
|
77
|
+
stateAssert(tf.exitCode === 0 && info.terraform_version === nativeLocalStateProtocol.tofuVersion
|
|
78
|
+
&& info.platform === `darwin_${process.arch === 'arm64' ? 'arm64' : 'amd64'}`, 'unqualified-combination');
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
tf.stdout.fill(0);
|
|
82
|
+
tf.stderr.fill(0);
|
|
83
|
+
}
|
|
84
|
+
return { python, tofu, pythonVersion, tofuVersion: '1.12.6', hostId: nativeStateHostId() };
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=native-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-system.js","sourceRoot":"","sources":["../../../src/adapters/state/native-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type InspectedState, type PreparedStateMigration, type PrivateStateCommandRunner, type ProtectedStateWorkspace, type StateBackendKind, type StateConfigurationProvider, type StateMigrationPlan, type StateNativeDriver, type StateNativeReview, type StateRecipe, type StateRecipeQualification } from '../../domain/repair/stateful.js';
|
|
2
|
+
export declare const implementedStateRecipeCombinations: readonly {
|
|
3
|
+
recipe: StateRecipe;
|
|
4
|
+
source: StateBackendKind;
|
|
5
|
+
destinations: readonly StateBackendKind[];
|
|
6
|
+
liveQualificationRequired: true;
|
|
7
|
+
}[];
|
|
8
|
+
export type { StateConfigurationAttestation, StateConfigurationProvider, StateRecipeQualification } from '../../domain/repair/stateful.js';
|
|
9
|
+
export declare class OpenTofuStateDriver implements StateNativeDriver {
|
|
10
|
+
private readonly options;
|
|
11
|
+
constructor(options: {
|
|
12
|
+
workspace: ProtectedStateWorkspace;
|
|
13
|
+
runner: PrivateStateCommandRunner;
|
|
14
|
+
configurations: StateConfigurationProvider;
|
|
15
|
+
qualification: StateRecipeQualification;
|
|
16
|
+
now?: () => number;
|
|
17
|
+
});
|
|
18
|
+
quiesce(): Promise<void>;
|
|
19
|
+
private withScratch;
|
|
20
|
+
private qualify;
|
|
21
|
+
private run;
|
|
22
|
+
private runQuiet;
|
|
23
|
+
private backendConfiguration;
|
|
24
|
+
private minimalRoot;
|
|
25
|
+
private materialize;
|
|
26
|
+
private copyState;
|
|
27
|
+
private verifyPlannedIdentities;
|
|
28
|
+
private rootPlan;
|
|
29
|
+
review(request: Parameters<StateNativeDriver['review']>[0]): Promise<StateNativeReview>;
|
|
30
|
+
private privateState;
|
|
31
|
+
prepare(plan: StateMigrationPlan, signal?: AbortSignal): Promise<PreparedStateMigration>;
|
|
32
|
+
verify(plan: StateMigrationPlan, current: Readonly<Record<string, InspectedState>>, signal?: AbortSignal): Promise<string>;
|
|
33
|
+
verifyDestinations(plan: StateMigrationPlan, current: Readonly<Record<string, InspectedState>>, signal?: AbortSignal): Promise<string>;
|
|
34
|
+
private verifyRoots;
|
|
35
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { lstat, mkdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { statefulRecipeVersion } from '../../domain/repair/stateful.js';
|
|
4
|
+
import { assertNoResourceChanges, inspectStateBytes, isStateDigest, stateAssert, stateDigest, stateObjectDigest, validateStateMappings, validateStatePlanBindings, verifyStateAccounting } from '../../domain/repair/stateful-invariants.js';
|
|
5
|
+
import { protectedStateScope } from './protected-workspace.js';
|
|
6
|
+
import { readPrivateNativeFile, writePrivateNativeFile } from './native-files.js';
|
|
7
|
+
export const implementedStateRecipeCombinations = ['local', 'azurerm'].flatMap((source) => [
|
|
8
|
+
{ recipe: 'address-refactor', source, destinations: [source], liveQualificationRequired: true },
|
|
9
|
+
...['local', 'azurerm'].map((destination) => ({
|
|
10
|
+
recipe: 'backend-relocation', source, destinations: [destination], liveQualificationRequired: true
|
|
11
|
+
})),
|
|
12
|
+
{ recipe: 'state-partition', source, destinations: ['local', 'azurerm'], liveQualificationRequired: true }
|
|
13
|
+
]);
|
|
14
|
+
export class OpenTofuStateDriver {
|
|
15
|
+
options;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.options = options;
|
|
18
|
+
}
|
|
19
|
+
async quiesce() {
|
|
20
|
+
stateAssert(this.options.runner.quiesce, 'process-tree-termination-unproven');
|
|
21
|
+
await this.options.runner.quiesce();
|
|
22
|
+
}
|
|
23
|
+
async withScratch(context, action) {
|
|
24
|
+
return this.options.workspace.withScratch(context, async (directory) => {
|
|
25
|
+
try {
|
|
26
|
+
return await action(directory);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await this.quiesce();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async qualify(plan) {
|
|
34
|
+
stateAssert(plan.inspection.live, 'live-scope-required');
|
|
35
|
+
validateStateMappings(plan.intent, plan.inspection.states);
|
|
36
|
+
validateStatePlanBindings(plan.intent, plan.inspection.bindings);
|
|
37
|
+
const source = plan.inspection.bindings.find((binding) => binding.id === plan.intent.sourceBackendId);
|
|
38
|
+
stateAssert(source, 'mapping-incomplete');
|
|
39
|
+
stateAssert(this.options.qualification, 'unqualified-combination');
|
|
40
|
+
await this.options.qualification.assertQualified({
|
|
41
|
+
recipeVersion: statefulRecipeVersion, recipe: plan.intent.recipe, source: source.kind,
|
|
42
|
+
destinations: plan.intent.destinationBackendIds.map((id) => {
|
|
43
|
+
const target = plan.inspection.bindings.find((binding) => binding.id === id);
|
|
44
|
+
stateAssert(target, 'mapping-incomplete');
|
|
45
|
+
return target.kind;
|
|
46
|
+
}),
|
|
47
|
+
executableDigest: this.options.runner.identityDigest, hostId: plan.context.hostId
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async run(cwd, args, operation, signal, stdin, allowed = [0]) {
|
|
51
|
+
const result = await this.options.runner.run({ cwd, args, operation, signal, ...(stdin ? { stdin } : {}) });
|
|
52
|
+
if (!allowed.includes(result.exitCode)) {
|
|
53
|
+
result.stdout.fill(0);
|
|
54
|
+
stateAssert(false, 'native-command-failed');
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
async runQuiet(cwd, args, operation, signal, stdin) {
|
|
59
|
+
const result = await this.run(cwd, args, operation, signal, stdin);
|
|
60
|
+
result.stdout.fill(0);
|
|
61
|
+
}
|
|
62
|
+
async backendConfiguration(directory, statePath) {
|
|
63
|
+
await writePrivateNativeFile(path.join(directory, 'liftoff-state-backend.tf.json'), JSON.stringify({
|
|
64
|
+
terraform: { backend: { local: { path: statePath } } }
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
async minimalRoot(directory, statePath, signal) {
|
|
68
|
+
await mkdir(directory, { mode: 0o700 });
|
|
69
|
+
const mirror = path.join(directory, 'provider-mirror');
|
|
70
|
+
await mkdir(mirror, { mode: 0o700 });
|
|
71
|
+
await writePrivateNativeFile(path.join(directory, 'liftoff.private.tfrc'), `disable_checkpoint = true\nprovider_installation {\n filesystem_mirror {\n path = ${JSON.stringify(mirror)}\n }\n}\n`);
|
|
72
|
+
await this.backendConfiguration(directory, statePath);
|
|
73
|
+
await this.runQuiet(directory, ['init', '-input=false', '-no-color', '-get=false'], 'inspect', signal);
|
|
74
|
+
}
|
|
75
|
+
async materialize(reference, directory, context, signal) {
|
|
76
|
+
await mkdir(directory, { mode: 0o700 });
|
|
77
|
+
const proof = await this.options.configurations.materialize(reference, directory, context, signal);
|
|
78
|
+
stateAssert(proof?.stateFormat === 'opentofu-v4-json', 'unsupported-encryption');
|
|
79
|
+
stateAssert(proof.configurationRef === reference && isStateDigest(proof.configurationDigest)
|
|
80
|
+
&& proof.artifactDigest === context.artifactDigest && proof.backendNeutral
|
|
81
|
+
&& proof.providerRegistration === 'disabled' && proof.provisioners.length === 0
|
|
82
|
+
&& proof.externalPrograms.length === 0 && proof.uninspectedDataSources.length === 0
|
|
83
|
+
&& proof.unresolvedModules.length === 0 && proof.moduleDigests.every(isStateDigest)
|
|
84
|
+
&& typeof proof.providerMirrorDirectory === 'string' && path.isAbsolute(proof.providerMirrorDirectory)
|
|
85
|
+
&& !/[\x00-\x1f]/.test(proof.providerMirrorDirectory)
|
|
86
|
+
&& proof.providers.length > 0 && proof.providers.every((provider) => /^registry\.(?:opentofu|terraform)\.org\/hashicorp\/azurerm$/.test(provider.source)
|
|
87
|
+
&& /^\d+\.\d+\.\d+$/.test(provider.version) && isStateDigest(provider.binaryDigest)), 'unsafe-planning-contract');
|
|
88
|
+
stateAssert(new Set(proof.providers.map((provider) => provider.source)).size === proof.providers.length, 'unsafe-planning-contract');
|
|
89
|
+
await this.options.configurations.verifyMaterialized(reference, directory, proof, signal);
|
|
90
|
+
await writePrivateNativeFile(path.join(directory, 'liftoff.private.tfrc'), `disable_checkpoint = true\nprovider_installation {\n filesystem_mirror {\n path = ${JSON.stringify(proof.providerMirrorDirectory)}\n include = ${JSON.stringify(proof.providers.map((provider) => provider.source))}\n }\n}\n`);
|
|
91
|
+
return proof;
|
|
92
|
+
}
|
|
93
|
+
async copyState(state, destination, context) {
|
|
94
|
+
stateAssert(state.stateRef && state.snapshot.digest, 'artifact-integrity');
|
|
95
|
+
const bytes = await this.options.workspace.get(state.stateRef, 'state', protectedStateScope(context));
|
|
96
|
+
try {
|
|
97
|
+
stateAssert(stateDigest(bytes) === state.snapshot.digest, 'artifact-integrity');
|
|
98
|
+
await writePrivateNativeFile(destination, bytes, true);
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
bytes.fill(0);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
verifyPlannedIdentities(plan, expected) {
|
|
105
|
+
const plannedValues = plan.planned_values;
|
|
106
|
+
stateAssert(plannedValues && typeof plannedValues === 'object', 'verification-incomplete');
|
|
107
|
+
const found = new Map();
|
|
108
|
+
const visit = (value) => {
|
|
109
|
+
stateAssert(value && typeof value === 'object', 'verification-incomplete');
|
|
110
|
+
const module = value;
|
|
111
|
+
stateAssert(module.resources === undefined || Array.isArray(module.resources), 'verification-incomplete');
|
|
112
|
+
for (const resource of module.resources ?? []) {
|
|
113
|
+
stateAssert(typeof resource.address === 'string' && typeof resource.values?.id === 'string' && !found.has(resource.address), 'verification-incomplete');
|
|
114
|
+
found.set(resource.address, stateDigest(resource.values.id));
|
|
115
|
+
}
|
|
116
|
+
stateAssert(module.child_modules === undefined || Array.isArray(module.child_modules), 'verification-incomplete');
|
|
117
|
+
for (const child of module.child_modules ?? [])
|
|
118
|
+
visit(child);
|
|
119
|
+
};
|
|
120
|
+
visit(plannedValues.root_module ?? {});
|
|
121
|
+
stateAssert(found.size === expected.length && expected.every((instance) => found.get(instance.address) === instance.identityDigest), 'resource-identity-changed');
|
|
122
|
+
}
|
|
123
|
+
async rootPlan(request) {
|
|
124
|
+
const attestation = await this.materialize(request.reference, request.directory, request.context, request.signal);
|
|
125
|
+
stateAssert(request.expectedConfigurationDigest === undefined || request.expectedConfigurationDigest === attestation.configurationDigest, 'configuration-changed');
|
|
126
|
+
await this.backendConfiguration(request.directory, request.statePath);
|
|
127
|
+
await this.runQuiet(request.directory, ['init', '-input=false', '-no-color', '-get=false', '-lockfile=readonly'], 'inspect', request.signal);
|
|
128
|
+
const saved = path.join(request.directory, 'reviewed.tfplan');
|
|
129
|
+
const result = await this.run(request.directory, [
|
|
130
|
+
'plan', '-input=false', '-no-color', '-refresh=true', '-lock=true', '-lock-timeout=10s',
|
|
131
|
+
'-detailed-exitcode', `-out=${saved}`
|
|
132
|
+
], request.operation, request.signal, undefined, [0, 2]);
|
|
133
|
+
result.stdout.fill(0);
|
|
134
|
+
const shown = await this.run(request.directory, ['show', '-json', saved], 'inspect', request.signal);
|
|
135
|
+
let parsed;
|
|
136
|
+
try {
|
|
137
|
+
parsed = JSON.parse(Buffer.from(shown.stdout).toString('utf8'));
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
stateAssert(false, 'verification-incomplete');
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
shown.stdout.fill(0);
|
|
144
|
+
}
|
|
145
|
+
stateAssert(typeof parsed.format_version === 'string' && /^1\.\d+$/.test(parsed.format_version), 'verification-incomplete');
|
|
146
|
+
assertNoResourceChanges(parsed, request.strict);
|
|
147
|
+
this.verifyPlannedIdentities(parsed, request.instances);
|
|
148
|
+
if (request.strict)
|
|
149
|
+
stateAssert(result.exitCode === 0, 'verification-incomplete');
|
|
150
|
+
await this.options.configurations.verifyMaterialized(request.reference, request.directory, attestation, request.signal);
|
|
151
|
+
const bytes = await readPrivateNativeFile(saved, 64 * 1024 * 1024);
|
|
152
|
+
let savedRef;
|
|
153
|
+
let savedDigest;
|
|
154
|
+
try {
|
|
155
|
+
const artifact = await this.options.workspace.put('plan', protectedStateScope(request.context), bytes);
|
|
156
|
+
savedRef = artifact.ref;
|
|
157
|
+
savedDigest = artifact.digest;
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
bytes.fill(0);
|
|
161
|
+
}
|
|
162
|
+
if (request.applyPrivateStateOnly) {
|
|
163
|
+
stateAssert(request.operation === 'transform', 'unsafe-planning-contract');
|
|
164
|
+
await this.runQuiet(request.directory, ['apply', '-input=false', '-no-color', saved], 'transform', request.signal);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
proofDigest: stateObjectDigest({
|
|
168
|
+
config: attestation.configurationDigest, plan: stateObjectDigest(parsed),
|
|
169
|
+
binary: this.options.runner.identityDigest, refresh: true
|
|
170
|
+
}),
|
|
171
|
+
savedRef, savedDigest, exitCode: result.exitCode, configurationDigest: attestation.configurationDigest
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async review(request) {
|
|
175
|
+
await this.qualify(request);
|
|
176
|
+
return this.withScratch(request.context, async (directory) => {
|
|
177
|
+
const source = request.inspection.states.find((state) => state.snapshot.backendId === request.intent.sourceBackendId);
|
|
178
|
+
const sourcePath = path.join(directory, 'source.tfstate');
|
|
179
|
+
await this.copyState(source, sourcePath, request.context);
|
|
180
|
+
const contracts = [];
|
|
181
|
+
let index = 0;
|
|
182
|
+
for (const reference of Object.values(request.intent.targetConfigurationRefs)) {
|
|
183
|
+
contracts.push(await this.materialize(reference, path.join(directory, `inspect-target-${index++}`), request.context, request.signal));
|
|
184
|
+
}
|
|
185
|
+
stateAssert(stateObjectDigest(contracts.map((entry) => [entry.configurationRef, entry.configurationDigest]).sort()) === request.intent.targetConfigurationDigest, 'configuration-changed');
|
|
186
|
+
const sourceRoot = path.join(directory, 'source-plan');
|
|
187
|
+
const proof = await this.rootPlan({
|
|
188
|
+
reference: request.intent.sourceConfigurationRef, directory: sourceRoot, statePath: sourcePath,
|
|
189
|
+
context: request.context, instances: source.instances, strict: true, operation: 'inspect', signal: request.signal
|
|
190
|
+
});
|
|
191
|
+
// Preview validates native address syntax without moving even private state.
|
|
192
|
+
for (const mapping of request.intent.mappings) {
|
|
193
|
+
if (mapping.sourceAddress === mapping.destinationAddress || mapping.disposition === 'preserve')
|
|
194
|
+
continue;
|
|
195
|
+
await this.runQuiet(sourceRoot, [
|
|
196
|
+
'state', 'mv', '-dry-run', '-lock=true', '-lock-timeout=10s', `-state=${sourcePath}`,
|
|
197
|
+
mapping.sourceAddress, mapping.destinationAddress
|
|
198
|
+
], 'inspect', request.signal);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
configurationDigest: request.context.configurationDigest,
|
|
202
|
+
configurationDigests: Object.fromEntries([
|
|
203
|
+
...contracts.map((contract) => [contract.configurationRef, contract.configurationDigest]),
|
|
204
|
+
[request.intent.sourceConfigurationRef, proof.configurationDigest]
|
|
205
|
+
]),
|
|
206
|
+
contractDigest: stateObjectDigest({ contracts, binary: this.options.runner.identityDigest }),
|
|
207
|
+
savedPlanRefs: [proof.savedRef], savedPlanDigests: [proof.savedDigest]
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async privateState(backendId, filename, original, context, purpose) {
|
|
212
|
+
const info = await lstat(filename).catch((error) => {
|
|
213
|
+
stateAssert(error.code === 'ENOENT', 'unsafe-path');
|
|
214
|
+
return null;
|
|
215
|
+
});
|
|
216
|
+
if (!info) {
|
|
217
|
+
const empty = inspectStateBytes({
|
|
218
|
+
...original.snapshot, backendId, exists: false, version: null, etag: null, size: 0
|
|
219
|
+
}, null);
|
|
220
|
+
return { ...empty, stateRef: null };
|
|
221
|
+
}
|
|
222
|
+
stateAssert(info.isFile() && !info.isSymbolicLink() && info.nlink === 1, 'unsafe-path');
|
|
223
|
+
stateAssert(info.size > 0 && info.size <= 32 * 1024 * 1024, 'invalid-state');
|
|
224
|
+
const bytes = await readPrivateNativeFile(filename, 32 * 1024 * 1024);
|
|
225
|
+
try {
|
|
226
|
+
const inspected = inspectStateBytes({
|
|
227
|
+
...original.snapshot, backendId, exists: true, size: bytes.byteLength,
|
|
228
|
+
observedAt: this.options.now?.() ?? Date.now()
|
|
229
|
+
}, bytes);
|
|
230
|
+
const saved = await this.options.workspace.put(purpose, protectedStateScope(context), bytes);
|
|
231
|
+
return { ...inspected, stateRef: saved.ref };
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
bytes.fill(0);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async prepare(plan, signal) {
|
|
238
|
+
await this.qualify({ context: plan.context, inspection: plan.inspection, intent: plan.intent, signal });
|
|
239
|
+
return this.withScratch(plan.context, async (directory) => {
|
|
240
|
+
const contracts = [];
|
|
241
|
+
let contractIndex = 0;
|
|
242
|
+
for (const reference of Object.values(plan.intent.targetConfigurationRefs)) {
|
|
243
|
+
contracts.push(await this.materialize(reference, path.join(directory, `recheck-target-${contractIndex++}`), plan.context, signal));
|
|
244
|
+
}
|
|
245
|
+
stateAssert(stateObjectDigest(contracts.map((entry) => [entry.configurationRef, entry.configurationDigest]).sort()) === plan.intent.targetConfigurationDigest
|
|
246
|
+
&& stateObjectDigest({ contracts, binary: this.options.runner.identityDigest }) === plan.review.contractDigest, 'configuration-changed');
|
|
247
|
+
for (let index = 0; index < plan.review.savedPlanRefs.length; index++) {
|
|
248
|
+
const bytes = await this.options.workspace.get(plan.review.savedPlanRefs[index], 'plan', protectedStateScope(plan.context));
|
|
249
|
+
try {
|
|
250
|
+
stateAssert(stateDigest(bytes) === plan.review.savedPlanDigests[index], 'artifact-integrity');
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
bytes.fill(0);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const source = plan.inspection.states.find((state) => state.snapshot.backendId === plan.intent.sourceBackendId);
|
|
257
|
+
const filenames = Object.fromEntries(plan.inspection.states.map((state, index) => [state.snapshot.backendId, path.join(directory, `state-${index}.tfstate`)]));
|
|
258
|
+
const sourcePath = filenames[plan.intent.sourceBackendId];
|
|
259
|
+
await this.copyState(source, sourcePath, plan.context);
|
|
260
|
+
const nativeRoot = path.join(directory, 'native');
|
|
261
|
+
await this.minimalRoot(nativeRoot, sourcePath, signal);
|
|
262
|
+
if (plan.intent.recipe === 'backend-relocation') {
|
|
263
|
+
const destinationPath = filenames[plan.intent.destinationBackendIds[0]];
|
|
264
|
+
await this.backendConfiguration(nativeRoot, destinationPath);
|
|
265
|
+
await this.runQuiet(nativeRoot, [
|
|
266
|
+
'init', '-migrate-state', '-input=true', '-no-color', '-get=false', '-lock-timeout=10s'
|
|
267
|
+
], 'transform', signal, Buffer.from('yes\n'));
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
for (const mapping of plan.intent.mappings) {
|
|
271
|
+
if (mapping.disposition === 'preserve'
|
|
272
|
+
|| (mapping.destinationBackendId === plan.intent.sourceBackendId && mapping.sourceAddress === mapping.destinationAddress))
|
|
273
|
+
continue;
|
|
274
|
+
await this.runQuiet(nativeRoot, [
|
|
275
|
+
'state', 'mv', '-lock=true', '-lock-timeout=10s', `-state=${sourcePath}`,
|
|
276
|
+
...(mapping.destinationBackendId === plan.intent.sourceBackendId ? [] : [`-state-out=${filenames[mapping.destinationBackendId]}`]),
|
|
277
|
+
mapping.sourceAddress, mapping.destinationAddress
|
|
278
|
+
], 'transform', signal);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const preliminary = {};
|
|
282
|
+
for (const state of plan.inspection.states) {
|
|
283
|
+
const id = state.snapshot.backendId;
|
|
284
|
+
if (plan.intent.recipe === 'backend-relocation' && id === plan.intent.sourceBackendId)
|
|
285
|
+
continue;
|
|
286
|
+
preliminary[id] = await this.privateState(id, filenames[id], state, plan.context, 'candidate');
|
|
287
|
+
}
|
|
288
|
+
verifyStateAccounting(plan.intent, source, preliminary, true);
|
|
289
|
+
const candidates = {};
|
|
290
|
+
const proofs = [];
|
|
291
|
+
let index = 0;
|
|
292
|
+
for (const [id, candidate] of Object.entries(preliminary)) {
|
|
293
|
+
if (candidate.instances.length === 0)
|
|
294
|
+
continue;
|
|
295
|
+
const reference = plan.intent.targetConfigurationRefs[id];
|
|
296
|
+
stateAssert(reference, 'mapping-incomplete');
|
|
297
|
+
await this.rootPlan({
|
|
298
|
+
reference, directory: path.join(directory, `target-prepare-${index}`), statePath: filenames[id],
|
|
299
|
+
context: plan.context, instances: candidate.instances, strict: false, operation: 'transform',
|
|
300
|
+
applyPrivateStateOnly: true, signal, expectedConfigurationDigest: plan.review.configurationDigests[reference]
|
|
301
|
+
});
|
|
302
|
+
const prepared = await this.privateState(id, filenames[id], candidate, plan.context, 'candidate');
|
|
303
|
+
const verified = await this.rootPlan({
|
|
304
|
+
reference, directory: path.join(directory, `target-verify-${index++}`), statePath: filenames[id],
|
|
305
|
+
context: plan.context, instances: prepared.instances, strict: true, operation: 'inspect', signal,
|
|
306
|
+
expectedConfigurationDigest: plan.review.configurationDigests[reference]
|
|
307
|
+
});
|
|
308
|
+
candidates[id] = prepared;
|
|
309
|
+
proofs.push(verified.proofDigest);
|
|
310
|
+
}
|
|
311
|
+
verifyStateAccounting(plan.intent, source, candidates, false);
|
|
312
|
+
return { candidates, verificationDigest: stateObjectDigest(proofs) };
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async verify(plan, current, signal) {
|
|
316
|
+
await this.qualify({ context: plan.context, inspection: plan.inspection, intent: plan.intent, signal });
|
|
317
|
+
const source = plan.inspection.states.find((state) => state.snapshot.backendId === plan.intent.sourceBackendId);
|
|
318
|
+
verifyStateAccounting(plan.intent, source, current, false);
|
|
319
|
+
return this.verifyRoots(plan, current, signal);
|
|
320
|
+
}
|
|
321
|
+
async verifyDestinations(plan, current, signal) {
|
|
322
|
+
await this.qualify({ context: plan.context, inspection: plan.inspection, intent: plan.intent, signal });
|
|
323
|
+
const ids = new Set(plan.intent.destinationBackendIds);
|
|
324
|
+
stateAssert(Object.keys(current).length === ids.size && Object.keys(current).every((id) => ids.has(id)), 'mapping-incomplete');
|
|
325
|
+
const source = plan.inspection.states.find((state) => state.snapshot.backendId === plan.intent.sourceBackendId);
|
|
326
|
+
const mappings = plan.intent.mappings.filter((mapping) => ids.has(mapping.destinationBackendId));
|
|
327
|
+
verifyStateAccounting({ ...plan.intent, mappings }, source, current, false);
|
|
328
|
+
return this.verifyRoots(plan, current, signal);
|
|
329
|
+
}
|
|
330
|
+
async verifyRoots(plan, current, signal) {
|
|
331
|
+
return this.withScratch(plan.context, async (directory) => {
|
|
332
|
+
const proofs = [];
|
|
333
|
+
let index = 0;
|
|
334
|
+
for (const [id, state] of Object.entries(current)) {
|
|
335
|
+
if (!state.snapshot.exists || state.instances.length === 0)
|
|
336
|
+
continue;
|
|
337
|
+
const filename = path.join(directory, `verify-${index}.tfstate`);
|
|
338
|
+
await this.copyState(state, filename, plan.context);
|
|
339
|
+
const proof = await this.rootPlan({
|
|
340
|
+
reference: plan.intent.targetConfigurationRefs[id], directory: path.join(directory, `verify-root-${index++}`),
|
|
341
|
+
statePath: filename, context: plan.context, instances: state.instances, strict: true, operation: 'inspect', signal,
|
|
342
|
+
expectedConfigurationDigest: plan.review.configurationDigests[plan.intent.targetConfigurationRefs[id]]
|
|
343
|
+
});
|
|
344
|
+
proofs.push(proof.proofDigest);
|
|
345
|
+
}
|
|
346
|
+
return stateObjectDigest(proofs);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=opentofu.js.map
|