gate-evm-tools 1.0.31 → 1.2.1
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/README.md +34 -20
- package/bin/cli.js +3 -0
- package/bin/delivery.cjs +8 -7
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +26 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/plan/index.d.ts.map +1 -1
- package/dist/commands/plan/index.js +1 -1
- package/dist/commands/plan/index.js.map +1 -1
- package/dist/core/preparation/batch.d.ts +26 -0
- package/dist/core/preparation/batch.d.ts.map +1 -0
- package/dist/core/preparation/batch.js +72 -0
- package/dist/core/preparation/batch.js.map +1 -0
- package/dist/core/preparation/evm.d.ts +23 -4
- package/dist/core/preparation/evm.d.ts.map +1 -1
- package/dist/core/preparation/evm.js +19 -3
- package/dist/core/preparation/evm.js.map +1 -1
- package/dist/core/preparation/evmManifestSync.d.ts +5 -0
- package/dist/core/preparation/evmManifestSync.d.ts.map +1 -1
- package/dist/core/preparation/evmManifestSync.js +15 -7
- package/dist/core/preparation/evmManifestSync.js.map +1 -1
- package/dist/core/preparation/index.d.ts +2 -2
- package/dist/core/preparation/index.d.ts.map +1 -1
- package/dist/core/preparation/manifest.d.ts +2 -0
- package/dist/core/preparation/manifest.d.ts.map +1 -1
- package/dist/core/preparation/manifest.js +2 -2
- package/dist/core/preparation/manifest.js.map +1 -1
- package/dist/core/preparation/normalize.d.ts.map +1 -1
- package/dist/core/preparation/normalize.js +53 -11
- package/dist/core/preparation/normalize.js.map +1 -1
- package/dist/core/preparation/transparent.d.ts +23 -0
- package/dist/core/preparation/transparent.d.ts.map +1 -0
- package/dist/core/preparation/transparent.js +103 -0
- package/dist/core/preparation/transparent.js.map +1 -0
- package/dist/core/preparation/types.d.ts +47 -5
- package/dist/core/preparation/types.d.ts.map +1 -1
- package/dist/core/preparation/zksync.d.ts.map +1 -1
- package/dist/core/preparation/zksync.js +2 -0
- package/dist/core/preparation/zksync.js.map +1 -1
- package/dist/custody/credential.d.ts.map +1 -1
- package/dist/custody/credential.js +1 -6
- package/dist/custody/credential.js.map +1 -1
- package/dist/deployment-evm/index.d.ts +4 -0
- package/dist/deployment-evm/index.d.ts.map +1 -0
- package/dist/deployment-evm/index.js +3 -0
- package/dist/deployment-evm/index.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +5 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow/index.d.ts +4 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist-cjs/core/preparation/batch.js +76 -0
- package/dist-cjs/core/preparation/batch.js.map +1 -0
- package/dist-cjs/core/preparation/evm.js +25 -7
- package/dist-cjs/core/preparation/evm.js.map +1 -1
- package/dist-cjs/core/preparation/evmManifestSync.js +15 -7
- package/dist-cjs/core/preparation/evmManifestSync.js.map +1 -1
- package/dist-cjs/core/preparation/manifest.js +2 -2
- package/dist-cjs/core/preparation/manifest.js.map +1 -1
- package/dist-cjs/core/preparation/normalize.js +53 -11
- package/dist-cjs/core/preparation/normalize.js.map +1 -1
- package/dist-cjs/core/preparation/transparent.js +110 -0
- package/dist-cjs/core/preparation/transparent.js.map +1 -0
- package/dist-cjs/core/preparation/zksync.js +2 -0
- package/dist-cjs/core/preparation/zksync.js.map +1 -1
- package/dist-cjs/custody/credential.js +1 -6
- package/dist-cjs/custody/credential.js.map +1 -1
- package/dist-cjs/deployment-evm/index.js +10 -0
- package/dist-cjs/deployment-evm/index.js.map +1 -0
- package/dist-cjs/sync/index.js +5 -0
- package/dist-cjs/sync/index.js.map +1 -1
- package/dist-cjs/workflow/index.js +11 -1
- package/dist-cjs/workflow/index.js.map +1 -1
- package/dist-runtime/config/hardhatAdapters.js +2 -1
- package/dist-runtime/config/hardhatAdapters.js.map +1 -1
- package/dist-runtime/delivery/aggregate-bootstrap.js +3 -1
- package/dist-runtime/delivery/aggregate-bootstrap.js.map +1 -1
- package/dist-runtime/delivery/aggregate-channel.js +7 -3
- package/dist-runtime/delivery/aggregate-channel.js.map +1 -1
- package/dist-runtime/delivery/aggregate-diagnostics.d.ts +14 -0
- package/dist-runtime/delivery/aggregate-diagnostics.js +73 -0
- package/dist-runtime/delivery/aggregate-diagnostics.js.map +1 -0
- package/dist-runtime/delivery/aggregate-inputs.d.ts +13 -9
- package/dist-runtime/delivery/aggregate-source.js +11 -3
- package/dist-runtime/delivery/aggregate-source.js.map +1 -1
- package/dist-runtime/delivery/aggregate-worker.js +12 -4
- package/dist-runtime/delivery/aggregate-worker.js.map +1 -1
- package/dist-runtime/delivery/aggregate.js +2 -2
- package/dist-runtime/delivery/aggregate.js.map +1 -1
- package/dist-runtime/delivery/business-extension.d.ts +10 -0
- package/dist-runtime/delivery/business-extension.js +38 -0
- package/dist-runtime/delivery/business-extension.js.map +1 -0
- package/dist-runtime/delivery/calldata-archive.d.ts +18 -0
- package/dist-runtime/delivery/calldata-archive.js +31 -0
- package/dist-runtime/delivery/calldata-archive.js.map +1 -0
- package/dist-runtime/delivery/calldata-details.d.ts +47 -0
- package/dist-runtime/delivery/calldata-details.js +94 -0
- package/dist-runtime/delivery/calldata-details.js.map +1 -0
- package/dist-runtime/delivery/calldata-format.d.ts +4 -0
- package/dist-runtime/delivery/calldata-format.js +17 -0
- package/dist-runtime/delivery/calldata-format.js.map +1 -0
- package/dist-runtime/delivery/calldata-preparations.d.ts +13 -0
- package/dist-runtime/delivery/calldata-preparations.js +85 -0
- package/dist-runtime/delivery/calldata-preparations.js.map +1 -0
- package/dist-runtime/delivery/calldata-review.d.ts +44 -0
- package/dist-runtime/delivery/calldata-review.js +131 -0
- package/dist-runtime/delivery/calldata-review.js.map +1 -0
- package/dist-runtime/delivery/codec-pin.d.ts +2 -2
- package/dist-runtime/delivery/codec-pin.js +4 -4
- package/dist-runtime/delivery/codec-pin.js.map +1 -1
- package/dist-runtime/delivery/compiler-files.js +3 -1
- package/dist-runtime/delivery/compiler-files.js.map +1 -1
- package/dist-runtime/delivery/compiler-pins.js +1 -1
- package/dist-runtime/delivery/compiler.js +17 -16
- package/dist-runtime/delivery/compiler.js.map +1 -1
- package/dist-runtime/delivery/config.d.ts +1 -1
- package/dist-runtime/delivery/config.js +27 -2
- package/dist-runtime/delivery/config.js.map +1 -1
- package/dist-runtime/delivery/configuration-definition.d.ts +9 -0
- package/dist-runtime/delivery/configuration-definition.js +33 -6
- package/dist-runtime/delivery/configuration-definition.js.map +1 -1
- package/dist-runtime/delivery/configuration.js +7 -4
- package/dist-runtime/delivery/configuration.js.map +1 -1
- package/dist-runtime/delivery/contract-source.d.ts +14 -0
- package/dist-runtime/delivery/contract-source.js +138 -0
- package/dist-runtime/delivery/contract-source.js.map +1 -0
- package/dist-runtime/delivery/custom-format.js +51 -24
- package/dist-runtime/delivery/custom-format.js.map +1 -1
- package/dist-runtime/delivery/development-inputs.d.ts +14 -0
- package/dist-runtime/delivery/development-inputs.js +76 -0
- package/dist-runtime/delivery/development-inputs.js.map +1 -0
- package/dist-runtime/delivery/development.d.ts +3 -1
- package/dist-runtime/delivery/development.js +24 -10
- package/dist-runtime/delivery/development.js.map +1 -1
- package/dist-runtime/delivery/eoa.d.ts +1 -0
- package/dist-runtime/delivery/execution-identity.d.ts +15 -0
- package/dist-runtime/delivery/execution-identity.js +33 -0
- package/dist-runtime/delivery/execution-identity.js.map +1 -0
- package/dist-runtime/delivery/existing-code.js +14 -6
- package/dist-runtime/delivery/existing-code.js.map +1 -1
- package/dist-runtime/delivery/history-package.d.ts +2 -0
- package/dist-runtime/delivery/history-package.js +70 -0
- package/dist-runtime/delivery/history-package.js.map +1 -0
- package/dist-runtime/delivery/history-registration.d.ts +1 -1
- package/dist-runtime/delivery/inputs.js +22 -15
- package/dist-runtime/delivery/inputs.js.map +1 -1
- package/dist-runtime/delivery/journal.js +18 -10
- package/dist-runtime/delivery/journal.js.map +1 -1
- package/dist-runtime/delivery/parameter-defaults.d.ts +10 -0
- package/dist-runtime/delivery/parameter-defaults.js +86 -0
- package/dist-runtime/delivery/parameter-defaults.js.map +1 -0
- package/dist-runtime/delivery/parameters.d.ts +2 -0
- package/dist-runtime/delivery/parameters.js +22 -0
- package/dist-runtime/delivery/parameters.js.map +1 -1
- package/dist-runtime/delivery/planning.d.ts +4 -1
- package/dist-runtime/delivery/planning.js +19 -3
- package/dist-runtime/delivery/planning.js.map +1 -1
- package/dist-runtime/delivery/preparation.js +43 -23
- package/dist-runtime/delivery/preparation.js.map +1 -1
- package/dist-runtime/delivery/production-environment.js +2 -1
- package/dist-runtime/delivery/production-environment.js.map +1 -1
- package/dist-runtime/delivery/production-finalization.js +23 -9
- package/dist-runtime/delivery/production-finalization.js.map +1 -1
- package/dist-runtime/delivery/production-intent.d.ts +2 -0
- package/dist-runtime/delivery/production-intent.js +16 -0
- package/dist-runtime/delivery/production-intent.js.map +1 -0
- package/dist-runtime/delivery/production.d.ts +129 -8
- package/dist-runtime/delivery/production.js +60 -11
- package/dist-runtime/delivery/production.js.map +1 -1
- package/dist-runtime/delivery/project-files.d.ts +3 -3
- package/dist-runtime/delivery/project-files.js +19 -14
- package/dist-runtime/delivery/project-files.js.map +1 -1
- package/dist-runtime/delivery/project-rpc.d.ts +19 -0
- package/dist-runtime/delivery/project-rpc.js +138 -0
- package/dist-runtime/delivery/project-rpc.js.map +1 -0
- package/dist-runtime/delivery/project.d.ts +3 -1
- package/dist-runtime/delivery/project.js +21 -8
- package/dist-runtime/delivery/project.js.map +1 -1
- package/dist-runtime/delivery/public-calldata.d.ts +25 -0
- package/dist-runtime/delivery/public-calldata.js +97 -0
- package/dist-runtime/delivery/public-calldata.js.map +1 -0
- package/dist-runtime/delivery/release-graph.d.ts +7 -3
- package/dist-runtime/delivery/release-graph.js +58 -25
- package/dist-runtime/delivery/release-graph.js.map +1 -1
- package/dist-runtime/delivery/release-history-capture.js +22 -26
- package/dist-runtime/delivery/release-history-capture.js.map +1 -1
- package/dist-runtime/delivery/release-history.d.ts +3 -2
- package/dist-runtime/delivery/release-history.js +97 -50
- package/dist-runtime/delivery/release-history.js.map +1 -1
- package/dist-runtime/delivery/release-inputs.d.ts +33 -0
- package/dist-runtime/delivery/release-inputs.js +129 -0
- package/dist-runtime/delivery/release-inputs.js.map +1 -0
- package/dist-runtime/delivery/release.d.ts +38 -14
- package/dist-runtime/delivery/release.js +81 -29
- package/dist-runtime/delivery/release.js.map +1 -1
- package/dist-runtime/delivery/safe.d.ts +1 -0
- package/dist-runtime/delivery/safe.js +13 -2
- package/dist-runtime/delivery/safe.js.map +1 -1
- package/dist-runtime/delivery/same-fork-baseline.d.ts +1 -1
- package/dist-runtime/delivery/same-fork-baseline.js +5 -4
- package/dist-runtime/delivery/same-fork-baseline.js.map +1 -1
- package/dist-runtime/delivery/setup.d.ts +1 -1
- package/dist-runtime/delivery/setup.js +21 -6
- package/dist-runtime/delivery/setup.js.map +1 -1
- package/dist-runtime/delivery/source.d.ts +1 -0
- package/dist-runtime/delivery/source.js +12 -10
- package/dist-runtime/delivery/source.js.map +1 -1
- package/dist-runtime/delivery/task-identity.d.ts +23 -0
- package/dist-runtime/delivery/task-identity.js +109 -0
- package/dist-runtime/delivery/task-identity.js.map +1 -0
- package/dist-runtime/delivery/toolchain.d.ts +3 -0
- package/dist-runtime/delivery/toolchain.js +52 -0
- package/dist-runtime/delivery/toolchain.js.map +1 -0
- package/dist-runtime/delivery/validation.js +7 -2
- package/dist-runtime/delivery/validation.js.map +1 -1
- package/dist-runtime/runtime-identity.json +2 -2
- package/dist-runtime/vendor/plan-codec/index.cjs +97 -20
- package/dist-runtime/vendor/plan-codec/index.d.cts +6 -0
- package/dist-runtime/vendor/plan-codec/provenance.json +9 -8
- package/dist-runtime/workflow/lib/calls.js +1 -0
- package/dist-runtime/workflow/lib/calls.js.map +1 -1
- package/dist-runtime/workflow/lib/checkCodeRunner.js +7 -4
- package/dist-runtime/workflow/lib/checkCodeRunner.js.map +1 -1
- package/dist-runtime/workflow/lib/context.d.ts +1 -0
- package/dist-runtime/workflow/lib/create2.d.ts +4 -26
- package/dist-runtime/workflow/lib/create2.js +2 -67
- package/dist-runtime/workflow/lib/create2.js.map +1 -1
- package/dist-runtime/workflow/lib/deploymentInfo.d.ts +2 -0
- package/dist-runtime/workflow/lib/deploymentInfo.js +6 -0
- package/dist-runtime/workflow/lib/deploymentInfo.js.map +1 -1
- package/dist-runtime/workflow/lib/deploymentRecords.d.ts +2 -0
- package/dist-runtime/workflow/lib/deploymentRecords.js +1 -1
- package/dist-runtime/workflow/lib/deploymentRecords.js.map +1 -1
- package/dist-runtime/workflow/lib/externalExecutionScanner.js +2 -1
- package/dist-runtime/workflow/lib/externalExecutionScanner.js.map +1 -1
- package/dist-runtime/workflow/lib/gateTool.js +2 -2
- package/dist-runtime/workflow/lib/gateTool.js.map +1 -1
- package/dist-runtime/workflow/lib/gateToolSync.d.ts +3 -0
- package/dist-runtime/workflow/lib/gateToolSync.js +5 -0
- package/dist-runtime/workflow/lib/gateToolSync.js.map +1 -1
- package/dist-runtime/workflow/lib/parameters.js +5 -0
- package/dist-runtime/workflow/lib/parameters.js.map +1 -1
- package/dist-runtime/workflow/lib/proxy.d.ts +1 -0
- package/dist-runtime/workflow/lib/proxy.js.map +1 -1
- package/dist-runtime/workflow/run.js +1 -3
- package/dist-runtime/workflow/run.js.map +1 -1
- package/dist-runtime/workflow/steps/deploy.js +53 -0
- package/dist-runtime/workflow/steps/deploy.js.map +1 -1
- package/dist-runtime/workflow/steps/upgrade.js +24 -10
- package/dist-runtime/workflow/steps/upgrade.js.map +1 -1
- package/docs/compiler-qualification.md +8 -2
- package/docs/delivery-aggregate.md +2 -0
- package/docs/delivery-calldata.md +27 -0
- package/docs/delivery-development.md +6 -0
- package/docs/delivery-execution-store.md +1 -1
- package/docs/delivery-inputs.md +55 -6
- package/docs/delivery-parameters.md +1 -1
- package/docs/delivery-release.md +77 -7
- package/docs/delivery-safe.md +7 -4
- package/docs/delivery-setup.md +72 -20
- package/docs/delivery-source.md +8 -8
- package/docs/direct-package-acceptance.md +2 -0
- package/docs/openzeppelin-acceptance.md +86 -0
- package/docs/openzeppelin-baseline.json +27 -0
- package/docs/openzeppelin-integration.md +115 -0
- package/docs/plans/2026-10-28-openzeppelin-toolkit-consolidation.md +396 -0
- package/docs/plans/2026-11-02-transparent-proxy-delivery.md +78 -0
- package/docs/superpowers/plans/2026-08-17-custody-hardhat-signers.md +1 -1
- package/docs/workflow-reference.md +12 -4
- package/docs/workflow-runtime.md +6 -0
- package/package.json +19 -5
- package/runtime/config/hardhatAdapters.ts +2 -1
- package/runtime/delivery/aggregate-bootstrap.ts +3 -1
- package/runtime/delivery/aggregate-channel.ts +6 -3
- package/runtime/delivery/aggregate-diagnostics.ts +63 -0
- package/runtime/delivery/aggregate-source.ts +6 -2
- package/runtime/delivery/aggregate-worker.ts +15 -5
- package/runtime/delivery/aggregate.ts +2 -2
- package/runtime/delivery/business-extension.ts +33 -0
- package/runtime/delivery/calldata-archive.ts +25 -0
- package/runtime/delivery/calldata-details.ts +90 -0
- package/runtime/delivery/calldata-format.ts +14 -0
- package/runtime/delivery/calldata-preparations.ts +76 -0
- package/runtime/delivery/calldata-review.ts +126 -0
- package/runtime/delivery/codec-pin.ts +3 -3
- package/runtime/delivery/compiler-files.ts +3 -1
- package/runtime/delivery/compiler-pins.ts +1 -1
- package/runtime/delivery/compiler.ts +18 -17
- package/runtime/delivery/config.ts +25 -2
- package/runtime/delivery/configuration-definition.ts +34 -7
- package/runtime/delivery/configuration.ts +8 -5
- package/runtime/delivery/contract-source.ts +112 -0
- package/runtime/delivery/custom-format.ts +20 -5
- package/runtime/delivery/development-inputs.ts +42 -0
- package/runtime/delivery/development.ts +14 -11
- package/runtime/delivery/execution-identity.ts +32 -0
- package/runtime/delivery/existing-code.ts +7 -6
- package/runtime/delivery/history-package.ts +50 -0
- package/runtime/delivery/inputs.ts +18 -11
- package/runtime/delivery/journal.ts +14 -10
- package/runtime/delivery/parameter-defaults.ts +75 -0
- package/runtime/delivery/parameters.ts +18 -0
- package/runtime/delivery/planning.ts +19 -5
- package/runtime/delivery/preparation.ts +17 -1
- package/runtime/delivery/production-environment.ts +2 -1
- package/runtime/delivery/production-finalization.ts +19 -10
- package/runtime/delivery/production-intent.ts +14 -0
- package/runtime/delivery/production.ts +51 -11
- package/runtime/delivery/project-files.ts +16 -11
- package/runtime/delivery/project-rpc.ts +116 -0
- package/runtime/delivery/project.ts +19 -7
- package/runtime/delivery/public-calldata.ts +74 -0
- package/runtime/delivery/release-graph.ts +44 -14
- package/runtime/delivery/release-history-capture.ts +19 -9
- package/runtime/delivery/release-history.ts +76 -22
- package/runtime/delivery/release-inputs.ts +107 -0
- package/runtime/delivery/release.ts +56 -18
- package/runtime/delivery/safe.ts +14 -3
- package/runtime/delivery/same-fork-baseline.ts +5 -4
- package/runtime/delivery/setup.ts +20 -8
- package/runtime/delivery/source.ts +10 -10
- package/runtime/delivery/task-identity.ts +85 -0
- package/runtime/delivery/toolchain.ts +48 -0
- package/runtime/delivery/validation.ts +7 -2
- package/runtime/vendor/plan-codec/index.cjs +97 -20
- package/runtime/vendor/plan-codec/index.d.cts +6 -0
- package/runtime/vendor/plan-codec/provenance.json +9 -8
- package/runtime/workflow/lib/calls.ts +1 -0
- package/runtime/workflow/lib/checkCodeRunner.ts +7 -3
- package/runtime/workflow/lib/context.ts +1 -0
- package/runtime/workflow/lib/create2.ts +7 -108
- package/runtime/workflow/lib/deploymentInfo.ts +8 -0
- package/runtime/workflow/lib/deploymentRecords.ts +3 -1
- package/runtime/workflow/lib/externalExecutionScanner.ts +2 -1
- package/runtime/workflow/lib/gateTool.ts +2 -2
- package/runtime/workflow/lib/gateToolSync.ts +8 -0
- package/runtime/workflow/lib/parameters.ts +4 -0
- package/runtime/workflow/lib/proxy.ts +1 -0
- package/runtime/workflow/run.ts +1 -2
- package/runtime/workflow/steps/deploy.ts +42 -0
- package/runtime/workflow/steps/upgrade.ts +19 -11
- package/bin/workflow.cjs +0 -19
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {deploymentPurpose} from './source';
|
|
2
|
+
import {parseCalldataReviews} from './calldata-review';
|
|
1
3
|
/** Developer-owned production qualification and two-phase, marker-last release publication. */
|
|
2
4
|
import fs from 'node:fs';
|
|
3
5
|
import path from 'node:path';
|
|
@@ -11,13 +13,16 @@ import {parsePreparationJournal} from './journal';
|
|
|
11
13
|
import {expectedDevelopmentAssertions} from './development';
|
|
12
14
|
import {verifyCapturedForkAudit} from './forkAudit';
|
|
13
15
|
import {parseCanonicalPlan,projectCanonicalDefinitions} from './source';
|
|
14
|
-
import {readReleaseUniverse,currentReleasePrerequisites,readReleaseGraph,sameReleaseData as same,type ReleaseGraphOptions} from './release-graph';
|
|
16
|
+
import {readReleaseUniverse,currentReleasePrerequisites,readReleaseGraph,isDevelopmentAcceptancePrerequisite,sameReleaseData as same,type ReleaseGraphOptions} from './release-graph';
|
|
15
17
|
import {aggregateInputHash,validateHistoricalDevelopmentFiles,verifyHistoricalDevelopmentChain,type HistoricalDevelopmentFiles} from './release-history';
|
|
16
18
|
import {atomicDevelopmentWrite,fileBytes,withDevelopmentFileLock,byteHash} from './materialization';
|
|
17
19
|
import {canonicalJson,deepFreeze,semanticHash,exactObject} from '../workflow/lib/canonicalData';
|
|
18
20
|
import {strictData} from './data';
|
|
19
21
|
import {historicalRegistrationFile} from './history-registration';
|
|
20
|
-
|
|
22
|
+
import {captureCommittedContractSource} from './contract-source';
|
|
23
|
+
import {captureReleaseInputs,readReleaseInputSnapshot,restoreReleaseInputs} from './release-inputs';
|
|
24
|
+
export type {ContractSourceIdentity} from './contract-source';
|
|
25
|
+
export {readReleaseGraph,isDevelopmentAcceptancePrerequisite} from './release-graph';
|
|
21
26
|
export {captureDevelopmentReleaseHistory} from './release-history-capture';
|
|
22
27
|
export type {HistoricalDevelopmentFiles} from './release-history';
|
|
23
28
|
type Scope=Omit<ReleaseGraphOptions,'releaseRef'>;
|
|
@@ -32,10 +37,11 @@ function taskEvidence(input:Scope&{planKey:string}){
|
|
|
32
37
|
if(!row||plan.lanes[row.lane].state!=='enabled'||row.task.status!=='completed'||row.task.result?.kind!=='success'||row.task.adoptedRev!==row.task.rev)throw Error('Prerequisite current task is incomplete or stale');
|
|
33
38
|
const result=row.task.result,codeRef=result.codeRef??(row.task.scope?.deployment as any)?.sourceCodeRef;
|
|
34
39
|
if(typeof codeRef!=='string'||!codeRef.trim()||!Array.isArray(result.evidence)||!result.evidence.length)throw Error('Prerequisite requires codeRef and actual report evidence');
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
const refs=result.evidence.map((entry:any)=>{if(!entry||typeof entry.ref!=='string')throw Error('Prerequisite report ref missing');return entry.ref as string;});
|
|
41
|
+
if(new Set(refs).size!==refs.length)throw Error('Duplicate prerequisite artifact');
|
|
42
|
+
for(const expected of row.task.expectedArtifacts??[])if(!refs.includes(expected))refs.push(expected);
|
|
43
|
+
const artifacts=refs.map(ref=>{portablePath(ref,'prerequisite artifact');const bytes=readInputBytes(root,ref);if(!bytes.length)throw Error('Empty prerequisite report/artifact');return {path:ref,sha256:inputDigest(bytes)};});
|
|
44
|
+
if(row.lane==='audit'&&!result.evidence.some((entry:any)=>entry.ref==='audit-reports/security-audit-report.md'))throw Error('Audit prerequisite requires actual security audit report');
|
|
39
45
|
return {root,envelope:{schema:'gate-delivery-prerequisite',version:1,producer:'gate-evm-tools/delivery-release',taskId:plan.taskId,planKey:row.task.planKey,rev:row.task.rev,definitionHash:semanticHash(projectCanonicalDefinitions(text,{roots:[row.task.planKey],mode:'full'}).snapshot),codeRef,artifacts}};
|
|
40
46
|
}
|
|
41
47
|
/** Invoke after the corresponding skill has produced its report and completed the current task.
|
|
@@ -44,15 +50,17 @@ export function recordDeliveryPrerequisite(input:Scope&{planKey:string}){const {
|
|
|
44
50
|
export function validateDeliveryPrerequisite(input:Scope&{planKey:string}){const {root,envelope}=taskEvidence(input),actual=JSON.parse(readInputBytes(root,prerequisitePath(input.taskId,input.planKey)).toString());same(actual,envelope,'Current prerequisite report/artifact binding');return deepFreeze(actual);}
|
|
45
51
|
function prerequisites(scope:Scope,history:ReturnType<typeof validateHistoricalDevelopmentFiles>){
|
|
46
52
|
const current=currentReleasePrerequisites(scope),receipts=[];
|
|
47
|
-
for(const {task} of current.required){if(
|
|
53
|
+
for(const {task} of current.required){if(isDevelopmentAcceptancePrerequisite(task)){const d=task.scope?.deployment as any;if(d?.environment!=='dev'||d.targetNetwork!==history.plan.target||d.deploymentId!==history.plan.deploymentId)throw Error('Development prerequisite scope mismatch');if(!verificationOnly(task)&&(task.planKey!==history.source.targets[0].request.sourceRef.planKey||task.rev!==history.source.targets[0].request.sourceRef.rev))throw Error('Stale development prerequisite revision');const evidence=task.result?.evidence;if(!Array.isArray(evidence)||!evidence.some((e:any)=>e.ref===scopePath(history,verificationOnly(task))))throw Error('Development prerequisite must reference actual acceptance/CheckCode');receipts.push({planKey:task.planKey,rev:task.rev,definitionHash:semanticHash(projectCanonicalDefinitions(current.text,{roots:[task.planKey],mode:'full'}).snapshot),evidenceHash:semanticHash(verificationOnly(task)?history.acceptance.checkCode:history.acceptance)});}
|
|
48
54
|
else receipts.push(validateDeliveryPrerequisite({...scope,planKey:task.planKey}));}
|
|
49
55
|
return receipts;
|
|
50
56
|
}
|
|
51
|
-
function
|
|
57
|
+
function verificationOnly(task:any){const actions=task.scope?.deployment?.allowedActions;return Array.isArray(actions)&&actions.length===1&&actions[0]==='verify';}
|
|
58
|
+
function scopePath(history:ReturnType<typeof validateHistoricalDevelopmentFiles>,verifyOnly:boolean){return verifyOnly?history.acceptance.checkCode.rawFile:`.gate-delivery/development/${history.plan.executionId}.acceptance.json`;}
|
|
52
59
|
function verifyQualification(aggregate:DeliveryAggregate,source:DeliveryAggregateOptions){
|
|
53
60
|
if(aggregate.version!==1||aggregateInputHash(aggregate)!==aggregate.inputsHash||semanticHash(aggregate.inputs.sourceDefinitions)!==aggregate.sourceDefinitionHash)throw Error('Qualification aggregate identity mismatch');
|
|
54
61
|
same(aggregate.collections.map(c=>c.plan.target),aggregate.inputs.business.targets.map(t=>t.id),'Complete target qualification');same(source.targets.map(t=>t.request.network),aggregate.inputs.business.targets.map(t=>t.id),'Current selected target order');
|
|
55
62
|
for(const [i,c] of aggregate.collections.entries()){const plan=parseDeliveryPlan(c.plan),request=source.targets[i].request;
|
|
63
|
+
parseCalldataReviews(c.calldata,plan.transactions);
|
|
56
64
|
if(plan.environment!=='prod'||plan.inputsHash!==aggregate.inputsHash||plan.sourceDefinitionHash!==aggregate.sourceDefinitionHash||plan.executionId!==source.targets[i].executionId||plan.operator!==request.operator?.toLowerCase()||!request.fork||!plan.transactions.length)throw Error('Invalid production qualification identity');
|
|
57
65
|
same(plan.runtimeIdentity,aggregate.inputs.runtime.declared,'Qualification runtime');expectedDevelopmentAssertions(c,aggregate.inputs.business.steps);
|
|
58
66
|
parsePreparationJournal(c.preparations,plan.transactions,plan.derivedBindings,{target:plan.target,chainId:plan.chainId,expectedStepIds:plan.deploymentBindings.map(b=>b.stepId)});
|
|
@@ -60,17 +68,22 @@ function verifyQualification(aggregate:DeliveryAggregate,source:DeliveryAggregat
|
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
function currentFiles(root:string,files:readonly {path:string;digest:string}[]){for(const file of files)if(inputDigest(readInputBytes(root,file.path))!==file.digest)throw Error(`Current release input changed: ${file.path}`);}
|
|
63
|
-
function currentCandidate(scope:Scope,c:any){
|
|
71
|
+
function currentCandidate(scope:Scope,c:any,requireCommittedSources=false){
|
|
64
72
|
if(c.schema!=='gate-delivery-release-candidate'||c.version!==1||c.generation!=='complete'||c.producer!=='gate-evm-tools/delivery-release')throw Error('Invalid completed release candidate');
|
|
65
73
|
same(c.scope,{projectRoot:scope.projectRoot,handoff:scope.handoff,taskId:scope.taskId,deploymentId:scope.deploymentId},'Release current scope');
|
|
66
74
|
const {candidateHash,...body}=c;same(semanticHash(body),candidateHash,'Release candidate hash');
|
|
75
|
+
if(c.inputSnapshot?.path!==`scripts/tasks/${scope.deploymentId}/releases/${c.releaseRef.releaseId}/inputs.snapshot.json`)throw Error('Noncanonical release input snapshot reference');
|
|
67
76
|
const root=projectRoot(scope.workspaceRoot,scope.projectRoot),source={workspaceRoot:scope.workspaceRoot,projectRoot:scope.projectRoot,selection:'release' as const,targets:c.targets};
|
|
77
|
+
if(requireCommittedSources)same(captureCommittedContractSource(root,c.aggregate),c.contractSource,'Current committed contract source');
|
|
78
|
+
const snapshot=readReleaseInputSnapshot(root,c.inputSnapshot);same(snapshot.contractSource,c.contractSource,'Release snapshot contract source');
|
|
79
|
+
const snapshotFiles=new Map(snapshot.files.map(file=>[file.path,file.digest]));
|
|
80
|
+
for(const file of c.aggregate.inputs.files)if(!file.path.split('/').includes('node_modules')&&snapshotFiles.get(file.path)!==file.digest)throw Error('Release snapshot does not cover qualified input');
|
|
81
|
+
for(const file of snapshot.files)if(inputDigest(readInputBytes(root,file.path))!==file.digest)throw Error(`Current release snapshot input changed: ${file.path}`);
|
|
68
82
|
verifyQualification(c.aggregate,source);currentFiles(root,c.aggregate.inputs.files);currentFiles(root,c.historical.files.filter((f:any)=>!historicalRegistrationFile(f.path)));
|
|
69
83
|
same(openAggregateSources({workspaceRoot:scope.workspaceRoot,projectRoot:scope.projectRoot,requests:c.targets.map((t:any)=>t.request)}).definitions,c.aggregate.inputs.sourceDefinitions,'Current full upstream source');
|
|
70
84
|
const h=validateHistoricalDevelopmentFiles({root,workspaceRoot:scope.workspaceRoot,projectRoot:scope.projectRoot,history:c.development});same(h.association,c.historical.association,'Historical development association');same(prerequisites(scope,h),c.prerequisites,'Current prerequisite evidence');
|
|
71
85
|
same(h.files.filter(f=>historicalRegistrationFile(f.path)),c.historical.files.filter((f:any)=>historicalRegistrationFile(f.path)),'Original historical registry baseline');
|
|
72
86
|
same(readReleaseUniverse(scope).targets,c.aggregate.inputs.business.targets.map((t:any)=>t.id),'Current full selected target set');
|
|
73
|
-
const docs=readInputBytes(root,'docs/prod-execution-plan.md');same(inputDigest(docs),c.explanationHash,'Production execution explanation');
|
|
74
87
|
return {root,source,history:h};
|
|
75
88
|
}
|
|
76
89
|
/** Qualification is generated by the actual owned aggregate, never accepted from caller JSON. */
|
|
@@ -81,17 +94,25 @@ export async function prepareDeliveryRelease(raw:ReleasePreparationOptions){
|
|
|
81
94
|
if(fileBytes(root,`scripts/tasks/${deploymentId}/releases/${input.releaseId}/release.json`)!==null)throw Error('Release already has a ready marker');
|
|
82
95
|
same(input.targets.map(t=>({network:t.request.network,sourceRef:t.request.sourceRef,purpose:t.request.purpose,environment:t.request.environment,mode:t.request.mode})),u.qualifications.map(t=>({network:(t.scope!.deployment as any).targetNetwork,sourceRef:{path:handoff,taskId,planKey:t.planKey,rev:t.rev},purpose:'prod-qualification',environment:'prod',mode:'simulate'})),'Exact current qualification tasks');
|
|
83
96
|
const history=validateHistoricalDevelopmentFiles({root,workspaceRoot,projectRoot:relative,history:input.development}),prerequisiteEvidence=prerequisites(scope,history);
|
|
97
|
+
const committedBefore=captureCommittedContractSource(root,history.aggregate);
|
|
84
98
|
await verifyHistoricalDevelopmentChain(history,root);
|
|
85
|
-
const explanation=readInputBytes(root,'docs/prod-execution-plan.md').toString();for(const ref of ['manifest.yaml','parameters.yaml','recovery'])if(!explanation.includes(ref))throw Error('Production explanation must reference canonical inputs and recovery instructions');
|
|
86
99
|
const source:DeliveryAggregateOptions={workspaceRoot,projectRoot:relative,selection:'release',targets:input.targets};
|
|
87
100
|
const aggregate=await collectDeliveryAggregate(source);verifyQualification(aggregate,source);
|
|
101
|
+
const contractSource=captureCommittedContractSource(root,aggregate),snapshot=captureReleaseInputs(root,aggregate,contractSource);
|
|
102
|
+
same(contractSource,committedBefore,'Contract source during release qualification');
|
|
103
|
+
const inputSnapshot={path:`scripts/tasks/${deploymentId}/releases/${input.releaseId}/inputs.snapshot.json`,hash:snapshot.snapshotHash,sha256:byteHash(encode(snapshot))};
|
|
88
104
|
const releaseRef={path:`scripts/tasks/${deploymentId}/releases/${input.releaseId}/release.json`,releaseId:input.releaseId,inputsHash:aggregate.inputsHash};
|
|
89
|
-
const body={schema:'gate-delivery-release-candidate',version:1,generation:'complete',producer:'gate-evm-tools/delivery-release',releaseRef,scope:{projectRoot:relative,handoff,taskId,deploymentId},targets:input.targets,development:input.development,aggregate,historical:{files:history.files,association:history.association,acceptanceHash:semanticHash(history.acceptance)},prerequisites:prerequisiteEvidence
|
|
90
|
-
const candidate=deepFreeze({...body,candidateHash:semanticHash(body)});
|
|
91
|
-
await withDevelopmentFileLock(root,async()=>{
|
|
105
|
+
const body={schema:'gate-delivery-release-candidate',version:1,generation:'complete',producer:'gate-evm-tools/delivery-release',releaseRef,scope:{projectRoot:relative,handoff,taskId,deploymentId},targets:input.targets,development:input.development,aggregate,contractSource,inputSnapshot,historical:{files:history.files,association:history.association,acceptanceHash:semanticHash(history.acceptance)},prerequisites:prerequisiteEvidence};
|
|
106
|
+
const candidate=deepFreeze({...body,candidateHash:semanticHash(body)});
|
|
107
|
+
await withDevelopmentFileLock(root,async()=>{
|
|
108
|
+
const previous=fileBytes(root,candidatePath(input.releaseId));if(previous!==null&&previous!==encode(candidate))throw Error('Release ID already belongs to a different frozen generation');
|
|
109
|
+
const saved=fileBytes(root,inputSnapshot.path);if(saved!==null&&saved!==encode(snapshot))throw Error('Immutable release input snapshot conflict');
|
|
110
|
+
atomicDevelopmentWrite(root,inputSnapshot.path,encode(snapshot));currentCandidate(scope,candidate,true);
|
|
111
|
+
atomicDevelopmentWrite(root,candidatePath(input.releaseId),encode(candidate));
|
|
112
|
+
});
|
|
92
113
|
return deepFreeze({status:'prepared' as const,releaseRef,sourceDefinitionHash:aggregate.sourceDefinitionHash,inputsHash:aggregate.inputsHash,candidateHash:candidate.candidateHash});
|
|
93
114
|
}
|
|
94
|
-
function bundleFor(c:any,graph:ReturnType<typeof readReleaseGraph>){return {schema:'gate-delivery-release',version:1,releaseRef:c.releaseRef,sourceDefinitionHash:c.aggregate.sourceDefinitionHash,inputsHash:c.aggregate.inputsHash,prodTaskGraphHash:graph.prodTaskGraphHash,prodTaskGraph:graph.graph,targets:c.aggregate.inputs.business.targets,operations:c.aggregate.inputs.business.steps,parameters:c.aggregate.inputs.business.parameters,qualification:c.aggregate.collections,runtime:c.aggregate.inputs.runtime,immutableFiles:c.aggregate.inputs.files,sourceDefinitions:c.aggregate.inputs.sourceDefinitions,historicalDevelopment:{...c.historical.association,acceptanceHash:c.historical.acceptanceHash},prerequisites:c.prerequisites,
|
|
115
|
+
function bundleFor(c:any,graph:ReturnType<typeof readReleaseGraph>){return {schema:'gate-delivery-release',version:1,releaseRef:c.releaseRef,sourceDefinitionHash:c.aggregate.sourceDefinitionHash,inputsHash:c.aggregate.inputsHash,prodTaskGraphHash:graph.prodTaskGraphHash,prodTaskGraph:graph.graph,targets:c.aggregate.inputs.business.targets,operations:c.aggregate.inputs.business.steps,parameters:c.aggregate.inputs.business.parameters,qualification:c.aggregate.collections,runtime:c.aggregate.inputs.runtime,immutableFiles:c.aggregate.inputs.files,sourceDefinitions:c.aggregate.inputs.sourceDefinitions,contractSource:c.contractSource,inputSnapshot:c.inputSnapshot,historicalDevelopment:{...c.historical.association,acceptanceHash:c.historical.acceptanceHash},prerequisites:c.prerequisites,recovery:{strategy:'resume-original-execution',instructions:'Reconcile the original per-network executionId before retrying; preserve submitted transactions, receipts and finality records. Never replay completed operations as a new execution.'},candidate:{path:candidatePath(c.releaseRef.releaseId),sha256:byteHash(encode(c))}};}
|
|
95
116
|
/** Finalizer rereads the actual handoff AFTER mainAgent writes all existing production stages. */
|
|
96
117
|
export async function finalizeDeliveryRelease(raw:Scope&{releaseId:string;onFileCommitted?:(file:string)=>void}){
|
|
97
118
|
// Detach own scalar data before the RPC boundary; caller options may be reused while it awaits.
|
|
@@ -103,16 +124,16 @@ export async function finalizeDeliveryRelease(raw:Scope&{releaseId:string;onFile
|
|
|
103
124
|
if(Object.values(input).some(value=>typeof value!=='string'))throw Error('Release finalization scope requires strings');
|
|
104
125
|
safeId(input.taskId,'taskId');safeId(input.deploymentId,'deploymentId');portablePath(input.handoff,'handoff');
|
|
105
126
|
const root=projectRoot(input.workspaceRoot,input.projectRoot),c=JSON.parse(readInputBytes(root,candidatePath(input.releaseId)).toString());
|
|
106
|
-
const initial=currentCandidate(input,c);await verifyHistoricalDevelopmentChain(initial.history,root);
|
|
127
|
+
const initial=currentCandidate(input,c,true);await verifyHistoricalDevelopmentChain(initial.history,root);
|
|
107
128
|
return withDevelopmentFileLock(root,async()=>{
|
|
108
|
-
same(JSON.parse(readInputBytes(root,candidatePath(input.releaseId)).toString()),c,'Current candidate generation');currentCandidate(input,c);
|
|
129
|
+
same(JSON.parse(readInputBytes(root,candidatePath(input.releaseId)).toString()),c,'Current candidate generation');currentCandidate(input,c,true);
|
|
109
130
|
const graph=readReleaseGraph({...input,releaseRef:c.releaseRef}),bundle=bundleFor(c,graph),bundleHash=semanticHash(bundle),bundlePath=`scripts/tasks/${input.deploymentId}/releases/${input.releaseId}/bundle.json`;
|
|
110
131
|
const marker={schema:'gate-delivery-release-ready',version:1,status:'release_ready',generation:'complete',releaseRef:c.releaseRef,sourceDefinitionHash:c.aggregate.sourceDefinitionHash,inputsHash:c.aggregate.inputsHash,prodTaskGraphHash:graph.prodTaskGraphHash,bundle:{path:bundlePath,hash:bundleHash,sha256:byteHash(encode(bundle))}};
|
|
111
132
|
const previous=fileBytes(root,c.releaseRef.path);if(previous!==null){same(JSON.parse(previous),marker,'Published release is immutable');return inspectDeliveryRelease({...input,releaseRef:c.releaseRef});}
|
|
112
133
|
const existing=fileBytes(root,bundlePath);if(existing!==null&&existing!==encode(bundle))throw Error('Immutable release bundle conflict');
|
|
113
134
|
atomicDevelopmentWrite(root,bundlePath,encode(bundle));onFileCommitted?.(bundlePath);
|
|
114
135
|
// Async notification or competing edits cannot publish stale graph/evidence. Authoritative marker comes last.
|
|
115
|
-
currentCandidate(input,c);same(readReleaseGraph({...input,releaseRef:c.releaseRef}),graph,'Current production graph');
|
|
136
|
+
currentCandidate(input,c,true);same(readReleaseGraph({...input,releaseRef:c.releaseRef}),graph,'Current production graph');
|
|
116
137
|
if(fileBytes(root,bundlePath)!==encode(bundle))throw Error('Prepared bundle changed before publication');
|
|
117
138
|
atomicDevelopmentWrite(root,c.releaseRef.path,encode(marker));return inspectDeliveryRelease({...input,releaseRef:c.releaseRef});
|
|
118
139
|
});
|
|
@@ -126,3 +147,20 @@ export function inspectDeliveryRelease(input:Scope&{releaseRef:ReleaseGraphOptio
|
|
|
126
147
|
const expected={schema:'gate-delivery-release-ready',version:1,status:'release_ready',generation:'complete',releaseRef:c.releaseRef,sourceDefinitionHash:c.aggregate.sourceDefinitionHash,inputsHash:c.aggregate.inputsHash,prodTaskGraphHash:graph.prodTaskGraphHash,bundle:{path:bundlePath,hash:semanticHash(bundle),sha256:byteHash(encode(bundle))}};
|
|
127
148
|
same(marker,expected,'Complete ready content identity');same(readInputBytes(root,bundlePath).toString(),encode(bundle),'Immutable published bundle bytes');return deepFreeze({status:'release_ready' as const,release:bundle,bundleHash:marker.bundle.hash});
|
|
128
149
|
}
|
|
150
|
+
/** File-only historical input recovery; current project edits do not rewrite the old release. */
|
|
151
|
+
export function restoreDeliveryReleaseInputs(raw:Scope&{releaseRef:ReleaseGraphOptions['releaseRef'];destination:string}){
|
|
152
|
+
const input=strictData(raw);exactObject(input,['workspaceRoot','projectRoot','handoff','taskId','deploymentId','releaseRef','destination'],'release input restore');
|
|
153
|
+
const root=projectRoot(input.workspaceRoot,input.projectRoot),ref=input.releaseRef;
|
|
154
|
+
safeId(input.deploymentId,'deploymentId');safeId(ref.releaseId,'releaseId');
|
|
155
|
+
const base=`scripts/tasks/${input.deploymentId}/releases/${ref.releaseId}`;
|
|
156
|
+
if(ref.path!==`${base}/release.json`)throw Error('Noncanonical release restore reference');
|
|
157
|
+
const marker=JSON.parse(readInputBytes(root,ref.path).toString());
|
|
158
|
+
if(marker.schema!=='gate-delivery-release-ready'||marker.version!==1||marker.status!=='release_ready'||marker.generation!=='complete')throw Error('Release restore requires a completed published release');
|
|
159
|
+
same(marker.releaseRef,ref,'Restore release reference');
|
|
160
|
+
const bytes=readInputBytes(root,`${base}/bundle.json`),bundle=JSON.parse(bytes.toString());
|
|
161
|
+
if(marker.bundle.path!==`${base}/bundle.json`||marker.bundle.sha256!==byteHash(bytes)||marker.bundle.hash!==semanticHash(bundle)||bytes.toString()!==encode(bundle))throw Error('Published release bundle changed');
|
|
162
|
+
if(bundle.schema!=='gate-delivery-release'||bundle.version!==1||bundle.inputSnapshot.path!==`${base}/inputs.snapshot.json`)throw Error('Invalid release restore bundle');
|
|
163
|
+
same(bundle.releaseRef,ref,'Restore bundle release reference');same(bundle.inputsHash,ref.inputsHash,'Restore bundle input identity');
|
|
164
|
+
const snapshot=readReleaseInputSnapshot(root,bundle.inputSnapshot);same(snapshot.contractSource,bundle.contractSource,'Restore committed contract source');
|
|
165
|
+
return {...restoreReleaseInputs(root,bundle.inputSnapshot,input.destination),releaseRef:ref};
|
|
166
|
+
}
|
package/runtime/delivery/safe.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { uint256 } from "./observations";
|
|
|
12
12
|
import type { EoaFinality } from "./eoa-observation";
|
|
13
13
|
import type { DeliveryPlan } from "./plan";
|
|
14
14
|
import { SAFE_RUNTIME_HASHES } from "./safe-manifest";
|
|
15
|
+
import { createCalldataInvocation } from './calldata-review';
|
|
15
16
|
export const SAFE_ADAPTER = deepFreeze({
|
|
16
17
|
id: "safe-1.4.1-call-only/v1",
|
|
17
18
|
version: "1.4.1",
|
|
@@ -326,14 +327,24 @@ export function verifySafeExec(
|
|
|
326
327
|
}
|
|
327
328
|
export function renderSafeExport(rawPlan: unknown, raw: unknown) {
|
|
328
329
|
const plan = immutableDeliveryPlan(rawPlan),
|
|
329
|
-
envelope = parseSafeEnvelope(raw, plan)
|
|
330
|
-
|
|
330
|
+
envelope = parseSafeEnvelope(raw, plan);
|
|
331
|
+
const unsignedExecTransaction = encodeSafeExec(envelope, '0x');
|
|
332
|
+
const payloads = envelope.operation === 1 ? [{ argumentPath: [2], invocation: createCalldataInvocation({
|
|
333
|
+
abi: multi.fragments, method: 'multiSend', args: [
|
|
334
|
+
'0x' + plan.transactions.slice(envelope.start, envelope.start + envelope.count).map(c =>
|
|
335
|
+
solidityPacked(['uint8', 'address', 'uint256', 'uint256', 'bytes'], [0, c.to, c.value, (c.data.length - 2) / 2, c.data]).slice(2)).join(''),
|
|
336
|
+
], data: envelope.data,
|
|
337
|
+
}) }] : [];
|
|
338
|
+
const unsignedExecReview = createCalldataInvocation({ abi: SAFE_INTERFACE.fragments, method: 'execTransaction',
|
|
339
|
+
args: [...execKeys.map(k => (envelope as any)[k]), '0x'], data: unsignedExecTransaction, payloads });
|
|
340
|
+
const model = deepFreeze({
|
|
331
341
|
schema: "gate-safe-export",
|
|
332
342
|
version: 1,
|
|
333
343
|
status: "artifact-delivered",
|
|
334
344
|
plan,
|
|
335
345
|
envelope,
|
|
336
|
-
unsignedExecTransaction
|
|
346
|
+
unsignedExecTransaction,
|
|
347
|
+
unsignedExecReview,
|
|
337
348
|
});
|
|
338
349
|
const json = canonicalJson(model);
|
|
339
350
|
return deepFreeze({
|
|
@@ -5,12 +5,13 @@ export interface SameForkInitialPreparation { request: GateToolPreparationReques
|
|
|
5
5
|
/** Stable initial preparation and full prior layout commitment. Auxiliary compiler randomness is excluded. */
|
|
6
6
|
export function sameForkBaselineDigest(initial: SameForkInitialPreparation, oldLayoutHash: string): string {
|
|
7
7
|
const request = normalizePreparationRequest(initial.request), plan = normalizePreparationPlan(initial.plan);
|
|
8
|
-
if (request.kind !== 'uups-placeholder-deploy' || plan.kind !== request.kind || plan.requestHash !== hashPreparationRequest(request)
|
|
9
|
-
|| plan.target !== request.target || !/^[a-f0-9]{64}$/.test(oldLayoutHash)) throw new Error('Invalid same-fork initial preparation');
|
|
8
|
+
if ((request.kind !== 'uups-placeholder-deploy' && request.kind !== 'transparent-deploy') || plan.kind !== request.kind || plan.requestHash !== hashPreparationRequest(request)
|
|
9
|
+
|| plan.proxyKind !== request.proxyKind || plan.target !== request.target || !/^[a-f0-9]{64}$/.test(oldLayoutHash)) throw new Error('Invalid same-fork initial preparation');
|
|
10
10
|
return semanticHash({kind:'same-fork',request,plan,oldLayoutHash});
|
|
11
11
|
}
|
|
12
|
-
export function matchesSameForkInitial(initial: SameForkInitialPreparation, target: string, chainId: string, proxy: string, implementation?: string): boolean {
|
|
13
|
-
return initial.request.kind === 'uups-placeholder-deploy' && initial.request.target === target && initial.plan.target === target && initial.plan.chainId === chainId
|
|
12
|
+
export function matchesSameForkInitial(initial: SameForkInitialPreparation, target: string, chainId: string, proxy: string, implementation?: string, proxyKind?: 'uups' | 'transparent'): boolean {
|
|
13
|
+
return (initial.request.kind === 'uups-placeholder-deploy' || initial.request.kind === 'transparent-deploy') && initial.request.target === target && initial.plan.target === target && initial.plan.chainId === chainId
|
|
14
|
+
&& initial.plan.proxyKind === initial.request.proxyKind && (proxyKind === undefined || initial.request.proxyKind === proxyKind)
|
|
14
15
|
&& initial.plan.deployments.some(d => d.role === 'proxy' && d.address.toLowerCase() === proxy.toLowerCase())
|
|
15
16
|
&& (implementation === undefined || initial.plan.deployments.some(d => d.role === 'implementation' && d.address.toLowerCase() === implementation.toLowerCase()));
|
|
16
17
|
}
|
|
@@ -4,16 +4,20 @@ import crypto from 'node:crypto';
|
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import YAML from 'yaml';
|
|
7
|
+
import { REVIEWED_DELIVERY_OVERRIDES } from './toolchain';
|
|
7
8
|
import { object } from './protocol';
|
|
8
|
-
import {
|
|
9
|
-
import { configDocument, validateDeliveryTarget, type DeliveryTarget } from './config';
|
|
10
|
-
export { readProjectNetworkSnapshots } from './project';
|
|
9
|
+
import { deliveryProjectMarker, projectRoot, readFile, confinedFile, stat, integratedConfig, readPublicProjectNetworkSnapshots, projectSourcesDirectory } from './project';
|
|
10
|
+
import { configDocument, parseDeliveryPublicTargets, validateDeliveryTarget, type DeliveryTarget } from './config';
|
|
11
|
+
export { readProjectNetworkSnapshots, readPublicProjectNetworkSnapshots } from './project';
|
|
11
12
|
export { loadDeliveryTarget } from './config';
|
|
12
13
|
export { configureDeliveryEnvironment } from './manifest';
|
|
13
14
|
export type { DeliveryTarget, DeliveryTargetConfig } from './config';
|
|
14
15
|
|
|
15
16
|
const TOOLCHAIN: Record<string, string> = { hardhat: '2.26.3', ethers: '6.15.0', '@nomicfoundation/hardhat-ethers': '3.1.0', typescript: '5.9.3', 'ts-node': '10.9.2' };
|
|
16
|
-
|
|
17
|
+
// Resolve our identity from the executing package, including an explicitly installed tarball.
|
|
18
|
+
const toolIdentity = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../../package.json'), 'utf8'));
|
|
19
|
+
if (toolIdentity.name !== 'gate-evm-tools' || typeof toolIdentity.version !== 'string') throw new Error('Invalid GateTool package identity');
|
|
20
|
+
const DEPENDENCIES: Record<string, string> = { 'gate-evm-tools': toolIdentity.version, '@openzeppelin/hardhat-upgrades': '3.9.1', '@openzeppelin/upgrades-core': '1.44.2', '@openzeppelin/contracts': '5.4.0' };
|
|
17
21
|
export interface DeliverySetupOptions {
|
|
18
22
|
workspaceRoot: string;
|
|
19
23
|
projectRoot: string;
|
|
@@ -65,10 +69,14 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
|
|
|
65
69
|
const targets = input.targets.map(validateDeliveryTarget);
|
|
66
70
|
if (new Set(targets.map(target => target.network)).size !== targets.length) throw new Error('Duplicate selected target');
|
|
67
71
|
const root = projectRoot(input.workspaceRoot, input.projectRoot);
|
|
68
|
-
|
|
72
|
+
deliveryProjectMarker(root);
|
|
69
73
|
const before = new Map<string, string | undefined>();
|
|
70
74
|
for (const file of ['.gate-template.json', 'package.json', 'hardhat.config.ts', 'config.yaml', 'contractInfo.json']) before.set(file, readFile(root, file));
|
|
71
75
|
const pkg = object(JSON.parse(before.get('package.json') ?? 'null'), 'package.json');
|
|
76
|
+
const overrides = pkg.overrides === undefined ? {} : object(pkg.overrides, 'package overrides');
|
|
77
|
+
for (const [name, version] of Object.entries(REVIEWED_DELIVERY_OVERRIDES)) {
|
|
78
|
+
if (overrides[name] !== undefined && overrides[name] !== version) throw new Error(`Reviewed delivery dependency override conflict: ${name}`);
|
|
79
|
+
}
|
|
72
80
|
const declarations: Record<string, unknown> = {};
|
|
73
81
|
for (const section of ['dependencies', 'devDependencies']) {
|
|
74
82
|
const entries = pkg[section] === undefined ? {} : object(pkg[section], section);
|
|
@@ -89,7 +97,7 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
|
|
|
89
97
|
const localTool = name === 'gate-evm-tools' && input.toolPackage === undefined && typeof declared === 'string' && /^file:.*\.tgz$/.test(declared);
|
|
90
98
|
if ((name in TOOLCHAIN && declared === undefined) || (declared !== undefined && declared !== version && !localTool)) throw new Error(`Dependency declaration conflict for ${name}: expected ${version}`);
|
|
91
99
|
}
|
|
92
|
-
const networks =
|
|
100
|
+
const networks = readPublicProjectNetworkSnapshots(root, targets.map(target => target.network));
|
|
93
101
|
const source = before.get('hardhat.config.ts')!;
|
|
94
102
|
const withPlugin = integratedConfig(source); // Check integration conflicts even when dependencies are missing.
|
|
95
103
|
const doc = configDocument(root);
|
|
@@ -106,6 +114,9 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
|
|
|
106
114
|
confinedFile(root, target.openzeppelin!.manifestDir, 'directory');
|
|
107
115
|
merge([network], target);
|
|
108
116
|
}
|
|
117
|
+
// Validate the same effective facilities used by input qualification, while keeping inherited
|
|
118
|
+
// addresses in their profiles so later base edits propagate to non-overridden targets.
|
|
119
|
+
parseDeliveryPublicTargets(Buffer.from(doc.toString()), Buffer.from(source), targets);
|
|
109
120
|
if (before.get('contractInfo.json') !== undefined) object(JSON.parse(before.get('contractInfo.json')!), 'contractInfo.json');
|
|
110
121
|
const dependencies: DeliveryInspection['dependencies'] = [];
|
|
111
122
|
const projectRequire = createRequire(path.join(root, 'package.json'));
|
|
@@ -140,10 +151,11 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
|
|
|
140
151
|
}
|
|
141
152
|
const writes = new Map<string, string>();
|
|
142
153
|
const missing = Object.entries(required).filter(([name]) => declarations[name] === undefined);
|
|
143
|
-
|
|
154
|
+
const missingOverrides = Object.entries(REVIEWED_DELIVERY_OVERRIDES).some(([name]) => overrides[name] === undefined);
|
|
155
|
+
if (missing.length || missingOverrides) {
|
|
144
156
|
const dev = { ...(pkg.devDependencies as Record<string, unknown> ?? {}) };
|
|
145
157
|
for (const [name, version] of missing) dev[name] = version;
|
|
146
|
-
writes.set('package.json', JSON.stringify({ ...pkg, devDependencies: dev }, null, 2) + '\n');
|
|
158
|
+
writes.set('package.json', JSON.stringify({ ...pkg, devDependencies: dev, overrides: { ...overrides, ...REVIEWED_DELIVERY_OVERRIDES } }, null, 2) + '\n');
|
|
147
159
|
}
|
|
148
160
|
if (changedYaml) writes.set('config.yaml', doc.toString());
|
|
149
161
|
if (before.get('contractInfo.json') === undefined) writes.set('contractInfo.json', '{}\n');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Actual-file source binding only. This API grants no host approval or execution authority. */
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
|
-
import {
|
|
4
|
+
import { deliveryProjectMarker, projectRoot, confinedFile } from './project-files';
|
|
5
5
|
import { object, parseDeliveryRequest, validateDeliveryRpc, type DeliveryRequest, type ChainIdProvider, type ProjectNetworkSnapshot } from './protocol';
|
|
6
6
|
import { loadPlanCodec } from './codec';
|
|
7
7
|
import type { Plan, PlanTask, DefinitionSelection, DefinitionSnapshot, DeepReadonly } from '../vendor/plan-codec/index.cjs';
|
|
@@ -37,11 +37,9 @@ export function parseCanonicalPlan(text: string): Plan { return loadPlanCodec().
|
|
|
37
37
|
export function projectCanonicalDefinitions(text: string, selection: DefinitionSelection): ReturnType<ReturnType<typeof loadPlanCodec>['projectDefinitions']> {
|
|
38
38
|
return loadPlanCodec().projectDefinitions(text, selection);
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
'prod-execution': ['release-prepare', 'release-execute', 'release-verify'],
|
|
44
|
-
};
|
|
40
|
+
export function deploymentPurpose(task: Pick<PlanTask, 'step' | 'scope'>) {
|
|
41
|
+
return loadPlanCodec().deploymentPurpose(task);
|
|
42
|
+
}
|
|
45
43
|
function sameRelease(actual: unknown, expected: DeliveryRequest['releaseRef']): boolean {
|
|
46
44
|
if (expected === undefined) return actual === undefined;
|
|
47
45
|
if (!actual || typeof actual !== 'object' || Array.isArray(actual)) return false;
|
|
@@ -78,7 +76,7 @@ function readSource(input: Omit<DeliverySourceOptions, 'sourceRoots'> & { source
|
|
|
78
76
|
const request = parseDeliveryRequest(input.request);
|
|
79
77
|
const workspace = projectRoot(input.workspaceRoot, '.');
|
|
80
78
|
const root = projectRoot(workspace, input.projectRoot);
|
|
81
|
-
|
|
79
|
+
deliveryProjectMarker(root);
|
|
82
80
|
const bytes = actualSource(workspace, request.sourceRef.path);
|
|
83
81
|
const text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
84
82
|
if (input.sourceRoots === undefined) (require('./input-files') as typeof import('./input-files')).assertUnambiguousHandoff(text);
|
|
@@ -89,15 +87,17 @@ function readSource(input: Omit<DeliverySourceOptions, 'sourceRoots'> & { source
|
|
|
89
87
|
const invocation = entries.find(({ task }) => task.planKey === request.sourceRef.planKey);
|
|
90
88
|
if (!invocation || invocation.task.rev !== request.sourceRef.rev) throw new Error('sourceRef planKey/rev does not match actual handoff');
|
|
91
89
|
if (plan.lanes[invocation.lane].state !== 'enabled' || invocation.task.status === 'cancelled') throw new Error('Invocation task is disabled or cancelled');
|
|
90
|
+
const requirementIssue = codec.deploymentRequirementIssue(plan, invocation.task);
|
|
91
|
+
if (requirementIssue) throw new Error(requirementIssue);
|
|
92
92
|
const deployment = object(invocation.task.scope?.deployment, 'invocation scope.deployment');
|
|
93
93
|
if (deployment.projectRoot !== input.projectRoot) throw new Error('Invocation projectRoot mismatch');
|
|
94
94
|
if (deployment.chainFamily !== 'evm' || deployment.framework !== 'hardhat2') throw new Error('Invocation requires an EVM Hardhat2 deployment');
|
|
95
|
-
if (
|
|
95
|
+
if (deploymentPurpose(invocation.task) !== request.purpose) throw new Error('Invocation purpose mismatch');
|
|
96
96
|
if (deployment.environment !== request.environment || deployment.targetNetwork !== request.network) throw new Error('Invocation environment/targetNetwork mismatch');
|
|
97
97
|
if (!Array.isArray(deployment.allowedActions) || !deployment.allowedActions.includes(request.mode)) throw new Error('Invocation mode is not in allowedActions');
|
|
98
98
|
if (!sameRelease(deployment.releaseRef, request.releaseRef)) throw new Error('Invocation releaseRef mismatch');
|
|
99
99
|
const sourceRoots = input.sourceRoots ?? (request.purpose === 'prod-execution'
|
|
100
|
-
? entries.filter(({ task }) => task
|
|
100
|
+
? entries.filter(({ task }) => deploymentPurpose(task) === 'prod-qualification'
|
|
101
101
|
&& (task.scope?.deployment as Record<string, unknown> | undefined)?.projectRoot === input.projectRoot
|
|
102
102
|
&& (task.scope?.deployment as Record<string, unknown> | undefined)?.deploymentId === deployment.deploymentId).map(({ task }) => task.planKey)
|
|
103
103
|
: [invocation.task.planKey]);
|
|
@@ -109,7 +109,7 @@ function readSource(input: Omit<DeliverySourceOptions, 'sourceRoots'> & { source
|
|
|
109
109
|
}
|
|
110
110
|
let production: ReturnType<typeof codec.projectDefinitions> | undefined;
|
|
111
111
|
if (request.purpose === 'prod-execution') {
|
|
112
|
-
const roots = entries.filter(({ task }) =>
|
|
112
|
+
const roots = entries.filter(({ task }) => deploymentPurpose(task) === 'prod-execution'
|
|
113
113
|
&& task.scope?.deployment && (task.scope.deployment as Record<string, unknown>).projectRoot === input.projectRoot
|
|
114
114
|
&& sameRelease((task.scope.deployment as Record<string, unknown>).releaseRef, request.releaseRef)).map(({ task }) => task.planKey);
|
|
115
115
|
production = codec.projectDefinitions(text, { roots, mode: 'full' });
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Allocate a round only after its concrete requirement revision is confirmed. */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { parseCanonicalPlan, projectCanonicalDefinitions, deploymentPurpose } from './source';
|
|
5
|
+
import { projectRoot, deliveryProjectMarker, confinedFile, stat } from './project-files';
|
|
6
|
+
import { readInputBytes, assertUnambiguousHandoff } from './input-files';
|
|
7
|
+
import { withDevelopmentFileLock, atomicDevelopmentWrite, fileBytes } from './materialization';
|
|
8
|
+
import { exactObject, semanticHash, canonicalJson } from '../workflow/lib/canonicalData';
|
|
9
|
+
import { safeId, portablePath, object } from './protocol';
|
|
10
|
+
|
|
11
|
+
export interface DeploymentRequirementRef { planKey: string; rev: number }
|
|
12
|
+
export function parseDeploymentRequirementRef(raw: unknown): DeploymentRequirementRef {
|
|
13
|
+
const ref = exactObject(raw, ['planKey', 'rev'], 'requirementRef');
|
|
14
|
+
safeId(ref.planKey, 'requirementRef.planKey');
|
|
15
|
+
if (!Number.isSafeInteger(ref.rev) || (ref.rev as number) < 1) throw Error('Invalid requirement revision');
|
|
16
|
+
return { planKey: ref.planKey as string, rev: ref.rev as number };
|
|
17
|
+
}
|
|
18
|
+
export interface CreateDeliveryTaskOptions {
|
|
19
|
+
workspaceRoot: string; projectRoot: string; handoff: string; taskId: string;
|
|
20
|
+
requirementRef: DeploymentRequirementRef; businessSlug: string; referenceDeploymentId?: string;
|
|
21
|
+
}
|
|
22
|
+
/** A reservation creates metadata only. The deployment Agent supplies executable content afterwards. */
|
|
23
|
+
export async function createDeliveryTask(input: CreateDeliveryTaskOptions) {
|
|
24
|
+
object(input, 'create deployment task', ['workspaceRoot', 'projectRoot', 'handoff', 'taskId', 'requirementRef', 'businessSlug', 'referenceDeploymentId']);
|
|
25
|
+
const root = projectRoot(input.workspaceRoot, input.projectRoot), workspace = projectRoot(input.workspaceRoot, '.');
|
|
26
|
+
deliveryProjectMarker(root);
|
|
27
|
+
portablePath(input.handoff, 'handoff'); safeId(input.taskId, 'taskId');
|
|
28
|
+
const ref = parseDeploymentRequirementRef(input.requirementRef);
|
|
29
|
+
if (typeof input.businessSlug !== 'string' || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(input.businessSlug)) throw Error('businessSlug must be a short lowercase business name');
|
|
30
|
+
if (input.referenceDeploymentId !== undefined) safeId(input.referenceDeploymentId, 'referenceDeploymentId');
|
|
31
|
+
return withDevelopmentFileLock(root, async () => {
|
|
32
|
+
const text = readInputBytes(workspace, input.handoff).toString(); assertUnambiguousHandoff(text);
|
|
33
|
+
const plan = parseCanonicalPlan(text);
|
|
34
|
+
if (plan.taskId !== input.taskId) throw Error('Requirement taskId mismatch');
|
|
35
|
+
const requirement = Object.values(plan.tasks).flat().find(t => t.planKey === ref.planKey);
|
|
36
|
+
if (!requirement || requirement.rev !== ref.rev || requirement.requirementConfirmation?.rev !== ref.rev
|
|
37
|
+
|| requirement.status === 'cancelled' || deploymentPurpose(requirement) !== 'analysis'
|
|
38
|
+
|| (requirement.scope?.deployment as any)?.projectRoot !== input.projectRoot) throw Error('Deployment requirement is unconfirmed or stale');
|
|
39
|
+
const d = requirement.scope!.deployment as any;
|
|
40
|
+
if (!d.requiredOperations?.length || !d.developmentNetwork || !Array.isArray(d.releaseTargetNetworks)) throw Error('Confirmed requirement scope is incomplete');
|
|
41
|
+
const identity = semanticHash({ taskId: input.taskId, projectRoot: input.projectRoot, requirementRef: ref });
|
|
42
|
+
const requirementHash = semanticHash(projectCanonicalDefinitions(text, { roots: [ref.planKey], mode: 'upstream' }).snapshot);
|
|
43
|
+
const registry = `.gate-delivery/deployment-requests/${identity}.json`;
|
|
44
|
+
const requestIdentity = { taskId: input.taskId, requirementRef: ref, requirementHash,
|
|
45
|
+
referenceDeploymentId: input.referenceDeploymentId ?? null };
|
|
46
|
+
let record: any;
|
|
47
|
+
const existing = fileBytes(root, registry);
|
|
48
|
+
if (existing !== null) {
|
|
49
|
+
record = JSON.parse(existing);
|
|
50
|
+
if (canonicalJson(record.requestIdentity) !== canonicalJson(requestIdentity)) throw Error('Confirmed requirement identity conflict');
|
|
51
|
+
safeId(record.deploymentId, 'reserved deploymentId');
|
|
52
|
+
} else {
|
|
53
|
+
const known = new Set(Object.values(plan.tasks).flat().map(t => (t.scope?.deployment as any)?.deploymentId).filter(Boolean));
|
|
54
|
+
const history = fileBytes(workspace, input.handoff.includes('/') ? `${input.handoff.slice(0, input.handoff.lastIndexOf('/'))}/handoff-ledger.jsonl` : 'handoff-ledger.jsonl');
|
|
55
|
+
if (history) for (const line of history.split('\n').filter(Boolean)) {
|
|
56
|
+
const item = JSON.parse(line);
|
|
57
|
+
for (const entry of item.tasks ?? []) { const id = entry.task?.scope?.deployment?.deploymentId; if (id) known.add(id); }
|
|
58
|
+
}
|
|
59
|
+
const date = new Date().toISOString().slice(0, 10).replaceAll('-', '');
|
|
60
|
+
let deploymentId: string;
|
|
61
|
+
do { deploymentId = `${input.businessSlug}-${date}-${randomBytes(4).toString('hex')}`; }
|
|
62
|
+
while (known.has(deploymentId) || stat(confinedFile(root, `scripts/tasks/${deploymentId}`, 'directory')));
|
|
63
|
+
record = { version: 1, deploymentId, releaseId: `${deploymentId}-release`, requestIdentity, state: 'reserved' };
|
|
64
|
+
// Publish reservation before creating the package, so a retry uses the same ID.
|
|
65
|
+
atomicDevelopmentWrite(root, registry, canonicalJson(record) + '\n');
|
|
66
|
+
}
|
|
67
|
+
const businessRoot = `scripts/tasks/${record.deploymentId}`;
|
|
68
|
+
const directory = confinedFile(root, businessRoot, 'directory');
|
|
69
|
+
const marker = `${businessRoot}/.request.json`;
|
|
70
|
+
const markerBytes = canonicalJson({ identity }) + '\n';
|
|
71
|
+
const previousMarker = fileBytes(root, marker);
|
|
72
|
+
if (stat(directory) && previousMarker !== markerBytes && fs.readdirSync(directory).length) throw Error('Reserved deployment directory is occupied; refusing to overwrite');
|
|
73
|
+
if (previousMarker !== null && previousMarker !== markerBytes) throw Error('Deployment reservation ownership mismatch');
|
|
74
|
+
if (previousMarker === null) atomicDevelopmentWrite(root, marker, markerBytes);
|
|
75
|
+
const metadata = { version: 1, id: record.deploymentId, requirementRef: ref,
|
|
76
|
+
developmentNetwork: d.developmentNetwork, releaseTargetNetworks: d.releaseTargetNetworks,
|
|
77
|
+
...(input.referenceDeploymentId ? { referenceDeploymentId: input.referenceDeploymentId } : {}) };
|
|
78
|
+
const taskPath = `${businessRoot}/task.yaml`, bytes = canonicalJson(metadata) + '\n';
|
|
79
|
+
const previous = fileBytes(root, taskPath);
|
|
80
|
+
if (previous !== null && previous !== bytes) throw Error('Reserved task metadata changed; refusing to overwrite');
|
|
81
|
+
if (previous === null) atomicDevelopmentWrite(root, taskPath, bytes);
|
|
82
|
+
if (record.state !== 'complete') atomicDevelopmentWrite(root, registry, canonicalJson({ ...record, state: 'complete' }) + '\n');
|
|
83
|
+
return { status: 'created' as const, deploymentId: record.deploymentId as string, releaseId: record.releaseId as string, businessRoot, specPath: taskPath, requirementRef: ref };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { compilerDependencyPins } from './compiler-dependency-pins';
|
|
2
|
+
|
|
3
|
+
/** Reviewed compiler adapter dependency selections; payload checks remain authoritative.
|
|
4
|
+
* Range-scoped entries preserve distinct dependency majors. Setup never overrides a conflicting project choice. */
|
|
5
|
+
export const REVIEWED_DELIVERY_OVERRIDES: Record<string, string> = {
|
|
6
|
+
"axios": "1.20.0",
|
|
7
|
+
"@aws-sdk/client-lambda": "3.1152.0",
|
|
8
|
+
"@aws-sdk/core": "3.978.3",
|
|
9
|
+
"@aws-sdk/credential-provider-env": "3.972.74",
|
|
10
|
+
"@aws-sdk/credential-provider-http": "3.972.76",
|
|
11
|
+
"@aws-sdk/credential-provider-ini": "3.973.19",
|
|
12
|
+
"@aws-sdk/credential-provider-login": "3.972.81",
|
|
13
|
+
"@aws-sdk/credential-provider-node": "3.972.86",
|
|
14
|
+
"@aws-sdk/credential-provider-process": "3.972.74",
|
|
15
|
+
"@aws-sdk/credential-provider-sso": "3.973.18",
|
|
16
|
+
"@aws-sdk/credential-provider-web-identity": "3.972.80",
|
|
17
|
+
"@aws-sdk/nested-clients": "3.997.48",
|
|
18
|
+
"@aws-sdk/signature-v4-multi-region": "3.996.48",
|
|
19
|
+
"@aws-sdk/token-providers": "3.1150.0",
|
|
20
|
+
"@aws-sdk/types": "3.974.6",
|
|
21
|
+
"@smithy/types": "4.19.0",
|
|
22
|
+
"@smithy/signature-v4": "5.7.4",
|
|
23
|
+
"@smithy/fetch-http-handler": "5.8.0",
|
|
24
|
+
"@smithy/credential-provider-imds": "4.5.2",
|
|
25
|
+
"@smithy/core": "3.36.0",
|
|
26
|
+
"@smithy/node-http-handler": "4.12.1",
|
|
27
|
+
"bowser": "2.14.1",
|
|
28
|
+
"follow-redirects": "1.16.1",
|
|
29
|
+
"undici@>=5 <6": "5.29.0",
|
|
30
|
+
"undici@>=6 <7": "6.29.0",
|
|
31
|
+
"tslib@>=1 <2": "1.14.1",
|
|
32
|
+
"tslib@>=2 <3": "2.7.0",
|
|
33
|
+
"semver@>=5 <6": "5.7.2",
|
|
34
|
+
"semver@>=6 <7": "6.3.1",
|
|
35
|
+
"semver@>=7 <8": "7.8.5",
|
|
36
|
+
"ansi-regex@>=6 <7": "6.4.0"
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// OZ's compiler adapter follows floating AWS/Smithy ranges. Freeze that reviewed
|
|
40
|
+
// family closure so a fresh npm resolution cannot select unqualified payloads.
|
|
41
|
+
// Other project dependencies keep their original constraints and payload checks.
|
|
42
|
+
for (const key of Object.keys(compilerDependencyPins)) {
|
|
43
|
+
if (!key.startsWith('@aws-sdk/') && !key.startsWith('@smithy/')) continue;
|
|
44
|
+
const at = key.lastIndexOf('@'), name = key.slice(0, at), version = key.slice(at + 1);
|
|
45
|
+
const existing = REVIEWED_DELIVERY_OVERRIDES[name];
|
|
46
|
+
if (existing && existing !== version) throw new Error('Ambiguous reviewed compiler dependency: ' + name);
|
|
47
|
+
REVIEWED_DELIVERY_OVERRIDES[name] = version;
|
|
48
|
+
}
|
|
@@ -118,13 +118,16 @@ export function createDeliveryValidation(
|
|
|
118
118
|
const args = first
|
|
119
119
|
? (first.constructorArgs ?? [])
|
|
120
120
|
: step.kind === "deploy"
|
|
121
|
-
? (step.args ?? [])
|
|
121
|
+
? (proxy ? (proxy.constructorArgs ?? []) : (step.args ?? []))
|
|
122
122
|
: (step.constructorArgs ??
|
|
123
123
|
(typeof proxy === "object"
|
|
124
124
|
? proxy?.constructorArgs
|
|
125
125
|
: undefined) ??
|
|
126
126
|
[]);
|
|
127
127
|
await argumentsFor(name as string, null, args, true);
|
|
128
|
+
if (step.kind === "deploy" && proxy?.kind === "transparent" && proxy.initializer !== false) {
|
|
129
|
+
await argumentsFor(name as string, String(proxy.initializer), step.args ?? [], true);
|
|
130
|
+
}
|
|
128
131
|
const init = (first?.call ?? step.call) as
|
|
129
132
|
| Record<string, unknown>
|
|
130
133
|
| undefined;
|
|
@@ -169,7 +172,9 @@ export function createDeliveryValidation(
|
|
|
169
172
|
true,
|
|
170
173
|
)
|
|
171
174
|
: declaredCreate2;
|
|
172
|
-
|
|
175
|
+
// Transparent proxy prediction depends on the prepared implementation salt/address.
|
|
176
|
+
// Its actual constructor and policies are independently checked by preparation semantics.
|
|
177
|
+
if (step.kind === "deploy" && create2 && proxy?.kind !== "transparent") {
|
|
173
178
|
const a = await read(first ? ERC1967_PROXY : (name as string));
|
|
174
179
|
const constructor = resolve(
|
|
175
180
|
first
|