@cassiomc1/forgeloop 1.13.0 → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_COMPATIBILITY.md +8 -0
- package/CONTRIBUTING.md +11 -7
- package/DOCS_INDEX.md +37 -4
- package/ENG/c-development-eng.md +2 -2
- package/ENG/cpp-development-eng.md +2 -2
- package/ENG/dotnet-aspnetcore-development-eng.md +7 -1
- package/ENG/flutter-development-eng.md +4 -2
- package/ENG/go-development-eng.md +2 -2
- package/ENG/java-development-eng.md +3 -3
- package/ENG/nodejs-backend-development-eng.md +10 -6
- package/ENG/php-development-eng.md +3 -3
- package/ENG/python-development-eng.md +205 -0
- package/ENG/rust-development-eng.md +42 -1
- package/ENG/sec-code-eng.md +7 -7
- package/ENG/sql-development-eng.md +4 -4
- package/ENG/swift-development-eng.md +5 -4
- package/ENG/test-code-eng.md +1 -1
- package/ENG/typescript-development-eng.md +4 -4
- package/EXECUTION_STATE.md +12 -0
- package/GUIDE_ROUTER.md +6 -0
- package/LICENSE +133 -21
- package/LOOP_ENGINEERING.md +28 -2
- package/LOOP_SYSTEM_DESIGN.md +10 -10
- package/ORCHESTRATOR_INTEGRATION.md +9 -5
- package/PROTOCOL_INTEGRATION.md +55 -2
- package/README.md +63 -59
- package/TERMINOLOGY.md +2 -0
- package/THIRD_PARTY_NOTICES.md +3 -4
- package/THREAT_MODEL.md +140 -1
- package/completions/_forgeloop +29 -3
- package/completions/forgeloop.bash +55 -3
- package/completions/forgeloop.fish +183 -1
- package/docs/ADVISORY_CONTEXT.md +25 -0
- package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
- package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
- package/docs/AGENT_PROTOCOL_SUMMARY.md +74 -39
- package/docs/AGENT_SKILL.md +66 -0
- package/docs/ARTIFACT_REFERENCE.md +171 -35
- package/docs/AUDIT_UX.md +46 -0
- package/docs/BROWSER_VERIFICATION.md +136 -0
- package/docs/CLI_REFERENCE.md +512 -8
- package/docs/CODE_ATTESTATION.md +2 -2
- package/docs/DOCUMENTATION_GUIDE.md +34 -11
- package/docs/GETTING_STARTED.md +3 -3
- package/docs/JEV_BENCHMARKS.md +31 -0
- package/docs/MODEL_ROUTING.md +37 -0
- package/docs/OPENSRC_ADAPTER.md +241 -0
- package/docs/PACKAGE_CONTENTS.md +46 -18
- package/docs/PROVIDERS.md +126 -0
- package/docs/PROVIDER_ARCHITECTURE.md +199 -0
- package/docs/RECIPES.md +9 -0
- package/docs/RELEASE_CHECKLIST.md +116 -12
- package/docs/SECURITY_REVIEW.md +71 -0
- package/docs/SELF_HOSTED_TESTS.md +121 -0
- package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
- package/docs/TEST_INTELLIGENCE.md +29 -0
- package/docs/TEST_PRUNING.md +14 -0
- package/docs/TROUBLESHOOTING.md +198 -1
- package/docs/UNIVERSAL_INTEGRATION.md +31 -0
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
- package/docs/diagrams/README.md +13 -9
- package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
- package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
- package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
- package/docs/documentation-manifest.json +774 -16
- package/docs/protocol-requirements.json +24 -0
- package/package.json +43 -11
- package/schemas/config.schema.json +14 -0
- package/schemas/context-plan.schema.json +18 -0
- package/schemas/semantic-decision.schema.json +46 -0
- package/schemas/task-bundle.schema.json +7 -2
- package/schemas/test-utility.schema.json +44 -0
- package/scripts/CI_VALIDATORS.md +6 -6
- package/scripts/benchmark-jev.mjs +5 -0
- package/scripts/benchmark-test-intelligence.mjs +4 -0
- package/scripts/generate-agent-protocol-summary.mjs +6 -3
- package/scripts/generate-forgeloop-skill.mjs +133 -0
- package/scripts/jev-smoke.mjs +19 -0
- package/scripts/run-mcp-clean-tests.mjs +30 -0
- package/skills/forgeloop/README.md +9 -0
- package/skills/forgeloop/SKILL.md +77 -0
- package/skills/forgeloop/references/lifecycle.md +9 -0
- package/skills/forgeloop/references/recovery.md +7 -0
- package/skills/forgeloop/references/verification.md +7 -0
- package/src/adapters/agent-browser/assertions.js +47 -0
- package/src/adapters/agent-browser/commands.js +54 -0
- package/src/adapters/agent-browser/index.js +3 -0
- package/src/adapters/agent-browser/locator.js +40 -0
- package/src/adapters/agent-browser/process.js +215 -0
- package/src/adapters/agent-browser/provider.js +316 -0
- package/src/adapters/emulated-services/constants.js +24 -0
- package/src/adapters/emulated-services/index.js +7 -0
- package/src/adapters/emulated-services/process.js +162 -0
- package/src/adapters/emulated-services/provider.js +289 -0
- package/src/adapters/opensrc/normalize.js +90 -0
- package/src/adapters/opensrc/process.js +248 -0
- package/src/adapters/opensrc/provider.js +338 -0
- package/src/adapters/opensrc/search.js +264 -0
- package/src/adapters/temporary-paths.js +18 -0
- package/src/adapters/typesafe/client.js +28 -0
- package/src/adapters/typesafe/engine.js +63 -0
- package/src/adapters/typesafe/normalize.js +41 -0
- package/src/cli.js +218 -174
- package/src/commands/action-show.js +5 -2
- package/src/commands/advance.js +5 -1
- package/src/commands/baseline.js +13 -11
- package/src/commands/checkpoint-revalidate.js +192 -0
- package/src/commands/complete.js +19 -3
- package/src/commands/context-plan.js +38 -0
- package/src/commands/contract-create.js +266 -0
- package/src/commands/contract-revise.js +236 -0
- package/src/commands/decision-show.js +14 -0
- package/src/commands/decision-status.js +22 -0
- package/src/commands/discover.js +41 -0
- package/src/commands/doctor.js +51 -13
- package/src/commands/gate-record.js +194 -0
- package/src/commands/gate-revalidate.js +135 -0
- package/src/commands/handoff-list.js +6 -1
- package/src/commands/handoff-show.js +6 -1
- package/src/commands/migrate-protocol.js +2 -2
- package/src/commands/model-route.js +40 -0
- package/src/commands/next.js +7 -1
- package/src/commands/policy-diff.js +25 -4
- package/src/commands/progress.js +17 -11
- package/src/commands/record-diagnosis.js +3 -0
- package/src/commands/route.js +146 -18
- package/src/commands/semantic-plan.js +41 -0
- package/src/commands/status.js +6 -1
- package/src/commands/storage-backup.js +15 -0
- package/src/commands/storage-migrate.js +5 -0
- package/src/commands/storage-migration-resume.js +5 -0
- package/src/commands/storage-migration-status.js +44 -0
- package/src/commands/storage-restore-resume.js +7 -0
- package/src/commands/storage-restore.js +8 -0
- package/src/commands/task-abandon.js +224 -0
- package/src/commands/task-list.js +8 -43
- package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
- package/src/commands/task-migrate.js +3 -3
- package/src/commands/task-recover.js +10 -2
- package/src/commands/task-repair-contract-bootstrap.js +263 -0
- package/src/commands/task-scope.js +18 -2
- package/src/commands/task-show.js +16 -2
- package/src/commands/test-inventory.js +5 -0
- package/src/commands/test-prune-plan.js +5 -0
- package/src/commands/test-prune-probe.js +5 -0
- package/src/commands/test-utility.js +5 -0
- package/src/commands/validate-protocol.js +39 -15
- package/src/commands/validate-receipt.js +8 -1
- package/src/config/guides.json +4 -0
- package/src/core/action-ledger-projection.js +10 -3
- package/src/core/actions.js +38 -75
- package/src/core/activation.js +11 -3
- package/src/core/approvals.js +17 -51
- package/src/core/artifact-registry.js +83 -2
- package/src/core/artifacts.js +81 -27
- package/src/core/attachment-paths.js +45 -0
- package/src/core/attestation-coverage.js +6 -1
- package/src/core/attestation-verifier.js +21 -2
- package/src/core/attestation.js +17 -6
- package/src/core/audit-ux.js +514 -0
- package/src/core/audit.js +6 -1
- package/src/core/browser-verification/constants.js +149 -0
- package/src/core/browser-verification/normalize.js +254 -0
- package/src/core/browser-verification/provider.js +519 -0
- package/src/core/browser-verification/service.js +115 -0
- package/src/core/bundles.js +160 -66
- package/src/core/checkpoint-revalidation.js +321 -0
- package/src/core/cli-command-definitions.js +350 -7
- package/src/core/code-manifest.js +9 -3
- package/src/core/command-executors.js +274 -108
- package/src/core/command-input.js +136 -44
- package/src/core/completion-artifacts.js +85 -34
- package/src/core/completion-ownership.js +19 -8
- package/src/core/completion-recovery-rebind.js +11 -1
- package/src/core/completion.js +64 -15
- package/src/core/config.js +3 -0
- package/src/core/conformance.js +2 -1
- package/src/core/context-compiler/budget.js +9 -0
- package/src/core/context-compiler/candidates.js +39 -0
- package/src/core/context-compiler/compiler.js +63 -0
- package/src/core/context-compiler/fingerprint.js +11 -0
- package/src/core/context-compiler/policy.js +13 -0
- package/src/core/context-compiler/result.js +23 -0
- package/src/core/continuity-lint.js +13 -2
- package/src/core/continuity-reconciliation.js +16 -3
- package/src/core/continuity.js +16 -8
- package/src/core/contract-bootstrap-recovery.js +656 -0
- package/src/core/contract-revision.js +209 -0
- package/src/core/decision/artifact.js +70 -0
- package/src/core/decision/benchmarks.js +103 -0
- package/src/core/decision/cache.js +27 -0
- package/src/core/decision/constants.js +58 -0
- package/src/core/decision/cutover.js +34 -0
- package/src/core/decision/engine.js +22 -0
- package/src/core/decision/errors.js +68 -0
- package/src/core/decision/events.js +104 -0
- package/src/core/decision/freshness.js +19 -0
- package/src/core/decision/normalizers/index.js +115 -0
- package/src/core/decision/policy.js +18 -0
- package/src/core/decision/projection.js +16 -0
- package/src/core/decision/question-registry.js +201 -0
- package/src/core/decision/request.js +26 -0
- package/src/core/decision/resolver.js +138 -0
- package/src/core/decision/result.js +58 -0
- package/src/core/decision/service.js +181 -0
- package/src/core/decision/state-builder.js +65 -0
- package/src/core/decision/task-bindings.js +35 -0
- package/src/core/decision/test-provider.js +32 -0
- package/src/core/decision/thresholds.js +15 -0
- package/src/core/diagnosis-model.js +11 -0
- package/src/core/diagnosis.js +10 -1
- package/src/core/diagnostic-projection.js +29 -12
- package/src/core/diagnostic-record.js +28 -3
- package/src/core/efficiency.js +6 -1
- package/src/core/error-codes.js +278 -0
- package/src/core/events.js +535 -147
- package/src/core/evidence-readiness.js +9 -0
- package/src/core/execution-prerequisites.js +36 -13
- package/src/core/execution-profile.js +63 -38
- package/src/core/execution.js +26 -40
- package/src/core/filesystem.js +11 -0
- package/src/core/gate-artifact.js +105 -19
- package/src/core/gate-provenance.js +125 -0
- package/src/core/handoff.js +26 -14
- package/src/core/history.js +39 -35
- package/src/core/hypothesis-projection.js +32 -0
- package/src/core/information-gain-projection.js +104 -100
- package/src/core/inspect.js +12 -3
- package/src/core/integration-invocation-policy.js +37 -4
- package/src/core/integration-resources.js +119 -87
- package/src/core/ledger-event-collection.js +189 -0
- package/src/core/ledger-relations.js +23 -0
- package/src/core/model-router/constants.js +10 -0
- package/src/core/model-router/policy.js +103 -0
- package/src/core/model-router/router.js +37 -0
- package/src/core/native-storage.js +12 -0
- package/src/core/next-action-continuity.js +31 -9
- package/src/core/next-action-model.js +58 -0
- package/src/core/next-action-phases.js +131 -43
- package/src/core/next-action-refresh.js +43 -9
- package/src/core/next-action-review-phase.js +9 -4
- package/src/core/next-action-verification-phase.js +2 -1
- package/src/core/next-action.js +56 -9
- package/src/core/phase.js +266 -103
- package/src/core/policy-engine.js +12 -13
- package/src/core/preflight-consistency.js +89 -62
- package/src/core/preflight-loaders.js +48 -9
- package/src/core/preflight-model.js +6 -1
- package/src/core/preflight.js +29 -12
- package/src/core/progress.js +21 -10
- package/src/core/protocol-info.js +68 -0
- package/src/core/protocol-migration.js +7 -6
- package/src/core/protocol.js +20 -0
- package/src/core/reconcile-closure.js +281 -67
- package/src/core/recovery-history.js +67 -47
- package/src/core/reflection.js +72 -77
- package/src/core/responsibility.js +25 -13
- package/src/core/resumability.js +154 -44
- package/src/core/route-artifact.js +28 -4
- package/src/core/router.js +67 -1
- package/src/core/runtime-context.js +123 -61
- package/src/core/schema-validation.js +11 -3
- package/src/core/security-review/constants.js +64 -0
- package/src/core/security-review/normalize.js +245 -0
- package/src/core/security-review/provider.js +204 -0
- package/src/core/security-review/service.js +134 -0
- package/src/core/semantic-planning/constants.js +19 -0
- package/src/core/semantic-planning/projection.js +94 -0
- package/src/core/semantic-planning/service.js +15 -0
- package/src/core/settlement.js +12 -1
- package/src/core/signing/bundle-file.js +53 -0
- package/src/core/signing/bundle-reference.js +15 -0
- package/src/core/signing/sigstore.js +60 -33
- package/src/core/signing/statement-file.js +27 -0
- package/src/core/sources.js +37 -0
- package/src/core/storage-runtime-registry.js +41 -0
- package/src/core/structural-quality/artifacts.js +20 -14
- package/src/core/structural-quality/service.js +81 -56
- package/src/core/target-layout.js +1 -1
- package/src/core/task-claim-state.js +249 -15
- package/src/core/task-command.js +21 -1
- package/src/core/task-conflict-inspection.js +133 -102
- package/src/core/task-descriptor.js +29 -22
- package/src/core/task-discovery.js +288 -90
- package/src/core/task-lock.js +66 -306
- package/src/core/task-migration-validation.js +5 -5
- package/src/core/task-migration.js +17 -287
- package/src/core/task-paths.js +13 -0
- package/src/core/task-recovery.js +1 -0
- package/src/core/task-snapshot.js +51 -8
- package/src/core/task-storage-migration.js +18 -0
- package/src/core/templates.js +23 -8
- package/src/core/test-intelligence/benchmarks.js +68 -0
- package/src/core/test-intelligence/inventory.js +73 -0
- package/src/core/test-intelligence/prune.js +94 -0
- package/src/core/test-intelligence/semantic-state.js +15 -0
- package/src/core/test-intelligence/service.js +40 -0
- package/src/core/test-intelligence/utility.js +50 -0
- package/src/core/trace.js +164 -105
- package/src/core/trajectory-evaluation.js +15 -3
- package/src/core/trajectory-metrics.js +47 -32
- package/src/core/transaction.js +16 -287
- package/src/core/verification-scope.js +20 -12
- package/src/core/work-state.js +100 -59
- package/src/integration.d.ts +492 -0
- package/src/integration.js +54 -0
- package/src/providers/README.md +47 -0
- package/src/providers/capabilities.js +46 -0
- package/src/providers/errors.js +15 -0
- package/src/providers/index.js +29 -0
- package/src/providers/json-snapshot.js +105 -0
- package/src/providers/registry.js +152 -0
- package/src/repository-index/binary-manager.js +7 -5
- package/src/storage/artifact-bytes.js +22 -0
- package/src/storage/attachment-binding.js +11 -0
- package/src/storage/attachment-files.js +82 -0
- package/src/storage/attachment-references.js +36 -0
- package/src/storage/backup.js +53 -0
- package/src/storage/capabilities.js +31 -0
- package/src/storage/connection-owner.js +119 -0
- package/src/storage/connection.js +376 -0
- package/src/storage/existing-project-scope.js +45 -0
- package/src/storage/export-destination.js +44 -0
- package/src/storage/exporter.js +284 -0
- package/src/storage/file-durability.js +46 -0
- package/src/storage/importer.js +461 -0
- package/src/storage/index.js +74 -0
- package/src/storage/leases.js +63 -0
- package/src/storage/ledger-event-snapshot.js +150 -0
- package/src/storage/ledger-relations.js +220 -0
- package/src/storage/legacy-maintenance-boundary.js +18 -0
- package/src/storage/legacy-signature.js +115 -0
- package/src/storage/maintenance-handoff.js +129 -0
- package/src/storage/maintenance-owner.js +42 -0
- package/src/storage/maintenance.js +310 -0
- package/src/storage/metadata-json.js +35 -0
- package/src/storage/migration-activate.js +59 -0
- package/src/storage/migration-archive.js +57 -0
- package/src/storage/migration-attachment-root.js +61 -0
- package/src/storage/migration-candidate.js +398 -0
- package/src/storage/migration-publication.js +143 -0
- package/src/storage/migration-rollback-admission.js +54 -0
- package/src/storage/migration-rollback-preparation.js +132 -0
- package/src/storage/migration-rollback-publication.js +183 -0
- package/src/storage/migration-rollback-release.js +66 -0
- package/src/storage/migration-rollback-source-stage.js +103 -0
- package/src/storage/migration-rollback.js +43 -0
- package/src/storage/migration-source-partition.js +56 -0
- package/src/storage/migration-source.js +255 -0
- package/src/storage/migration-terminal.js +39 -0
- package/src/storage/migration-validation.js +75 -0
- package/src/storage/migration.js +43 -0
- package/src/storage/operational-attachments.js +49 -0
- package/src/storage/operational-context.js +50 -0
- package/src/storage/project-backup.js +98 -0
- package/src/storage/project-bootstrap.js +24 -0
- package/src/storage/project-boundary.js +79 -0
- package/src/storage/project-read-snapshot.js +18 -0
- package/src/storage/project-replacement.js +137 -0
- package/src/storage/project-restore.js +203 -0
- package/src/storage/record-definitions.js +45 -0
- package/src/storage/repository.js +507 -0
- package/src/storage/restore-journal.js +62 -0
- package/src/storage/restore-layout.js +30 -0
- package/src/storage/restore-preparation.js +84 -0
- package/src/storage/restore-replacement-archive.js +162 -0
- package/src/storage/restore-replacement-owner.js +31 -0
- package/src/storage/restore-replacement-preparation.js +128 -0
- package/src/storage/restore-replacement.js +142 -0
- package/src/storage/restore-terminal.js +32 -0
- package/src/storage/runtime.js +31 -0
- package/src/storage/schema.js +214 -0
- package/src/storage/singleton-import.js +84 -0
- package/src/storage/snapshot-continuity.js +16 -0
- package/src/storage/snapshot.js +36 -0
- package/src/storage/storage-marker.js +79 -0
- package/src/storage/task-guards.js +107 -0
- package/src/storage/topology.js +42 -0
- package/src/storage/transaction.js +179 -0
- package/src/storage/unit-of-work.js +663 -0
- package/src/storage/windows-process-incarnation.js +206 -0
- package/.forgeloop/forgeloop.gitignore +0 -4
- package/LICENSE-DOCS.md +0 -13
- package/src/core/transaction-maintenance.js +0 -70
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
import { needsExistingProjectScope, withExistingProjectScope } from "../../storage/existing-project-scope.js";
|
|
1
2
|
import { execFile } from "node:child_process";
|
|
2
3
|
import { promisify } from "node:util";
|
|
3
4
|
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { ensureWithin, assertSafePath } from "../filesystem.js";
|
|
7
|
+
import { withSigningStatementFile } from "./statement-file.js";
|
|
8
|
+
import { withSigningBundleFile } from "./bundle-file.js";
|
|
9
|
+
import { getOperationalStore } from "../../storage/operational-context.js";
|
|
10
|
+
import { withOperationalAttachmentFile } from "../../storage/operational-attachments.js";
|
|
6
11
|
|
|
7
12
|
const execFileAsync = promisify(execFile);
|
|
8
13
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
9
14
|
const MAX_OUTPUT_BYTES = 8 * 1024 * 1024;
|
|
10
15
|
|
|
16
|
+
async function withExistingSigningReadScope(target, read) {
|
|
17
|
+
if (await needsExistingProjectScope(target)) return withExistingProjectScope(target, read, { readOnly: true });
|
|
18
|
+
return read();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function signingTaskId(target, statementPath) {
|
|
22
|
+
const store = getOperationalStore(target);
|
|
23
|
+
const taskKey = /^\.forgeloop\/task-state\/([a-f0-9]{64})\/attestations\/statement\.json$/u.exec(statementPath)?.[1];
|
|
24
|
+
const taskId = store && taskKey ? store.taskRow(taskKey)?.task_id : null;
|
|
25
|
+
return taskId;
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
export function createSigstoreSigningProvider({
|
|
12
29
|
command = "cosign",
|
|
13
30
|
execFileImpl = execFileAsync,
|
|
@@ -21,7 +38,7 @@ export function createSigstoreSigningProvider({
|
|
|
21
38
|
killSignal: "SIGTERM",
|
|
22
39
|
maxBuffer: MAX_OUTPUT_BYTES,
|
|
23
40
|
});
|
|
24
|
-
|
|
41
|
+
const provider = {
|
|
25
42
|
name: "sigstore",
|
|
26
43
|
async detect() {
|
|
27
44
|
try {
|
|
@@ -43,13 +60,13 @@ export function createSigstoreSigningProvider({
|
|
|
43
60
|
try {
|
|
44
61
|
await assertSafePath(target, statementPath);
|
|
45
62
|
await assertSafePath(target, destinationPath);
|
|
46
|
-
await run([
|
|
63
|
+
const signed = await withSigningBundleFile(target, destinationPath, statementPath, bundleAbsolute => withSigningStatementFile(target, statementPath, statementAbsolute => run([
|
|
47
64
|
"attest-blob",
|
|
48
|
-
"--statement",
|
|
49
|
-
"--bundle",
|
|
65
|
+
"--statement", statementAbsolute,
|
|
66
|
+
"--bundle", bundleAbsolute,
|
|
50
67
|
"--yes",
|
|
51
|
-
], { cwd: path.resolve(target) });
|
|
52
|
-
return { status: "VALID",
|
|
68
|
+
], { cwd: path.resolve(target) })));
|
|
69
|
+
return { status: "VALID", ...signed };
|
|
53
70
|
} catch (error) {
|
|
54
71
|
const unavailable = error.code === "ENOENT" || error.cause?.code === "ENOENT";
|
|
55
72
|
const timedOut = error.code === "ETIMEDOUT" || error.killed === true || error.signal === "SIGTERM";
|
|
@@ -67,33 +84,42 @@ export function createSigstoreSigningProvider({
|
|
|
67
84
|
async verify({ target, statementPath, bundlePath, policy = {} } = {}) {
|
|
68
85
|
if (!bundlePath) return { status: "UNSIGNED", signer: null };
|
|
69
86
|
try {
|
|
70
|
-
await
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
return await withExistingSigningReadScope(target, async () => {
|
|
88
|
+
await assertSafePath(target, statementPath);
|
|
89
|
+
await assertSafePath(target, bundlePath);
|
|
90
|
+
const taskId = signingTaskId(target, statementPath);
|
|
91
|
+
const statementAbsolute = ensureWithin(target, statementPath);
|
|
92
|
+
const bundleAbsolute = ensureWithin(target, bundlePath);
|
|
93
|
+
const args = [
|
|
94
|
+
"verify-blob-attestation",
|
|
95
|
+
"--statement", statementAbsolute,
|
|
96
|
+
"--bundle", bundleAbsolute,
|
|
97
|
+
];
|
|
98
|
+
const identities = Array.isArray(policy.identities)
|
|
99
|
+
? [...new Set(policy.identities.filter((value) => typeof value === "string" && value.length > 0))]
|
|
100
|
+
: [];
|
|
101
|
+
if (policy.identity) args.push("--certificate-identity", policy.identity);
|
|
102
|
+
else if (identities.length === 1) args.push("--certificate-identity", identities[0]);
|
|
103
|
+
else if (identities.length > 1) {
|
|
104
|
+
const exactAlternatives = identities
|
|
105
|
+
.map((value) => value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"))
|
|
106
|
+
.join("|");
|
|
107
|
+
args.push("--certificate-identity-regexp", `^(?:${exactAlternatives})$`);
|
|
108
|
+
}
|
|
109
|
+
if (policy.issuer) args.push("--certificate-oidc-issuer", policy.issuer);
|
|
110
|
+
if (policy.trustedRoot) {
|
|
111
|
+
await assertSafePath(target, policy.trustedRoot);
|
|
112
|
+
args.push("--trusted-root", ensureWithin(target, policy.trustedRoot));
|
|
113
|
+
}
|
|
114
|
+
await withSigningStatementFile(target, statementPath, statementFilename => {
|
|
115
|
+
args[args.indexOf("--statement") + 1] = statementFilename;
|
|
116
|
+
return withOperationalAttachmentFile(target, bundlePath, taskId, bundleFilename => {
|
|
117
|
+
args[args.indexOf("--bundle") + 1] = bundleFilename;
|
|
118
|
+
return run(args, { cwd: path.resolve(target) });
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
return { status: "VALID", signer: policy.identity ?? (identities.length === 1 ? identities[0] : null) };
|
|
122
|
+
});
|
|
97
123
|
} catch (error) {
|
|
98
124
|
if (error.code === "E_ATTESTATION_SIGNER_UNAVAILABLE") throw error;
|
|
99
125
|
const unavailable = error.code === "ENOENT" || error.cause?.code === "ENOENT";
|
|
@@ -126,6 +152,7 @@ export function createSigstoreSigningProvider({
|
|
|
126
152
|
}
|
|
127
153
|
},
|
|
128
154
|
};
|
|
155
|
+
return provider;
|
|
129
156
|
}
|
|
130
157
|
|
|
131
158
|
/**
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { needsExistingProjectScope, withExistingProjectScope } from "../../storage/existing-project-scope.js";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { assertSafePath, ensureWithin, writeFileAtomic } from "../filesystem.js";
|
|
6
|
+
import { getOperationalStore, readOperationalText } from "../../storage/operational-context.js";
|
|
7
|
+
|
|
8
|
+
/** Present selected canonical bytes to external signers without a legacy mirror. */
|
|
9
|
+
export async function withSigningStatementFile(target, statementPath, callback) {
|
|
10
|
+
if (await needsExistingProjectScope(target)) {
|
|
11
|
+
return withExistingProjectScope(target, () => withSigningStatementFile(target, statementPath, callback), { readOnly: true });
|
|
12
|
+
}
|
|
13
|
+
await assertSafePath(target, statementPath);
|
|
14
|
+
const source = readOperationalText(target, statementPath);
|
|
15
|
+
if (!source.selected) return callback(ensureWithin(target, statementPath));
|
|
16
|
+
const invalid = message => Object.assign(new Error(message), { code: "E_ATTESTATION_STATEMENT_INVALID" });
|
|
17
|
+
if (source.text === null) throw invalid("Selected attestation statement is missing");
|
|
18
|
+
if (getOperationalStore(target).db.isTransaction) throw invalid("External signing cannot run inside a SQLite write transaction");
|
|
19
|
+
const directory = await mkdtemp(path.join(os.tmpdir(), "forgeloop-signing-statement-"));
|
|
20
|
+
try {
|
|
21
|
+
const filename = path.join(directory, "statement.json");
|
|
22
|
+
await writeFileAtomic(filename, source.text);
|
|
23
|
+
const result = await callback(filename);
|
|
24
|
+
if (readOperationalText(target, statementPath).text !== source.text) throw invalid("Attestation statement changed during external signing");
|
|
25
|
+
return result;
|
|
26
|
+
} finally { await rm(directory, { recursive: true, force: true }); }
|
|
27
|
+
}
|
package/src/core/sources.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
import { CONTRACT_PRESET_IDS } from "./contract-presets.js";
|
|
1
2
|
import { PROTOCOL_VERSION } from "./protocol.js";
|
|
2
3
|
|
|
4
|
+
const CONTRACT_PRESET_PREFIX = "contract-preset:";
|
|
5
|
+
const BUILTIN_CONTRACT_PRESET_REFS = new Set(
|
|
6
|
+
CONTRACT_PRESET_IDS.map((presetId) => `${CONTRACT_PRESET_PREFIX}${presetId}`),
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export function isBuiltinContractPresetRef(ref) {
|
|
10
|
+
return typeof ref === "string" && BUILTIN_CONTRACT_PRESET_REFS.has(ref);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function externalContractSourceRefs(refs = []) {
|
|
14
|
+
return refs.filter((ref) => !isBuiltinContractPresetRef(ref));
|
|
15
|
+
}
|
|
16
|
+
|
|
3
17
|
export const SOURCE_REGISTRY_SCHEMA_VERSION = 1;
|
|
4
18
|
export const SOURCE_KINDS = Object.freeze([
|
|
5
19
|
"user-request",
|
|
@@ -84,3 +98,26 @@ export function assertSourceProvenance(registry, refs = [], { expectedKind } = {
|
|
|
84
98
|
}
|
|
85
99
|
return true;
|
|
86
100
|
}
|
|
101
|
+
|
|
102
|
+
export function assertContractPresetRefs(refs = []) {
|
|
103
|
+
for (const ref of refs) {
|
|
104
|
+
if (typeof ref === "string" && ref.startsWith(CONTRACT_PRESET_PREFIX) && !isBuiltinContractPresetRef(ref)) {
|
|
105
|
+
const error = new Error(`Unknown built-in contract preset source: ${ref}`);
|
|
106
|
+
error.code = "E_PROFILE_SOURCE_UNKNOWN";
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function assertContractSourceProvenance(registry, refs = []) {
|
|
114
|
+
assertContractPresetRefs(refs);
|
|
115
|
+
const externalRefs = externalContractSourceRefs(refs);
|
|
116
|
+
if (externalRefs.length === 0) return true;
|
|
117
|
+
if (!registry) {
|
|
118
|
+
const error = new Error("External contract source references require a source registry");
|
|
119
|
+
error.code = "E_PROFILE_SOURCE_MISSING";
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
return assertSourceProvenance(registry, externalRefs);
|
|
123
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const owners = new WeakMap();
|
|
2
|
+
function closed(message) { return Object.assign(new Error(message), { code: "E_STORAGE_RUNTIME_CLOSED" }); }
|
|
3
|
+
|
|
4
|
+
/** Register lazy ownership without importing a SQLite implementation. */
|
|
5
|
+
export function attachStorageConnectionOwner(context) {
|
|
6
|
+
let owner;
|
|
7
|
+
let loading;
|
|
8
|
+
let closing = false;
|
|
9
|
+
let closePromise;
|
|
10
|
+
const pending = new Set();
|
|
11
|
+
const getOwner = () => loading ??= import("../storage/connection-owner.js").then(module => {
|
|
12
|
+
owner = module.createStorageConnectionOwner();
|
|
13
|
+
return owner;
|
|
14
|
+
});
|
|
15
|
+
const proxy = {
|
|
16
|
+
run(target, callback, options) {
|
|
17
|
+
if (closing) return Promise.reject(closed("Persistent storage runtime is closing or closed"));
|
|
18
|
+
const request = getOwner().then(value => value.run(target, callback, options));
|
|
19
|
+
pending.add(request);
|
|
20
|
+
const finished = () => { pending.delete(request); };
|
|
21
|
+
request.then(finished, finished);
|
|
22
|
+
return request;
|
|
23
|
+
},
|
|
24
|
+
close() {
|
|
25
|
+
if (owner?.isActive()) return Promise.reject(closed("Close the runtime outside an active command"));
|
|
26
|
+
if (closePromise) return closePromise;
|
|
27
|
+
closing = true;
|
|
28
|
+
closePromise = (async () => {
|
|
29
|
+
await Promise.all([...pending].map(request => request.catch(() => undefined)));
|
|
30
|
+
if (loading) await (await loading).close();
|
|
31
|
+
})();
|
|
32
|
+
return closePromise;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
owners.set(context, proxy);
|
|
36
|
+
return proxy.close;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getStorageConnectionOwner(context) {
|
|
40
|
+
return context && typeof context === "object" ? owners.get(context) ?? null : null;
|
|
41
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { needsExistingProjectScope, withExistingProjectScope } from "../../storage/existing-project-scope.js";
|
|
1
2
|
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { listOperationalArtifactNames, operationalArtifactExists } from "../../storage/operational-context.js";
|
|
2
4
|
|
|
3
5
|
import {
|
|
4
6
|
canonicalFingerprint,
|
|
@@ -205,21 +207,25 @@ export async function writeStructuralQualityBaseline(
|
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
export async function listStructuralQualityEvaluations(target, taskId, packageRoot = getPackageRoot()) {
|
|
210
|
+
if (await needsExistingProjectScope(target)) {
|
|
211
|
+
return withExistingProjectScope(target, () => listStructuralQualityEvaluations(target, taskId, packageRoot), { readOnly: true });
|
|
212
|
+
}
|
|
208
213
|
const relativeDirectory = taskStructuralQualityEvaluationsDirectory(taskId);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
let names = listOperationalArtifactNames(target, taskId, "structural-quality/evaluations");
|
|
215
|
+
if (names === null) {
|
|
216
|
+
await assertSafePath(target, relativeDirectory);
|
|
217
|
+
const absoluteDirectory = ensureWithin(target, relativeDirectory);
|
|
218
|
+
if (!(await fileExists(absoluteDirectory))) return [];
|
|
219
|
+
try {
|
|
220
|
+
names = (await readdir(absoluteDirectory, { withFileTypes: true })).filter(entry => entry.isFile()).map(entry => entry.name);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
throw qualityArtifactError(E_STRUCTURAL_QUALITY_EVIDENCE_STALE, `Unable to list structural-quality evaluations: ${error.message}`, [relativeDirectory]);
|
|
223
|
+
}
|
|
217
224
|
}
|
|
218
|
-
const candidates =
|
|
219
|
-
.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return match ? { name: entry.name, verificationCycle: Number(match[1]), attempt: Number(match[2]) } : null;
|
|
225
|
+
const candidates = names
|
|
226
|
+
.map((name) => {
|
|
227
|
+
const match = /^cycle-(\d+)-attempt-(\d+)\.json$/u.exec(name);
|
|
228
|
+
return match ? { name, verificationCycle: Number(match[1]), attempt: Number(match[2]) } : null;
|
|
223
229
|
})
|
|
224
230
|
.filter(Boolean)
|
|
225
231
|
.filter((item) => item.verificationCycle >= 1 && item.attempt >= 1)
|
|
@@ -267,7 +273,7 @@ export async function writeStructuralQualityEvaluation(target, taskId, verificat
|
|
|
267
273
|
throw qualityArtifactError(E_STRUCTURAL_QUALITY_EVIDENCE_STALE, `Evaluation identity does not match ${relativePath}`, [relativePath]);
|
|
268
274
|
}
|
|
269
275
|
validateStructuralQualityArtifact(value, relativePath);
|
|
270
|
-
const existing = await fileExists(ensureWithin(target, relativePath));
|
|
276
|
+
const existing = operationalArtifactExists(target, relativePath) ?? await fileExists(ensureWithin(target, relativePath));
|
|
271
277
|
if (existing) {
|
|
272
278
|
const current = await readStructuralQualityEvaluation(target, taskId, cycle, normalizedAttempt, packageRoot);
|
|
273
279
|
if (current.fingerprint === canonicalFingerprint(value)) return { ...current, existing: true, identical: true };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { needsExistingProjectScope } from "../../storage/existing-project-scope.js";
|
|
2
|
+
import { withProjectReadSnapshot } from "../../storage/project-read-snapshot.js";
|
|
1
3
|
import { canonicalFingerprint, readJsonArtifact } from "../artifacts.js";
|
|
2
4
|
import { readConfig } from "../config.js";
|
|
3
5
|
import { readContract } from "../contract.js";
|
|
@@ -36,6 +38,22 @@ import {
|
|
|
36
38
|
import { appendProtocolEvent } from "../events.js";
|
|
37
39
|
import { getPackageRoot } from "../templates.js";
|
|
38
40
|
import { withTaskMutation } from "../task-command.js";
|
|
41
|
+
import { withTaskTransaction } from "../transaction.js";
|
|
42
|
+
import { getOperationalStore } from "../../storage/operational-context.js";
|
|
43
|
+
|
|
44
|
+
async function withQualityMutation(target, options, operation, callback) {
|
|
45
|
+
const native = Boolean(getOperationalStore(target)) || await needsExistingProjectScope(target);
|
|
46
|
+
for (let retry = 0; ; retry += 1) {
|
|
47
|
+
try {
|
|
48
|
+
return await withTaskMutation(target, options, operation, callback);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
// These callbacks persist an already captured observation. A native
|
|
51
|
+
// conflict discards their staged writes; rerun admission and bindings
|
|
52
|
+
// against current records without invoking the provider again.
|
|
53
|
+
if (!native || error.code !== "E_STATE_REVISION_CONFLICT" || retry >= 2) throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
39
57
|
import { findTaskById } from "../task-discovery.js";
|
|
40
58
|
import { currentChangedPaths } from "../repository.js";
|
|
41
59
|
import { assertClaimsCoverChangedPaths } from "../task-scope.js";
|
|
@@ -142,7 +160,11 @@ function normalizeScanResult(result, provider, detection, projectPath) {
|
|
|
142
160
|
};
|
|
143
161
|
}
|
|
144
162
|
|
|
145
|
-
export async function resolveStructuralQualityContext({
|
|
163
|
+
export async function resolveStructuralQualityContext(options = {}) {
|
|
164
|
+
return withProjectReadSnapshot(options.target, () => resolveStructuralQualityContextObservation(options));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function resolveStructuralQualityContextObservation({
|
|
146
168
|
target,
|
|
147
169
|
packageRoot = getPackageRoot(),
|
|
148
170
|
taskId,
|
|
@@ -378,31 +400,43 @@ export async function captureStructuralQualityBaseline({ target, packageRoot = g
|
|
|
378
400
|
scope: updatedInputs.scope,
|
|
379
401
|
snapshot: scan.snapshot,
|
|
380
402
|
};
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
return withTaskTransaction({ target, taskId, packageRoot, operation: "quality-baseline" }, async () => {
|
|
404
|
+
const currentInputs = await taskInputs(target, packageRoot, taskId, { runtimeContext, timeoutMs, maxOutputBytes });
|
|
405
|
+
if (currentInputs.state.phase !== "PLANNED"
|
|
406
|
+
|| currentInputs.contract.fingerprint !== inputs.contract.fingerprint
|
|
407
|
+
|| currentInputs.route.fingerprint !== inputs.route.fingerprint
|
|
408
|
+
|| structuralQualityPolicyFingerprint(currentInputs.policy) !== policyFingerprint
|
|
409
|
+
|| currentInputs.scopeFingerprint !== inputs.scopeFingerprint) {
|
|
410
|
+
throw qualityError(E_STRUCTURAL_QUALITY_OBSERVATION_EPOCH_STALE, "Task baseline configuration changed during observation");
|
|
411
|
+
}
|
|
412
|
+
await assertReadyPreflight(target, packageRoot, taskId);
|
|
413
|
+
const currentBaseline = await readStructuralQualityBaseline(target, taskId, packageRoot);
|
|
414
|
+
const written = await writeStructuralQualityBaseline(target, taskId, value, packageRoot, { phase: currentInputs.state.phase, replace, taskId });
|
|
415
|
+
if (!written.identical) {
|
|
416
|
+
await appendProtocolEvent(target, {
|
|
417
|
+
taskId,
|
|
418
|
+
event: "STRUCTURAL_QUALITY_BASELINE_RECORDED",
|
|
419
|
+
details: {
|
|
420
|
+
artifactRef: written.path,
|
|
421
|
+
artifactFingerprint: written.fingerprint,
|
|
422
|
+
providerId: scan.provider.id,
|
|
423
|
+
providerVersion: scan.provider.version,
|
|
424
|
+
replaced: Boolean(currentBaseline),
|
|
425
|
+
supersededFingerprint: currentBaseline?.fingerprint ?? null,
|
|
426
|
+
},
|
|
427
|
+
}, packageRoot, { taskId });
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
status: written.existing ? "REPLACED" : "CAPTURED",
|
|
431
|
+
mode: policy.mode,
|
|
432
|
+
provider: scan.provider,
|
|
433
|
+
artifactRef: written.path,
|
|
434
|
+
artifactFingerprint: written.fingerprint,
|
|
435
|
+
baseline: written.value,
|
|
436
|
+
existing: written.existing,
|
|
437
|
+
identical: written.identical,
|
|
438
|
+
};
|
|
439
|
+
});
|
|
406
440
|
}
|
|
407
441
|
|
|
408
442
|
async function persistEvaluationAndCheck({ target, packageRoot, taskId, inputs, persisted, authorityContext, runtimeContext }) {
|
|
@@ -443,7 +477,7 @@ async function persistEvaluationAndCheck({ target, packageRoot, taskId, inputs,
|
|
|
443
477
|
runtimeContext,
|
|
444
478
|
taskId: context?.taskId ?? taskId,
|
|
445
479
|
});
|
|
446
|
-
const recorded = await
|
|
480
|
+
const recorded = await withQualityMutation(target, { taskId, packageRoot }, "quality-verify-check", async (context) => {
|
|
447
481
|
const effectiveTaskId = context?.taskId ?? taskId;
|
|
448
482
|
const evaluations = await listStructuralQualityEvaluations(target, effectiveTaskId, packageRoot);
|
|
449
483
|
const latest = evaluations
|
|
@@ -599,34 +633,33 @@ export async function evaluateStructuralQuality({ target, packageRoot = getPacka
|
|
|
599
633
|
|
|
600
634
|
// Execute provider observation OUTSIDE task mutation lock
|
|
601
635
|
const sourceFingerprintBefore = await computeMaterialSourceFingerprint(target);
|
|
636
|
+
// Every non-pass branch binds the same reserved task/cycle and source epoch.
|
|
637
|
+
const evaluationInputs = {
|
|
638
|
+
taskId,
|
|
639
|
+
inputs: initialInputs,
|
|
640
|
+
cycle,
|
|
641
|
+
attempt,
|
|
642
|
+
policy,
|
|
643
|
+
baseline,
|
|
644
|
+
sourceMaterialFingerprint: sourceFingerprintBefore,
|
|
645
|
+
};
|
|
602
646
|
let evaluation;
|
|
603
647
|
|
|
604
648
|
if (!baseline) {
|
|
605
649
|
evaluation = nonPassEvaluation({
|
|
606
|
-
|
|
607
|
-
inputs: initialInputs,
|
|
608
|
-
cycle,
|
|
609
|
-
attempt,
|
|
610
|
-
policy,
|
|
650
|
+
...evaluationInputs,
|
|
611
651
|
reasonCode: E_STRUCTURAL_QUALITY_BASELINE_MISSING,
|
|
612
652
|
sourceObservation: { beforeFingerprint: sourceFingerprintBefore, afterFingerprint: sourceFingerprintBefore, stable: true },
|
|
613
|
-
sourceMaterialFingerprint: sourceFingerprintBefore,
|
|
614
653
|
});
|
|
615
654
|
} else {
|
|
616
655
|
try {
|
|
617
656
|
const scopeChanged = baseline.value.bindings?.scopeFingerprint !== initialInputs.scopeFingerprint;
|
|
618
657
|
if (scopeChanged) {
|
|
619
658
|
evaluation = nonPassEvaluation({
|
|
620
|
-
|
|
621
|
-
inputs: initialInputs,
|
|
622
|
-
cycle,
|
|
623
|
-
attempt,
|
|
624
|
-
policy,
|
|
659
|
+
...evaluationInputs,
|
|
625
660
|
reasonCode: E_STRUCTURAL_QUALITY_EVALUATION_INCOMPARABLE,
|
|
626
661
|
reasonCodes: ["PROVIDER_CONFIG_CHANGED"],
|
|
627
|
-
baseline,
|
|
628
662
|
sourceObservation: { beforeFingerprint: sourceFingerprintBefore, afterFingerprint: sourceFingerprintBefore, stable: true },
|
|
629
|
-
sourceMaterialFingerprint: sourceFingerprintBefore,
|
|
630
663
|
});
|
|
631
664
|
evaluation.comparison.reasonCodes = [E_STRUCTURAL_QUALITY_EVALUATION_INCOMPARABLE, "PROVIDER_CONFIG_CHANGED"];
|
|
632
665
|
} else {
|
|
@@ -643,18 +676,12 @@ export async function evaluateStructuralQuality({ target, packageRoot = getPacka
|
|
|
643
676
|
|
|
644
677
|
if (!isStable) {
|
|
645
678
|
evaluation = nonPassEvaluation({
|
|
646
|
-
|
|
647
|
-
inputs: initialInputs,
|
|
648
|
-
cycle,
|
|
649
|
-
attempt,
|
|
650
|
-
policy,
|
|
679
|
+
...evaluationInputs,
|
|
651
680
|
reasonCode: E_STRUCTURAL_QUALITY_SOURCE_DRIFT,
|
|
652
681
|
providerId: scan.provider.id,
|
|
653
682
|
providerVersion: scan.provider.version,
|
|
654
683
|
detection: scan.detection,
|
|
655
|
-
baseline,
|
|
656
684
|
sourceObservation: { beforeFingerprint: sourceFingerprintBefore, afterFingerprint: sourceFingerprintAfter, stable: false },
|
|
657
|
-
sourceMaterialFingerprint: sourceFingerprintBefore,
|
|
658
685
|
});
|
|
659
686
|
} else {
|
|
660
687
|
const updatedInputs = initialInputs;
|
|
@@ -699,26 +726,20 @@ export async function evaluateStructuralQuality({ target, packageRoot = getPacka
|
|
|
699
726
|
const sourceFingerprintAfter = await computeMaterialSourceFingerprint(target).catch(() => sourceFingerprintBefore);
|
|
700
727
|
const code = error.code ?? E_STRUCTURAL_QUALITY_PROVIDER_UNAVAILABLE;
|
|
701
728
|
evaluation = nonPassEvaluation({
|
|
702
|
-
|
|
703
|
-
inputs: initialInputs,
|
|
704
|
-
cycle,
|
|
705
|
-
attempt,
|
|
706
|
-
policy,
|
|
729
|
+
...evaluationInputs,
|
|
707
730
|
reasonCode: code,
|
|
708
731
|
providerId: policy.provider,
|
|
709
|
-
baseline,
|
|
710
732
|
sourceObservation: {
|
|
711
733
|
beforeFingerprint: sourceFingerprintBefore,
|
|
712
734
|
afterFingerprint: sourceFingerprintAfter,
|
|
713
735
|
stable: sourceFingerprintBefore === sourceFingerprintAfter,
|
|
714
736
|
},
|
|
715
|
-
sourceMaterialFingerprint: sourceFingerprintBefore,
|
|
716
737
|
});
|
|
717
738
|
}
|
|
718
739
|
}
|
|
719
740
|
|
|
720
741
|
// Commit under task mutation lock
|
|
721
|
-
const captured = await
|
|
742
|
+
const captured = await withQualityMutation(target, { taskId, packageRoot }, "quality-verify-evaluation", async (context) => {
|
|
722
743
|
const lockedTaskId = context?.taskId ?? taskId;
|
|
723
744
|
const inputs = await taskInputs(target, packageRoot, lockedTaskId, { runtimeContext, timeoutMs, maxOutputBytes });
|
|
724
745
|
if (inputs.state.phase !== "VERIFYING") {
|
|
@@ -908,7 +929,11 @@ function projectionFromArtifacts(policy, baseline, current, state, evaluations =
|
|
|
908
929
|
return projection;
|
|
909
930
|
}
|
|
910
931
|
|
|
911
|
-
export async function projectStructuralQualityStatus(
|
|
932
|
+
export async function projectStructuralQualityStatus(options = {}) {
|
|
933
|
+
return withProjectReadSnapshot(options.target, () => projectStructuralQualityStatusObservation(options));
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
async function projectStructuralQualityStatusObservation({ target, packageRoot = getPackageRoot(), taskId, runtimeContext } = {}) {
|
|
912
937
|
const config = await loadOptionalConfig(target, packageRoot);
|
|
913
938
|
const policy = configuredPolicy(config);
|
|
914
939
|
if (!policy || policy.mode === "off") return emptyProjection(null);
|
|
@@ -26,7 +26,7 @@ export function targetPathForSource(sourcePath) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function legacyPathForSource(sourcePath) {
|
|
29
|
-
return sourcePath
|
|
29
|
+
return sourcePath;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export function isKitPath(relativePath) {
|