@empire-builder-kit/nx 1.0.0-rc.37 → 1.0.0-rc.39
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 +18 -0
- package/executors.json +5 -0
- package/generators.json +10 -0
- package/package.json +20 -3
- package/src/aws-authority/index.d.ts +1 -0
- package/src/aws-authority/index.js +1 -0
- package/src/aws-authority/lambda-policy-ordering.d.ts +38 -0
- package/src/aws-authority/lambda-policy-ordering.js +56 -0
- package/src/aws-authority/stage-authority.d.ts +11 -3
- package/src/aws-authority/stage-authority.js +615 -29
- package/src/blueprints/external-sandbox.js +21 -9
- package/src/blueprints/manifest.d.ts +1 -1
- package/src/blueprints/resolver.js +28 -15
- package/src/cli/bootstrap.d.ts +1 -1
- package/src/cli/deploy-runtime.d.ts +6 -0
- package/src/cli/deploy-runtime.js +58 -0
- package/src/cli/dev-command.d.ts +16 -4
- package/src/cli/dev-command.js +63 -0
- package/src/cli/main.d.ts +7 -1
- package/src/cli/main.js +128 -20
- package/src/cli/output.d.ts +1 -1
- package/src/developer-agent/context.js +41 -9
- package/src/developer-agent/generator-planning.js +16 -2
- package/src/developer-agent/git-inspection.d.ts +6 -2
- package/src/developer-agent/git-inspection.js +78 -6
- package/src/developer-agent/model.d.ts +4 -2
- package/src/developer-agent/operation-registry.d.ts +5 -0
- package/src/developer-agent/operation-registry.js +179 -23
- package/src/developer-agent/preview-changes.d.ts +2 -0
- package/src/developer-agent/preview-changes.js +14 -2
- package/src/developer-agent/preview-source.js +3 -0
- package/src/developer-agent/validation.js +20 -8
- package/src/developer-agent/workspace-inspection.js +37 -3
- package/src/executors/deployment-plan/deployment-plan.d.ts +2 -0
- package/src/executors/deployment-plan/deployment-plan.js +51 -4
- package/src/executors/dev-doctor/dev-doctor.js +13 -6
- package/src/executors/dev-task-cleanup/dev-task-cleanup.d.ts +23 -0
- package/src/executors/dev-task-cleanup/dev-task-cleanup.js +145 -0
- package/src/executors/dev-task-cleanup/schema.json +9 -0
- package/src/executors/dev-task-cleanup/task-stack-absence.d.ts +27 -0
- package/src/executors/dev-task-cleanup/task-stack-absence.js +281 -0
- package/src/executors/dev-task-cleanup/task-stack-checkpoint.d.ts +12 -0
- package/src/executors/dev-task-cleanup/task-stack-checkpoint.js +92 -0
- package/src/executors/fleet/fleet.js +1 -1
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +28 -1
- package/src/executors/local-deploy/local-deploy.d.ts +8 -1
- package/src/executors/local-deploy/local-deploy.js +97 -24
- package/src/executors/local-deploy/schema.json +8 -0
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +30 -18
- package/src/executors/sst-lifecycle/governed-native-operation.d.ts +2 -0
- package/src/executors/sst-lifecycle/governed-native-operation.js +9 -0
- package/src/executors/sst-lifecycle/run-sst-command.d.ts +5 -0
- package/src/executors/sst-lifecycle/run-sst-command.js +220 -32
- package/src/executors/sst-lifecycle/sst-environment-source.d.ts +8 -0
- package/src/executors/sst-lifecycle/sst-environment-source.js +54 -0
- package/src/executors/sst-lifecycle/task-unlock.d.ts +15 -0
- package/src/executors/sst-lifecycle/task-unlock.js +126 -0
- package/src/foundation/capability-plan.d.ts +43 -0
- package/src/foundation/capability-plan.js +168 -0
- package/src/foundation/discovery.d.ts +14 -11
- package/src/foundation/discovery.js +32 -6
- package/src/foundation/index.d.ts +1 -0
- package/src/foundation/index.js +1 -0
- package/src/foundation/local-database-contract.d.ts +20 -0
- package/src/foundation/local-database-contract.js +262 -13
- package/src/foundation/local-private-smoke-access.d.ts +20 -0
- package/src/foundation/local-private-smoke-access.js +197 -0
- package/src/foundation/preflight.js +37 -18
- package/src/foundation/private-smoke-access.js +10 -2
- package/src/foundation/private-smoke-admission.d.ts +3 -1
- package/src/foundation/private-smoke-admission.js +29 -8
- package/src/foundation/private-smoke-control-plane.js +17 -6
- package/src/foundation/provision-database-bindings.d.ts +5 -0
- package/src/foundation/provision-database-bindings.js +41 -8
- package/src/foundation/provision-logical-database.js +13 -8
- package/src/foundation/requirements.d.ts +3 -3
- package/src/foundation/requirements.js +24 -12
- package/src/foundation/router-waf.d.ts +1 -0
- package/src/foundation/router-waf.js +14 -1
- package/src/generators/blueprint/blueprint.d.ts +5 -0
- package/src/generators/blueprint/blueprint.js +102 -0
- package/src/generators/blueprint/files.d.ts +6 -0
- package/src/generators/blueprint/files.js +217 -0
- package/src/generators/blueprint/schema.d.ts +4 -0
- package/src/generators/blueprint/schema.json +18 -0
- package/src/generators/formatting.js +24 -1
- package/src/generators/logging-registry.d.ts +2 -0
- package/src/generators/logging-registry.js +22 -0
- package/src/generators/preset/workspace-files-adopter-skills.d.ts +7 -0
- package/src/generators/preset/workspace-files-adopter-skills.js +301 -0
- package/src/generators/preset/workspace-files-ci-install.d.ts +2 -0
- package/src/generators/preset/workspace-files-ci-install.js +196 -0
- package/src/generators/preset/workspace-files-developer-agent.js +40 -13
- package/src/generators/preset/workspace-files-performance-load.js +8 -0
- package/src/generators/preset/workspace-files-stage-authority.js +40 -1
- package/src/generators/preset/workspace-files-thin-deploy.js +66 -34
- package/src/generators/preset/workspace-files-thin-docs.js +64 -18
- package/src/generators/preset/workspace-files.d.ts +4 -0
- package/src/generators/preset/workspace-files.js +159 -91
- package/src/generators/repository-policy/repository-policy.js +37 -0
- package/src/generators/slice/built-in-plan-api-contract-files.js +42 -7
- package/src/generators/slice/built-in-plan-api-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-api-files.js +47 -389
- package/src/generators/slice/built-in-plan-async-work-files.js +19 -1912
- package/src/generators/slice/built-in-plan-authorization-files.js +92 -329
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +36 -2
- package/src/generators/slice/built-in-plan-authorization-storage.d.ts +3 -0
- package/src/generators/slice/built-in-plan-authorization-storage.js +119 -0
- package/src/generators/slice/built-in-plan-background-work-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-background-work-files.js +15 -5
- package/src/generators/slice/built-in-plan-data-deletion-files.js +2 -830
- package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-data-files.js +61 -1164
- package/src/generators/slice/built-in-plan-data-lifecycle-files.js +53 -28
- package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +18 -2
- package/src/generators/slice/built-in-plan-data-retention-job-files.js +7 -2446
- package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +30 -6
- package/src/generators/slice/built-in-plan-data-rights-files.js +6 -4482
- package/src/generators/slice/built-in-plan-database-lifecycle-files.js +4 -15
- package/src/generators/slice/built-in-plan-foundation-files.d.ts +2 -1
- package/src/generators/slice/built-in-plan-foundation-files.js +34 -10
- package/src/generators/slice/built-in-plan-frontend-files.js +2 -2
- package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-infrastructure-files.js +180 -522
- package/src/generators/slice/built-in-plan-key-value-cleanup.d.ts +4 -0
- package/src/generators/slice/built-in-plan-key-value-cleanup.js +100 -0
- package/src/generators/slice/built-in-plan-key-value-consumer.d.ts +4 -0
- package/src/generators/slice/built-in-plan-key-value-consumer.js +151 -0
- package/src/generators/slice/built-in-plan-key-value-deletion.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-deletion.js +377 -0
- package/src/generators/slice/built-in-plan-key-value-delivery.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-delivery.js +120 -0
- package/src/generators/slice/built-in-plan-key-value-export.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-export.js +595 -0
- package/src/generators/slice/built-in-plan-key-value-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-files.js +31 -0
- package/src/generators/slice/built-in-plan-key-value-holds.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-holds.js +189 -0
- package/src/generators/slice/built-in-plan-key-value-infrastructure.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-infrastructure.js +102 -0
- package/src/generators/slice/built-in-plan-key-value-performance.d.ts +5 -0
- package/src/generators/slice/built-in-plan-key-value-performance.js +530 -0
- package/src/generators/slice/built-in-plan-key-value-provider.d.ts +4 -0
- package/src/generators/slice/built-in-plan-key-value-provider.js +366 -0
- package/src/generators/slice/built-in-plan-key-value-records.d.ts +3 -0
- package/src/generators/slice/built-in-plan-key-value-records.js +232 -0
- package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +103 -0
- package/src/generators/slice/built-in-plan-key-value-retention-job-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-job-files.js +160 -0
- package/src/generators/slice/built-in-plan-key-value-retention-maintenance.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-maintenance.js +329 -0
- package/src/generators/slice/built-in-plan-key-value-retention-worker.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-worker.js +477 -0
- package/src/generators/slice/built-in-plan-key-value-retention.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention.js +184 -0
- package/src/generators/slice/built-in-plan-metadata-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-metadata-files.js +140 -28
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +36 -19
- package/src/generators/slice/built-in-plan-operations-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-operations-files.js +89 -50
- package/src/generators/slice/built-in-plan-performance-files.js +84 -1010
- package/src/generators/slice/built-in-plan-project-files.js +116 -67
- package/src/generators/slice/built-in-plan-release-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-release-files.js +64 -15
- package/src/generators/slice/built-in-plan-reliability-files.js +54 -28
- package/src/generators/slice/built-in-plan-shared.d.ts +4 -2
- package/src/generators/slice/built-in-plan-shared.js +41 -19
- package/src/generators/slice/built-in-plan-sql-events.d.ts +2 -0
- package/src/generators/slice/built-in-plan-sql-events.js +257 -0
- package/src/generators/slice/built-in-plan-testing-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-testing-files.js +184 -132
- package/src/generators/slice/built-in-plan-testing-persistence-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-testing-persistence-files.js +178 -0
- package/src/generators/slice/built-in-plan-thin-release-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-thin-release-files.js +35 -2
- package/src/generators/slice/built-in-plan-verification-files.js +70 -0
- package/src/generators/slice/built-in-plan-web-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-web-files.js +206 -14
- package/src/generators/slice/built-in-plan-workload-role-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-workload-role-files.js +113 -274
- package/src/generators/slice/built-in-plan.d.ts +9 -1
- package/src/generators/slice/built-in-plan.js +49 -21
- package/src/generators/slice/data-policy-review-seed.d.ts +2 -0
- package/src/generators/slice/data-policy-review-seed.js +22 -0
- package/src/generators/slice/deployed-smoke-readiness.d.ts +2 -0
- package/src/generators/slice/deployed-smoke-readiness.js +214 -0
- package/src/generators/slice/local-source-identity.d.ts +2 -0
- package/src/generators/slice/local-source-identity.js +31 -0
- package/src/generators/slice/persistence-contract.d.ts +14 -0
- package/src/generators/slice/persistence-contract.js +32 -0
- package/src/generators/slice/slice.js +29 -24
- package/src/generators/sql/schema.d.ts +7 -0
- package/src/generators/sql/schema.json +38 -0
- package/src/generators/sql/sql.d.ts +6 -0
- package/src/generators/sql/sql.js +53 -0
- package/src/generators/upgrade/sql-seeded-reconciliation.d.ts +2 -0
- package/src/generators/upgrade/sql-seeded-reconciliation.js +170 -0
- package/src/generators/upgrade/upgrade.d.ts +2 -0
- package/src/generators/upgrade/upgrade.js +136 -9
- package/src/generators/workload/workload.js +51 -2
- package/src/local-dev/browser-verification.d.ts +37 -0
- package/src/local-dev/browser-verification.js +281 -0
- package/src/local-dev/contracts.d.ts +10 -1
- package/src/local-dev/contracts.js +114 -13
- package/src/local-dev/dev-command-core.js +24 -5
- package/src/local-dev/docker-credential-health.d.ts +14 -0
- package/src/local-dev/docker-credential-health.js +94 -0
- package/src/local-dev/environment-inspector.d.ts +7 -0
- package/src/local-dev/environment-inspector.js +42 -15
- package/src/local-dev/environment-state.js +2 -2
- package/src/local-dev/errors.d.ts +1 -1
- package/src/local-dev/errors.js +2 -0
- package/src/local-dev/fleet-client.js +2 -2
- package/src/local-dev/fleet-configuration.js +57 -25
- package/src/local-dev/fleet-inventory.js +46 -18
- package/src/local-dev/fleet-ipc.d.ts +7 -0
- package/src/local-dev/fleet-ipc.js +14 -2
- package/src/local-dev/fleet-launcher.d.ts +6 -0
- package/src/local-dev/fleet-launcher.js +14 -2
- package/src/local-dev/fleet-logs.js +50 -22
- package/src/local-dev/fleet-process.d.ts +20 -1
- package/src/local-dev/fleet-process.js +197 -41
- package/src/local-dev/fleet-runner-evidence.d.ts +5 -0
- package/src/local-dev/fleet-runner-evidence.js +56 -0
- package/src/local-dev/fleet-runtime.js +268 -229
- package/src/local-dev/fleet-session.d.ts +2 -0
- package/src/local-dev/fleet-session.js +28 -11
- package/src/local-dev/fleet-slice-runner-daemon.js +4 -0
- package/src/local-dev/fleet-state.d.ts +5 -2
- package/src/local-dev/fleet-state.js +25 -4
- package/src/local-dev/fleet-supervisor.d.ts +3 -0
- package/src/local-dev/fleet-supervisor.js +66 -11
- package/src/local-dev/fleet-web-start.d.ts +12 -0
- package/src/local-dev/fleet-web-start.js +48 -0
- package/src/local-dev/identity.js +3 -14
- package/src/local-dev/index.d.ts +1 -0
- package/src/local-dev/index.js +1 -0
- package/src/local-dev/native-completion.d.ts +9 -0
- package/src/local-dev/native-completion.js +130 -0
- package/src/local-dev/nx-workspace.d.ts +4 -2
- package/src/local-dev/nx-workspace.js +11 -6
- package/src/local-dev/personal-stage.d.ts +4 -5
- package/src/local-dev/personal-stage.js +6 -54
- package/src/local-dev/port-claims.d.ts +13 -0
- package/src/local-dev/port-claims.js +46 -0
- package/src/local-dev/ports.d.ts +14 -2
- package/src/local-dev/ports.js +78 -3
- package/src/local-dev/private-state.d.ts +6 -0
- package/src/local-dev/private-state.js +126 -34
- package/src/local-dev/process-group.d.ts +4 -0
- package/src/local-dev/process-group.js +29 -0
- package/src/local-dev/process-identity.d.ts +8 -0
- package/src/local-dev/process-identity.js +31 -1
- package/src/local-dev/proxy.js +11 -12
- package/src/local-dev/runtime-paths.js +1 -1
- package/src/local-dev/slice-claim.js +1 -1
- package/src/local-dev/slice-runner.d.ts +15 -6
- package/src/local-dev/slice-runner.js +189 -54
- package/src/local-dev/task-attachment.d.ts +17 -0
- package/src/local-dev/task-attachment.js +73 -0
- package/src/local-dev/task-authority.d.ts +10 -0
- package/src/local-dev/task-authority.js +27 -0
- package/src/local-dev/task-identity.d.ts +33 -0
- package/src/local-dev/task-identity.js +418 -0
- package/src/local-dev/task-native-writer.d.ts +18 -0
- package/src/local-dev/task-native-writer.js +329 -0
- package/src/local-dev/tls.js +3 -1
- package/src/local-dev/web-launch.d.ts +9 -0
- package/src/local-dev/web-launch.js +130 -0
- package/src/ownership/composition.d.ts +2 -1
- package/src/ownership/composition.js +1 -0
- package/src/performance/scenario.d.ts +22 -0
- package/src/performance/scenario.js +100 -92
- package/src/repository-policy/deployment-plan.d.ts +2 -2
- package/src/repository-policy/deployment-plan.js +2 -1
- package/src/repository-policy/policy.js +38 -3
- package/src/schemas/blueprint-v1.json +5 -4
- package/src/schemas/foundation-requirement-v1.json +5 -4
- package/src/schemas/testing-evidence-result-v1.json +1 -1
- package/src/secrets/operator.d.ts +3 -1
- package/src/secrets/operator.js +22 -3
- package/src/sst-environment-source-format.d.ts +3 -0
- package/src/sst-environment-source-format.js +20 -0
- package/src/supply-chain/blueprint-trust-git.js +13 -3
- package/src/supply-chain/build-output.js +15 -0
- package/src/supply-chain/generated-blueprint-trust-command.js +18 -1
- package/src/testing-evidence/fixture-scope.d.ts +2 -1
- package/src/testing-evidence/fixture-scope.js +4 -2
- package/src/testing-evidence/result.d.ts +2 -1
- package/src/testing-evidence/result.js +18 -4
- package/src/workload-roles/standard-slice.js +2 -3
- package/src/api-contract/baseline-update.js.map +0 -1
- package/src/api-contract/compatibility.js.map +0 -1
- package/src/api-contract/contract-graph.js.map +0 -1
- package/src/api-contract/evidence.js.map +0 -1
- package/src/api-contract/index.js.map +0 -1
- package/src/api-contract/model.fixtures.d.ts +0 -2
- package/src/api-contract/model.fixtures.js +0 -81
- package/src/api-contract/model.fixtures.js.map +0 -1
- package/src/api-contract/model.js.map +0 -1
- package/src/api-contract/rollout.js.map +0 -1
- package/src/authorization/compatibility.js.map +0 -1
- package/src/authorization/index.js.map +0 -1
- package/src/aws/child-environment.js.map +0 -1
- package/src/aws/identity.js.map +0 -1
- package/src/aws-authority/index.js.map +0 -1
- package/src/aws-authority/stage-authority.js.map +0 -1
- package/src/blueprints/execution.js.map +0 -1
- package/src/blueprints/external-sandbox.js.map +0 -1
- package/src/blueprints/index.js.map +0 -1
- package/src/blueprints/inputs.js.map +0 -1
- package/src/blueprints/manifest.js.map +0 -1
- package/src/blueprints/resolver.js.map +0 -1
- package/src/blueprints/transitions.js.map +0 -1
- package/src/cli/agent-command.js.map +0 -1
- package/src/cli/agent-runtime.js.map +0 -1
- package/src/cli/blueprint-authority.js.map +0 -1
- package/src/cli/blueprint-command.js.map +0 -1
- package/src/cli/bootstrap.js.map +0 -1
- package/src/cli/dev-command.js.map +0 -1
- package/src/cli/main.js.map +0 -1
- package/src/cli/output.js.map +0 -1
- package/src/cli/personal-secret-runtime.js.map +0 -1
- package/src/cli/secret-terminal.js.map +0 -1
- package/src/container-images.js.map +0 -1
- package/src/data-lifecycle/index.js.map +0 -1
- package/src/data-lifecycle/model.fixtures.d.ts +0 -2
- package/src/data-lifecycle/model.fixtures.js +0 -244
- package/src/data-lifecycle/model.fixtures.js.map +0 -1
- package/src/data-lifecycle/model.js.map +0 -1
- package/src/data-lifecycle/sensitive-artifacts.js.map +0 -1
- package/src/data-lifecycle/validation.js.map +0 -1
- package/src/database-retirement/contract.js.map +0 -1
- package/src/database-retirement/index.js.map +0 -1
- package/src/deterministic-order.js.map +0 -1
- package/src/developer-agent/context.js.map +0 -1
- package/src/developer-agent/generator-planning.js.map +0 -1
- package/src/developer-agent/generator-preview.js.map +0 -1
- package/src/developer-agent/git-inspection.js.map +0 -1
- package/src/developer-agent/handoff.js.map +0 -1
- package/src/developer-agent/index.js.map +0 -1
- package/src/developer-agent/model.js.map +0 -1
- package/src/developer-agent/operation-registry.js.map +0 -1
- package/src/developer-agent/ordering.js.map +0 -1
- package/src/developer-agent/planning.js.map +0 -1
- package/src/developer-agent/preview-changes.js.map +0 -1
- package/src/developer-agent/preview-source.js.map +0 -1
- package/src/developer-agent/validation.js.map +0 -1
- package/src/developer-agent/workspace-inspection.js.map +0 -1
- package/src/developer-agent/workspace-path.js.map +0 -1
- package/src/executors/blueprint-trust/blueprint-trust.js.map +0 -1
- package/src/executors/blueprint-verification/blueprint-verification.js.map +0 -1
- package/src/executors/deploy/deploy.js.map +0 -1
- package/src/executors/deployment-plan/deployment-plan.js.map +0 -1
- package/src/executors/dev/dev.js.map +0 -1
- package/src/executors/dev-doctor/dev-doctor.js.map +0 -1
- package/src/executors/dev-setup/dev-setup.js.map +0 -1
- package/src/executors/developer-context/developer-context.js.map +0 -1
- package/src/executors/fleet/fleet.js.map +0 -1
- package/src/executors/foundation-preflight/foundation-preflight.js.map +0 -1
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +0 -1
- package/src/executors/foundation-profile-preflight/production-database-safeguard.js.map +0 -1
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +0 -1
- package/src/executors/github-bootstrap/github-bootstrap.js.map +0 -1
- package/src/executors/infrastructure-plan/infrastructure-plan.js.map +0 -1
- package/src/executors/local-deploy/federated-credential-transport.js.map +0 -1
- package/src/executors/local-deploy/fixtures/local-deploy-state-machine.mjs +0 -53
- package/src/executors/local-deploy/local-approval.js.map +0 -1
- package/src/executors/local-deploy/local-deploy.js.map +0 -1
- package/src/executors/refresh/refresh.js.map +0 -1
- package/src/executors/remove/remove.js.map +0 -1
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +0 -1
- package/src/executors/secret-guardrails/secret-guardrails.js.map +0 -1
- package/src/executors/secret-initialize/secret-initialize.js.map +0 -1
- package/src/executors/secret-metadata/secret-metadata.js.map +0 -1
- package/src/executors/sst-lifecycle/generated-secret-retirement.js.map +0 -1
- package/src/executors/sst-lifecycle/governed-native-operation.js.map +0 -1
- package/src/executors/sst-lifecycle/logging-preflight.js.map +0 -1
- package/src/executors/sst-lifecycle/run-sst-command.js.map +0 -1
- package/src/executors/sst-lifecycle/secret-preflight.js.map +0 -1
- package/src/executors/sst-lifecycle/sst-environment-source.js.map +0 -1
- package/src/executors/unlock/unlock.js.map +0 -1
- package/src/executors/work-markers/work-markers.js.map +0 -1
- package/src/foundation/discovery.js.map +0 -1
- package/src/foundation/index.js.map +0 -1
- package/src/foundation/local-database-contract.js.map +0 -1
- package/src/foundation/logging-preflight.js.map +0 -1
- package/src/foundation/logging.js.map +0 -1
- package/src/foundation/partial-state.js.map +0 -1
- package/src/foundation/preflight.js.map +0 -1
- package/src/foundation/private-smoke-access.js.map +0 -1
- package/src/foundation/private-smoke-admission.js.map +0 -1
- package/src/foundation/private-smoke-control-plane.js.map +0 -1
- package/src/foundation/provision-database-bindings.js.map +0 -1
- package/src/foundation/provision-logical-database.js.map +0 -1
- package/src/foundation/requirements.js.map +0 -1
- package/src/foundation/router-origin-proof.js.map +0 -1
- package/src/foundation/router-waf-rate-rehearsal.js.map +0 -1
- package/src/foundation/router-waf.js.map +0 -1
- package/src/foundation/stages.js.map +0 -1
- package/src/frontend-security/index.js.map +0 -1
- package/src/frontend-security/security-headers.js.map +0 -1
- package/src/generators/feature-registry.js.map +0 -1
- package/src/generators/formatting.js.map +0 -1
- package/src/generators/function/function.js.map +0 -1
- package/src/generators/job/job.js.map +0 -1
- package/src/generators/logging-registry.js.map +0 -1
- package/src/generators/post-generation-install.js.map +0 -1
- package/src/generators/preset/dependency-overrides.js.map +0 -1
- package/src/generators/preset/generator.js.map +0 -1
- package/src/generators/preset/tool-versions.js.map +0 -1
- package/src/generators/preset/workspace-files-ci-acceptance.js.map +0 -1
- package/src/generators/preset/workspace-files-developer-agent.js.map +0 -1
- package/src/generators/preset/workspace-files-ecr-inspector.js.map +0 -1
- package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +0 -1
- package/src/generators/preset/workspace-files-performance-cost.js.map +0 -1
- package/src/generators/preset/workspace-files-performance-load.js.map +0 -1
- package/src/generators/preset/workspace-files-stage-authority.js.map +0 -1
- package/src/generators/preset/workspace-files-thin-deploy.js.map +0 -1
- package/src/generators/preset/workspace-files-thin-docs.js.map +0 -1
- package/src/generators/preset/workspace-files-thin-release.js.map +0 -1
- package/src/generators/preset/workspace-files-workload-role-baseline.js.map +0 -1
- package/src/generators/preset/workspace-files.js.map +0 -1
- package/src/generators/repository-policy/repository-policy.js.map +0 -1
- package/src/generators/repository-policy/tree-policy.js.map +0 -1
- package/src/generators/service/service.js.map +0 -1
- package/src/generators/slice/built-in-plan-api-contract-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-api-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-async-work-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-authorization-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-background-work-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-deletion-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-lifecycle-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-rights-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-foundation-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-frontend-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-infrastructure-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-metadata-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-operations-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-performance-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-project-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-release-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-reliability-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-shared.js.map +0 -1
- package/src/generators/slice/built-in-plan-testing-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-thin-release-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-verification-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-web-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-workload-role-files.js.map +0 -1
- package/src/generators/slice/built-in-plan.js.map +0 -1
- package/src/generators/slice/slice.js.map +0 -1
- package/src/generators/upgrade/upgrade.js.map +0 -1
- package/src/generators/workload/frozen-container.js.map +0 -1
- package/src/generators/workload/performance-registration.js.map +0 -1
- package/src/generators/workload/reliability-registration.js.map +0 -1
- package/src/generators/workload/service-performance-files.js.map +0 -1
- package/src/generators/workload/workload.js.map +0 -1
- package/src/git-policy/action-pins.js.map +0 -1
- package/src/git-policy/github-bootstrap.js.map +0 -1
- package/src/git-policy/index.js.map +0 -1
- package/src/git-policy/routing.js.map +0 -1
- package/src/index.js.map +0 -1
- package/src/infrastructure-change/convergence.js.map +0 -1
- package/src/infrastructure-change/drift.js.map +0 -1
- package/src/infrastructure-change/index.js.map +0 -1
- package/src/infrastructure-change/local-capability.js.map +0 -1
- package/src/infrastructure-change/model.js.map +0 -1
- package/src/infrastructure-change/normalize.js.map +0 -1
- package/src/infrastructure-change/plan.js.map +0 -1
- package/src/infrastructure-change/risk.js.map +0 -1
- package/src/infrastructure-change/summary.js.map +0 -1
- package/src/local-dev/context-discovery.js.map +0 -1
- package/src/local-dev/contract-validation.js.map +0 -1
- package/src/local-dev/contracts.js.map +0 -1
- package/src/local-dev/control-contract.js.map +0 -1
- package/src/local-dev/dev-command-core.js.map +0 -1
- package/src/local-dev/effects.js.map +0 -1
- package/src/local-dev/environment-inspector.js.map +0 -1
- package/src/local-dev/environment-state.js.map +0 -1
- package/src/local-dev/errors.js.map +0 -1
- package/src/local-dev/fleet-client.js.map +0 -1
- package/src/local-dev/fleet-configuration.js.map +0 -1
- package/src/local-dev/fleet-inventory.js.map +0 -1
- package/src/local-dev/fleet-ipc.js.map +0 -1
- package/src/local-dev/fleet-launcher.js.map +0 -1
- package/src/local-dev/fleet-lock.js.map +0 -1
- package/src/local-dev/fleet-logs.js.map +0 -1
- package/src/local-dev/fleet-process.js.map +0 -1
- package/src/local-dev/fleet-runtime.js.map +0 -1
- package/src/local-dev/fleet-session.js.map +0 -1
- package/src/local-dev/fleet-slice-runner-daemon.js.map +0 -1
- package/src/local-dev/fleet-startup.js.map +0 -1
- package/src/local-dev/fleet-state.js.map +0 -1
- package/src/local-dev/fleet-supervisor-daemon.js.map +0 -1
- package/src/local-dev/fleet-supervisor.js.map +0 -1
- package/src/local-dev/gateway-daemon.js.map +0 -1
- package/src/local-dev/gateway.js.map +0 -1
- package/src/local-dev/identity.js.map +0 -1
- package/src/local-dev/index.js.map +0 -1
- package/src/local-dev/local-context.js.map +0 -1
- package/src/local-dev/nx-workspace.js.map +0 -1
- package/src/local-dev/personal-secret-ledger.js.map +0 -1
- package/src/local-dev/personal-stage.js.map +0 -1
- package/src/local-dev/portless.js.map +0 -1
- package/src/local-dev/ports.js.map +0 -1
- package/src/local-dev/private-state.js.map +0 -1
- package/src/local-dev/process-identity.js.map +0 -1
- package/src/local-dev/proxy.js.map +0 -1
- package/src/local-dev/runtime-paths.js.map +0 -1
- package/src/local-dev/secret-slice-claim.js.map +0 -1
- package/src/local-dev/slice-claim.js.map +0 -1
- package/src/local-dev/slice-runner.js.map +0 -1
- package/src/local-dev/tls.js.map +0 -1
- package/src/ownership/composition.js.map +0 -1
- package/src/ownership/foundation-record.js.map +0 -1
- package/src/ownership/hash.js.map +0 -1
- package/src/ownership/index.js.map +0 -1
- package/src/ownership/json-ownership.js.map +0 -1
- package/src/ownership/record.js.map +0 -1
- package/src/ownership/workspace-record.js.map +0 -1
- package/src/performance/cost-collection.js.map +0 -1
- package/src/performance/cost-controls.js.map +0 -1
- package/src/performance/evidence.js.map +0 -1
- package/src/performance/index.js.map +0 -1
- package/src/performance/load-safety.js.map +0 -1
- package/src/performance/model.js.map +0 -1
- package/src/performance/pr-artifact-budget.js.map +0 -1
- package/src/performance/runner.js.map +0 -1
- package/src/performance/scenario-endpoint.js.map +0 -1
- package/src/performance/scenario.js.map +0 -1
- package/src/performance/test-fixtures.d.ts +0 -7
- package/src/performance/test-fixtures.js +0 -167
- package/src/performance/test-fixtures.js.map +0 -1
- package/src/performance/unit-cost.js.map +0 -1
- package/src/release/index.js.map +0 -1
- package/src/release/lifecycle.js.map +0 -1
- package/src/release/manifest.js.map +0 -1
- package/src/release/rollout.js.map +0 -1
- package/src/release/source-authority.js.map +0 -1
- package/src/repository-policy/aurora-preflight.js.map +0 -1
- package/src/repository-policy/capacity-migration.js.map +0 -1
- package/src/repository-policy/deployment-plan.js.map +0 -1
- package/src/repository-policy/foundation-profile.js.map +0 -1
- package/src/repository-policy/index.js.map +0 -1
- package/src/repository-policy/policy.js.map +0 -1
- package/src/secrets/adapters.js.map +0 -1
- package/src/secrets/aws-control-plane.js.map +0 -1
- package/src/secrets/declaration-verification.js.map +0 -1
- package/src/secrets/generated-aws-control-plane.js.map +0 -1
- package/src/secrets/guardrails.js.map +0 -1
- package/src/secrets/index.js.map +0 -1
- package/src/secrets/metadata.js.map +0 -1
- package/src/secrets/model.js.map +0 -1
- package/src/secrets/operator.js.map +0 -1
- package/src/secrets/permissions.js.map +0 -1
- package/src/secrets/personal-command.js.map +0 -1
- package/src/secrets/personal-ledger.js.map +0 -1
- package/src/secrets/registry.js.map +0 -1
- package/src/secrets/verification.js.map +0 -1
- package/src/secrets/workload-access.js.map +0 -1
- package/src/sst-environment-source-format.js.map +0 -1
- package/src/supply-chain/action-pins.js.map +0 -1
- package/src/supply-chain/blueprint-trust-git.js.map +0 -1
- package/src/supply-chain/blueprint-trust-process.js.map +0 -1
- package/src/supply-chain/blueprint-trust.js.map +0 -1
- package/src/supply-chain/blueprint-verification-authority.js.map +0 -1
- package/src/supply-chain/blueprint-verification-execution.js.map +0 -1
- package/src/supply-chain/build-output-bounds.js.map +0 -1
- package/src/supply-chain/build-output.js.map +0 -1
- package/src/supply-chain/common.js.map +0 -1
- package/src/supply-chain/container-artifact-contract.js.map +0 -1
- package/src/supply-chain/container-release.js.map +0 -1
- package/src/supply-chain/ecr-applicability.js.map +0 -1
- package/src/supply-chain/ecr-scanning.js.map +0 -1
- package/src/supply-chain/ecs-deployed-image.js.map +0 -1
- package/src/supply-chain/errors.js.map +0 -1
- package/src/supply-chain/generated-blueprint-trust-command.js.map +0 -1
- package/src/supply-chain/generated-command.js.map +0 -1
- package/src/supply-chain/generated-container-release-command.js.map +0 -1
- package/src/supply-chain/generated-ecr-collector-command.js.map +0 -1
- package/src/supply-chain/generated-files.js.map +0 -1
- package/src/supply-chain/generated-scanner-command.js.map +0 -1
- package/src/supply-chain/index.js.map +0 -1
- package/src/supply-chain/inventory.js.map +0 -1
- package/src/supply-chain/license-expression.js.map +0 -1
- package/src/supply-chain/pnpm-toolchain-authority.js.map +0 -1
- package/src/supply-chain/policy.js.map +0 -1
- package/src/supply-chain/publication.js.map +0 -1
- package/src/supply-chain/sbom.js.map +0 -1
- package/src/supply-chain/scanner.js.map +0 -1
- package/src/supply-chain/vendored-source.js.map +0 -1
- package/src/testing-evidence/fixture-scope.js.map +0 -1
- package/src/testing-evidence/index.js.map +0 -1
- package/src/testing-evidence/quarantine.js.map +0 -1
- package/src/testing-evidence/result.js.map +0 -1
- package/src/testing-evidence/runner-adapter.js.map +0 -1
- package/src/testing-evidence/sensitive-artifacts.js.map +0 -1
- package/src/validation.js.map +0 -1
- package/src/work-markers/index.js.map +0 -1
- package/src/work-markers/work-markers.js.map +0 -1
- package/src/workload-roles/account-baseline.js.map +0 -1
- package/src/workload-roles/authority.js.map +0 -1
- package/src/workload-roles/aws-adapter.js.map +0 -1
- package/src/workload-roles/aws-internal-handler.js.map +0 -1
- package/src/workload-roles/aws-s3-state.js.map +0 -1
- package/src/workload-roles/aws-sdk-control-plane.js.map +0 -1
- package/src/workload-roles/boundary.js.map +0 -1
- package/src/workload-roles/convergence.js.map +0 -1
- package/src/workload-roles/effective-policy.js.map +0 -1
- package/src/workload-roles/handler.js.map +0 -1
- package/src/workload-roles/history.js.map +0 -1
- package/src/workload-roles/index.js.map +0 -1
- package/src/workload-roles/injection.js.map +0 -1
- package/src/workload-roles/manifest.js.map +0 -1
- package/src/workload-roles/provisioner.js.map +0 -1
- package/src/workload-roles/registration.js.map +0 -1
- package/src/workload-roles/stage-boundary.js.map +0 -1
- package/src/workload-roles/standard-slice.js.map +0 -1
- package/src/workspace-deployment/affected-lifecycle.js.map +0 -1
- package/src/workspace-deployment/identity.js.map +0 -1
- package/src/workspace-deployment/index.js.map +0 -1
- package/src/workspace-deployment/migration-evidence.js.map +0 -1
- package/src/workspace-deployment/migration.js.map +0 -1
- package/src/workspace-deployment/ownership.js.map +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderKeyValueRetentionInfrastructureFiles = renderKeyValueRetentionInfrastructureFiles;
|
|
4
|
+
/** Framework retention uses native DynamoDB regardless of optional feature SQL. */
|
|
5
|
+
function renderKeyValueRetentionInfrastructureFiles(name, pascalName) {
|
|
6
|
+
return {
|
|
7
|
+
'infra/key-value-retention.ts': `export function createKeyValueRetentionInfrastructure(input: {
|
|
8
|
+
keyValue: { environment: Record<string, any>; dataPermissions: any[] };
|
|
9
|
+
workspace: string;
|
|
10
|
+
eventBusArn: any;
|
|
11
|
+
alertTopicArn: any;
|
|
12
|
+
schedule: { scheduleExpression: string; state: 'ENABLED' | 'DISABLED' };
|
|
13
|
+
scheduleName: string;
|
|
14
|
+
managedLogGroup(logicalName: string, component: string, alertTopicArn: any): any;
|
|
15
|
+
lambdaLogging(logGroupName: any): any;
|
|
16
|
+
register(stateMachineArn: any): any;
|
|
17
|
+
}) {
|
|
18
|
+
// Personal hot fleets do not create protected retention orchestration.
|
|
19
|
+
// They still exercise the native data/approval APIs.
|
|
20
|
+
if ($dev) return {};
|
|
21
|
+
const environment = { ...input.keyValue.environment, EBK_WORKSPACE: input.workspace,
|
|
22
|
+
EBK_WORKLOAD_IDENTITY: '${name}:data-retention-job' };
|
|
23
|
+
const workerLogs = input.managedLogGroup('${pascalName}DataRetentionWorkerLogs', 'job-data-retention', input.alertTopicArn);
|
|
24
|
+
const maintenanceLogs = input.managedLogGroup('${pascalName}DataRetentionMaintenanceLogs', 'job-data-retention-maintenance', input.alertTopicArn);
|
|
25
|
+
const workflowLogs = input.managedLogGroup('${pascalName}DataRetentionWorkflowLogs', 'job-data-retention-orchestration', input.alertTopicArn);
|
|
26
|
+
const worker = new sst.aws.Function('${pascalName}DataRetentionWorker', {
|
|
27
|
+
handler: 'jobs/data-retention/src/run.handler', dev: false, timeout: '5 minutes',
|
|
28
|
+
environment, permissions: [...input.keyValue.dataPermissions,
|
|
29
|
+
{ actions: ['events:PutEvents'], resources: [input.eventBusArn] }],
|
|
30
|
+
...input.lambdaLogging(workerLogs.logGroup.name),
|
|
31
|
+
});
|
|
32
|
+
const maintenance = new sst.aws.Function('${pascalName}DataRetentionMaintenance', {
|
|
33
|
+
handler: 'jobs/data-retention/src/maintenance.handler', dev: false, timeout: '5 minutes',
|
|
34
|
+
environment, permissions: input.keyValue.dataPermissions,
|
|
35
|
+
// Conditional record/run/checkpoint transactions coordinate overlap. Do
|
|
36
|
+
// not require spare account-level reserved concurrency on a fresh account.
|
|
37
|
+
...input.lambdaLogging(maintenanceLogs.logGroup.name),
|
|
38
|
+
});
|
|
39
|
+
const partition = aws.getPartitionOutput({}).partition;
|
|
40
|
+
const account = aws.getCallerIdentityOutput({}).accountId;
|
|
41
|
+
const region = aws.getRegionOutput({}).name;
|
|
42
|
+
const workflowName = '${name}-' + $app.stage + '-data-retention';
|
|
43
|
+
const workflowArn = $interpolate\`arn:\${partition}:states:\${region}:\${account}:stateMachine:\${workflowName}\`;
|
|
44
|
+
// The normal Slice-level IAM transform supplies the mandatory stage path and
|
|
45
|
+
// boundary. This runtime role invokes only this handler, not arbitrary Lambdas.
|
|
46
|
+
const role = new aws.iam.Role('${pascalName}DataRetentionRole', {
|
|
47
|
+
assumeRolePolicy: $jsonStringify({ Version: '2012-10-17', Statement: [{ Effect: 'Allow',
|
|
48
|
+
Principal: { Service: 'states.amazonaws.com' }, Action: 'sts:AssumeRole',
|
|
49
|
+
Condition: { StringEquals: { 'aws:SourceAccount': account }, ArnEquals: { 'aws:SourceArn': workflowArn } } }] }),
|
|
50
|
+
inlinePolicies: [{ name: 'runtime', policy: $jsonStringify({ Version: '2012-10-17', Statement: [
|
|
51
|
+
{ Effect: 'Allow', Action: ['lambda:InvokeFunction'], Resource: [worker.arn] },
|
|
52
|
+
// CloudWatch's log-delivery control APIs do not support resource scoping.
|
|
53
|
+
{ Effect: 'Allow', Action: ['logs:CreateLogDelivery', 'logs:GetLogDelivery', 'logs:UpdateLogDelivery',
|
|
54
|
+
'logs:DeleteLogDelivery', 'logs:ListLogDeliveries', 'logs:PutResourcePolicy', 'logs:DescribeResourcePolicies', 'logs:DescribeLogGroups'], Resource: '*' },
|
|
55
|
+
] }) }],
|
|
56
|
+
});
|
|
57
|
+
const stateMachine = new aws.sfn.StateMachine('${pascalName}DataRetention', {
|
|
58
|
+
name: workflowName, type: 'STANDARD', roleArn: role.arn,
|
|
59
|
+
loggingConfiguration: { includeExecutionData: false, level: 'ERROR', logDestination: $interpolate\`\${workflowLogs.logGroup.arn}:*\` },
|
|
60
|
+
definition: $jsonStringify({ StartAt: 'Initialize', TimeoutSeconds: 2700, States: {
|
|
61
|
+
Initialize: { Type: 'Pass', Parameters: { 'command.$': '$', attempt: 1 }, Next: 'RunDataRetention' },
|
|
62
|
+
RunDataRetention: { Type: 'Task', Resource: worker.arn, InputPath: '$.command', ResultPath: '$.page', TimeoutSeconds: 250,
|
|
63
|
+
Retry: [{ ErrorEquals: ['Lambda.ServiceException', 'Lambda.AWSLambdaException', 'Lambda.SdkClientException', 'Lambda.TooManyRequestsException'],
|
|
64
|
+
IntervalSeconds: 2, BackoffRate: 2, MaxAttempts: 2 }], Next: 'CheckCompletion' },
|
|
65
|
+
CheckCompletion: { Type: 'Choice', Choices: [
|
|
66
|
+
{ And: [{ Variable: '$.page.complete', BooleanEquals: true },
|
|
67
|
+
{ Variable: '$.page.evidence.kind', StringEquals: 'data-lifecycle-evidence' },
|
|
68
|
+
{ Variable: '$.page.evidence.outcome', StringEquals: 'succeeded' }], Next: 'DataRetentionSucceeded' },
|
|
69
|
+
{ And: [{ Variable: '$.page.complete', BooleanEquals: false },
|
|
70
|
+
{ Variable: '$.page.checkpointComplete', BooleanEquals: false },
|
|
71
|
+
{ Variable: '$.attempt', NumericLessThan: 100 }], Next: 'NextPage' },
|
|
72
|
+
], Default: 'DataRetentionFailed' },
|
|
73
|
+
NextPage: { Type: 'Pass', Parameters: { 'command.$': '$.command', 'attempt.$': 'States.MathAdd($.attempt, 1)' }, Next: 'RunDataRetention' },
|
|
74
|
+
DataRetentionSucceeded: { Type: 'Succeed', OutputPath: '$.page' },
|
|
75
|
+
DataRetentionFailed: { Type: 'Fail', Error: 'IncompleteRetention', Cause: 'Native retention did not return bounded completed evidence; inspect the retained run.' },
|
|
76
|
+
} }),
|
|
77
|
+
});
|
|
78
|
+
const registration = input.register(stateMachine.arn);
|
|
79
|
+
const failureAlarm = new aws.cloudwatch.MetricAlarm('${pascalName}DataRetentionFailure', {
|
|
80
|
+
name: '${name}-' + $app.stage + '-retention-job-failure', alarmActions: [input.alertTopicArn],
|
|
81
|
+
alarmDescription: JSON.stringify({ schemaVersion: 1, slice: '${name}', owner: '${name}-product', route: '${name}-on-call',
|
|
82
|
+
businessSymptom: 'The native retention Job terminated unsuccessfully.', id: 'retention-job-failure', runbook: 'jobs/data-retention/README.md' }),
|
|
83
|
+
comparisonOperator: 'GreaterThanOrEqualToThreshold', evaluationPeriods: 1, threshold: 1, treatMissingData: 'notBreaching',
|
|
84
|
+
metricQueries: [...['ExecutionsFailed', 'ExecutionsTimedOut', 'ExecutionsAborted'].map((metricName, index) => ({
|
|
85
|
+
id: 'm' + index, metric: { dimensions: { StateMachineArn: stateMachine.arn }, metricName, namespace: 'AWS/States', period: 60, stat: 'Sum' }, returnData: false })),
|
|
86
|
+
{ expression: 'm0+m1+m2', id: 'failures', label: 'Retention terminal execution failures', returnData: true }],
|
|
87
|
+
});
|
|
88
|
+
const rule = new aws.cloudwatch.EventRule('${pascalName}DataRetentionMaintenanceSchedule', {
|
|
89
|
+
name: input.scheduleName, ...input.schedule,
|
|
90
|
+
});
|
|
91
|
+
const permission = new aws.lambda.Permission('${pascalName}DataRetentionMaintenanceSchedulePermission', {
|
|
92
|
+
action: 'lambda:InvokeFunction', function: maintenance.arn, principal: 'events.amazonaws.com', sourceArn: rule.arn,
|
|
93
|
+
});
|
|
94
|
+
const target = new aws.cloudwatch.EventTarget('${pascalName}DataRetentionMaintenanceTarget', {
|
|
95
|
+
arn: maintenance.arn, rule: rule.name, targetId: 'DataRetentionMaintenance',
|
|
96
|
+
}, { dependsOn: [permission] });
|
|
97
|
+
return { dataRetention: { worker, workerLogs, workflowLogs, role, stateMachine, registration, failureAlarm },
|
|
98
|
+
dataRetentionMaintenance: { maintenance, maintenanceLogs, rule, permission, target } };
|
|
99
|
+
}
|
|
100
|
+
`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=built-in-plan-key-value-retention-infrastructure.js.map
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderKeyValueRetentionJobFiles = renderKeyValueRetentionJobFiles;
|
|
4
|
+
const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
|
|
5
|
+
/** Native DynamoDB retention packaging, independent of feature-owned optional SQL. */
|
|
6
|
+
function renderKeyValueRetentionJobFiles(name, runtimeVersion) {
|
|
7
|
+
return {
|
|
8
|
+
'jobs/data-retention/package.json': (0, built_in_plan_shared_js_1.json)({
|
|
9
|
+
name: `@${name}/job-data-retention`,
|
|
10
|
+
private: true,
|
|
11
|
+
type: 'module',
|
|
12
|
+
version: '0.0.0',
|
|
13
|
+
scripts: {
|
|
14
|
+
build: 'tsc -p tsconfig.build.json',
|
|
15
|
+
lint: 'eslint .',
|
|
16
|
+
test: 'vitest run',
|
|
17
|
+
typecheck: 'tsc --noEmit -p tsconfig.json',
|
|
18
|
+
verify: 'pnpm run lint && pnpm run typecheck && pnpm test && pnpm run build',
|
|
19
|
+
},
|
|
20
|
+
dependencies: {
|
|
21
|
+
'@aws-sdk/client-dynamodb': built_in_plan_shared_js_1.PRODUCT_VERSIONS.awsDynamoDb,
|
|
22
|
+
'@aws-sdk/client-eventbridge': built_in_plan_shared_js_1.PRODUCT_VERSIONS.awsEventBridge,
|
|
23
|
+
'@empire-builder-kit/runtime': runtimeVersion,
|
|
24
|
+
},
|
|
25
|
+
devDependencies: {
|
|
26
|
+
'@types/node': built_in_plan_shared_js_1.PRODUCT_VERSIONS.typesNode,
|
|
27
|
+
typescript: '~5.9.2',
|
|
28
|
+
vitest: built_in_plan_shared_js_1.PRODUCT_VERSIONS.vitest,
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
'jobs/data-retention/README.md': `# Data retention Job
|
|
32
|
+
|
|
33
|
+
The Slice's data-retention target starts its registered Step Functions workflow.
|
|
34
|
+
SST packages the native Lambda handlers from this source; no SQL connection,
|
|
35
|
+
container image, Fargate task or VPC is required for DynamoDB-default retention.
|
|
36
|
+
Adding relational storage does not move these existing records into SQL.
|
|
37
|
+
|
|
38
|
+
Run \`pnpm nx run ${name}:data-retention -- --report --stage=development\`
|
|
39
|
+
from the workspace. The launcher records the caller checkout's HEAD by default;
|
|
40
|
+
an explicitly supplied EBK_SOURCE_COMMIT must be a full commit SHA. This is
|
|
41
|
+
caller provenance, not proof of deployed code or permission to apply retention.
|
|
42
|
+
The deployed worker still requires its exact workload identity and approved run.
|
|
43
|
+
|
|
44
|
+
Report reads at most 1,000 records per invocation in consistent pages of 50.
|
|
45
|
+
It checkpoints progress across larger tables, freezes at most 10,000 selected
|
|
46
|
+
deletion candidates per report and returns a bounded run reference. Healthy
|
|
47
|
+
records do not consume that candidate limit. Each workflow execution remains
|
|
48
|
+
bounded to 100 worker attempts and 45 minutes. To continue an interrupted or
|
|
49
|
+
budget-exhausted report, use
|
|
50
|
+
\`pnpm nx run ${name}:data-retention -- --report --stage=development --run-ref=<run-uuid>\`
|
|
51
|
+
from the same source commit. The worker reloads the original selection time,
|
|
52
|
+
correlation and policy binding; the new invocation cannot expand the selection.
|
|
53
|
+
Failures print the original \`EBK_SOURCE_COMMIT=<commit>\` command binding.
|
|
54
|
+
Keep that checkout and its artifacts; setting this variable is not permission
|
|
55
|
+
to substitute different deployed code. Report replay is refused after review
|
|
56
|
+
or execution begins, so a report cannot overwrite retained apply evidence.
|
|
57
|
+
Missing, expired or changed checkpoints are refused, not restarted. Only a
|
|
58
|
+
completed report can be reviewed. A later report
|
|
59
|
+
handles any remaining due records after the approved batch is applied.
|
|
60
|
+
Reporting never deletes domain data.
|
|
61
|
+
The authenticated API requests review; apply requires a different direct human's
|
|
62
|
+
approval of that exact report. Each apply invocation handles at most 100 records.
|
|
63
|
+
The workflow continues from the persisted checkpoint until complete=true; only
|
|
64
|
+
that final result is accepted evidence. Failure preserves the same run for
|
|
65
|
+
governed retry. Changed candidates require a new report and approval.
|
|
66
|
+
|
|
67
|
+
The seeded adapter owns record selection. Keep it aligned with data/policy.json.
|
|
68
|
+
Never log raw identifiers, record content or credentials. Native deletion checks
|
|
69
|
+
holds and atomically commits the record change, audit, ledger and event intent.
|
|
70
|
+
Delivery is at least once; downstream inboxes deduplicate events.
|
|
71
|
+
An active delivery lease returns a pending checkpoint without completed apply
|
|
72
|
+
evidence. The same approved run continues after acknowledgement or lease expiry.
|
|
73
|
+
Workflow event intents retain their publication acknowledgement without TTL
|
|
74
|
+
until the matching completion receipt commits. That transaction starts the
|
|
75
|
+
ordinary seven-day delivered-intent TTL; an interrupted completion or a long
|
|
76
|
+
maintenance pause cannot discard its delivery proof. A deletion ledger alone
|
|
77
|
+
does not prove publication.
|
|
78
|
+
|
|
79
|
+
Control maintenance is independent of domain retention: its scheduled Lambda
|
|
80
|
+
checks the exact ${name}:retention-maintenance authority, active control holds,
|
|
81
|
+
400-day control retention and bounded resumable work.
|
|
82
|
+
Control-hold inspection checkpoints up to 1,000 entries per invocation; pruning
|
|
83
|
+
does not begin until that inspection completes. Each pruning pass handles at
|
|
84
|
+
most another 1,000 control records within the same time budget. Old export-rate
|
|
85
|
+
metadata is removed only after every request is outside the 400-day control
|
|
86
|
+
retention window, using an exact version check so concurrent requests survive.
|
|
87
|
+
Pending deletion completion has its own transactional work records, not a scan
|
|
88
|
+
of historical approvals. Its stored authorization can finish an already-committed
|
|
89
|
+
deletion after a policy update; starting a deletion still requires current policy.
|
|
90
|
+
Completion failures retain content-free failure markers and fail the worker;
|
|
91
|
+
inspect those pending records and retry reconciliation, never erase them as
|
|
92
|
+
ordinary historical metadata.
|
|
93
|
+
Explicit pauses/cadence in operations/background-work.json survive generation. Database capacity does not
|
|
94
|
+
silently enable or disable this work. Incomplete maintenance is not success and
|
|
95
|
+
continues from its checkpoint on the next enabled scheduled invocation.
|
|
96
|
+
|
|
97
|
+
Run this project's test/typecheck/build for an affected worker edit. These checks
|
|
98
|
+
do not replace the generated adopter's fleet, AWS or release acceptance.
|
|
99
|
+
`,
|
|
100
|
+
'jobs/data-retention/src/retention-contract.spec.ts': `import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
101
|
+
import { selectRetentionCandidate } from './adapter.js';
|
|
102
|
+
import { authorizeRetentionMaintenance } from './maintenance.js';
|
|
103
|
+
import { authorizeRetentionOperation } from './run.js';
|
|
104
|
+
import { runNativeRetention } from '../../../data/retention-worker.js';
|
|
105
|
+
import { RETENTION_DAYS } from '../../../data/retention-state.js';
|
|
106
|
+
import { productRecordReference } from '../../../data/pseudonymous-reference.js';
|
|
107
|
+
|
|
108
|
+
// Refusal tests must finish before any provider request, even with valid table configuration.
|
|
109
|
+
const io = vi.hoisted(() => ({ dataStore: vi.fn(() => { throw new Error('Unexpected provider access'); }) }));
|
|
110
|
+
vi.mock('../../../data/key-value.js', () => io);
|
|
111
|
+
const recordId = '11111111-1111-4111-8111-111111111111';
|
|
112
|
+
const runId = '22222222-2222-4222-8222-222222222222';
|
|
113
|
+
const at = '2026-09-12T12:00:00.000Z';
|
|
114
|
+
const dueAt = new Date(Date.parse(at) + RETENTION_DAYS * 86_400_000).toISOString();
|
|
115
|
+
const row = { id: recordId, version: 1, value: { id: recordId, name: 'fixture', ownerId: 'owner',
|
|
116
|
+
runScope: 'retention-test', createdAt: at, lastActivityAt: at, testExpiresAt: null } };
|
|
117
|
+
function identity() {
|
|
118
|
+
vi.stubEnv('EBK_STAGE', 'development-task-fixture');
|
|
119
|
+
vi.stubEnv('EBK_WORKLOAD_IDENTITY', '${name}:data-retention-job');
|
|
120
|
+
}
|
|
121
|
+
afterEach(() => { vi.unstubAllEnvs(); vi.clearAllMocks(); });
|
|
122
|
+
describe('native retention contract', () => {
|
|
123
|
+
it('selects due records by last activity, with exact identity and version', () => {
|
|
124
|
+
expect(selectRetentionCandidate(row, at)).toBeNull();
|
|
125
|
+
expect(selectRetentionCandidate(row, dueAt)).toEqual({ categoryId: 'product-record', locationId: 'primary-database',
|
|
126
|
+
recordId, recordVersion: 1, recordRef: productRecordReference(recordId), dueAt });
|
|
127
|
+
});
|
|
128
|
+
it('keeps test-run records in the separate protected cleanup path', () => {
|
|
129
|
+
expect(selectRetentionCandidate({ ...row, value: { ...row.value, testExpiresAt: dueAt } }, dueAt)).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
it('refuses malformed or substituted record identity', () => {
|
|
132
|
+
expect(() => selectRetentionCandidate({ ...row, id: 'different' }, dueAt)).toThrow();
|
|
133
|
+
});
|
|
134
|
+
it('authorizes report, apply and maintenance as the exact generated machine workload', async () => {
|
|
135
|
+
identity();
|
|
136
|
+
for (const mode of ['report', 'apply'] as const) {
|
|
137
|
+
const principal = await authorizeRetentionOperation(mode, at, runId);
|
|
138
|
+
expect(principal.actor.id).toBe('${name}:data-retention-job');
|
|
139
|
+
}
|
|
140
|
+
expect((await authorizeRetentionMaintenance(at)).actor.id).toBe('${name}:data-retention-job');
|
|
141
|
+
expect(io.dataStore).not.toHaveBeenCalled();
|
|
142
|
+
});
|
|
143
|
+
it('rejects a substituted workload before provider access', async () => {
|
|
144
|
+
identity(); vi.stubEnv('EBK_WORKLOAD_IDENTITY', 'other:data-retention-job');
|
|
145
|
+
await expect(authorizeRetentionOperation('report', at, runId)).rejects.toThrow();
|
|
146
|
+
await expect(authorizeRetentionMaintenance(at)).rejects.toThrow();
|
|
147
|
+
expect(io.dataStore).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
it.each(['stage', 'sourceCommit', 'slice', 'approvalRequestId'] as const)('rejects a mismatched %s before provider access', async (field) => {
|
|
150
|
+
identity();
|
|
151
|
+
const command = { mode: 'report' as const, runId, approvalRequestId: '', asOf: at, correlationId: runId,
|
|
152
|
+
slice: '${name}', stage: 'development-task-fixture', sourceCommit: 'a'.repeat(40), [field]: 'invalid' };
|
|
153
|
+
await expect(runNativeRetention(command)).rejects.toThrow();
|
|
154
|
+
expect(io.dataStore).not.toHaveBeenCalled();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=built-in-plan-key-value-retention-job-files.js.map
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderKeyValueRetentionMaintenanceFiles = renderKeyValueRetentionMaintenanceFiles;
|
|
4
|
+
const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
|
|
5
|
+
/** Control retention is independent of domain retention, database choice and schedule cadence. */
|
|
6
|
+
function renderKeyValueRetentionMaintenanceFiles(name, pascalName) {
|
|
7
|
+
const prefix = (0, built_in_plan_shared_js_1.lowerCamelIdentifier)(pascalName);
|
|
8
|
+
return {
|
|
9
|
+
'jobs/data-retention/src/maintenance.ts': `import { randomUUID } from 'node:crypto';
|
|
10
|
+
import {
|
|
11
|
+
createAuthorizationEvaluator, defineCoarseAdmission, digestApprovalRequest, expireApprovalRequest,
|
|
12
|
+
toAuthorizationAuditRecord, type ApprovalRequest, type AuthorizationPrincipal,
|
|
13
|
+
} from '@empire-builder-kit/runtime/authorization';
|
|
14
|
+
import {
|
|
15
|
+
evaluateDataLifecycleHolds, normalizeDataLifecycleRuntimeHold, parseDataLifecycleChangeEvent, DATA_LIFECYCLE_SAFE_REFERENCE_PATTERN,
|
|
16
|
+
transitionDataLifecycleDeletion, type DataLifecycleDeletionRequestV1, type DataLifecycleRuntimeHoldV1,
|
|
17
|
+
} from '@empire-builder-kit/runtime/data-lifecycle';
|
|
18
|
+
import type { KeyValueChange, KeyValueRecord } from '@empire-builder-kit/runtime/key-value';
|
|
19
|
+
import { createLogger } from '@empire-builder-kit/runtime/logging';
|
|
20
|
+
import { ${prefix}AuthorizationActions, ${prefix}AuthorizationPolicy } from '../../../authorization/policy.js';
|
|
21
|
+
import { dataStore } from '../../../data/key-value.js';
|
|
22
|
+
import { canonicalDataRightsNow, dataRightsSubjectReference, plusDataRightsDays } from '../../../data/data-rights-shared.js';
|
|
23
|
+
import { ${pascalName}ControlMetadataRuntimePolicy } from '../../../data/runtime-policy.cjs';
|
|
24
|
+
import { requireRetainedRetentionPlan, retentionApprovalInput, retentionStage, RETENTION_RUNS, type RetentionRun } from '../../../data/retention-state.js';
|
|
25
|
+
|
|
26
|
+
const TENANT = 'application';
|
|
27
|
+
const WORKLOAD = '${name}:data-retention-job';
|
|
28
|
+
const CHECKPOINTS = 'data-maintenance-checkpoints';
|
|
29
|
+
const CHECKPOINT = 'lifecycle-control';
|
|
30
|
+
const COLLECTIONS = [
|
|
31
|
+
'authorization-audit', 'data-lifecycle-audit', 'data-lifecycle-ledger',
|
|
32
|
+
'record-deletions', 'record-exports', 'delegation-grants', 'approval-requests',
|
|
33
|
+
'data-lifecycle-holds', 'record-mutations', 'data-retention-receipts',
|
|
34
|
+
'data-retention-candidates', 'data-retention-executions', 'data-retention-snapshots', RETENTION_RUNS,
|
|
35
|
+
'data-lifecycle-downstream-copies', 'data-lifecycle-receipts', 'export-rate',
|
|
36
|
+
] as const;
|
|
37
|
+
type Collection = typeof COLLECTIONS[number];
|
|
38
|
+
type Row = KeyValueRecord & { id: string };
|
|
39
|
+
type Value = Record<string, unknown>;
|
|
40
|
+
interface Checkpoint { schemaVersion: 1; collection: number; afterId: string | null }
|
|
41
|
+
function object(value: unknown): Value {
|
|
42
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Control metadata is malformed.');
|
|
43
|
+
return value as Value;
|
|
44
|
+
}
|
|
45
|
+
function timestamp(value: unknown): string {
|
|
46
|
+
if (typeof value !== 'string') throw new Error('Control metadata timestamp is missing.');
|
|
47
|
+
return canonicalDataRightsNow(value);
|
|
48
|
+
}
|
|
49
|
+
function past(value: unknown, at: string, days = 0): boolean {
|
|
50
|
+
return plusDataRightsDays(timestamp(value), days) <= at;
|
|
51
|
+
}
|
|
52
|
+
function approval(value: unknown, id: string): ApprovalRequest {
|
|
53
|
+
const result = object(value) as unknown as ApprovalRequest;
|
|
54
|
+
if (result.schemaVersion !== 1 || result.id !== id || result.slice !== '${name}' ||
|
|
55
|
+
!Number.isSafeInteger(result.revision) || result.revision < 0 ||
|
|
56
|
+
!['pending', 'approved', 'executing', 'executed', 'expired', 'rejected'].includes(result.status))
|
|
57
|
+
throw new Error('Control approval does not match its stored identity.');
|
|
58
|
+
timestamp(result.requestedAt); timestamp(result.expiresAt);
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
const remove = (collection: Collection, row: Row): KeyValueChange => ({ action: 'delete', collection, id: row.id, expectedVersion: row.version });
|
|
62
|
+
const check = (collection: string, id: string, version: number): KeyValueChange => ({ action: 'check', collection, id, expectedVersion: version });
|
|
63
|
+
const put = (collection: string, row: Row, value: unknown): KeyValueChange => ({ action: 'put', collection, id: row.id, expectedVersion: row.version, value });
|
|
64
|
+
|
|
65
|
+
export async function authorizeRetentionMaintenance(at: string): Promise<AuthorizationPrincipal> {
|
|
66
|
+
timestamp(at); retentionStage();
|
|
67
|
+
if (process.env.EBK_WORKLOAD_IDENTITY !== WORKLOAD) throw new Error('Retention maintenance workload identity is invalid.');
|
|
68
|
+
const principal: AuthorizationPrincipal = { actor: { id: WORKLOAD, type: 'service' }, audience: WORKLOAD,
|
|
69
|
+
authority: { machineIdentityId: WORKLOAD, mode: 'machine' }, kind: 'agent', roles: [], scopes: [], subject: { id: WORKLOAD, type: 'service' } };
|
|
70
|
+
await createAuthorizationEvaluator({ admission: defineCoarseAdmission({ anyOf: [{ kinds: ['agent'], subjectTypes: ['service'] }] }),
|
|
71
|
+
policy: ${prefix}AuthorizationPolicy, requiredPolicyVersion: ${prefix}AuthorizationPolicy.version }).authorize({
|
|
72
|
+
action: ${prefix}AuthorizationActions.retentionMaintenance,
|
|
73
|
+
context: { facts: { operationId: CHECKPOINT }, now: at, stage: retentionStage() }, principal,
|
|
74
|
+
resource: { attributes: { collection: true }, type: 'slice' },
|
|
75
|
+
});
|
|
76
|
+
return principal;
|
|
77
|
+
}
|
|
78
|
+
function declaredHolds(holds: readonly DataLifecycleRuntimeHoldV1[], at: string) {
|
|
79
|
+
// Native record-hold commands own product-record holds. Control-metadata
|
|
80
|
+
// holds are explicit policy declarations, not inferred from domain ownership.
|
|
81
|
+
for (const hold of holds) {
|
|
82
|
+
if (hold.categoryId !== 'lifecycle-control-metadata') continue;
|
|
83
|
+
if (evaluateDataLifecycleHolds({ categoryId: hold.categoryId, holds: [hold], now: at,
|
|
84
|
+
operation: 'deletion', scopeRef: hold.scopeRef }).blocked)
|
|
85
|
+
throw new Error('Retention maintenance is blocked by an active control-metadata hold.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function terminalRun(runId: string, at: string) {
|
|
89
|
+
const row = await dataStore().get(TENANT, RETENTION_RUNS, runId);
|
|
90
|
+
if (!row) return null;
|
|
91
|
+
const value = object(row.value) as unknown as RetentionRun;
|
|
92
|
+
if (value.kind !== 'data-retention-run' || value.schemaVersion !== 1 || value.slice !== '${name}' || value.stage !== retentionStage())
|
|
93
|
+
throw new Error('Retention metadata belongs to a different Slice or stage.');
|
|
94
|
+
requireRetainedRetentionPlan(value.plan, runId);
|
|
95
|
+
if (!['reported', 'completed', 'approval-pending', 'approval-approved', 'approval-rejected', 'expired', 'applying', 'retry-required'].includes(value.status))
|
|
96
|
+
throw new Error('Retention metadata status is invalid.');
|
|
97
|
+
const expected = { reported: null, completed: 'executed', 'approval-pending': 'pending', 'approval-approved': 'approved',
|
|
98
|
+
'approval-rejected': 'rejected', expired: 'expired', applying: 'executing', 'retry-required': 'executing' };
|
|
99
|
+
if ((value.approval?.status ?? null) !== expected[value.status] || value.approval &&
|
|
100
|
+
(value.approval.requestDigest !== digestApprovalRequest(retentionApprovalInput(value.plan)) || value.approval.resource.id !== runId))
|
|
101
|
+
throw new Error('Retention metadata approval binding is invalid.');
|
|
102
|
+
if (value.expiresAt !== plusDataRightsDays(timestamp(value.createdAt), 400)) throw new Error('Retention metadata expiry is invalid.');
|
|
103
|
+
const eligible = past(value.expiresAt, at) && ['reported', 'completed', 'approval-rejected', 'expired'].includes(value.status);
|
|
104
|
+
if (value.status === 'completed' && (value.approval?.status !== 'executed' || !value.approval.execution?.completedAt))
|
|
105
|
+
throw new Error('Retention completion metadata is inconsistent.');
|
|
106
|
+
return { row: { ...row, id: runId }, value, eligible };
|
|
107
|
+
}
|
|
108
|
+
async function hasRunChild(collection: 'data-retention-candidates' | 'data-retention-receipts', runId: string) {
|
|
109
|
+
const page = await dataStore().list(TENANT, collection, { limit: 1, afterId: runId });
|
|
110
|
+
return page.records[0]?.id.startsWith(runId + ':') ?? false;
|
|
111
|
+
}
|
|
112
|
+
/** Returns only conditional control-record changes; never domain or external-object effects. */
|
|
113
|
+
async function changesFor(collection: Collection, row: Row, at: string): Promise<KeyValueChange[]> {
|
|
114
|
+
const value = object(row.value), store = dataStore();
|
|
115
|
+
switch (collection) {
|
|
116
|
+
case 'export-rate': {
|
|
117
|
+
if (!Array.isArray(value.requestedAt) || value.requestedAt.length > 100 ||
|
|
118
|
+
value.requestedAt.some(at => typeof at !== 'string')) throw new Error('Export rate metadata is malformed.');
|
|
119
|
+
// Version-bound deletion cannot erase a concurrently renewed limiter.
|
|
120
|
+
return value.requestedAt.every(requestedAt => past(requestedAt, at, 400)) ? [remove(collection, row)] : [];
|
|
121
|
+
}
|
|
122
|
+
case 'data-lifecycle-receipts': {
|
|
123
|
+
const { expiresAt, ...event } = value;
|
|
124
|
+
const retained = parseDataLifecycleChangeEvent(event);
|
|
125
|
+
if (retained.categoryId !== 'product-record' || expiresAt !== plusDataRightsDays(retained.occurredAt, 400))
|
|
126
|
+
throw new Error('Lifecycle receipt scope or expiry differs.');
|
|
127
|
+
return past(expiresAt, at) ? [remove(collection, row)] : [];
|
|
128
|
+
}
|
|
129
|
+
case 'data-lifecycle-downstream-copies': {
|
|
130
|
+
if (value.copyId !== '${name}-lifecycle-consumer' || value.recipient !== '${name}' ||
|
|
131
|
+
value.purpose !== 'lifecycle-reconciliation' || typeof value.sourceSlice !== 'string' ||
|
|
132
|
+
!/^[a-z][a-z0-9-]{0,62}$/.test(value.sourceSlice) || typeof value.pseudonymousKey !== 'string' ||
|
|
133
|
+
!DATA_LIFECYCLE_SAFE_REFERENCE_PATTERN.test(value.pseudonymousKey) || !['correction', 'deletion'].includes(String(value.action)) ||
|
|
134
|
+
value.status !== (value.action === 'deletion' ? 'deleted' : 'reconciled') ||
|
|
135
|
+
!Array.isArray(value.holdRefs) || value.holdRefs.some(ref => typeof ref !== 'string' || !ref) ||
|
|
136
|
+
value.expiresAt !== plusDataRightsDays(timestamp(value.updatedAt), 400))
|
|
137
|
+
throw new Error('Lifecycle downstream copy scope or expiry differs.');
|
|
138
|
+
return value.holdRefs.length === 0 && past(value.expiresAt, at) ? [remove(collection, row)] : [];
|
|
139
|
+
}
|
|
140
|
+
case 'authorization-audit':
|
|
141
|
+
if (value.slice !== '${name}' || value.stage !== retentionStage()) throw new Error('Authorization audit scope differs.');
|
|
142
|
+
return past(value.timestamp, at, 400) ? [remove(collection, row)] : [];
|
|
143
|
+
case 'data-lifecycle-audit':
|
|
144
|
+
if (value.slice !== '${name}' || value.stage !== retentionStage() || value.expiresAt !== plusDataRightsDays(timestamp(object(value.audit).timestamp), 400))
|
|
145
|
+
throw new Error('Lifecycle audit scope or expiry differs.');
|
|
146
|
+
return past(value.expiresAt, at) ? [remove(collection, row)] : [];
|
|
147
|
+
case 'data-lifecycle-ledger':
|
|
148
|
+
if (value.expiresAt !== plusDataRightsDays(timestamp(value.effectiveAt), 400)) throw new Error('Lifecycle ledger expiry differs.');
|
|
149
|
+
return past(value.expiresAt, at) ? [remove(collection, row)] : [];
|
|
150
|
+
case 'record-mutations':
|
|
151
|
+
// Pending outbox records have no TTL and are owned by the dispatcher.
|
|
152
|
+
// This is only bounded, content-free API retry metadata.
|
|
153
|
+
if (value.expiresAt !== plusDataRightsDays(timestamp(value.occurredAt), 400)) throw new Error('Record retry expiry differs.');
|
|
154
|
+
return past(value.expiresAt, at) ? [remove(collection, row)] : [];
|
|
155
|
+
case 'delegation-grants': {
|
|
156
|
+
if (value.id !== row.id || value.slice !== '${name}' || row.version !== Number(value.revision) + 1) throw new Error('Delegation metadata identity differs.');
|
|
157
|
+
return past(value.expiresAt, at) && past(value.issuedAt, at, 400) ? [remove(collection, row)] : [];
|
|
158
|
+
}
|
|
159
|
+
case 'approval-requests': {
|
|
160
|
+
const current = approval(value, row.id);
|
|
161
|
+
if (row.version !== current.revision + 1) throw new Error('Approval metadata revision differs.');
|
|
162
|
+
const expired = expireApprovalRequest(current, at);
|
|
163
|
+
if (expired !== current) return [put(collection, row, expired)];
|
|
164
|
+
return current.status !== 'executing' && past(current.expiresAt, at, 400) ? [remove(collection, row)] : [];
|
|
165
|
+
}
|
|
166
|
+
case 'data-lifecycle-holds': {
|
|
167
|
+
const hold = normalizeDataLifecycleRuntimeHold(value as unknown as DataLifecycleRuntimeHoldV1, 0);
|
|
168
|
+
if (hold.holdId !== row.id) throw new Error('Hold metadata identity differs.');
|
|
169
|
+
if (hold.categoryId !== 'product-record') throw new Error('Stored control holds are unsupported; declare control-metadata holds in data/policy.json.');
|
|
170
|
+
return hold.status === 'released' && past(hold.expiresAt, at, 400) ? [remove(collection, row)] : [];
|
|
171
|
+
}
|
|
172
|
+
case 'record-deletions': {
|
|
173
|
+
const current = approval(value.approval, row.id);
|
|
174
|
+
const lifecycle = object(value.lifecycle) as unknown as DataLifecycleDeletionRequestV1;
|
|
175
|
+
if (value.kind !== 'record-deletion' || value.schemaVersion !== 1 || current.action !== '${name}:record-delete' || lifecycle.kind !== 'data-deletion')
|
|
176
|
+
throw new Error('Deletion control identity differs.');
|
|
177
|
+
const expired = expireApprovalRequest(current, at);
|
|
178
|
+
if (expired !== current) {
|
|
179
|
+
if (!['requested', 'verified', 'held'].includes(lifecycle.status)) throw new Error('Unstarted deletion approval has active effects.');
|
|
180
|
+
return [put(collection, row, { ...value, approval: expired,
|
|
181
|
+
lifecycle: transitionDataLifecycleDeletion(lifecycle, { type: 'reject', at, reasonCode: 'approval-expired' }) })];
|
|
182
|
+
}
|
|
183
|
+
const terminal = ['expired', 'rejected'].includes(current.status) && lifecycle.status === 'rejected' ||
|
|
184
|
+
current.status === 'executed' && lifecycle.status === 'completed' && lifecycle.primaryStatus === 'completed' && lifecycle.downstreamCopies.every(copy => copy.status === 'completed');
|
|
185
|
+
return terminal && past(lifecycle.updatedAt, at, 400) ? [remove(collection, row)] : [];
|
|
186
|
+
}
|
|
187
|
+
case 'record-exports': {
|
|
188
|
+
// The dedicated export cleanup owns object/version deletion, approval
|
|
189
|
+
// expiry and the outstanding-capacity binding. Never bypass that worker.
|
|
190
|
+
const current = approval(value.approval, row.id), lifecycle = object(value.lifecycle);
|
|
191
|
+
if (value.kind !== 'record-export' || value.schemaVersion !== 1 || current.action !== '${name}:record-export' || lifecycle.kind !== 'data-export')
|
|
192
|
+
throw new Error('Export control identity differs.');
|
|
193
|
+
if (value.cleanupState !== 'completed' || !['completed', 'rejected'].includes(String(lifecycle.status)) || !past(lifecycle.updatedAt, at, 400)) return [];
|
|
194
|
+
if (!Array.isArray(value.versions) || value.versions.length !== 0 || !['executed', 'expired', 'rejected'].includes(current.status))
|
|
195
|
+
throw new Error('Export control lacks completed cleanup evidence.');
|
|
196
|
+
const capacity = await store.get(TENANT, 'export-capacity', 'outstanding');
|
|
197
|
+
const ids = capacity ? object(capacity.value).ids : [];
|
|
198
|
+
if (!Array.isArray(ids)) throw new Error('Export capacity metadata is invalid.');
|
|
199
|
+
if (ids.includes(row.id)) return [];
|
|
200
|
+
return [check('export-capacity', 'outstanding', capacity?.version ?? 0), remove(collection, row)];
|
|
201
|
+
}
|
|
202
|
+
case 'data-retention-receipts': {
|
|
203
|
+
if (value.kind !== 'retention-receipt' || typeof value.eventId !== 'string' || row.id !== value.runId + ':' + value.eventId || typeof value.runId !== 'string' ||
|
|
204
|
+
value.expiresAt !== plusDataRightsDays(timestamp(value.appliedAt), 400)) throw new Error('Retention receipt binding differs.');
|
|
205
|
+
if (!past(value.expiresAt, at)) return [];
|
|
206
|
+
const retained = await terminalRun(value.runId, at);
|
|
207
|
+
if (!retained?.eligible || retained.value.status !== 'completed') return [];
|
|
208
|
+
if (value.publishedAt === null) throw new Error('Completed retention run retains unpublished delivery.');
|
|
209
|
+
if (!past(value.publishedAt, at)) throw new Error('Retention publication time is invalid.');
|
|
210
|
+
if (value.planDigest !== digestApprovalRequest(retentionApprovalInput(retained.value.plan))) throw new Error('Retention receipt plan binding differs.');
|
|
211
|
+
return [check(RETENTION_RUNS, value.runId, retained.row.version), remove(collection, row)];
|
|
212
|
+
}
|
|
213
|
+
case 'data-retention-candidates': {
|
|
214
|
+
if (typeof value.runId !== 'string' || value.slice !== '${name}' || value.stage !== retentionStage() || !row.id.startsWith(value.runId + ':'))
|
|
215
|
+
throw new Error('Retention candidate metadata scope differs.');
|
|
216
|
+
if (!past(value.expiresAt, at)) return [];
|
|
217
|
+
const retained = await terminalRun(value.runId, at);
|
|
218
|
+
if (retained) return retained.eligible && !await hasRunChild('data-retention-receipts', value.runId)
|
|
219
|
+
? [check(RETENTION_RUNS, value.runId, retained.row.version), remove(collection, row)] : [];
|
|
220
|
+
const snapshot = await store.get(TENANT, 'data-retention-snapshots', value.runId);
|
|
221
|
+
const building = snapshot ? object(snapshot.value) : null;
|
|
222
|
+
if (!snapshot || building?.status !== 'building') return [];
|
|
223
|
+
if (building.kind !== 'retention-snapshot' || building.runId !== value.runId || building.slice !== '${name}' || building.stage !== retentionStage() ||
|
|
224
|
+
building.expiresAt !== plusDataRightsDays(timestamp(building.createdAt), 400) || value.expiresAt !== building.expiresAt)
|
|
225
|
+
throw new Error('Unfinished retention snapshot binding differs.');
|
|
226
|
+
if (!past(building.expiresAt, at)) return [];
|
|
227
|
+
return [check(RETENTION_RUNS, value.runId, 0), check('data-retention-snapshots', value.runId, snapshot.version), remove(collection, row)];
|
|
228
|
+
}
|
|
229
|
+
case 'data-retention-executions': {
|
|
230
|
+
if (value.kind !== 'retention-execution' || value.runId !== row.id) throw new Error('Retention execution identity differs.');
|
|
231
|
+
const retained = await terminalRun(row.id, at);
|
|
232
|
+
if (!retained?.eligible || retained.value.status !== 'completed' || await hasRunChild('data-retention-receipts', row.id)) return [];
|
|
233
|
+
if (value.completedAt !== retained.value.approval?.execution?.completedAt || object(value.checkpoint).complete !== true ||
|
|
234
|
+
value.planDigest !== digestApprovalRequest(retentionApprovalInput(retained.value.plan)) || value.approvalId !== retained.value.approval?.id)
|
|
235
|
+
throw new Error('Retention execution lacks final completion evidence.');
|
|
236
|
+
return [check(RETENTION_RUNS, row.id, retained.row.version), remove(collection, row)];
|
|
237
|
+
}
|
|
238
|
+
case 'data-retention-snapshots': {
|
|
239
|
+
if (value.kind !== 'retention-snapshot' || value.runId !== row.id || value.stage !== retentionStage() || value.slice !== '${name}' ||
|
|
240
|
+
value.expiresAt !== plusDataRightsDays(timestamp(value.createdAt), 400)) throw new Error('Retention snapshot scope or expiry differs.');
|
|
241
|
+
if (!past(value.expiresAt, at) || await hasRunChild('data-retention-candidates', row.id) || await hasRunChild('data-retention-receipts', row.id)) return [];
|
|
242
|
+
const retained = await terminalRun(row.id, at);
|
|
243
|
+
if (retained ? !retained.eligible : value.status !== 'building') return [];
|
|
244
|
+
return [check(RETENTION_RUNS, row.id, retained?.row.version ?? 0), remove(collection, row)];
|
|
245
|
+
}
|
|
246
|
+
case RETENTION_RUNS: {
|
|
247
|
+
const retained = await terminalRun(row.id, at);
|
|
248
|
+
if (!retained || retained.row.version !== row.version) throw new Error('Retention run changed during maintenance.');
|
|
249
|
+
const current = retained.value.approval;
|
|
250
|
+
if (current && ['approval-pending', 'approval-approved'].includes(retained.value.status)) {
|
|
251
|
+
const expired = expireApprovalRequest(approval(current, current.id), at);
|
|
252
|
+
if (expired !== current) return [put(collection, row, { ...retained.value, approval: expired, status: 'expired', updatedAt: at })];
|
|
253
|
+
}
|
|
254
|
+
if (!retained.eligible || await hasRunChild('data-retention-candidates', row.id) || await hasRunChild('data-retention-receipts', row.id)) return [];
|
|
255
|
+
const execution = await store.get(TENANT, 'data-retention-executions', row.id);
|
|
256
|
+
const snapshot = await store.get(TENANT, 'data-retention-snapshots', row.id);
|
|
257
|
+
if (execution || snapshot) return [];
|
|
258
|
+
return [check('data-retention-executions', row.id, 0), check('data-retention-snapshots', row.id, 0), remove(collection, row)];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export async function runRetentionMaintenance(options: { budgetMs?: number; maxItems?: number } = {}) {
|
|
264
|
+
const at = new Date().toISOString();
|
|
265
|
+
const principal = await authorizeRetentionMaintenance(at);
|
|
266
|
+
const budget = options.budgetMs ?? 240_000, maximum = options.maxItems ?? 1000;
|
|
267
|
+
if (!Number.isSafeInteger(budget) || budget < 1 || budget > 240_000 || !Number.isSafeInteger(maximum) || maximum < 1 || maximum > 1000)
|
|
268
|
+
throw new Error('Retention maintenance requires bounded work.');
|
|
269
|
+
const deadline = Date.now() + budget, store = dataStore();
|
|
270
|
+
declaredHolds(${pascalName}ControlMetadataRuntimePolicy.declaredHolds, at);
|
|
271
|
+
const loaded = await store.get(TENANT, CHECKPOINTS, CHECKPOINT);
|
|
272
|
+
let version = loaded?.version ?? 0;
|
|
273
|
+
let cursor: Checkpoint = loaded ? object(loaded.value) as unknown as Checkpoint : { schemaVersion: 1, collection: 0, afterId: null };
|
|
274
|
+
if (cursor.schemaVersion !== 1 || !Number.isInteger(cursor.collection) || cursor.collection < 0 || cursor.collection >= COLLECTIONS.length ||
|
|
275
|
+
(cursor.afterId !== null && (typeof cursor.afterId !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(cursor.afterId))))
|
|
276
|
+
throw new Error('Retention maintenance checkpoint is invalid.');
|
|
277
|
+
const invocation = randomUUID();
|
|
278
|
+
const audit = toAuthorizationAuditRecord({ action: ${prefix}AuthorizationActions.retentionMaintenance,
|
|
279
|
+
context: { facts: { operationId: CHECKPOINT }, now: at, stage: retentionStage() }, principal, resource: { attributes: { collection: true }, type: 'slice' } },
|
|
280
|
+
{ decision: 'allow', obligations: [], policyVersion: ${prefix}AuthorizationPolicy.version },
|
|
281
|
+
{ correlationId: invocation, pseudonymousSubjectId: dataRightsSubjectReference(WORKLOAD), slice: '${name}', stage: retentionStage(), timestamp: at });
|
|
282
|
+
await store.commit({ tenantId: TENANT, changes: [
|
|
283
|
+
{ action: 'put', collection: CHECKPOINTS, id: CHECKPOINT, expectedVersion: version, value: cursor },
|
|
284
|
+
{ action: 'put', collection: 'authorization-audit', id: invocation, expectedVersion: 0, value: audit },
|
|
285
|
+
] }); version++;
|
|
286
|
+
// The committed policy above is the complete control-hold authority for this
|
|
287
|
+
// deployment, on every invocation and regardless of cursor. Record-hold APIs
|
|
288
|
+
// cannot create control holds. Their history is pruned below, not scanned as
|
|
289
|
+
// a mutable global authority snapshot before unrelated control work.
|
|
290
|
+
let scanned = 0, deleted = 0, reconciled = 0, complete = false;
|
|
291
|
+
while (scanned < maximum && Date.now() < deadline) {
|
|
292
|
+
const collection = COLLECTIONS[cursor.collection];
|
|
293
|
+
const page = await store.list(TENANT, collection, { limit: Math.min(50, maximum - scanned), ...(cursor.afterId ? { afterId: cursor.afterId } : {}) });
|
|
294
|
+
let afterId = cursor.afterId;
|
|
295
|
+
for (const row of page.records) {
|
|
296
|
+
if (Date.now() >= deadline) break;
|
|
297
|
+
if (afterId && row.id <= afterId) throw new Error('Control inventory did not advance.');
|
|
298
|
+
const changes = await changesFor(collection, row, at);
|
|
299
|
+
if (changes.length) {
|
|
300
|
+
await store.commit({ tenantId: TENANT, changes: [check(CHECKPOINTS, CHECKPOINT, version), ...changes] });
|
|
301
|
+
deleted += changes.filter(change => change.action === 'delete').length;
|
|
302
|
+
reconciled += changes.filter(change => change.action === 'put').length;
|
|
303
|
+
}
|
|
304
|
+
afterId = row.id; scanned++;
|
|
305
|
+
}
|
|
306
|
+
const consumed = page.records.length === 0 || afterId === page.records.at(-1)?.id;
|
|
307
|
+
if (page.nextId && (page.records.length === 0 || page.nextId !== page.records.at(-1)?.id)) throw new Error('Control inventory cursor is invalid.');
|
|
308
|
+
if (consumed && !page.nextId) {
|
|
309
|
+
if (cursor.collection + 1 === COLLECTIONS.length) { cursor = { schemaVersion: 1, collection: 0, afterId: null }; complete = true; }
|
|
310
|
+
else cursor = { schemaVersion: 1, collection: cursor.collection + 1, afterId: null };
|
|
311
|
+
} else cursor = { ...cursor, afterId };
|
|
312
|
+
await store.commit({ tenantId: TENANT, changes: [{ action: 'put', collection: CHECKPOINTS, id: CHECKPOINT, expectedVersion: version, value: cursor }] }); version++;
|
|
313
|
+
if (complete || !consumed) break;
|
|
314
|
+
}
|
|
315
|
+
return { complete, scanned, deleted, reconciled };
|
|
316
|
+
}
|
|
317
|
+
export async function handler(_event: unknown, context?: { getRemainingTimeInMillis(): number }) {
|
|
318
|
+
const logger = createLogger({ component: 'job-data-retention-maintenance', feature: 'data-lifecycle', operation: 'retention-maintenance',
|
|
319
|
+
slice: '${name}', stage: process.env.EBK_STAGE ?? 'unknown', workspace: process.env.EBK_WORKSPACE ?? '${name}' });
|
|
320
|
+
try {
|
|
321
|
+
const result = await runRetentionMaintenance({ budgetMs: Math.min(240_000, (context?.getRemainingTimeInMillis() ?? 250_000) - 10_000) });
|
|
322
|
+
logger.info('Native control maintenance completed', { attributes: result, outcome: result.complete ? 'success' : 'unknown' });
|
|
323
|
+
return result;
|
|
324
|
+
} catch (error) { logger.error('Native control maintenance failed', { outcome: 'failure' }); throw error; }
|
|
325
|
+
}
|
|
326
|
+
`,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=built-in-plan-key-value-retention-maintenance.js.map
|