akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4
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/CHANGELOG.md +756 -0
- package/dist/akm +94 -196
- package/dist/cli/shared.js +6 -2
- package/dist/cli.js +22 -9
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +2 -2
- package/dist/commands/health/checks.js +30 -75
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +0 -38
- package/dist/commands/health/improve-metrics.js +123 -562
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +11 -106
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -73
- package/dist/commands/health.js +122 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +538 -1075
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- package/dist/commands/improve/execution.js +3 -5
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +29 -166
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +12 -7
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +443 -1063
- package/dist/commands/improve/ledger.js +114 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +459 -1172
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +14 -118
- package/dist/commands/improve/memory/memory-improve.js +4 -3
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -10
- package/dist/commands/improve/preparation.js +851 -2339
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +621 -1367
- package/dist/commands/improve/salience.js +46 -232
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +323 -0
- package/dist/commands/proposal/drain.js +251 -644
- package/dist/commands/proposal/proposal-cli.js +3 -18
- package/dist/commands/proposal/proposal-types.js +20 -41
- package/dist/commands/proposal/proposal.js +1 -2
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +502 -1487
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +13 -89
- package/dist/commands/read/curate.js +63 -413
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +2 -13
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +7 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +2 -11
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/stash-cli.js +1 -1
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +9 -8
- package/dist/commands/tasks/tasks.js +326 -930
- package/dist/commands/tasks/validate.js +42 -21
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +0 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +11 -12
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +291 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +1 -33
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +163 -68
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +21 -95
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-lock.js +76 -173
- package/dist/core/logs-db.js +2 -2
- package/dist/core/paths.js +0 -27
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +108 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +293 -1012
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/graph-db.js +106 -46
- package/dist/indexer/ensure-index.js +44 -85
- package/dist/indexer/graph/graph-extraction.js +340 -562
- package/dist/indexer/graph/graph-related.js +130 -0
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +139 -151
- package/dist/indexer/indexer.js +524 -846
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +81 -90
- package/dist/indexer/passes/metadata.js +132 -200
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +1 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +181 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +2 -7
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +10 -15
- package/dist/llm/graph-extract.js +3 -12
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/metadata-enhance.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +2 -34
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +60 -23
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +1 -2
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +43937 -93313
- package/dist/scripts/akm-migrate.js +43697 -93071
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +0 -17
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +168 -0
- package/dist/storage/repositories/index-connection.js +34 -70
- package/dist/storage/repositories/index-entries-repository.js +69 -111
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +83 -269
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +192 -220
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +35 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +34 -27
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +129 -277
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +125 -745
- package/dist/tasks/backends/schtasks.js +101 -620
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/scheduler-binding.js +18 -238
- package/dist/tasks/scheduler-invocation.js +52 -52
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +363 -679
- package/dist/tasks/source/parse-task-source.js +160 -10
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +2 -2
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +41 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
- package/docs/reference/cli.md +182 -125
- package/docs/reference/configuration.md +49 -56
- package/docs/reference/data-and-telemetry.md +19 -20
- package/docs/reference/tasks.md +86 -38
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +87 -406
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -21
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/config/retired-experimental-keys-shim.js +0 -62
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -78
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -2,71 +2,27 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* The child workflow executor
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* The child workflow executor. `driveChildWorkflowUnit` is the one place a
|
|
6
|
+
* `child-workflow`-targeted unit is published (idempotently) and driven,
|
|
7
|
+
* reached from `native-executor.ts`'s dispatch seam: (1) validate the resolved
|
|
8
|
+
* `with:` bindings against the child's `params:`; (2) derive the deterministic
|
|
9
|
+
* invocation key; (3) publish the child run idempotently; (4) drive it with
|
|
10
|
+
* the same engine as a top-level run unless it is already `blocked`/`failed`;
|
|
11
|
+
* (5) map the child's final status onto this unit's outcome.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* child run idempotently (`publishChildWorkflowRun`, P3a); (5) read the
|
|
15
|
-
* published row's status; (6) drive it with the SAME engine the top-level path
|
|
16
|
-
* uses (`runWorkflowSteps`) unless it is already terminal-for-this-invocation
|
|
17
|
-
* (`blocked`/`failed`, rows A-22/A-23); (7) map the child's FINAL status
|
|
18
|
-
* through §3.4's table onto this unit's outcome.
|
|
19
|
-
*
|
|
20
|
-
* ## Why `runWorkflowSteps` is reached through a LAZY dynamic import, not a
|
|
21
|
-
* static one (B-N5, and the §7 preservation-gate contingency)
|
|
22
|
-
*
|
|
23
|
-
* `native-executor.ts` must import `driveChildWorkflowUnit` FROM this file
|
|
24
|
-
* (the dispatch seam calls it inline, §3.2) — that edge is fixed. `run-
|
|
25
|
-
* workflow.ts` imports `native-executor.ts` (existing, load-bearing:
|
|
26
|
-
* `executeStepPlan`). If this file ALSO imported `runWorkflowSteps` from
|
|
27
|
-
* `./run-workflow` STATICALLY, the three edges would close a static cycle
|
|
28
|
-
* (native-executor.ts -> child-workflow.ts -> run-workflow.ts ->
|
|
29
|
-
* native-executor.ts), which `tests/architecture/import-cycle-ratchet.test.ts`
|
|
30
|
-
* (shrink-only, EMPTY baseline — an absolute gate) forbids outright; adding an
|
|
31
|
-
* entry to admit it is not an option the ratchet allows. Per this spec's own
|
|
32
|
-
* §7 checklist ("if the ratchet objects, the drive is reached through an
|
|
33
|
-
* injected function value, the pattern `ir/freeze-v4.ts`'s `ChildFreezeFn`
|
|
34
|
-
* already establishes"), the drive is instead reached through
|
|
35
|
-
* {@link driveWithRealEngine}'s `await import("./run-workflow.js")` — a
|
|
36
|
-
* DYNAMIC import, invisible to the static-graph cycle ratchet by design (its
|
|
37
|
-
* own doc: "dynamic `import()` is excluded because it is the repo's
|
|
38
|
-
* sanctioned lazy-loading escape hatch"), registered in
|
|
39
|
-
* `DYNAMIC_IMPORT_BASELINE` (scripts/lint-import-cycles.ts) as a genuine
|
|
40
|
-
* lazy-load: the vast majority of workflow runs compose no child at all, so
|
|
41
|
-
* loading `run-workflow.ts`'s full engine (lease heartbeat, retry loop) is
|
|
42
|
-
* deferred until a `child-workflow` unit is actually dispatched. Bun/Node
|
|
43
|
-
* cache a module on first dynamic import, so this costs nothing on repeat
|
|
44
|
-
* calls, and it resolves the SAME module namespace object a test's
|
|
45
|
-
* `import * as runWorkflowModule from "./run-workflow.js"` holds — a
|
|
46
|
-
* `spyOn(runWorkflowModule, "runWorkflowSteps")` is therefore observed
|
|
47
|
-
* exactly as if this module had imported it statically. Unlike a registered
|
|
48
|
-
* function value (which would depend on `run-workflow.ts` having already
|
|
49
|
-
* been loaded by SOME OTHER file — fragile for a test file exercising this
|
|
50
|
-
* seam in isolation), a dynamic import always resolves correctly regardless
|
|
51
|
-
* of what the rest of the process has loaded. This is the ONLY runtime
|
|
52
|
-
* indirection in the whole drive: no second executor is created, and
|
|
53
|
-
* `driveRun` itself is never exported (B-N5's "no second executor" holds).
|
|
13
|
+
* `runWorkflowSteps` is reached through a lazy dynamic import: a static one
|
|
14
|
+
* would close the cycle native-executor -> child-workflow -> run-workflow ->
|
|
15
|
+
* native-executor, and most runs compose no child at all.
|
|
54
16
|
*/
|
|
55
17
|
import { randomUUID } from "node:crypto";
|
|
56
18
|
import { TransientError } from "../../core/errors.js";
|
|
57
19
|
import { withWorkflowRunsRepo } from "../../storage/repositories/workflow-runs-repository.js";
|
|
58
20
|
import { validateWorkflowParams } from "../ir/params.js";
|
|
59
|
-
import { canonicalPlanJson
|
|
60
|
-
import { frozenStepRows } from "../runtime/plan-classifier.js";
|
|
21
|
+
import { canonicalPlanJson } from "../ir/plan-hash.js";
|
|
61
22
|
import { workflowRunExportedResult } from "../runtime/run-outputs.js";
|
|
23
|
+
import { frozenStepRows } from "../runtime/run-plan.js";
|
|
62
24
|
import { computeChildInvocationKey } from "./child-invocation.js";
|
|
63
|
-
/**
|
|
64
|
-
* The real engine's `runWorkflowSteps`, reached ONLY through a dynamic
|
|
65
|
-
* import — see the module doc for why. The return value is deliberately
|
|
66
|
-
* unused by the caller: this module always RE-READS the child run row from
|
|
67
|
-
* the repository afterward (spec step 7) rather than trusting the driver's
|
|
68
|
-
* return value, so no result shape needs to be shared across the seam.
|
|
69
|
-
*/
|
|
25
|
+
/** The real engine, via a dynamic import (see the module doc). The caller re-reads the child row afterward. */
|
|
70
26
|
async function driveWithRealEngine(options) {
|
|
71
27
|
const { runWorkflowSteps } = await import("./run-workflow.js");
|
|
72
28
|
await runWorkflowSteps(options);
|
|
@@ -74,39 +30,19 @@ async function driveWithRealEngine(options) {
|
|
|
74
30
|
function errorMessage(err) {
|
|
75
31
|
return err instanceof Error ? err.message : String(err);
|
|
76
32
|
}
|
|
77
|
-
/**
|
|
33
|
+
/** Another live process holds the child run's lock file (run-workflow.ts). */
|
|
78
34
|
function isLeaseBusyError(err) {
|
|
79
|
-
return err instanceof TransientError && err.
|
|
35
|
+
return err instanceof TransientError && err.code === "RUN_LEASE_HELD";
|
|
80
36
|
}
|
|
81
|
-
/**
|
|
37
|
+
/** The `child_workflow_failed` message. */
|
|
82
38
|
function childWorkflowFailedMessage(input) {
|
|
83
39
|
return (`Child workflow run ${input.childRunId} (${input.childRef}) failed at step "${input.childStepId}". ` +
|
|
84
40
|
`Inspect it with \`akm workflow status ${input.childRunId}\`; the parent run's step ` +
|
|
85
41
|
`"${input.parentStepId}" cannot advance until it succeeds.`);
|
|
86
42
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Steps 1-3 (spec §3.3): integrity re-check, param validation, and the
|
|
89
|
-
* deterministic invocation key. Returns either the key or an already-shaped
|
|
90
|
-
* `child_workflow_publish_failed` outcome.
|
|
91
|
-
*/
|
|
43
|
+
/** Param validation and the deterministic invocation key, or a `child_workflow_publish_failed` outcome. */
|
|
92
44
|
function precheckAndDeriveInvocationKey(input) {
|
|
93
45
|
const { request, target, ctx, childParams, inputHash } = input;
|
|
94
|
-
// Step 1 — integrity re-check (row A-10).
|
|
95
|
-
const recomputedPlanHash = computePlanHash(target.frozenPlan);
|
|
96
|
-
if (recomputedPlanHash !== target.planHash) {
|
|
97
|
-
return {
|
|
98
|
-
ok: false,
|
|
99
|
-
outcome: {
|
|
100
|
-
unitId: request.unitId,
|
|
101
|
-
ok: false,
|
|
102
|
-
failureReason: "child_workflow_publish_failed",
|
|
103
|
-
error: `Workflow step "${request.stepId}" composes child workflow ${target.ref}, but its embedded plan's ` +
|
|
104
|
-
`recomputed hash (${recomputedPlanHash}) does not match the frozen target's planHash (${target.planHash}). ` +
|
|
105
|
-
"The frozen plan has been corrupted or tampered with.",
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
// Step 2 — resolved params against the child's declared param schemas (row A-11).
|
|
110
46
|
const paramErrors = validateWorkflowParams(target.frozenPlan, childParams);
|
|
111
47
|
if (paramErrors.length > 0) {
|
|
112
48
|
return {
|
|
@@ -120,7 +56,6 @@ function precheckAndDeriveInvocationKey(input) {
|
|
|
120
56
|
},
|
|
121
57
|
};
|
|
122
58
|
}
|
|
123
|
-
// Step 3 — the deterministic invocation key (B-N8: parentUnitId is request.unitId, the parent unit's journalBaseId).
|
|
124
59
|
return {
|
|
125
60
|
ok: true,
|
|
126
61
|
invocationKey: computeChildInvocationKey({
|
|
@@ -131,11 +66,8 @@ function precheckAndDeriveInvocationKey(input) {
|
|
|
131
66
|
};
|
|
132
67
|
}
|
|
133
68
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* transaction open on this connection — this seam is reached from
|
|
137
|
-
* dispatchJournaledAttempt, outside resumeWorkflowRun's and
|
|
138
|
-
* completeWorkflowStep's own transactions.
|
|
69
|
+
* Publish the child run idempotently and return the pre-drive row. Runs with
|
|
70
|
+
* no transaction open on this connection (reached from the dispatch seam).
|
|
139
71
|
*/
|
|
140
72
|
async function publishChildRun(input, invocationKey) {
|
|
141
73
|
const { request, target, ctx, childParams } = input;
|
|
@@ -162,7 +94,6 @@ async function publishChildRun(input, invocationKey) {
|
|
|
162
94
|
updatedAt: now,
|
|
163
95
|
agentHarness: parentRow.agent_harness,
|
|
164
96
|
agentSessionId: parentRow.agent_session_id,
|
|
165
|
-
checkinArmedAt: now,
|
|
166
97
|
},
|
|
167
98
|
steps: frozenStepRows(target.frozenPlan).map((row) => ({ ...row, runId: childRunId })),
|
|
168
99
|
planJson: canonicalPlanJson(target.frozenPlan),
|
|
@@ -183,11 +114,9 @@ async function publishChildRun(input, invocationKey) {
|
|
|
183
114
|
}
|
|
184
115
|
}
|
|
185
116
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* (re-read after the drive) or an already-shaped `child_workflow_busy` /
|
|
190
|
-
* `child_workflow_drive_failed` outcome.
|
|
117
|
+
* Drive the published child run with the real engine unless it is already
|
|
118
|
+
* `blocked`/`failed` (never re-driven). Returns the final re-read row, or a
|
|
119
|
+
* `child_workflow_busy` / `child_workflow_drive_failed` outcome.
|
|
191
120
|
*/
|
|
192
121
|
async function driveChildRun(input, childRow) {
|
|
193
122
|
const { request, target, ctx } = input;
|
|
@@ -201,27 +130,13 @@ async function driveChildRun(input, childRow) {
|
|
|
201
130
|
...(ctx.dispatcher ? { dispatcher: ctx.dispatcher } : {}),
|
|
202
131
|
...(ctx.maxConcurrency !== undefined ? { maxConcurrency: ctx.maxConcurrency } : {}),
|
|
203
132
|
...(ctx.eventSource !== undefined ? { eventSource: ctx.eventSource } : {}),
|
|
204
|
-
//
|
|
205
|
-
// own `finally` remains the single owner of the process-lifecycle
|
|
206
|
-
// drain for the whole process (row A-24).
|
|
133
|
+
// The parent's own `finally` owns the process-lifecycle drain; no maxSteps/maxRetries.
|
|
207
134
|
disposeDispatchResources: () => { },
|
|
208
|
-
// B-N7: deliberately no maxSteps, no maxRetries (rows A-25, A-26).
|
|
209
135
|
};
|
|
210
136
|
try {
|
|
211
|
-
// The re-read
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// getRunById — must be caught. Left to escape, it skips past
|
|
215
|
-
// dispatchJournaledAttempt's finishJournaledDispatch (no try/catch
|
|
216
|
-
// wraps this seam there by design), so the parent's reserved attempt
|
|
217
|
-
// row is never finished; the throw then propagates through runUnit
|
|
218
|
-
// into concurrentMap's worker (src/core/concurrent.ts), which SWALLOWS
|
|
219
|
-
// it and leaves the unit's outcome slot `undefined`, which
|
|
220
|
-
// executeStepPlanInConnection then maps to the false diagnostic
|
|
221
|
-
// "unit was not dispatched (aborted or scheduler failure)" — losing
|
|
222
|
-
// the real cause and leaving the composing attempt row stuck
|
|
223
|
-
// `running` forever (unrecoverable by inspection; a resume + re-drive
|
|
224
|
-
// reproduces the identical false diagnostic).
|
|
137
|
+
// The re-read stays inside this try: an escaped throw would skip the
|
|
138
|
+
// parent attempt's finish and leave its row `running` with a false
|
|
139
|
+
// "not dispatched" diagnostic.
|
|
225
140
|
await driveWithRealEngine(driveOptions);
|
|
226
141
|
const finalRow = (await withWorkflowRunsRepo((repo) => repo.getRunById(childRow.id))) ?? childRow;
|
|
227
142
|
return { ok: true, finalRow };
|
|
@@ -244,22 +159,8 @@ async function driveChildRun(input, childRow) {
|
|
|
244
159
|
},
|
|
245
160
|
};
|
|
246
161
|
}
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
// handling") was false: no handling exists at this seam
|
|
250
|
-
// (dispatchJournaledAttempt awaits this call with no try of its own),
|
|
251
|
-
// so an uncaught throw here escaped all the way into the scheduler and
|
|
252
|
-
// was silently swallowed (R1, above). Reachable causes include the
|
|
253
|
-
// child's own LeaseHeartbeat.assertAlive() firing mid-drive,
|
|
254
|
-
// requireExecutableWorkflowPlan rejecting a
|
|
255
|
-
// tampered child plan_json, and the child's status changing between
|
|
256
|
-
// this function's own step 5 read and the drive's internal
|
|
257
|
-
// getNextWorkflowStep re-read — none of which match
|
|
258
|
-
// isLeaseBusyError's text. child_workflow_drive_failed is a SIBLING of
|
|
259
|
-
// child_workflow_publish_failed (row A-10…A-12): same shape, same
|
|
260
|
-
// errorMessage(err) content, but naming the child run id and ref
|
|
261
|
-
// (already known at this point, unlike the publish arm above) since
|
|
262
|
-
// driving — not publishing — is what failed.
|
|
162
|
+
// Every other throw (a repository error mid-drive, a status race) maps
|
|
163
|
+
// to child_workflow_drive_failed — never rethrown into the scheduler.
|
|
263
164
|
return {
|
|
264
165
|
ok: false,
|
|
265
166
|
outcome: {
|
|
@@ -278,10 +179,7 @@ async function driveChildRun(input, childRow) {
|
|
|
278
179
|
};
|
|
279
180
|
}
|
|
280
181
|
}
|
|
281
|
-
/**
|
|
282
|
-
* `driveChildWorkflowUnit` — the ONE child drive (spec §3.3). Every failure
|
|
283
|
-
* before step 6 (publication) produces `child_workflow_publish_failed`.
|
|
284
|
-
*/
|
|
182
|
+
/** The one child drive. Every failure before the drive produces `child_workflow_publish_failed`. */
|
|
285
183
|
export async function driveChildWorkflowUnit(input) {
|
|
286
184
|
const { request, ctx } = input;
|
|
287
185
|
const precheck = precheckAndDeriveInvocationKey(input);
|
|
@@ -304,10 +202,7 @@ export async function driveChildWorkflowUnit(input) {
|
|
|
304
202
|
status: finalRow.status,
|
|
305
203
|
currentStepId: finalRow.current_step_id,
|
|
306
204
|
};
|
|
307
|
-
//
|
|
308
|
-
// own dispatch signal is what aborted it — checked against the RE-READ
|
|
309
|
-
// status (not the signal alone) so an already-terminal child is never
|
|
310
|
-
// misreported as aborted.
|
|
205
|
+
// Checked against the re-read status, so an already-terminal child is never misreported as aborted.
|
|
311
206
|
if (finalRow.status === "active" && ctx.signal?.aborted) {
|
|
312
207
|
return {
|
|
313
208
|
unitId: request.unitId,
|
|
@@ -351,12 +246,8 @@ export async function driveChildWorkflowUnit(input) {
|
|
|
351
246
|
childRun: childRunSummary,
|
|
352
247
|
};
|
|
353
248
|
default:
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
// reached by this phase's fixtures — B-N7 forwards no maxSteps/
|
|
357
|
-
// maxRetries, so nothing else can leave a driven child non-terminal
|
|
358
|
-
// without an abort). Treated conservatively as a failure so the
|
|
359
|
-
// parent never silently advances on an unresolved child.
|
|
249
|
+
// A driven child left non-terminal (its own gate loop exhausted) fails
|
|
250
|
+
// the unit, so the parent never advances on an unresolved child.
|
|
360
251
|
return {
|
|
361
252
|
unitId: request.unitId,
|
|
362
253
|
ok: false,
|
|
@@ -2,37 +2,17 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* The
|
|
6
|
-
* anything about its outcome reaches durable state.
|
|
7
|
-
*
|
|
8
|
-
* This is a LEAF module on purpose. Both dispatch paths need it — the unit path
|
|
9
|
-
* (`exec/native-executor.ts`) and the gate-judge path (`exec/frozen-judge.ts`) —
|
|
10
|
-
* and the judge path is reached from `runtime/runs.ts`, which the executor's own
|
|
11
|
-
* dependency chain runs back into. Keeping the helpers here (importing only
|
|
12
|
-
* `core/redaction` plus erased types) means the judge can reuse the exact unit
|
|
13
|
-
* scrub without opening a runtime import cycle.
|
|
14
|
-
*
|
|
15
|
-
* @module workflows/exec/dispatch-redaction
|
|
5
|
+
* The one redaction contract every frozen-workflow dispatch (unit or gate
|
|
6
|
+
* judge) is held to before anything about its outcome reaches durable state.
|
|
7
|
+
* A leaf module, so the judge path reuses it without an import cycle.
|
|
16
8
|
*/
|
|
17
9
|
import { collectSensitiveValues, isEnvPassthroughValueSafeToExpose, redactSensitiveText, redactSensitiveValue, } from "../../core/redaction.js";
|
|
18
10
|
import { lookupApiKeyFileValue, lookupApiKeySecretRefValue } from "../../integrations/agent/engine-resolution.js";
|
|
19
11
|
/**
|
|
20
|
-
* Every exact value that must never
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* value the redaction policy does not consider safe to expose.
|
|
25
|
-
*
|
|
26
|
-
* Shared by the unit path and the gate-judge path. There is deliberately ONE
|
|
27
|
-
* collector: a second, parallel implementation is exactly how a dispatch path
|
|
28
|
-
* silently loses the scrub.
|
|
29
|
-
*
|
|
30
|
-
* The credential values are read from `process.env` (or disk / the secret
|
|
31
|
-
* store, for a file- or store-backed one) AT CALL TIME, so a caller must
|
|
32
|
-
* collect no earlier than the dispatch whose outcome it scrubs. A snapshot
|
|
33
|
-
* taken when the dispatch was merely *planned* can predate a credential the
|
|
34
|
-
* dispatch then resolves live, leaving the exact value it must remove out of
|
|
35
|
-
* the set.
|
|
12
|
+
* Every exact value that must never reach the journal from one dispatch: the
|
|
13
|
+
* resolved `env` bindings, the engine's (and SDK fallback's) credential from
|
|
14
|
+
* env, file, or secret store, and unsafe passthrough values. Read at call time,
|
|
15
|
+
* so collect no earlier than the dispatch being scrubbed.
|
|
36
16
|
*/
|
|
37
17
|
export function collectWorkflowDispatchSensitiveValues(dispatch, env) {
|
|
38
18
|
const values = new Set([...Object.values(env ?? {}), ...(dispatch.sensitiveValues ?? [])]);
|
|
@@ -87,18 +67,8 @@ export function collectWorkflowDispatchSensitiveValues(dispatch, env) {
|
|
|
87
67
|
return collectSensitiveValues(values);
|
|
88
68
|
}
|
|
89
69
|
/**
|
|
90
|
-
* Scrub a dispatch outcome before
|
|
91
|
-
*
|
|
92
|
-
* The `failureReason` downgrade is part of the contract: if redaction ALTERED
|
|
93
|
-
* the reason, the reason itself carried a secret, and the persisted failure
|
|
94
|
-
* vocabulary must not become a side channel for it.
|
|
95
|
-
*
|
|
96
|
-
* Structurally typed over `{ failureReason? }` rather than importing
|
|
97
|
-
* `UnitOutcome` from `step-work.ts`: this module must stay a LEAF, and even an
|
|
98
|
-
* erased `import type` edge here would put `frozen-judge → step-work →
|
|
99
|
-
* runtime/runs → frozen-judge` back on the static import graph (the
|
|
100
|
-
* import-cycle ratchet is shrink-only). Callers keep their exact outcome type
|
|
101
|
-
* through the generic.
|
|
70
|
+
* Scrub a dispatch outcome before anything about it is journaled. A
|
|
71
|
+
* `failureReason` the scrub altered carried a secret, so it is downgraded.
|
|
102
72
|
*/
|
|
103
73
|
export function redactUnitOutcome(outcome, sensitiveValues) {
|
|
104
74
|
const redacted = redactSensitiveValue(outcome, sensitiveValues);
|
|
@@ -107,13 +77,7 @@ export function redactUnitOutcome(outcome, sensitiveValues) {
|
|
|
107
77
|
}
|
|
108
78
|
return redacted;
|
|
109
79
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Scrub a value THROWN out of a dispatch. A rejection is as durable as a
|
|
112
|
-
* resolved failure — the message becomes the blocked step's notes — so it goes
|
|
113
|
-
* through the same value set. Re-wrapped ONLY when redaction actually changed
|
|
114
|
-
* the message, so an untouched throw keeps its original object (and its type,
|
|
115
|
-
* which callers branch on) byte-identical.
|
|
116
|
-
*/
|
|
80
|
+
/** Scrub a value thrown out of a dispatch; re-wrapped only when the scrub changed its message. */
|
|
117
81
|
function redactDispatchError(err, sensitiveValues) {
|
|
118
82
|
if (sensitiveValues.length === 0 || !(err instanceof Error))
|
|
119
83
|
return err;
|
|
@@ -125,13 +89,9 @@ function redactDispatchError(err, sensitiveValues) {
|
|
|
125
89
|
return replacement;
|
|
126
90
|
}
|
|
127
91
|
/**
|
|
128
|
-
* Wrap a dispatcher so
|
|
129
|
-
* `sensitiveValues`
|
|
130
|
-
*
|
|
131
|
-
* unredacted. Used at seams whose results head STRAIGHT for durable state (the
|
|
132
|
-
* gate judge, on both its agent and its llm branch); the unit path instead
|
|
133
|
-
* scrubs once at its own journal boundary (`dispatchJournaledAttempt`), AFTER
|
|
134
|
-
* the structured-output parse loop has seen the raw text.
|
|
92
|
+
* Wrap a dispatcher so both its outcome and its thrown error are scrubbed with
|
|
93
|
+
* the request's `sensitiveValues` (the gate judge; the unit path scrubs at its
|
|
94
|
+
* own journal boundary after the structured-output parse).
|
|
135
95
|
*/
|
|
136
96
|
export function withDispatchRedaction(inner) {
|
|
137
97
|
return async (request, feedback) => {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* Materialize a unit's frozen environment at dispatch. Env-file values are the
|
|
6
|
+
* one deliberately live input to a frozen plan: freeze records each ref's
|
|
7
|
+
* owner, key set and `${secret:…}` names; the values (and the secrets they
|
|
8
|
+
* name) are read here, per dispatch, and nothing is returned until every read
|
|
9
|
+
* has succeeded.
|
|
10
|
+
*/
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import dotenv from "dotenv";
|
|
14
|
+
import { assetPathForName } from "../../core/asset/asset-placement.js";
|
|
15
|
+
import { compareCodePoints, isWithin } from "../../core/common.js";
|
|
16
|
+
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
17
|
+
export const SECRET_TOKEN_RE = /\$\{secret:([A-Za-z0-9_./-]+)\}/g;
|
|
18
|
+
export function materializeFrozenWorkflowEnvironment(descriptors, options = {}) {
|
|
19
|
+
const values = {};
|
|
20
|
+
const sensitive = new Set();
|
|
21
|
+
const audits = [];
|
|
22
|
+
for (const descriptor of descriptors) {
|
|
23
|
+
if (descriptor.kind === "literal") {
|
|
24
|
+
values[descriptor.name] = descriptor.value;
|
|
25
|
+
if (descriptor.value)
|
|
26
|
+
sensitive.add(descriptor.value);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (descriptor.kind === "pass-through") {
|
|
30
|
+
const value = options.readPassThrough ? options.readPassThrough(descriptor.name) : process.env[descriptor.name];
|
|
31
|
+
if (value !== undefined) {
|
|
32
|
+
values[descriptor.name] = value;
|
|
33
|
+
if (value)
|
|
34
|
+
sensitive.add(value);
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const source = options.readEnvFile ? options.readEnvFile(descriptor) : readEnvFile(descriptor.owner);
|
|
39
|
+
const parsed = dotenv.parse(typeof source === "string" ? source : Buffer.from(source));
|
|
40
|
+
const keys = Object.keys(parsed).sort(compareCodePoints);
|
|
41
|
+
if (!sameStrings(keys, descriptor.keys))
|
|
42
|
+
invalid(`environment ${descriptor.ref} key set changed after it was frozen`);
|
|
43
|
+
const secretValues = new Map();
|
|
44
|
+
for (const name of descriptor.secretNames) {
|
|
45
|
+
const raw = options.readSecret ? options.readSecret({ name, descriptor }) : readSecret(descriptor.owner, name);
|
|
46
|
+
if (raw === undefined) {
|
|
47
|
+
throw new NotFoundError(`Environment ${descriptor.ref} references missing secret ${name}; nothing was materialized.`, "FILE_NOT_FOUND");
|
|
48
|
+
}
|
|
49
|
+
const value = typeof raw === "string" ? raw : Buffer.from(raw).toString("utf8");
|
|
50
|
+
secretValues.set(name, value);
|
|
51
|
+
if (value)
|
|
52
|
+
sensitive.add(value);
|
|
53
|
+
}
|
|
54
|
+
for (const [key, rawValue] of Object.entries(parsed)) {
|
|
55
|
+
const resolved = rawValue.replace(SECRET_TOKEN_RE, (_token, name) => {
|
|
56
|
+
const secret = secretValues.get(name);
|
|
57
|
+
if (secret === undefined)
|
|
58
|
+
invalid(`environment ${descriptor.ref} secret ${name} was not frozen`);
|
|
59
|
+
return secret;
|
|
60
|
+
});
|
|
61
|
+
values[key] = resolved;
|
|
62
|
+
if (resolved)
|
|
63
|
+
sensitive.add(resolved);
|
|
64
|
+
}
|
|
65
|
+
audits.push({
|
|
66
|
+
eventType: "env_access",
|
|
67
|
+
ref: descriptor.ref,
|
|
68
|
+
keys: [...descriptor.keys],
|
|
69
|
+
secretNames: [...descriptor.secretNames],
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return { values, sensitiveValues: [...sensitive], audits };
|
|
73
|
+
}
|
|
74
|
+
function readEnvFile(owner) {
|
|
75
|
+
if (!isWithin(owner.requestedPath, owner.requestedRoot))
|
|
76
|
+
invalid(`env file ${owner.relativePath} escapes its bundle`);
|
|
77
|
+
return fs.readFileSync(owner.requestedPath);
|
|
78
|
+
}
|
|
79
|
+
function readSecret(owner, name) {
|
|
80
|
+
const secretsRoot = path.join(owner.requestedRoot, "secrets");
|
|
81
|
+
const secretPath = assetPathForName("secret", secretsRoot, name);
|
|
82
|
+
if (!isWithin(secretPath, secretsRoot))
|
|
83
|
+
invalid(`secret name ${name} escapes its bundle`);
|
|
84
|
+
try {
|
|
85
|
+
return fs.readFileSync(secretPath);
|
|
86
|
+
}
|
|
87
|
+
catch (cause) {
|
|
88
|
+
if (cause.code === "ENOENT")
|
|
89
|
+
return undefined;
|
|
90
|
+
throw cause;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function sameStrings(left, right) {
|
|
94
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
95
|
+
}
|
|
96
|
+
function invalid(message) {
|
|
97
|
+
throw new UsageError(`Invalid frozen workflow environment: ${message}.`, "WORKFLOW_SOURCE_INVALID");
|
|
98
|
+
}
|