forge-workflow 0.1.0-beta.5 → 0.1.0-beta.7
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/AGENTS.md +4 -0
- package/CHANGELOG.md +48 -0
- package/CLAUDE.md +0 -12
- package/CODING_STANDARDS.md +72 -0
- package/bin/forge.js +12 -1
- package/docs/guides/MIGRATION.md +3 -3
- package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
- package/docs/reference/INSTALL.md +4 -0
- package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
- package/docs/reference/RELEASE.md +4 -4
- package/docs/reference/github-accounts.md +134 -0
- package/docs/reference/shepherd.md +63 -13
- package/lib/adapters/pr-state-adapter.js +15 -2
- package/lib/base-remote.js +138 -0
- package/lib/beta5-compatibility-evidence.js +1093 -0
- package/lib/bun-lockfile-proof.js +413 -0
- package/lib/bun-workflow-pins.js +461 -0
- package/lib/capabilities/index.js +9 -0
- package/lib/capabilities/model.js +141 -0
- package/lib/capabilities/probes.js +347 -0
- package/lib/codex-skills.js +2 -2
- package/lib/commands/_manifest.js +1 -0
- package/lib/commands/_registry.js +48 -18
- package/lib/commands/clean.js +57 -1
- package/lib/commands/doctor.js +37 -6
- package/lib/commands/gate.js +197 -27
- package/lib/commands/github.js +215 -0
- package/lib/commands/hooks.js +54 -6
- package/lib/commands/memory.js +66 -2
- package/lib/commands/merge.js +720 -73
- package/lib/commands/plan.js +33 -2
- package/lib/commands/pr.js +2 -0
- package/lib/commands/preflight.js +10 -2
- package/lib/commands/push.js +120 -9
- package/lib/commands/recall.js +95 -61
- package/lib/commands/release.js +23 -2
- package/lib/commands/remember.js +28 -4
- package/lib/commands/serve.js +26 -9
- package/lib/commands/setup.js +132 -4
- package/lib/commands/shepherd.js +578 -72
- package/lib/commands/ship.js +15 -69
- package/lib/commands/skill.js +8 -0
- package/lib/commands/team.js +47 -8
- package/lib/commands/test.js +163 -4
- package/lib/commands/validate.js +78 -22
- package/lib/commands/worktree.js +155 -19
- package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
- package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
- package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
- package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
- package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
- package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
- package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
- package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
- package/lib/forge-issues.js +78 -0
- package/lib/gate-events.js +98 -10
- package/lib/github-context.js +308 -0
- package/lib/global-flags.js +1 -0
- package/lib/hook-renderer.js +29 -1
- package/lib/issue-render.js +19 -0
- package/lib/kernel/broker.js +723 -31
- package/lib/kernel/claim-reconciler.js +238 -0
- package/lib/kernel/lease-enforcer.js +9 -4
- package/lib/kernel/legacy-claim-repair.js +442 -0
- package/lib/kernel/live-claim-projection.js +26 -0
- package/lib/kernel/migrations.js +118 -3
- package/lib/kernel/readiness-model.js +184 -12
- package/lib/kernel/schema.js +49 -1
- package/lib/kernel/sqlite-driver.js +3322 -183
- package/lib/kernel/taxonomy-validator.js +4 -1
- package/lib/kernel/windows-private-acl.js +239 -0
- package/lib/memory/hygiene.js +191 -0
- package/lib/memory/router.js +94 -27
- package/lib/memory/usage-evidence.js +4 -0
- package/lib/memory-digest.js +59 -0
- package/lib/merge-rules.js +135 -17
- package/lib/npm-publish-workflow.js +233 -40
- package/lib/package-root.js +2 -0
- package/lib/pr-monitor/auto-actions.js +169 -28
- package/lib/pr-monitor/differ.js +110 -4
- package/lib/pr-monitor/events.js +0 -0
- package/lib/pr-monitor/flow-monitor.js +1424 -0
- package/lib/pr-monitor/gather.js +251 -44
- package/lib/pr-monitor/journal.js +0 -37
- package/lib/pr-monitor/monitor.js +117 -10
- package/lib/pr-monitor/process-identity.js +117 -0
- package/lib/pr-monitor/reconcile-executor.js +1101 -625
- package/lib/pr-monitor/reconcile.js +0 -0
- package/lib/pr-monitor/render-summary.js +121 -24
- package/lib/pr-monitor/review-preflight.js +269 -0
- package/lib/pr-monitor/shepherd-lease.js +28 -19
- package/lib/pr-monitor/verdict.js +438 -0
- package/lib/pr-monitor/watch-lifecycle.js +144 -38
- package/lib/pr-monitor/watch-owner.js +1414 -0
- package/lib/pr-monitor/watch.js +129 -58
- package/lib/pr-shepherd.js +17 -3
- package/lib/project-memory.js +145 -3
- package/lib/protected-state-authority.js +799 -4
- package/lib/protected-state-surfaces.js +181 -3
- package/lib/release-readiness.js +2 -3
- package/lib/review-adapter.js +65 -0
- package/lib/skills-sync.js +65 -32
- package/lib/validation/risk-manifest.js +339 -0
- package/lib/validation-receipt.js +190 -0
- package/lib/workflow/enforce-stage.js +44 -0
- package/lib/workflow/plan-authority.js +225 -0
- package/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
- package/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
- package/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
- package/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
- package/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
- package/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
- package/node_modules/@forge/contracts/index.js +32 -0
- package/node_modules/@forge/contracts/package.json +35 -0
- package/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
- package/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
- package/node_modules/@forge/contracts/src/baseline.js +23 -0
- package/node_modules/@forge/contracts/src/canonical.js +151 -0
- package/node_modules/@forge/contracts/src/definitions.js +176 -0
- package/node_modules/@forge/contracts/src/identity.js +42 -0
- package/node_modules/@forge/contracts/src/schema.js +72 -0
- package/node_modules/@forge/contracts/src/validate.js +305 -0
- package/node_modules/@forge/flow/index.js +114 -0
- package/node_modules/@forge/flow/package.json +34 -0
- package/node_modules/@forge/flow/src/bounded-loop.js +415 -0
- package/node_modules/@forge/flow/src/efficiency-supervisor.js +89 -0
- package/node_modules/@forge/flow/src/executor.js +279 -0
- package/node_modules/@forge/flow/src/monitor-durability.js +419 -0
- package/node_modules/@forge/flow/src/monitor-runtime.js +460 -0
- package/node_modules/@forge/flow/src/process-lifecycle.js +469 -0
- package/node_modules/@forge/flow/src/skill-runtime.js +343 -0
- package/node_modules/@forge/memory/index.js +331 -0
- package/node_modules/@forge/memory/package.json +34 -0
- package/node_modules/@forge/memory/src/authority-provider.js +67 -0
- package/node_modules/@forge/memory/src/backend-registry.js +166 -0
- package/node_modules/@forge/memory/src/feedback-intake.js +243 -0
- package/node_modules/@forge/memory/src/pr-lifecycle-authority.js +946 -0
- package/node_modules/@forge/memory/src/usage-evidence.js +205 -0
- package/package.json +16 -4
- package/packages/flow/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/index.js +32 -0
- package/packages/flow/node_modules/@forge/contracts/package.json +35 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
- package/packages/flow/node_modules/@forge/contracts/src/baseline.js +23 -0
- package/packages/flow/node_modules/@forge/contracts/src/canonical.js +151 -0
- package/packages/flow/node_modules/@forge/contracts/src/definitions.js +176 -0
- package/packages/flow/node_modules/@forge/contracts/src/identity.js +42 -0
- package/packages/flow/node_modules/@forge/contracts/src/schema.js +72 -0
- package/packages/flow/node_modules/@forge/contracts/src/validate.js +305 -0
- package/packages/memory/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/index.js +32 -0
- package/packages/memory/node_modules/@forge/contracts/package.json +35 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
- package/packages/memory/node_modules/@forge/contracts/src/baseline.js +23 -0
- package/packages/memory/node_modules/@forge/contracts/src/canonical.js +151 -0
- package/packages/memory/node_modules/@forge/contracts/src/definitions.js +176 -0
- package/packages/memory/node_modules/@forge/contracts/src/identity.js +42 -0
- package/packages/memory/node_modules/@forge/contracts/src/schema.js +72 -0
- package/packages/memory/node_modules/@forge/contracts/src/validate.js +305 -0
- package/scripts/commitlint.js +13 -15
- package/scripts/generate-risk-manifest.js +91 -0
- package/scripts/github-context-bridge.sh +10 -0
- package/scripts/legacy-claim-repair.js +145 -0
- package/scripts/lib/behavioral-eval-runtime.js +3 -2
- package/scripts/process-tree.js +14 -2
- package/scripts/protected-state-check.js +440 -17
- package/scripts/sync-agent-skills.js +333 -34
- package/scripts/test-full-suite.js +704 -18
- package/scripts/test-profile.js +13 -3
- package/scripts/test.js +96 -15
- package/skills/coverage.json +1 -0
- package/skills/review/SKILL.md +2 -0
- package/skills/review/evals/scorecard.json +2 -2
- package/skills/setup/SKILL.md +18 -0
- package/skills/setup/evals/scorecard.json +3 -3
- package/skills/shepherd/SKILL.md +19 -2
- package/skills/shepherd/evals/scorecard.json +3 -3
- package/skills/validate/SKILL.md +3 -0
- package/skills/validate/evals/scorecard.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { parse } = require('yaml');
|
|
7
|
+
const { stableStringify } = require('../lib/kernel/evaluators');
|
|
8
|
+
const { hashManifest, validateManifest } = require('../lib/validation/risk-manifest');
|
|
9
|
+
const crypto = require('node:crypto');
|
|
10
|
+
|
|
11
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
12
|
+
const SOURCE_PATH = path.join(ROOT, 'validation', 'risk-manifest.source.yaml');
|
|
13
|
+
const OUTPUT_PATH = path.join(ROOT, 'validation', 'risk-manifest.v1.json');
|
|
14
|
+
|
|
15
|
+
function sha256(value) {
|
|
16
|
+
return `sha256:${crypto.createHash('sha256').update(value, 'utf8').digest('hex')}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function compareText(left, right) {
|
|
20
|
+
if (left === right) return 0;
|
|
21
|
+
return left < right ? -1 : 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function sortById(entries) {
|
|
25
|
+
return [...entries].sort((left, right) => compareText(left.id, right.id));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function normalizeSource(source) {
|
|
29
|
+
const canonicalSource = source.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
|
|
30
|
+
const parsed = parse(canonicalSource);
|
|
31
|
+
const manifest = {
|
|
32
|
+
schema_id: parsed.schema_id,
|
|
33
|
+
revision: parsed.revision,
|
|
34
|
+
source_hash: sha256(canonicalSource),
|
|
35
|
+
generator_version: 'forge-risk-manifest-generator.v1',
|
|
36
|
+
commands: sortById(parsed.commands).map((command) => ({
|
|
37
|
+
...command,
|
|
38
|
+
argv: [...command.argv],
|
|
39
|
+
})),
|
|
40
|
+
gates: sortById(parsed.gates).map((gate) => ({
|
|
41
|
+
...gate,
|
|
42
|
+
command_ids: [...gate.command_ids].sort(compareText),
|
|
43
|
+
})),
|
|
44
|
+
lanes: sortById(parsed.lanes).map((lane) => ({
|
|
45
|
+
...lane,
|
|
46
|
+
command_ids: [...lane.command_ids].sort(compareText),
|
|
47
|
+
})),
|
|
48
|
+
risks: sortById(parsed.risks).map((risk) => ({
|
|
49
|
+
...risk,
|
|
50
|
+
gate_ids: [...risk.gate_ids].sort(),
|
|
51
|
+
})),
|
|
52
|
+
owners: sortById(parsed.owners).map((owner) => ({
|
|
53
|
+
...owner,
|
|
54
|
+
risk_ids: [...owner.risk_ids].sort(),
|
|
55
|
+
canonical_test_ids: [...owner.canonical_test_ids].sort(),
|
|
56
|
+
dependent_routes: [...owner.dependent_routes].sort(),
|
|
57
|
+
platform_runtime_additions: [...owner.platform_runtime_additions].sort(),
|
|
58
|
+
lanes: [...owner.lanes].sort(),
|
|
59
|
+
package_roots: [...owner.package_roots].sort(),
|
|
60
|
+
selectors: [...owner.selectors].sort((left, right) => compareText(left.kind, right.kind)
|
|
61
|
+
|| compareText(left.prefix, right.prefix)),
|
|
62
|
+
})),
|
|
63
|
+
unknown_owner_fallback: {
|
|
64
|
+
...parsed.unknown_owner_fallback,
|
|
65
|
+
required_gates: [...parsed.unknown_owner_fallback.required_gates].sort(),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
manifest.manifest_hash = hashManifest(manifest);
|
|
69
|
+
validateManifest(manifest);
|
|
70
|
+
return JSON.parse(stableStringify(manifest));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function generateRiskManifest(source) {
|
|
74
|
+
return `${JSON.stringify(normalizeSource(source), null, 2)}\n`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function main(args = process.argv.slice(2)) {
|
|
78
|
+
const generated = generateRiskManifest(fs.readFileSync(SOURCE_PATH, 'utf8'));
|
|
79
|
+
if (args.includes('--check')) {
|
|
80
|
+
if (!fs.existsSync(OUTPUT_PATH) || fs.readFileSync(OUTPUT_PATH, 'utf8') !== generated) {
|
|
81
|
+
console.error('Risk manifest is stale. Run: node scripts/generate-risk-manifest.js');
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
fs.writeFileSync(OUTPUT_PATH, generated, 'utf8');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (require.main === module) main();
|
|
90
|
+
|
|
91
|
+
module.exports = { generateRiskManifest, normalizeSource };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# GH_CMD bridge: re-enter this Forge runtime without credentials in the Bash parent.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
: "${FORGE_GITHUB_RUNTIME:?Forge GitHub runtime is required}"
|
|
6
|
+
if [[ -n "${FORGE_GITHUB_ENTRY:-}" ]]; then
|
|
7
|
+
exec "$FORGE_GITHUB_RUNTIME" "$FORGE_GITHUB_ENTRY" github run -- gh "$@"
|
|
8
|
+
else
|
|
9
|
+
exec "$FORGE_GITHUB_RUNTIME" github run -- gh "$@"
|
|
10
|
+
fi
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
createBuiltinSQLiteDriver,
|
|
8
|
+
hardenBackupPermissions,
|
|
9
|
+
hardenBackupPermissionsBatch,
|
|
10
|
+
} = require('../lib/kernel/sqlite-driver');
|
|
11
|
+
const {
|
|
12
|
+
ClaimRepairError,
|
|
13
|
+
createVerifiedClaimRepairBackup,
|
|
14
|
+
} = require('../lib/kernel/legacy-claim-repair');
|
|
15
|
+
|
|
16
|
+
const HELP = `Usage:
|
|
17
|
+
bun scripts/legacy-claim-repair.js --dry-run --database <kernel.sqlite> --backup <separate.sqlite> --at <canonical-UTC>
|
|
18
|
+
bun scripts/legacy-claim-repair.js --apply --database <kernel.sqlite> --backup <separate.sqlite> --at <canonical-UTC> --approved-digest <sha256> --actor <identity>
|
|
19
|
+
|
|
20
|
+
The tool never discovers or repairs a database automatically. Apply is rejected
|
|
21
|
+
without a verified restorable backup and the exact human-approved dry-run digest.`;
|
|
22
|
+
|
|
23
|
+
function parseArgs(argv = []) {
|
|
24
|
+
const result = { mode: null };
|
|
25
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
26
|
+
const arg = argv[index];
|
|
27
|
+
if (arg === '--help' || arg === '-h') return { help: true };
|
|
28
|
+
if (arg === '--dry-run' || arg === '--apply') {
|
|
29
|
+
const mode = arg.slice(2);
|
|
30
|
+
if (result.mode && result.mode !== mode) throw new Error('Choose exactly one of --dry-run or --apply');
|
|
31
|
+
result.mode = mode;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const names = {
|
|
35
|
+
'--database': 'databasePath',
|
|
36
|
+
'--backup': 'backupPath',
|
|
37
|
+
'--at': 'observedAt',
|
|
38
|
+
'--approved-digest': 'approvedDigest',
|
|
39
|
+
'--actor': 'actor',
|
|
40
|
+
};
|
|
41
|
+
if (!Object.hasOwn(names, arg)) throw new Error(`Unknown argument: ${arg}`);
|
|
42
|
+
const name = names[arg];
|
|
43
|
+
const value = argv[index + 1];
|
|
44
|
+
if (!value || value.startsWith('--')) throw new Error(`${arg} requires a value`);
|
|
45
|
+
result[name] = value;
|
|
46
|
+
index += 1;
|
|
47
|
+
}
|
|
48
|
+
if (!result.mode) throw new Error('Choose exactly one of --dry-run or --apply');
|
|
49
|
+
for (const required of ['databasePath', 'backupPath', 'observedAt']) {
|
|
50
|
+
if (!result[required]) throw new Error(`Missing required option: ${required}`);
|
|
51
|
+
}
|
|
52
|
+
for (const requiredPath of ['databasePath', 'backupPath']) {
|
|
53
|
+
if (!path.isAbsolute(result[requiredPath])) {
|
|
54
|
+
throw new Error(`${requiredPath} must be an absolute path`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (result.mode === 'apply' && !result.approvedDigest) {
|
|
58
|
+
throw new Error('--apply requires --approved-digest');
|
|
59
|
+
}
|
|
60
|
+
if (result.mode === 'apply' && !result.actor) {
|
|
61
|
+
throw new Error('--apply requires --actor');
|
|
62
|
+
}
|
|
63
|
+
if (result.mode === 'dry-run' && result.approvedDigest) {
|
|
64
|
+
throw new Error('--approved-digest is valid only with --apply');
|
|
65
|
+
}
|
|
66
|
+
if (result.mode === 'dry-run' && result.actor) {
|
|
67
|
+
throw new Error('--actor is valid only with --apply');
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function run(options, dependencies = {}) {
|
|
73
|
+
const openDriver = dependencies.openDriver
|
|
74
|
+
|| (databasePath => createBuiltinSQLiteDriver({ databasePath }));
|
|
75
|
+
const createBackup = dependencies.createVerifiedClaimRepairBackup
|
|
76
|
+
|| createVerifiedClaimRepairBackup;
|
|
77
|
+
const hardenPath = dependencies.hardenPath || hardenBackupPermissions;
|
|
78
|
+
const hardenPaths = dependencies.hardenPaths
|
|
79
|
+
|| (dependencies.hardenPath ? dependencies.hardenPath.batch : hardenBackupPermissionsBatch);
|
|
80
|
+
const sourceDriver = openDriver(options.databasePath);
|
|
81
|
+
try {
|
|
82
|
+
if (options.mode === 'dry-run') {
|
|
83
|
+
const backup = await createBackup({
|
|
84
|
+
sourceDriver,
|
|
85
|
+
backupPath: options.backupPath,
|
|
86
|
+
observedAt: options.observedAt,
|
|
87
|
+
openDriver,
|
|
88
|
+
hardenPath,
|
|
89
|
+
hardenPaths,
|
|
90
|
+
});
|
|
91
|
+
const preflight = await sourceDriver.preflightLegacyClaimRepair({ observedAt: options.observedAt });
|
|
92
|
+
if (preflight.digest !== backup.plan_digest) {
|
|
93
|
+
throw new ClaimRepairError(
|
|
94
|
+
'CLAIM_REPAIR_BACKUP_DRIFT',
|
|
95
|
+
'Live claim authority changed while binding the reported preflight to its verified backup',
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return { ok: true, preflight, backup };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const receipt = await sourceDriver.applyLegacyClaimRepair({
|
|
102
|
+
observedAt: options.observedAt,
|
|
103
|
+
approvedDigest: options.approvedDigest,
|
|
104
|
+
backupPath: options.backupPath,
|
|
105
|
+
actor: options.actor,
|
|
106
|
+
});
|
|
107
|
+
return { ok: true, receipt };
|
|
108
|
+
} finally {
|
|
109
|
+
sourceDriver.close();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function main(argv = process.argv.slice(2)) {
|
|
114
|
+
try {
|
|
115
|
+
const options = parseArgs(argv);
|
|
116
|
+
if (options.help) {
|
|
117
|
+
process.stdout.write(`${HELP}\n`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
process.stdout.write(`${JSON.stringify(await run(options), null, 2)}\n`);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const recoveryPath = error?.code === 'CLAIM_REPAIR_BACKUP_POSTCOMMIT_DRIFT'
|
|
123
|
+
&& typeof error?.details?.recovery_path === 'string'
|
|
124
|
+
? error.details.recovery_path
|
|
125
|
+
: null;
|
|
126
|
+
process.stderr.write(`${JSON.stringify({
|
|
127
|
+
ok: false,
|
|
128
|
+
error: {
|
|
129
|
+
code: error?.code || 'CLAIM_REPAIR_USAGE',
|
|
130
|
+
message: error?.message || String(error),
|
|
131
|
+
...(recoveryPath ? { recovery_path: recoveryPath } : {}),
|
|
132
|
+
},
|
|
133
|
+
}, null, 2)}\n`);
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (require.main === module) void main();
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
HELP,
|
|
142
|
+
main,
|
|
143
|
+
parseArgs,
|
|
144
|
+
run,
|
|
145
|
+
};
|
|
@@ -156,6 +156,7 @@ function createPrAdapter(projectRoot, execFile = execFileSync) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
async function resolveAttribution(projectRoot, head, env, deps = {}) {
|
|
159
|
+
const prExec = deps.runGh ? (_command, args, options) => deps.runGh(args, options) : deps.execFileSync;
|
|
159
160
|
const branch = resolveBranch(projectRoot, deps.execFileSync);
|
|
160
161
|
const requestedIssueId = env.FORGE_EVAL_ISSUE_ID;
|
|
161
162
|
if (requestedIssueId && !UUID.test(String(requestedIssueId))) {
|
|
@@ -172,11 +173,11 @@ async function resolveAttribution(projectRoot, head, env, deps = {}) {
|
|
|
172
173
|
}
|
|
173
174
|
const pr = explicitPr
|
|
174
175
|
? Number(env.FORGE_EVAL_PR)
|
|
175
|
-
: resolvePrFromGh(projectRoot,
|
|
176
|
+
: resolvePrFromGh(projectRoot, prExec);
|
|
176
177
|
if (!pr) throw new Error('attribution.pr_unavailable');
|
|
177
178
|
let state;
|
|
178
179
|
try {
|
|
179
|
-
const adapter = deps.prAdapter || createPrAdapter(projectRoot,
|
|
180
|
+
const adapter = deps.prAdapter || createPrAdapter(projectRoot, prExec);
|
|
180
181
|
state = await adapter.readState(pr);
|
|
181
182
|
} catch {
|
|
182
183
|
throw new Error('attribution.pr_unavailable');
|
package/scripts/process-tree.js
CHANGED
|
@@ -9,6 +9,7 @@ const { spawnSync: defaultSpawnSync } = require('node:child_process');
|
|
|
9
9
|
const MANIFEST_ENV = 'FORGE_TEST_PROCESS_MANIFEST';
|
|
10
10
|
const TOKEN_ENV = 'FORGE_TEST_PROCESS_TOKEN';
|
|
11
11
|
const INSTANCE_ENV = 'FORGE_TEST_PROCESS_INSTANCE';
|
|
12
|
+
const SESSION_ENV = 'FORGE_SESSION_ID';
|
|
12
13
|
const MANIFEST_VERSION = 1;
|
|
13
14
|
const DEFAULT_MANIFEST_DIR = path.join(os.tmpdir(), 'forge-test-processes');
|
|
14
15
|
|
|
@@ -326,7 +327,11 @@ function createProcessTree(options = {}) {
|
|
|
326
327
|
if (!identity && !hasCustomIdentity) return `unverified:${pid}`;
|
|
327
328
|
return identity;
|
|
328
329
|
};
|
|
329
|
-
|
|
330
|
+
// A Forge claim records FORGE_SESSION_ID. Use that same stable runtime token
|
|
331
|
+
// for the root manifest, while preserving an inherited manifest token for
|
|
332
|
+
// nested process trees that are already attached to their parent run.
|
|
333
|
+
const inheritedToken = nonEmptyString(options.token) || nonEmptyString(env[TOKEN_ENV]);
|
|
334
|
+
const token = String(inheritedToken || env[SESSION_ENV] || randomUUID());
|
|
330
335
|
const explicitManifestPath = nonEmptyString(options.manifestPath);
|
|
331
336
|
const environmentManifestPath = nonEmptyString(env[MANIFEST_ENV]);
|
|
332
337
|
const manifestDir = options.manifestDir || DEFAULT_MANIFEST_DIR;
|
|
@@ -351,7 +356,11 @@ function createProcessTree(options = {}) {
|
|
|
351
356
|
const existing = readProcessManifest(manifestPath, fsApi, processApi);
|
|
352
357
|
// An environment-provided path may belong to another run. Treat that as
|
|
353
358
|
// unverifiable and fail closed; never overwrite or reap another run's marker.
|
|
354
|
-
const
|
|
359
|
+
const inheritedManifestVerified = explicitManifestPath
|
|
360
|
+
|| !environmentManifestPath
|
|
361
|
+
|| Boolean(inheritedToken && existing?.token === inheritedToken);
|
|
362
|
+
const usable = inheritedManifestVerified
|
|
363
|
+
&& (!markerExists || (existing && existing.token === token));
|
|
355
364
|
let manifest = existing && existing.token === token
|
|
356
365
|
? existing
|
|
357
366
|
: (usable ? createInitialManifest(token, processApi, getProcessIdentity, instanceId) : null);
|
|
@@ -749,11 +758,14 @@ function reconcileProcessManifests(options = {}) {
|
|
|
749
758
|
}
|
|
750
759
|
|
|
751
760
|
module.exports = {
|
|
761
|
+
DEFAULT_MANIFEST_DIR,
|
|
752
762
|
INSTANCE_ENV,
|
|
753
763
|
MANIFEST_ENV,
|
|
754
764
|
MANIFEST_VERSION,
|
|
755
765
|
TOKEN_ENV,
|
|
756
766
|
createProcessTree,
|
|
767
|
+
defaultGetProcessIdentity,
|
|
768
|
+
isValidManifest,
|
|
757
769
|
readProcessManifest,
|
|
758
770
|
reapProcessManifest,
|
|
759
771
|
reconcileProcessManifests,
|