@cassiomc1/forgeloop 0.1.13 → 0.1.15
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/.forgeloop/forgeloop.gitignore +1 -0
- package/LOOP_ENGINEERING.md +61 -5
- package/PROTOCOL_INTEGRATION.md +104 -0
- package/README.md +34 -16
- package/THREAT_MODEL.md +9 -0
- package/package.json +1 -1
- package/schemas/authority.schema.json +34 -0
- package/schemas/check.schema.json +2 -0
- package/schemas/execution.schema.json +63 -0
- package/src/cli.js +64 -12
- package/src/commands/inspect.js +2 -0
- package/src/commands/prepare-completion.js +2 -2
- package/src/commands/run-check.js +83 -0
- package/src/commands/validate-protocol.js +18 -0
- package/src/core/artifacts.js +8 -0
- package/src/core/audit.js +2 -2
- package/src/core/bundles.js +72 -0
- package/src/core/checks.js +28 -5
- package/src/core/completion-artifacts.js +346 -65
- package/src/core/completion-recovery.js +4 -0
- package/src/core/completion-relationships.js +39 -4
- package/src/core/completion.js +48 -8
- package/src/core/coverage.js +15 -2
- package/src/core/evidence-readiness.js +57 -6
- package/src/core/execution.js +185 -0
- package/src/core/inspect.js +3 -1
- package/src/core/next-action.js +87 -9
- package/src/core/phase.js +29 -6
- package/src/core/protocol.js +5 -0
- package/src/core/receipt.js +6 -6
- package/src/core/runtime-context.js +80 -0
- package/src/core/schema-validation.js +1 -0
- package/src/core/templates.js +1 -0
- package/src/core/trusted-authority.js +296 -0
- package/src/core/verification-capability.js +1110 -0
package/LOOP_ENGINEERING.md
CHANGED
|
@@ -52,6 +52,7 @@ the supported ForgeLoop lifecycle commands or canonical ForgeLoop APIs:
|
|
|
52
52
|
- `.forgeloop/work-state.json`
|
|
53
53
|
- `.forgeloop/events.ndjson`
|
|
54
54
|
- `.forgeloop/execution-receipt.json`
|
|
55
|
+
- `.forgeloop/executions/<executionId>.json`
|
|
55
56
|
- completion recovery metadata
|
|
56
57
|
- canonical check/evidence state
|
|
57
58
|
- terminal-result lifecycle state
|
|
@@ -108,6 +109,60 @@ rules permit it.
|
|
|
108
109
|
A missing checker must never be converted into environmental mutation merely
|
|
109
110
|
to make verification pass.
|
|
110
111
|
|
|
112
|
+
### Verification command resolution modes and validator enforcement
|
|
113
|
+
|
|
114
|
+
Every verification command path is classified by resolution mode:
|
|
115
|
+
|
|
116
|
+
| Mode | Examples | May install software | Authority required |
|
|
117
|
+
| --- | --- | --- | --- |
|
|
118
|
+
| `LOCAL_EXECUTABLE` | `node scripts/test.js`, `python3 -m unittest`, `./bin/check` | No | No |
|
|
119
|
+
| `LOCAL_PACKAGE_BINARY` | `./node_modules/.bin/tool`, `npm test`, `pnpm test`, `yarn test` | No | No |
|
|
120
|
+
| `NON_INSTALLING_RESOLUTION` | `npx --no-install tool`, `npx --no tool` | No | No |
|
|
121
|
+
| `INSTALL_CAPABLE_RESOLUTION` | `npx tool`, `npm exec tool`, `npm x tool`, `pnpm dlx tool`, `yarn dlx tool`, `bunx tool`, `uvx tool`, `pipx run tool` | Yes | Yes (`E_INSTALLATION_AUTHORITY_REQUIRED`) |
|
|
122
|
+
| `EXPLICIT_INSTALLATION` | `npm install tool`, `pnpm add tool`, `pip install tool`, `cargo install tool` | Yes | Yes (`E_INSTALLATION_AUTHORITY_REQUIRED`) |
|
|
123
|
+
|
|
124
|
+
**Validator-enforced rule**: Any verification command executed via an installation-capable or explicit-installation resolution mode without a valid canonical installation authority grant is rejected by `record-check`, `audit`, and `complete` with error code `E_INSTALLATION_AUTHORITY_REQUIRED`, `E_AUTHORITY_INVALID`, `E_AUTHORITY_SCOPE_MISMATCH`, or `E_AUTHORITY_UNTRUSTED_SOURCE` and cannot contribute to `VALID` completion.
|
|
125
|
+
|
|
126
|
+
Recognized command dispatchers (such as `npm test`, `npm start`, `npm stop`, `npm restart`, `npm run <script>`, `npm run-script <script>`, `npm rum <script>`, `npm urn <script>`) are classified by their effective package resolution behavior across recognized lifecycle scripts before process launch. npm invocation parsing recognizes options (e.g. `--silent`, `--loglevel=error`) before the subcommand. Recognized npm-script dispatch is resolved recursively before process launch. `npm restart` uses npm's restart-specific lifecycle semantics (`prerestart`, `prestop`, `stop`, `poststop`, `prestart`, `start`, `poststart`, `postrestart` when `restart` is absent; `prerestart`, `restart`, `postrestart` when `restart` is present) rather than generic pre/main/post handling. ForgeLoop fails closed (`mayInstall: true`) when recursive npm-script resolution encounters a cycle or exceeds its maximum resolution depth (16). ForgeLoop does not resolve npm workspace selection in `run-check` for `0.1.15`. npm script executions using `--workspace`, `-w`, `--workspaces`, or `--ws` fail closed (`E_COMMAND_RESOLUTION_AMBIGUOUS`) because the effective `package.json` execution context may differ from the current ForgeLoop target. Run ForgeLoop against the selected workspace directory directly instead. If any nested lifecycle script invokes an installation-capable command (such as `npx`, `npm exec`, or `pnpm dlx`), the execution is elevated to `INSTALL_CAPABLE_RESOLUTION` and blocked before launch without authority.
|
|
127
|
+
|
|
128
|
+
**npm Classification Model**: npm classification is semantic and fail-closed. Unknown npm commands are not assumed safe. The classifier specifically identifies install-capable families including: `exec`/`x`, `install` aliases, `ci` aliases, `install-test` families, `install-ci-test` families, `update` aliases, `audit fix`, and conditional `init`/`create`/`innit` invocations. Unknown or ambiguous semantics fail closed (`E_COMMAND_RESOLUTION_AMBIGUOUS`).
|
|
129
|
+
|
|
130
|
+
Use `forgeloop run-check --id <id> --requirement <requirement> -- <argv>` for
|
|
131
|
+
observed command evidence. ForgeLoop preserves the exact argv vector, target
|
|
132
|
+
cwd, resolution classification, timestamps, exit status, and task/check
|
|
133
|
+
binding in `.forgeloop/executions/<executionId>.json` before recording the
|
|
134
|
+
check. Resolution is classified before process launch; install-capable
|
|
135
|
+
resolution is rejected without a valid host-attested authority, while
|
|
136
|
+
`npx --no-install` remains a non-installing path and may fail honestly when a
|
|
137
|
+
tool is absent. `run-check` launches the supplied argv without a shell.
|
|
138
|
+
|
|
139
|
+
`forgeloop record-check` is serialization-only. Its `--command` value is
|
|
140
|
+
metadata and is never executed. A `kind: command`, `evidenceKind: OBSERVED`
|
|
141
|
+
check must carry `provenance: FORGELOOP_EXECUTED` and a valid `executionRef`;
|
|
142
|
+
manual or actor-reported observations must use an explicit non-command kind or
|
|
143
|
+
provenance and must not be upgraded to command execution evidence. Completion,
|
|
144
|
+
audit, protocol validation, and bundles revalidate the referenced artifact and
|
|
145
|
+
its task, check, requirement, cycle, cwd, status, and exit-code binding.
|
|
146
|
+
|
|
147
|
+
Authority cannot be self-issued by the actor consuming it. Boolean fields inside verification evidence (such as `installationAuthorized: true`) are not sufficient proof of installation authority. Installation authority must be established via a canonical authority grant supplied by a host/operator trust boundary and referenced via `installationAuthorityRef`.
|
|
148
|
+
|
|
149
|
+
The runtime authority context has two modes:
|
|
150
|
+
|
|
151
|
+
- `NONE` is the default for the actor-facing standalone CLI. `FORGELOOP_AUTHORITY_FILE` and `FORGELOOP_AUTHORITY_DIR` may select candidate source metadata for compatibility and diagnostics, but they do not make a source trusted. An environment-selected source is rejected with `E_AUTHORITY_UNTRUSTED_SOURCE` when it is used for an installation-capable verification.
|
|
152
|
+
- `HOST_ATTESTED` is an internal integration context supplied by a host-owned wrapper, embedded API, or equivalent boundary. It may select a trusted authority file, directory, or in-memory provider only when the actor cannot replace that context at command invocation time. The CLI exposes no flag that promotes a source to `HOST_ATTESTED`.
|
|
153
|
+
|
|
154
|
+
External path is not equivalent to external authority ownership. The host-attested source must still resolve outside the actor-writable target, and a project-local `.forgeloop/authorities/` artifact remains an untrusted reference, cache, diagnostic, or mirror by default. A local claim such as `source: operator` is not proof of operator authority.
|
|
155
|
+
|
|
156
|
+
ForgeLoop validates authority semantics, while the host defines the trust boundary. If the host grants the actor write access to the configured attested source, the host boundary is compromised and ForgeLoop cannot distinguish operator authority from actor fabrication without a stronger external trust anchor.
|
|
157
|
+
|
|
158
|
+
### Stale receipt recovery invariant
|
|
159
|
+
|
|
160
|
+
Every recovery action returned by `forgeloop next` must be executable from the state that produced it. When work state changes legitimately after preparing a completion receipt, `forgeloop prepare-completion` refreshes the receipt and re-binds it to current state and changed paths without requiring manual deletion of `.forgeloop/execution-receipt.json`.
|
|
161
|
+
|
|
162
|
+
### Conformance profile escalation policy
|
|
163
|
+
|
|
164
|
+
A run started in Standard conformance must not be silently escalated to Strict after validator-backed completion. Strict validation is a separate conformance profile. If Strict revalidation is performed after Standard `COMPLETE`, it is treated as a distinct revalidation cycle and does not retroactively invalidate a valid Standard result.
|
|
165
|
+
|
|
111
166
|
## Blocking vs Non-Blocking Decisions
|
|
112
167
|
|
|
113
168
|
Classify every unresolved decision before deciding whether to ask the user.
|
|
@@ -476,7 +531,7 @@ prepare-completion
|
|
|
476
531
|
↓
|
|
477
532
|
run applicable project checks
|
|
478
533
|
↓
|
|
479
|
-
record
|
|
534
|
+
run commands with run-check; record manual observations with record-check
|
|
480
535
|
↓ forgeloop next
|
|
481
536
|
advance --to REVIEWING
|
|
482
537
|
↓ forgeloop next
|
|
@@ -491,10 +546,11 @@ subsequent `record-check` operations; completion remains invalid until required
|
|
|
491
546
|
observed evidence, review state, chronology, and validator requirements are
|
|
492
547
|
satisfied.
|
|
493
548
|
|
|
494
|
-
The host agent runs applicable checks after the receipt exists,
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
549
|
+
The host agent runs applicable checks after the receipt exists, uses `run-check`
|
|
550
|
+
for commands, and uses `record-check` for manual or non-command observations.
|
|
551
|
+
`run-check` records exact command provenance; `record-check` records supplied
|
|
552
|
+
metadata only and never executes its `--command` value. Query `forgeloop next`
|
|
553
|
+
before each subsequent lifecycle action.
|
|
498
554
|
|
|
499
555
|
Continue until the terminal outcome is either validator-backed `COMPLETE` or
|
|
500
556
|
an explicitly reported `BLOCKED` / `PARTIALLY VERIFIED` result with exact
|
package/PROTOCOL_INTEGRATION.md
CHANGED
|
@@ -128,6 +128,7 @@ The following protocol artifacts are strictly owned by ForgeLoop:
|
|
|
128
128
|
- `.forgeloop/work-state.json`
|
|
129
129
|
- `.forgeloop/events.ndjson`
|
|
130
130
|
- `.forgeloop/execution-receipt.json`
|
|
131
|
+
- `.forgeloop/executions/<executionId>.json`
|
|
131
132
|
- Canonical check, evidence, and terminal-result state
|
|
132
133
|
|
|
133
134
|
If the required CLI or API capability cannot be resolved:
|
|
@@ -140,6 +141,38 @@ If the required CLI or API capability cannot be resolved:
|
|
|
140
141
|
|
|
141
142
|
Report the corresponding ForgeLoop dimension as `NOT_VERIFIED` / `E_FORGELOOP_CLI_UNAVAILABLE`.
|
|
142
143
|
|
|
144
|
+
## Trusted command provenance
|
|
145
|
+
|
|
146
|
+
Command verification has two explicit paths:
|
|
147
|
+
|
|
148
|
+
- `forgeloop run-check --id <id> --requirement <requirement> -- <argv>` owns
|
|
149
|
+
execution. It classifies the exact argv before launch, uses a non-shell
|
|
150
|
+
process boundary, records the target cwd, resolution mode, timestamps,
|
|
151
|
+
exit status, and task/check binding in
|
|
152
|
+
`.forgeloop/executions/<executionId>.json`, then records an `OBSERVED` check
|
|
153
|
+
with `provenance: FORGELOOP_EXECUTED`.
|
|
154
|
+
- `forgeloop record-check` owns serialization only. `--command` is metadata and
|
|
155
|
+
is never launched. A `kind: command` check with `evidenceKind: OBSERVED`
|
|
156
|
+
requires both `executionRef` and `FORGELOOP_EXECUTED`; manual or actor-reported
|
|
157
|
+
observations use their explicit non-command/provenance values and remain
|
|
158
|
+
distinguishable from process execution.
|
|
159
|
+
|
|
160
|
+
`run-check` rejects install-capable resolution before process launch unless the
|
|
161
|
+
host supplies a valid trusted authority context. `npm exec` and `npm x` are
|
|
162
|
+
installation-capable resolution paths. Recognized command dispatchers (such as
|
|
163
|
+
`npm test`, `npm restart`, `npm run`, `npm rum`, `npm urn`) are resolved
|
|
164
|
+
recursively across recognized lifecycle scripts before launch with cycle
|
|
165
|
+
detection, leading option normalization, and restart-specific lifecycle fallback.
|
|
166
|
+
npm workspace script executions (`--workspace`, `-w`, `--workspaces`, `--ws`) fail
|
|
167
|
+
closed before launch with `E_COMMAND_RESOLUTION_AMBIGUOUS` because the effective
|
|
168
|
+
`package.json` context cannot be proven from the root target. Unknown npm command semantics are rejected before execution rather than downgraded to local execution. ForgeLoop uses an explicit non-installing allowlist instead of assuming that unrecognized npm commands are safe. `npx --no-install` is
|
|
169
|
+
an allowed non-installing resolution and can return a normal failed result when
|
|
170
|
+
the requested tool is unavailable. Completion, audit, `validate-protocol`, and task
|
|
171
|
+
bundles revalidate execution references rather than trusting duplicated check
|
|
172
|
+
metadata. Invalid or missing references return `E_EXECUTION_REF_INVALID`; an
|
|
173
|
+
observed command without ForgeLoop provenance returns
|
|
174
|
+
`E_COMMAND_PROVENANCE_UNATTESTED`.
|
|
175
|
+
|
|
143
176
|
## Missing tool capability
|
|
144
177
|
|
|
145
178
|
A missing tool is a capability gap, not installation authority.
|
|
@@ -152,6 +185,77 @@ not already available:
|
|
|
152
185
|
- otherwise report the affected verification dimension as not verified with
|
|
153
186
|
`E_VERIFICATION_TOOL_UNAVAILABLE`.
|
|
154
187
|
|
|
188
|
+
Every verification command is classified by resolution mode (`LOCAL_EXECUTABLE`,
|
|
189
|
+
`LOCAL_PACKAGE_BINARY`, `NON_INSTALLING_RESOLUTION`, `INSTALL_CAPABLE_RESOLUTION`,
|
|
190
|
+
`EXPLICIT_INSTALLATION`). Any command that uses an install-capable or installation
|
|
191
|
+
path without a valid canonical authority reference is rejected by `record-check`,
|
|
192
|
+
`audit`, and `complete` with `E_INSTALLATION_AUTHORITY_REQUIRED`, `E_AUTHORITY_INVALID`,
|
|
193
|
+
`E_AUTHORITY_SCOPE_MISMATCH`, or `E_AUTHORITY_UNTRUSTED_SOURCE`.
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
capability ≠ authority
|
|
197
|
+
evidence ≠ authority grant
|
|
198
|
+
actor claim ≠ operator grant
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Authority cannot be self-issued by the actor consuming it. Boolean fields inside
|
|
202
|
+
verification evidence are not sufficient proof of installation authority.
|
|
203
|
+
|
|
204
|
+
### Authority provenance
|
|
205
|
+
|
|
206
|
+
Authority provenance is external to actor-authored project state. An external
|
|
207
|
+
path is not equivalent to external authority ownership:
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
outside target
|
|
211
|
+
≠
|
|
212
|
+
outside actor control
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The standalone CLI uses `trustMode: NONE`. `FORGELOOP_AUTHORITY_FILE` and
|
|
216
|
+
`FORGELOOP_AUTHORITY_DIR` select candidate authority sources, but they do not
|
|
217
|
+
make a source trusted in actor-facing execution. Environment-selected sources
|
|
218
|
+
are rejected with `E_AUTHORITY_UNTRUSTED_SOURCE` for install-capable checks.
|
|
219
|
+
|
|
220
|
+
Trusted authority requires an explicit `HOST_ATTESTED` runtime context supplied
|
|
221
|
+
through an integration boundary the active actor cannot replace at command
|
|
222
|
+
invocation time. Configuration is not trust:
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
environment-selected source
|
|
226
|
+
≠
|
|
227
|
+
host-attested source
|
|
228
|
+
|
|
229
|
+
configuration
|
|
230
|
+
≠
|
|
231
|
+
trust
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The host-attested source must still resolve outside the actor-writable target. A
|
|
235
|
+
project-local authority reference may identify a grant, but it does not create
|
|
236
|
+
the root of trust.
|
|
237
|
+
|
|
238
|
+
```text
|
|
239
|
+
actor-authored evidence
|
|
240
|
+
≠
|
|
241
|
+
trusted authority
|
|
242
|
+
|
|
243
|
+
project-local file
|
|
244
|
+
≠
|
|
245
|
+
host grant
|
|
246
|
+
|
|
247
|
+
declared provenance
|
|
248
|
+
≠
|
|
249
|
+
verified provenance
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
A local artifact claiming `source: operator` is not sufficient proof of operator
|
|
253
|
+
authority. The actor-facing CLI must not expose an equivalent of
|
|
254
|
+
`--authority-source-attested-by-host` or `--trusted-authority-file` that
|
|
255
|
+
self-promotes a source. If the host exposes the attested source as writable to
|
|
256
|
+
the actor, the host boundary has been compromised and ForgeLoop cannot provide
|
|
257
|
+
cryptographic attestation by itself.
|
|
258
|
+
|
|
155
259
|
Never convert `PROTOCOL_LIMITED` into environmental mutation by implicitly
|
|
156
260
|
installing a package.
|
|
157
261
|
|
package/README.md
CHANGED
|
@@ -109,11 +109,15 @@ The regression suite injects failures at these boundaries and verifies that
|
|
|
109
109
|
owned cleanup. The frozen published installation under
|
|
110
110
|
[`tests/fixtures/legacy-0.1.6/`](./tests/fixtures/legacy-0.1.6/) is derived
|
|
111
111
|
from the real npm tarball, includes provenance and digests, and is copied into
|
|
112
|
-
The
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
The latest verified published npm release is `@cassiomc1/forgeloop@0.1.14`.
|
|
113
|
+
The repository package candidate is `@cassiomc1/forgeloop@0.1.15`; it is not
|
|
114
|
+
published yet.
|
|
115
|
+
Earlier `0.1.8`, `0.1.9`, `0.1.10`, `0.1.11`, `0.1.12`, and `0.1.13` references are historical; never move
|
|
116
|
+
their tags or `v0.1.10`. Release `0.1.14` enforces verification installation
|
|
117
|
+
authority, provides recoverable stale receipt lifecycle in `prepare-completion`,
|
|
118
|
+
and validates single-actor protocol runs. The `0.1.15` candidate adds trusted
|
|
119
|
+
command execution provenance without changing the v1 lifecycle or authority
|
|
120
|
+
boundary.
|
|
117
121
|
|
|
118
122
|
## How to prompt ForgeLoop
|
|
119
123
|
|
|
@@ -203,12 +207,14 @@ project without overwriting local instructions. When the package is available
|
|
|
203
207
|
in the npm registry, use the commands below; otherwise use the repository
|
|
204
208
|
checkout fallback.
|
|
205
209
|
|
|
206
|
-
The current
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
The current repository package candidate is `@cassiomc1/forgeloop@0.1.15` and is
|
|
211
|
+
not yet published.
|
|
212
|
+
The latest verified published npm release is `@cassiomc1/forgeloop@0.1.14`.
|
|
213
|
+
For reproducible published-package runs or release-identity checks,
|
|
214
|
+
pin the published version:
|
|
209
215
|
|
|
210
216
|
```bash
|
|
211
|
-
npx @cassiomc1/forgeloop@0.1.
|
|
217
|
+
npx @cassiomc1/forgeloop@0.1.14 --version
|
|
212
218
|
npx @cassiomc1/forgeloop init
|
|
213
219
|
npx @cassiomc1/forgeloop doctor
|
|
214
220
|
npx @cassiomc1/forgeloop update
|
|
@@ -231,7 +237,8 @@ npx @cassiomc1/forgeloop advance --to PLANNED
|
|
|
231
237
|
npx @cassiomc1/forgeloop advance --to EXECUTING
|
|
232
238
|
npx @cassiomc1/forgeloop advance --to VERIFYING
|
|
233
239
|
npx @cassiomc1/forgeloop prepare-completion --json
|
|
234
|
-
npx @cassiomc1/forgeloop
|
|
240
|
+
npx @cassiomc1/forgeloop run-check --json --id tests --requirement tests -- npm test
|
|
241
|
+
npx @cassiomc1/forgeloop record-check --id docs-review --kind manual-review --requirement "documentation synchronized" --status passed --evidence-kind OBSERVED --provenance MANUAL_OBSERVATION --result "reviewed" --json
|
|
235
242
|
npx @cassiomc1/forgeloop record-terminal-result --requirement "Package published" --type PUBLICATION --status published --source "npm publish" --result "Published package to npm" --json
|
|
236
243
|
npx @cassiomc1/forgeloop advance --to REVIEWING
|
|
237
244
|
npx @cassiomc1/forgeloop audit --json
|
|
@@ -261,7 +268,7 @@ implementation
|
|
|
261
268
|
→ forgeloop next
|
|
262
269
|
→ prepare-completion
|
|
263
270
|
→ forgeloop next
|
|
264
|
-
→ checks + record-check
|
|
271
|
+
→ checks + run-check/record-check
|
|
265
272
|
→ forgeloop next
|
|
266
273
|
→ advance --to REVIEWING
|
|
267
274
|
→ forgeloop next
|
|
@@ -285,10 +292,15 @@ Before implementation, write the canonical contract, persist the route, create
|
|
|
285
292
|
required gate artifacts under `.forgeloop/gates/`, and require `preflight` to
|
|
286
293
|
return `READY`. `advance` enforces legal phase transitions; it never runs the
|
|
287
294
|
project's commands. After implementation, advance to `VERIFYING`, use
|
|
288
|
-
`prepare-completion` to create a safe receipt skeleton,
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
295
|
+
`prepare-completion` to create a safe receipt skeleton, use `run-check` for
|
|
296
|
+
commands, and use `record-check` for manual or non-command observations.
|
|
297
|
+
`run-check` accepts the exact argv after `--`, classifies resolution before
|
|
298
|
+
launch, blocks install-capable resolution without trusted host authority, and
|
|
299
|
+
writes `.forgeloop/executions/<executionId>.json` before recording the check.
|
|
300
|
+
`record-check` never executes `--command`; that option is metadata only. A
|
|
301
|
+
command check with `OBSERVED` evidence must reference a ForgeLoop execution
|
|
302
|
+
artifact with `provenance: FORGELOOP_EXECUTED`. Advance to `REVIEWING` before
|
|
303
|
+
running `audit` and `complete`.
|
|
292
304
|
`audit` is a read-only consistency check. `complete` validates the final
|
|
293
305
|
contract, route, gates, phase ledger, structured evidence, coverage, receipt,
|
|
294
306
|
and freshness before it can return `VALID`. `report` renders the same result as
|
|
@@ -372,12 +384,18 @@ target project. Its main threat boundaries are:
|
|
|
372
384
|
| Data exposure | Receipts and checkpoints reject secret-like keys and values; examples use placeholders, and the repository secret scanner runs in CI. |
|
|
373
385
|
| Unsafe update overwrite | `update` preserves locally modified files and the target's `.forgeloop/kit/PROJECT_PROFILE.md`; adoption and writes remain bounded to the selected target. |
|
|
374
386
|
| Dependency supply chain | Runtime code uses Node built-ins only; the package does not install agents, providers, plugins, or remote services. |
|
|
387
|
+
| Installation authority provenance | Standalone CLI uses `trustMode: NONE`: environment-selected `FORGELOOP_AUTHORITY_FILE`/`FORGELOOP_AUTHORITY_DIR` sources are untrusted candidates; only an internal `HOST_ATTESTED` context may select a trusted source outside the actor-writable target. Project-local authority claims remain untrusted. |
|
|
375
388
|
| Stale replay | Work state records contract and repository fingerprints; drift requires revalidation and never reruns destructive or publication actions automatically. |
|
|
376
389
|
| Unverified publication | Receipts carry explicit publication booleans; local success never implies a push, pull request, merge, release, or deployment. |
|
|
390
|
+
| Unattested observed command | `record-check --command` is metadata only; command `OBSERVED` evidence requires a bound ForgeLoop execution artifact. `run-check` preserves exact argv, target cwd, resolution mode, timestamps, and exit status, and rejects install-capable resolution before launch without trusted host authority. |
|
|
377
391
|
|
|
378
392
|
The full boundary inventory, residual limitations, and executable evidence are
|
|
379
393
|
in [`THREAT_MODEL.md`](./THREAT_MODEL.md).
|
|
380
394
|
|
|
395
|
+
An external path is not equivalent to external authority ownership. Actor-controlled
|
|
396
|
+
environment configuration is not sufficient proof of host/operator authority;
|
|
397
|
+
trusted authority requires a host-attested integration boundary.
|
|
398
|
+
|
|
381
399
|
The CLI cannot protect a target from a separately privileged or hostile process
|
|
382
400
|
that changes the filesystem after validation. Consumers must still review
|
|
383
401
|
permissions, package provenance, and external actions before granting authority.
|
|
@@ -642,7 +660,7 @@ adoption. Local rendering requires Node.js 22+ and FFmpeg.
|
|
|
642
660
|
The source repository keeps canonical documents at the root for package
|
|
643
661
|
development and validation. A bootstrapped target uses the hidden-kit layout
|
|
644
662
|
shown above; mutable contract, route, state, gate, event, preflight, and
|
|
645
|
-
receipt artifacts remain directly under `.forgeloop/`.
|
|
663
|
+
receipt and execution artifacts remain directly under `.forgeloop/`.
|
|
646
664
|
|
|
647
665
|
## Maintenance
|
|
648
666
|
|
package/THREAT_MODEL.md
CHANGED
|
@@ -20,6 +20,7 @@ remaining trust boundaries and their executable evidence.
|
|
|
20
20
|
| Lifecycle artifact repair | Direct state or receipt edits fabricate a legal recovery or terminal phase | Work state, receipt, evidence checks, and event ledger | New verification cycles record phase events and fingerprints; validators reject state/ledger divergence and future lifecycle evidence | Local artifacts are detection-oriented, not cryptographically tamper-proof against a privileged process rewriting every linked artifact | `tests/lifecycle-evidence-recovery.test.js`, `tests/completion-ergonomics.test.js` |
|
|
21
21
|
| Unsupported profile fact | Turns an agent decision into a durable user fact | `PROJECT_PROFILE.md` and `.forgeloop/sources.json` | Source IDs, source-kind validation, unknown-reference rejection, and explicit misclassification failures | Arbitrary Markdown semantics still require a human or host-specific parser | `tests/profile-provenance.test.js`, `src/core/profile.js` |
|
|
22
22
|
| Weak verification | Treats a vague or inferred claim as observed evidence | Receipt checks and coverage | Versioned check schema, contradictory-status rejection, observed-evidence requirements, and coverage matrix | Evidence remains local and declarative; it is not a remote attestation service | `tests/evidence-coverage.test.js`, `tests/completion.test.js` |
|
|
23
|
+
| Unattested observed command | An actor supplies `--command "..."` or forged command metadata and makes an unrun process appear to be observed evidence | Check provenance, execution artifact, and process boundary | `run-check` captures exact argv, cwd, resolution, timestamps, exit status, and task/check binding; it classifies before launch, uses `shell: false`, and rejects install-capable resolution without trusted authority. `record-check --command` is metadata only; command `OBSERVED` checks require `FORGELOOP_EXECUTED` plus a valid `executionRef`; completion, audit, protocol validation, and bundles revalidate it | The local execution artifact is not cryptographic remote attestation, and a separately privileged process can alter the target after execution | `tests/run-check.test.js`, `tests/completion-cli.test.js`, `tests/verification-capability.test.js`, `tests/validate-protocol-cli.test.js` |
|
|
23
24
|
| Malicious receipt | Turns local claims into false publication or completion claims | Execution receipt JSON | Semantic evidence checks for completion, checks, review, push, commit, and deployment; explicit publication booleans | Evidence text is declarative and must still be reviewed for provenance | `tests/receipt-semantics.test.js`, `tests/observability.test.js` |
|
|
24
25
|
| Malicious task brief | Grants a child task more authority than intended | Delegation brief JSON and host harness | Relative path boundaries, guide/verification/authority checks, secret-free validation, set validation, parent integration ownership | The host harness remains responsible for OS permissions and execution policy | `tests/delegation.test.js`, `tests/delegation-set.test.js` |
|
|
25
26
|
| Artifact content exposure | Sensitive material enters portable artifacts or diagnostics | State, receipt, delegation, evidence, and repository text | Nested key/value detection, shaped marker patterns, scanner coverage, no content echo in errors | Content scanners cannot prove that an unknown encoding is harmless | `tests/security-limits.test.js`, `tests/test_scan_secrets.py`, `scripts/scan_secrets.py` |
|
|
@@ -35,6 +36,14 @@ remaining trust boundaries and their executable evidence.
|
|
|
35
36
|
| Lifecycle simulation after CLI resolution failure | A runtime manually writes protocol-owned JSON and falsely claims conformance when the CLI is unresolved | Lifecycle-owned protocol state and CLI availability | CLI-owned artifact policy, universal adapter prohibition, validator-backed completion, append-only ledger hash chain | A privileged local process can tamper with local files; ForgeLoop detects consistency, not remote attestation | `tests/discovery-surfaces.test.js`, `tests/lifecycle.test.js`, `LOOP_ENGINEERING.md` |
|
|
36
37
|
| Unauthorized verification dependency installation | The active actor mutates the environment by downloading or installing a missing checker merely to satisfy verification | Verification capability discovery and installation authority | Missing verification tool policy, non-installing resolution first, explicit installation authority, equivalent-check fallback, NOT_VERIFIED degradation | A privileged external process may still install tools outside ForgeLoop's control | `tests/verification-capability.test.js`, `tests/discovery-surfaces.test.js`, `LOOP_ENGINEERING.md` |
|
|
37
38
|
| False delegation requirement | A valid single-actor run is incorrectly reported as incomplete because a validator demands artifacts for delegation that never occurred | Validator delegation scope resolution | Canonical delegationIsInScope predicate, conditional delegation validation in validateTaskArtifactSet and validate-protocol | Malformed or externally injected artifacts may require INCONSISTENT classification | `tests/conformance.test.js`, `tests/validate-protocol-cli.test.js` |
|
|
39
|
+
| Self-asserted authority bypass | The active actor supplies `installationAuthorized=true` inside its own verification evidence and thereby grants itself authority | Authority provenance and verification evidence | Boolean claims are ignored; scoped authority references, task/type/tool validation, and validator revalidation in `record-check`/`audit`/`complete` require a trusted source | A host-controlled source is still a semantic trust boundary and is not cryptographic attestation | `tests/verification-capability.test.js`, `tests/authority.test.js`, `tests/stale-receipt-recovery.test.js` |
|
|
40
|
+
| Forged local authority artifact | The active actor creates `.forgeloop/authorities/auth-modlens.json`, claims `source=operator`, and uses the reference to authorize its own installation-capable check | Host/operator authority source versus actor-writable project state | Resolve grants only from an explicit `HOST_ATTESTED` runtime context with an external source outside the target; reject project-local grants with `E_AUTHORITY_UNTRUSTED_SOURCE`; revalidate in `record-check`/`audit`/`complete` | If the host exposes the attested source as writable to the actor, ForgeLoop cannot distinguish genuine grants from actor fabrication without a stronger trust anchor | Local fake rejection, host-attested external acceptance, inside-target rejection, post-record removal and revocation tests |
|
|
41
|
+
| Environment-injected trust root | The active actor creates an authority file outside the project target and sets `FORGELOOP_AUTHORITY_FILE` or `FORGELOOP_AUTHORITY_DIR` when invoking ForgeLoop | Actor-controlled process environment versus host-attested runtime authority | Standalone CLI uses `trustMode: NONE`; environment-selected sources are metadata/candidates only and fail with `E_AUTHORITY_UNTRUSTED_SOURCE`; trusted authority requires an internal `HOST_ATTESTED` context not exposed as a self-assertable CLI option | If the host integration allows the actor to mutate or replace the attested source/context, the host trust boundary is compromised | Environment-injection rejection, standalone audit/complete rejection, host-attested positive path |
|
|
42
|
+
| Stale receipt recovery dead-end | Work state changes after preparing a receipt, leaving a mismatch that cannot be refreshed because the old receipt is rejected during re-preparation | Preparation lifecycle and recovery action resolution | Recoverable stale receipt binding in `prepareCompletion`, executable `PREPARE_COMPLETION` return from `next`, atomic refresh of stateFingerprint and changedPaths | Manual file corruption outside CLI commands requires manual diagnostic recovery | `tests/stale-receipt-recovery.test.js`, `tests/next-executability.test.js` |
|
|
43
|
+
| Recursive npm script dispatch | A recognized npm lifecycle script invokes another npm script, which later invokes an installation-capable resolver (e.g. `test` -> `npm run visual` -> `npx package`) | Recognized npm dispatcher semantics before ForgeLoop process launch | Recursive npm-script resolution with cycle detection, maximum depth (16), lifecycle hook inspection, restart special semantics, and fail-closed behavior when the resolver cannot prove the chain is non-installing | Opaque executables may spawn arbitrary descendants. Full descendant-process attestation requires host-level process controls and is outside this release | `tests/run-check.test.js`, `tests/verification-capability.test.js` |
|
|
44
|
+
| npm invocation rewriting and workspace dispatch | npm configuration flags appear before the subcommand, or npm workspace selectors cause script execution to occur against a package.json different from the ForgeLoop target root | Raw npm argv versus effective npm command and execution context | Canonical npm invocation parsing, effective subcommand extraction, workspace flag detection across the full npm argv, and fail-closed workspace script handling when the selected package.json cannot be proven from the current target | ForgeLoop 0.1.15 intentionally does not implement full npm workspace resolution. Users should execute run-check from the selected workspace target directory | `tests/run-check.test.js`, `tests/verification-capability.test.js` |
|
|
45
|
+
| Unclassified npm Install-Capable Command | The npm security classifier recognizes only a small denylist of package-mutating commands. Another official npm command or alias with install/update/bootstrap semantics falls through as a local package command | Effective npm command semantics versus ForgeLoop's command classifier | Semantic npm command classification with explicit install-capable families, explicit script-dispatch families, a deliberately small non-installing allowlist, and fail-closed behavior for unknown or ambiguous npm commands | Future npm commands are blocked until ForgeLoop explicitly classifies them | `tests/verification-capability.test.js`, `tests/run-check.test.js` |
|
|
46
|
+
| npm Option Value Ambiguity | An unknown npm config option with a separate value appears before the effective subcommand, and a parser misinterprets the option value as the npm subcommand | Raw npm argv and unsupported config syntax | Recognize self-contained `--key=value`, explicitly supported options-with-value, and known boolean options. Unknown long option followed by a non-option token fails closed with `NPM_OPTION_VALUE_AMBIGUOUS` | Unsupported npm config grammar is intentionally rejected rather than guessed | `tests/verification-capability.test.js`, `tests/run-check.test.js` |
|
|
38
47
|
|
|
39
48
|
## Boundary rules
|
|
40
49
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "forgeloop://schemas/authority.schema.json",
|
|
4
|
+
"title": "ForgeLoop installation authority grant",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schemaVersion",
|
|
8
|
+
"protocolVersion",
|
|
9
|
+
"authorityId",
|
|
10
|
+
"taskId",
|
|
11
|
+
"type",
|
|
12
|
+
"status",
|
|
13
|
+
"scope",
|
|
14
|
+
"source"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schemaVersion": { "const": 1 },
|
|
18
|
+
"protocolVersion": { "const": 1 },
|
|
19
|
+
"authorityId": { "type": "string", "minLength": 1 },
|
|
20
|
+
"taskId": { "type": "string", "minLength": 1 },
|
|
21
|
+
"type": { "enum": ["SOFTWARE_INSTALLATION"] },
|
|
22
|
+
"status": { "enum": ["AUTHORIZED", "REVOKED", "EXPIRED"] },
|
|
23
|
+
"scope": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["tool"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"tool": { "type": "string", "minLength": 1 }
|
|
28
|
+
},
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
},
|
|
31
|
+
"source": { "enum": ["operator", "host", "project-policy"] }
|
|
32
|
+
},
|
|
33
|
+
"additionalProperties": false
|
|
34
|
+
}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"status": { "enum": ["passed", "failed", "blocked", "not-run"] },
|
|
14
14
|
"evidenceKind": { "enum": ["OBSERVED", "INFERRED", "NOT_VERIFIED", "BLOCKED"] },
|
|
15
15
|
"source": { "type": "string", "minLength": 1 },
|
|
16
|
+
"executionRef": { "type": "string", "minLength": 1 },
|
|
17
|
+
"provenance": { "enum": ["FORGELOOP_EXECUTED", "ACTOR_REPORTED", "MANUAL_OBSERVATION"] },
|
|
16
18
|
"exitCode": { "type": "integer" },
|
|
17
19
|
"timestamp": { "type": "string", "minLength": 1 },
|
|
18
20
|
"repositoryFingerprint": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "forgeloop://schemas/execution.schema.json",
|
|
4
|
+
"title": "ForgeLoop command execution artifact",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schemaVersion",
|
|
8
|
+
"protocolVersion",
|
|
9
|
+
"executionId",
|
|
10
|
+
"taskId",
|
|
11
|
+
"checkId",
|
|
12
|
+
"requirement",
|
|
13
|
+
"verificationCycle",
|
|
14
|
+
"kind",
|
|
15
|
+
"argv",
|
|
16
|
+
"cwd",
|
|
17
|
+
"resolution",
|
|
18
|
+
"startedAt",
|
|
19
|
+
"finishedAt",
|
|
20
|
+
"status",
|
|
21
|
+
"exitCode"
|
|
22
|
+
],
|
|
23
|
+
"properties": {
|
|
24
|
+
"schemaVersion": { "const": 1 },
|
|
25
|
+
"protocolVersion": { "const": 1 },
|
|
26
|
+
"executionId": { "type": "string", "minLength": 1 },
|
|
27
|
+
"taskId": { "type": "string", "minLength": 1 },
|
|
28
|
+
"checkId": { "type": "string", "minLength": 1 },
|
|
29
|
+
"requirement": { "type": "string", "minLength": 1 },
|
|
30
|
+
"verificationCycle": { "type": "integer", "minimum": 1 },
|
|
31
|
+
"kind": { "const": "COMMAND_EXECUTION" },
|
|
32
|
+
"argv": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"minItems": 1,
|
|
35
|
+
"items": { "type": "string", "minLength": 1 }
|
|
36
|
+
},
|
|
37
|
+
"cwd": { "type": "string", "minLength": 1 },
|
|
38
|
+
"resolution": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"required": ["resolutionMode", "mayInstall", "installer", "tool"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"resolutionMode": { "type": "string", "minLength": 1 },
|
|
43
|
+
"mayInstall": { "type": "boolean" },
|
|
44
|
+
"installer": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
|
|
45
|
+
"tool": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] }
|
|
46
|
+
},
|
|
47
|
+
"additionalProperties": false
|
|
48
|
+
},
|
|
49
|
+
"dispatch": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"properties": {
|
|
52
|
+
"kind": { "type": "string", "minLength": 1 },
|
|
53
|
+
"scriptName": { "type": "string", "minLength": 1 }
|
|
54
|
+
},
|
|
55
|
+
"additionalProperties": false
|
|
56
|
+
},
|
|
57
|
+
"startedAt": { "type": "string", "minLength": 1 },
|
|
58
|
+
"finishedAt": { "type": "string", "minLength": 1 },
|
|
59
|
+
"status": { "enum": ["passed", "failed"] },
|
|
60
|
+
"exitCode": { "oneOf": [{ "type": "integer", "minimum": 0 }, { "type": "null" }] }
|
|
61
|
+
},
|
|
62
|
+
"additionalProperties": false
|
|
63
|
+
}
|