opencode-secrets-obfuscation 0.1.0 → 0.1.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/LICENSE +21 -21
- package/README.md +11 -21
- package/package.json +29 -23
- package/plugin.mjs +3847 -0
- package/.editorconfig +0 -12
- package/.github/workflows/ci.yml +0 -75
- package/.github/workflows/release.yml +0 -50
- package/.node-version +0 -1
- package/AGENTS.md +0 -23
- package/INSTALL.md +0 -104
- package/docs/checkpoint.md +0 -68
- package/docs/history/1-spec-review.md +0 -233
- package/docs/history/10-p0-launch-prerequisites-review.md +0 -186
- package/docs/history/11-p0-job-containment-review.md +0 -188
- package/docs/history/12-p0-api-client.md +0 -15
- package/docs/history/13-p0-status-review.md +0 -122
- package/docs/history/14-p0-containment-final-review.md +0 -84
- package/docs/history/15-config-source-implementation.md +0 -27
- package/docs/history/16-sanitizer-implementation.md +0 -65
- package/docs/history/17-store-policy-implementation.md +0 -36
- package/docs/history/18-pure-mvp-review.md +0 -182
- package/docs/history/19-pure-mvp-re-review.md +0 -142
- package/docs/history/2-p0-runtime-prerequisites.md +0 -163
- package/docs/history/20-pure-mvp-final-review.md +0 -116
- package/docs/history/21-pure-mvp-review-final.md +0 -109
- package/docs/history/22-pure-mvp-signoff-review.md +0 -113
- package/docs/history/23-pure-mvp-signoff-review.md +0 -75
- package/docs/history/24-owned-tools-implementation.md +0 -27
- package/docs/history/25-v2-plugin-integration.md +0 -53
- package/docs/history/26-owned-tools-review.md +0 -138
- package/docs/history/27-owned-tools-final-review.md +0 -93
- package/docs/history/28-owned-tools-signoff.md +0 -98
- package/docs/history/3-p0-harness-foundation.md +0 -105
- package/docs/history/4-p0-source-opening.md +0 -78
- package/docs/history/5-qualification-gate-review.md +0 -133
- package/docs/history/6-p0-infrastructure-review.md +0 -275
- package/docs/history/7-p0-job-containment.md +0 -29
- package/docs/history/8-p0-evidence-support.md +0 -52
- package/docs/history/9-p0-launch-plan.md +0 -88
- package/docs/spec/design.md +0 -111
- package/docs/spec/intent.md +0 -81
- package/docs/spec/plan.md +0 -78
- package/docs/testing.md +0 -157
- package/scripts/build-plugin.mjs +0 -84
- package/scripts/install-opencode-ci.ps1 +0 -39
- package/scripts/install-opencode-ci.sh +0 -27
- package/scripts/smoke.mjs +0 -105
- package/scripts/verify-package.mjs +0 -18
- package/src/README.md +0 -22
- package/src/budgets/index.ts +0 -49
- package/src/config/README.md +0 -4
- package/src/config/options.ts +0 -76
- package/src/diagnostics/README.md +0 -4
- package/src/opencode/v2/filter.ts +0 -350
- package/src/opencode/v2/index.ts +0 -86
- package/src/opencode/v2/runtime.ts +0 -207
- package/src/opencode/v2/transports/README.md +0 -5
- package/src/runtime/http-transport.ts +0 -20
- package/src/sanitize/README.md +0 -4
- package/src/sanitize/index.ts +0 -454
- package/src/sources/README.md +0 -5
- package/src/sources/dotenv.ts +0 -133
- package/src/sources/native/README.md +0 -5
- package/src/store/index.ts +0 -64
- package/tests/README.md +0 -26
- package/tests/contract/plugin-v2.test.ts +0 -29
- package/tests/fixtures/README.md +0 -9
- package/tests/fixtures/job-child.mjs +0 -18
- package/tests/fixtures/plugins/README.md +0 -8
- package/tests/fixtures/process-child.mjs +0 -20
- package/tests/fixtures/services/README.md +0 -10
- package/tests/integration/components.test.ts +0 -5
- package/tests/integration/transparent-runtime.test.ts +0 -97
- package/tests/integration/windows-job.test.ts +0 -71
- package/tests/p0-host/README.md +0 -24
- package/tests/p0-host/linux-job.sh +0 -61
- package/tests/p0-host/windows-job.ps1 +0 -51
- package/tests/p0-native/README.md +0 -33
- package/tests/p0-native/windows-handle-loader.tests.ps1 +0 -191
- package/tests/scaffold/repository.test.ts +0 -105
- package/tests/smoke/README.md +0 -37
- package/tests/smoke/cases.json +0 -17
- package/tests/smoke/qualification.json +0 -20
- package/tests/smoke/runtime-candidate.json +0 -111
- package/tests/support/README.md +0 -32
- package/tests/support/child-process.ts +0 -235
- package/tests/support/host-api.ts +0 -123
- package/tests/support/opencode-environment.ts +0 -239
- package/tests/support/qualification.ts +0 -154
- package/tests/support/recording-endpoint.ts +0 -242
- package/tests/support/run-directory.ts +0 -179
- package/tests/support/smoke-cases.ts +0 -289
- package/tests/unit/budgets.test.ts +0 -35
- package/tests/unit/config.test.ts +0 -40
- package/tests/unit/dotenv.test.ts +0 -72
- package/tests/unit/filter-size.test.ts +0 -132
- package/tests/unit/harness.test.ts +0 -228
- package/tests/unit/host-api.test.ts +0 -122
- package/tests/unit/opencode-environment.test.ts +0 -161
- package/tests/unit/qualification.test.ts +0 -128
- package/tests/unit/recording-endpoint.test.ts +0 -188
- package/tests/unit/sanitize.test.ts +0 -159
- package/tests/unit/smoke-cases.test.ts +0 -20
- package/tsconfig.json +0 -20
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# 27 — Owned tools final review
|
|
2
|
-
|
|
3
|
-
Date: 2026-10-13
|
|
4
|
-
|
|
5
|
-
## Scope and evidence
|
|
6
|
-
|
|
7
|
-
Reviewed the current P4 implementation and integration boundary:
|
|
8
|
-
|
|
9
|
-
- `src/tools/index.ts`
|
|
10
|
-
- `src/opencode/v2/index.ts`
|
|
11
|
-
- `tests/unit/tools.test.ts`
|
|
12
|
-
- `tests/integration/tools.test.ts`
|
|
13
|
-
- `tests/contract/plugin-v2.test.ts`
|
|
14
|
-
- `package.json` and the installed dependency tree
|
|
15
|
-
- histories [24](24-owned-tools-implementation.md), [25](25-v2-plugin-integration.md), and [26](26-owned-tools-review.md)
|
|
16
|
-
- the V2 plugin documentation and `docs/spec/{design,plan}.md`
|
|
17
|
-
|
|
18
|
-
No source or test files were changed. No OpenCode process, ACL/source-loader probe, or
|
|
19
|
-
host qualification run was performed.
|
|
20
|
-
|
|
21
|
-
Executed evidence:
|
|
22
|
-
|
|
23
|
-
```text
|
|
24
|
-
npm run typecheck PASS
|
|
25
|
-
node --test tests/unit/tools.test.ts \
|
|
26
|
-
tests/integration/tools.test.ts \
|
|
27
|
-
tests/contract/plugin-v2.test.ts 15 pass, 0 fail, 0 skip
|
|
28
|
-
git diff --check PASS (line-ending warnings only)
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The focused suite is exactly 15 tests: 9 unit, 3 integration, and 3 V2 contract
|
|
32
|
-
tests.
|
|
33
|
-
|
|
34
|
-
## Decision
|
|
35
|
-
|
|
36
|
-
**Injected owned-tool boundary: conditional signoff-ready.** The pure P4 boundary
|
|
37
|
-
now resolves the principal findings from history 26: source and catalog inputs must
|
|
38
|
-
be frozen/admitted, source entries are capability/session filtered, output and working
|
|
39
|
-
budgets are bounded, HTTP authorization precedes transport use, response bodies and
|
|
40
|
-
headers are not projected, and non-cooperative requests terminate with a fixed error.
|
|
41
|
-
The native V2 entrypoint typechecks and registers documented Effect hooks and
|
|
42
|
-
`codemode: false` tools.
|
|
43
|
-
|
|
44
|
-
This is not signoff for an installed plugin-only MVP, a protected deployment, or a
|
|
45
|
-
production transport. The tests exercise injected objects and API shapes; they do
|
|
46
|
-
not establish native host behavior, serialization ordering, captured-executor
|
|
47
|
-
lifecycle, or real network/filesystem security.
|
|
48
|
-
|
|
49
|
-
## New must-fix findings
|
|
50
|
-
|
|
51
|
-
### 1. Source budget is not checked after adding source headers — medium
|
|
52
|
-
|
|
53
|
-
`credentialsRead` checks `maxBytes` and `maxWorkingBytes` while enumerating entries,
|
|
54
|
-
then adds per-source header costs at `src/tools/index.ts:166-169` without checking
|
|
55
|
-
the updated totals. A caller can therefore receive a result exceeding a deliberately
|
|
56
|
-
lower configured source budget when the entries fit but the headers do not. The
|
|
57
|
-
canonical sink's separate ceiling does not enforce the caller's lower source budget.
|
|
58
|
-
Check and fail after header accounting, before constructing `lines`.
|
|
59
|
-
|
|
60
|
-
### 2. Snapshot/catalog identity uniqueness is not enforced — medium
|
|
61
|
-
|
|
62
|
-
The admission predicates validate individual records but do not reject duplicate
|
|
63
|
-
source entries/bindings, duplicate source IDs across a published source snapshot, or
|
|
64
|
-
duplicate capability identities/names in a catalog. This conflicts with the design's
|
|
65
|
-
whole-snapshot duplicate rejection rule and makes catalog lookup (`find` in the HTTP
|
|
66
|
-
executor) order-dependent. The native source/catalog adapters must reject ambiguous
|
|
67
|
-
identities atomically before publication.
|
|
68
|
-
|
|
69
|
-
These findings are implementation follow-ups, not reasons to reject the narrow
|
|
70
|
-
injected-boundary conclusion; they block claiming the complete source-admission
|
|
71
|
-
contract until fixed and tested.
|
|
72
|
-
|
|
73
|
-
## Explicit remaining limitations
|
|
74
|
-
|
|
75
|
-
1. **Default unavailable factory.** `makeEffect()` uses
|
|
76
|
-
`unavailableRuntimeFactory` unless a qualified `CoreRuntimeFactory` is injected.
|
|
77
|
-
The default tools fail with `CREDENTIAL_RUNTIME_UNAVAILABLE`; this is intentional,
|
|
78
|
-
not a working source-backed runtime.
|
|
79
|
-
2. **Native source loader absent.** No opened-handle, filesystem/ACL, dotenv parser,
|
|
80
|
-
source watcher, or source-to-admitted-snapshot adapter is integrated. The current
|
|
81
|
-
boundary accepts only an already admitted immutable snapshot.
|
|
82
|
-
3. **Trusted HTTP transport absent.** `HttpTransport` is injected. DNS/address
|
|
83
|
-
selection and pinning, TLS peer/hostname verification, proxy and redirect refusal,
|
|
84
|
-
header/parser limits, connection policy, and real socket cancellation remain
|
|
85
|
-
trusted transport responsibilities and are not qualified here.
|
|
86
|
-
4. **Host qualification absent.** No real V2 host was launched. Tool discovery,
|
|
87
|
-
schema/serialization, hook ordering and abort behavior, progress/publication
|
|
88
|
-
sinks, reload/unload, captured executors, and host readiness are unverified.
|
|
89
|
-
The isolated real-host smoke/qualification gates remain open.
|
|
90
|
-
|
|
91
|
-
Accordingly, the correct release wording is **injected, trusted-boundary component
|
|
92
|
-
ready subject to the two fixes above**, not “MVP qualified,” “host protected,” or
|
|
93
|
-
“production ready.”
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# 28 — P4 owned-tools sign-off
|
|
2
|
-
|
|
3
|
-
Date: 2026-10-13
|
|
4
|
-
|
|
5
|
-
## Scope and evidence
|
|
6
|
-
|
|
7
|
-
Reviewed the current owned-tool and native V2 boundary:
|
|
8
|
-
|
|
9
|
-
- `src/tools/index.ts`
|
|
10
|
-
- `src/opencode/v2/index.ts`
|
|
11
|
-
- `src/store/index.ts` (`ActivationStore.isEnrolled`)
|
|
12
|
-
- `package.json` and `package-lock.json`
|
|
13
|
-
- tests and histories 24–27
|
|
14
|
-
|
|
15
|
-
No source files, tests, or package files were changed. No OpenCode process was
|
|
16
|
-
launched.
|
|
17
|
-
|
|
18
|
-
Executed evidence:
|
|
19
|
-
|
|
20
|
-
```text
|
|
21
|
-
npm run typecheck PASS
|
|
22
|
-
node --test tests/contract/*.test.ts 3 pass, 9 TODO, 0 fail
|
|
23
|
-
node --test tests/unit/tools.test.ts \
|
|
24
|
-
tests/integration/tools.test.ts 15 pass, 0 fail
|
|
25
|
-
git diff --check PASS (line-ending warnings only)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The direct package pins are exact and agree between the manifest, lockfile, and
|
|
29
|
-
installed tree: `@opencode/plugin` 2.0.28, `effect` 4.0.1, `typescript` 5.9.3,
|
|
30
|
-
and `@types/node` 24.19.2.
|
|
31
|
-
|
|
32
|
-
## Findings
|
|
33
|
-
|
|
34
|
-
The latest fixes address the owned-tool findings from history 27:
|
|
35
|
-
|
|
36
|
-
- Source and catalog admission validates the complete frozen snapshot before
|
|
37
|
-
publication. Duplicate source entries, bindings, and catalog identities are
|
|
38
|
-
rejected atomically; duplicate source IDs are rejected before read output.
|
|
39
|
-
- Source headers are included in byte and working-memory accounting before any
|
|
40
|
-
output lines are constructed. Entry counts, UTF-8 sizes, fixed ceilings, and
|
|
41
|
-
sink budgets are bounded.
|
|
42
|
-
- Read visibility is bound through source/key/capability bindings and session
|
|
43
|
-
membership. `ActivationStore.isEnrolled` checks active state, generation,
|
|
44
|
-
location, session, and agent, and is used before both tools proceed.
|
|
45
|
-
- Admitted snapshots and catalogs are immutable/frozen and generation-bound;
|
|
46
|
-
callers cannot supply arbitrary mutable source objects to the read path.
|
|
47
|
-
- HTTP authorization and store proof precede transport use. Timeout/abort and
|
|
48
|
-
resolved-response cleanup require bounded cancellation completion, with a
|
|
49
|
-
fixed operation error on failure. Response bodies and headers are not
|
|
50
|
-
projected.
|
|
51
|
-
- The native V2 adapter has typed tool executors and documented hook
|
|
52
|
-
registration. Its default runtime remains explicitly unavailable.
|
|
53
|
-
|
|
54
|
-
## Decision
|
|
55
|
-
|
|
56
|
-
**CONDITIONAL GO — injected owned-tool boundary only.** The pure executors are
|
|
57
|
-
sign-off-ready as an injected component when supplied an already admitted
|
|
58
|
-
immutable snapshot and a separately trusted/qualified transport. This is not a
|
|
59
|
-
claim that the component protects an installed OpenCode deployment.
|
|
60
|
-
|
|
61
|
-
**NO-GO — installed plugin.** The default plugin factory is
|
|
62
|
-
`unavailableRuntimeFactory`; its credential tools intentionally fail with
|
|
63
|
-
`CREDENTIAL_RUNTIME_UNAVAILABLE`. No source loader, activation assembly, or
|
|
64
|
-
production core factory is installed.
|
|
65
|
-
|
|
66
|
-
**NO-GO — default factory as a functional runtime.** `makeEffect()` without an
|
|
67
|
-
injected factory is a safe unavailable fallback, not a working credential
|
|
68
|
-
runtime and not a shipping/default-runtime claim.
|
|
69
|
-
|
|
70
|
-
**NO-GO — host qualification.** No real OpenCode host was launched. Contract
|
|
71
|
-
tests prove package/API shape only; they do not qualify discovery,
|
|
72
|
-
serialization, hook ordering, abort behavior, reload/unload, or host readiness.
|
|
73
|
-
|
|
74
|
-
## Residual gates
|
|
75
|
-
|
|
76
|
-
### Source/admission
|
|
77
|
-
|
|
78
|
-
Implement and qualify native source opening, ACL/location binding, dotenv
|
|
79
|
-
parsing, handle allocation, reload/watch behavior, and the adapter that
|
|
80
|
-
constructs and publishes complete admitted snapshots. Prove aggregate quotas,
|
|
81
|
-
generation transitions, teardown ordering, and no stale snapshot/executor
|
|
82
|
-
visibility under reload.
|
|
83
|
-
|
|
84
|
-
### Transport
|
|
85
|
-
|
|
86
|
-
Provide a separately trusted transport and tests for DNS/address selection and
|
|
87
|
-
pinning, TLS peer/hostname verification, proxy and redirect refusal, parser and
|
|
88
|
-
header limits, connection reuse policy, secret-safe logging, and real socket
|
|
89
|
-
cancellation. The current tests qualify only the injected transport contract.
|
|
90
|
-
|
|
91
|
-
### Host/plugin
|
|
92
|
-
|
|
93
|
-
Supply a qualified `CoreRuntimeFactory`, then run the isolated real-host smoke
|
|
94
|
-
and qualification gates for tool discovery, schema/result serialization,
|
|
95
|
-
session/agent mapping, hook ordering, error publication, captured-executor
|
|
96
|
-
lifecycle, teardown, reload, and abort behavior. Until those gates pass, do
|
|
97
|
-
not describe this as an installed MVP, protected host, or production-ready
|
|
98
|
-
plugin.
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# P0 harness foundation
|
|
2
|
-
|
|
3
|
-
Status: implemented test infrastructure only; no product or OpenCode runtime was launched.
|
|
4
|
-
|
|
5
|
-
## Scope
|
|
6
|
-
|
|
7
|
-
- `tests/support/run-directory.ts` creates a unique directory below an explicit
|
|
8
|
-
absolute root, writes an exact ownership marker, and verifies private
|
|
9
|
-
permissions. POSIX mode is verified as `0700`; Windows uses `icacls` with
|
|
10
|
-
inheritance removed and verifies the resulting full-control ACL query. Any
|
|
11
|
-
permission/verification uncertainty fails closed.
|
|
12
|
-
- Cleanup first validates the directory, regular single-link marker, and exact
|
|
13
|
-
marker bytes. It traverses with `lstat`, removes links as links, never follows
|
|
14
|
-
them, and removes only that validated directory.
|
|
15
|
-
- `tests/support/child-process.ts` requires an explicit executable, argument
|
|
16
|
-
vector, absolute cwd, explicit allowlisted environment, and bounded startup,
|
|
17
|
-
overall, and output limits. It never invokes a shell or inherits the parent
|
|
18
|
-
environment. Failures expose fixed error codes only; captured output remains
|
|
19
|
-
in the private result/error boundary.
|
|
20
|
-
- `tests/fixtures/process-child.mjs` is a synthetic Node-only child fixture.
|
|
21
|
-
|
|
22
|
-
## Process-tree boundary
|
|
23
|
-
|
|
24
|
-
The helper tracks and kills only the PID returned by its own `spawn` call. It
|
|
25
|
-
does not discover, signal, or claim to terminate arbitrary descendants. A
|
|
26
|
-
future real-service harness must add an OS-native process-group/job boundary
|
|
27
|
-
and qualify its behavior per platform before making a process-tree cleanup
|
|
28
|
-
claim. Timeouts and cancellation are therefore only a guarantee about the
|
|
29
|
-
owned direct child within this helper's boundary.
|
|
30
|
-
|
|
31
|
-
## Evidence
|
|
32
|
-
|
|
33
|
-
The unit suite covers marker ownership, exact cleanup, link-safe cleanup where
|
|
34
|
-
the platform permits link creation, supplied environment/cwd, output limits,
|
|
35
|
-
overall timeout, and pre-cancellation. It launches only `process.execPath`
|
|
36
|
-
with the checked-in synthetic fixture and synthetic values.
|
|
37
|
-
|
|
38
|
-
Initial red run (before the support modules existed): `npm.cmd run test:unit`
|
|
39
|
-
failed with `ERR_MODULE_NOT_FOUND` for `tests/support/run-directory.ts`.
|
|
40
|
-
Passing focused run after implementation: `node --test
|
|
41
|
-
tests/unit/harness.test.ts` — 6 passed, 0 skipped.
|
|
42
|
-
|
|
43
|
-
Repository `npm.cmd run check` remains blocked by a concurrent untracked
|
|
44
|
-
`tests/unit/recording-endpoint.test.ts`, which imports the missing
|
|
45
|
-
`tests/support/recording-endpoint.ts`; that file is outside this task's owned
|
|
46
|
-
paths and was not modified. The owned files pass standalone TypeScript
|
|
47
|
-
checking.
|
|
48
|
-
|
|
49
|
-
## Corrective evidence (review 6)
|
|
50
|
-
|
|
51
|
-
The infrastructure review found lifecycle, cancellation, executable identity,
|
|
52
|
-
ACL, and recursive-cleanup defects. The owned files were repaired without
|
|
53
|
-
claiming a hostile real-host boundary:
|
|
54
|
-
|
|
55
|
-
- Child failures now stop accepting output, signal the directly spawned PID,
|
|
56
|
-
escalate to a forced signal after a grace period, and reject only after child
|
|
57
|
-
and stdio close. If that cannot be proven within the bound they return the
|
|
58
|
-
fixed `TEARDOWN_FAILED` code. Pre-cancel is checked before hashing/spawn and
|
|
59
|
-
the fixture's marker test makes an accidental launch observable.
|
|
60
|
-
- Options are runtime-validated, the explicit executable is an actual
|
|
61
|
-
regular-file SHA-256 match supplied by the caller, and Windows environment
|
|
62
|
-
names are case-insensitively de-duplicated. Hash-before-launch is an
|
|
63
|
-
artifact identity check, not a hostile replacement/race-proof launch claim.
|
|
64
|
-
- Existing roots are never chmod/ACL-modified. POSIX roots/ancestors are
|
|
65
|
-
checked for ownership and unsafe write permissions. Windows uses the current
|
|
66
|
-
SID and fixed System32 Windows PowerShell/.NET ACL introspection; new
|
|
67
|
-
directories are assigned exactly one current-SID full-control ACE with
|
|
68
|
-
container/object inheritance, and child ACL verification is tested.
|
|
69
|
-
- Cleanup is intentionally narrowed: after exact marker validation it removes
|
|
70
|
-
only an empty marker-only directory. Nested content, links, and races are
|
|
71
|
-
refused as `RUN_DIRECTORY_CONTENT_UNSAFE`; tests remove their own known
|
|
72
|
-
synthetic paths in `finally` blocks. This is not handle-relative,
|
|
73
|
-
race-free recursive cleanup.
|
|
74
|
-
|
|
75
|
-
Focused corrective run: `node --test tests/unit/harness.test.ts` — 11 passed,
|
|
76
|
-
1 platform skip. Standalone TypeScript checking of the three owned TypeScript files
|
|
77
|
-
also passed. The current `npm.cmd run check` reaches the full suite but fails
|
|
78
|
-
the concurrent agent's `tests/integration/windows-job.test.ts` (`P0-JOB`:
|
|
79
|
-
five Windows job containment cases with native `CreateProcess failed: 87` or
|
|
80
|
-
missing child PID); that integration test and host fixture are outside this
|
|
81
|
-
task's owned paths and were not modified.
|
|
82
|
-
|
|
83
|
-
Remaining blockers are unchanged for real-host use: no qualified POSIX
|
|
84
|
-
process-group or Windows Job Object tree boundary, no hostile-race-proof
|
|
85
|
-
opened-object executable launch, and no handle-relative private-tree cleanup.
|
|
86
|
-
This direct-child helper is unavailable as an actual OpenCode host/service
|
|
87
|
-
isolation boundary until those platform qualifications and the P0 native/host
|
|
88
|
-
gates are complete.
|
|
89
|
-
|
|
90
|
-
## Follow-up correction
|
|
91
|
-
|
|
92
|
-
The final staging review identified three test-infrastructure issues and an
|
|
93
|
-
inaccurate cancellation comment. Ancestor validation now permits trusted
|
|
94
|
-
root-owned Linux ancestors when their write/sticky permissions are safe, while
|
|
95
|
-
new run directories must remain current-UID-owned and `0700`. Missing root
|
|
96
|
-
hierarchy components are created one at a time with private permissions; no
|
|
97
|
-
existing ancestor is chmodded or ACL-modified. Tests cover both a fresh nested
|
|
98
|
-
root and a root-owned sticky ancestor.
|
|
99
|
-
|
|
100
|
-
Child containment now rejects absolute cross-volume `relative()` results and
|
|
101
|
-
proper `..` components before ACL inspection. The Windows-only cross-volume
|
|
102
|
-
test is an explicit platform skip elsewhere, not a false pass. The child
|
|
103
|
-
helper comment now distinguishes pre-spawn cancellation checks from the
|
|
104
|
-
post-spawn cancellation listener; the post-spawn test confirms cancellation
|
|
105
|
-
waits for teardown before cleanup.
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# P0-C — source-opening feasibility spike
|
|
2
|
-
|
|
3
|
-
Date: 2026-10-13
|
|
4
|
-
Status: **Windows partial feasibility; not a platform qualification (corrected 2026-10-13, infrastructure follow-up)**
|
|
5
|
-
|
|
6
|
-
## Environment inspected
|
|
7
|
-
|
|
8
|
-
- Windows 11 Pro, build 26200, ARM64.
|
|
9
|
-
- The fixture proved the opened handle is on `NTFS` using
|
|
10
|
-
`GetVolumeInformationByHandleW`; the separate `fsutil` query was denied.
|
|
11
|
-
- No `cl`, `clang`, `clang-cl`, `gcc`, CMake, or .NET SDK was installed.
|
|
12
|
-
- PowerShell's legacy `Add-Type` C# compiler was available. No WSL/Linux tool
|
|
13
|
-
environment was found or installed.
|
|
14
|
-
|
|
15
|
-
## Executed evidence
|
|
16
|
-
|
|
17
|
-
`tests/p0-native/windows-handle-loader.tests.ps1` was added as a dependency-free
|
|
18
|
-
native API fixture. It uses P/Invoke rather than ordinary `ReadAllText` or an
|
|
19
|
-
`icacls` preflight. The test creates and ACL-hardens its private temporary
|
|
20
|
-
directory before writing a synthetic source, then:
|
|
21
|
-
|
|
22
|
-
1. opens the directory and final file by component-relative `NtCreateFile` with
|
|
23
|
-
both `OBJ_DONT_REPARSE` and `FILE_OPEN_REPARSE_POINT` active (the prior
|
|
24
|
-
report incorrectly described this as untested because it overlooked the
|
|
25
|
-
masked options defect);
|
|
26
|
-
2. obtains final-handle identity/link count and reads via that same handle;
|
|
27
|
-
3. attempts to create a symbolic link, reporting Win32 error `1314`
|
|
28
|
-
(`ERROR_PRIVILEGE_NOT_HELD`) without treating setup failure as rejection;
|
|
29
|
-
4. creates a native hard link successfully and asserts the opened object's link
|
|
30
|
-
count is two; and
|
|
31
|
-
5. attempts an ancestor directory junction through the native reparse ioctl
|
|
32
|
-
(setup error `4392`, `ERROR_REPARSE_TAG_INVALID`), then uses the OS Junction
|
|
33
|
-
primitive to create the same synthetic adversary and verifies the ancestor
|
|
34
|
-
is rejected. The native creator error remains recorded; the fallback is not
|
|
35
|
-
counted as native-creator qualification.
|
|
36
|
-
6. inspects owner/DACL through native `GetSecurityInfo` on opened handles. The
|
|
37
|
-
policy accepts only the current service SID, SYSTEM, and built-in
|
|
38
|
-
Administrators; rejects unknown/broad ACEs, deny ACEs, wrong owners, and
|
|
39
|
-
missing current-SID read or ancestor replacement masks. A one-link source is
|
|
40
|
-
accepted; a genuine native hard link is rejected by policy with link count
|
|
41
|
-
two. A broad inherited `BUILTIN\Users` ancestor/file fixture is rejected.
|
|
42
|
-
7. renames the opened positive file, creates a replacement at the original
|
|
43
|
-
name, then rewinds and reads through the original handle; identity remains
|
|
44
|
-
unchanged before/after the swap and the original handle remains readable.
|
|
45
|
-
|
|
46
|
-
The corrected fixture was executed on this host and returned the deliberate
|
|
47
|
-
partial result
|
|
48
|
-
`P0-C-WINDOWS: PARTIAL (NTFS/relative/identity/read/post-read/hardlink; gaps=reparse-create-1314,junction-native-create-4392)`.
|
|
49
|
-
The core relative-open/identity/read/post-read checks and genuine native
|
|
50
|
-
hard-link setup ran. Symlink setup was unavailable for the precise privilege
|
|
51
|
-
error above; the OS Junction fallback allowed the actual ancestor rejection
|
|
52
|
-
assertion to run. The `fsutil` denial does not establish hard-link support or
|
|
53
|
-
filesystem type; the handle APIs establish those tested facts instead.
|
|
54
|
-
No result is represented as a qualification pass.
|
|
55
|
-
|
|
56
|
-
## Result against R8
|
|
57
|
-
|
|
58
|
-
The native API route is feasible without a product package dependency, but the
|
|
59
|
-
P0 gate is **not met**. The fixture demonstrates a narrow handle-relative
|
|
60
|
-
primitive candidate; it now proves the configured no-reparse flags on a real
|
|
61
|
-
NTFS handle path, native owner/DACL inspection for the tested ACE shapes,
|
|
62
|
-
single-link policy, ancestor replacement-mask policy, and post-swap identity
|
|
63
|
-
stability for this run. It does not prove all effective-token combinations,
|
|
64
|
-
service-SID resolution, every ACE/tag variant, final size consistency under
|
|
65
|
-
mutation, concurrent ACL changes, or safe concurrency. Linux/ext4 is entirely
|
|
66
|
-
untested. Alternate data streams, mount types, symbolic-link tag variants, and
|
|
67
|
-
other reparse tags remain untested. Ordinary path reads and ACL preflights
|
|
68
|
-
remain insufficient.
|
|
69
|
-
|
|
70
|
-
## Recommendation / blocker
|
|
71
|
-
|
|
72
|
-
Do not select a JavaScript-only or path-based loader. Before architecture is
|
|
73
|
-
committed, build or adopt one small audited Windows helper exposing only a
|
|
74
|
-
bounded handle-relative open/read/identity operation, with native ACL effective
|
|
75
|
-
rights and ancestor replacement checks, and a matching Linux `openat2`
|
|
76
|
-
implementation. Pin and review its source/build artifact. If those tests cannot
|
|
77
|
-
be completed, advertise no filesystem source platform rather than weakening R8;
|
|
78
|
-
the fallback should be a dedicated supervised helper/service, not `readFile`.
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
# Qualification gate review
|
|
2
|
-
|
|
3
|
-
Scope: `tests/support/qualification.ts` and `tests/unit/qualification.test.ts` only.
|
|
4
|
-
This is a review of the bookkeeping assessor, not evidence that any host, plugin,
|
|
5
|
-
capture, or security property has been qualified.
|
|
6
|
-
|
|
7
|
-
## Verdict
|
|
8
|
-
|
|
9
|
-
**Not a real qualification gate yet.** The selected-case bookkeeping logic is
|
|
10
|
-
mostly fail-closed for well-typed, schema-validated inputs: it rejects empty or
|
|
11
|
-
oversized selections, duplicate required IDs, missing/duplicate/unexpected
|
|
12
|
-
evidence, stale run/build/profile/platform/expectation identity, non-passing
|
|
13
|
-
statuses, and missing assertion/capture references. The tests cover those paths.
|
|
14
|
-
That is useful bookkeeping, but it does not establish runtime evidence.
|
|
15
|
-
|
|
16
|
-
## Must fix before treating this API as a safety boundary
|
|
17
|
-
|
|
18
|
-
1. **Malformed runtime input can throw instead of returning a safe failure** —
|
|
19
|
-
`tests/support/qualification.ts:56-64,72-74,92-94`. TypeScript types do not
|
|
20
|
-
validate JSON. Values such as a non-string `runID`/case `id`, a null record,
|
|
21
|
-
or a non-array/null `captureIDs` can make regex/string operations or
|
|
22
|
-
`.length`/`.some` throw. If the caller guarantees schema validation, that
|
|
23
|
-
validator must be a mandatory, explicit adapter at this boundary; otherwise
|
|
24
|
-
validate all shapes here and return a safe `INVALID_*` result. Add unit tests
|
|
25
|
-
proving malformed external objects cannot escape as exceptions and that
|
|
26
|
-
diagnostics contain only safe codes/counts.
|
|
27
|
-
|
|
28
|
-
## Qualification blockers that belong to the future real harness
|
|
29
|
-
|
|
30
|
-
1. **No authoritative case binding or completeness** —
|
|
31
|
-
`tests/support/qualification.ts:47-68` accepts any syntactically valid
|
|
32
|
-
selected ID. It does not load/bind `tests/smoke/cases.json`, reject an ID
|
|
33
|
-
absent from the inventory, require the profile/expectation declared by the
|
|
34
|
-
inventory, or require the complete enforced-profile selection. A caller can
|
|
35
|
-
therefore qualify an invented subset. The file's header at lines 2-5
|
|
36
|
-
correctly disclaims this. The future runner must reject unknown IDs, empty
|
|
37
|
-
selections, missing implementations, stale evidence, and incomplete
|
|
38
|
-
enforced-profile selections, as required by `docs/testing.md:76-83`.
|
|
39
|
-
|
|
40
|
-
2. **Capture IDs are only nonempty opaque references** —
|
|
41
|
-
`tests/support/qualification.ts:92-94` checks syntax/count, not that a
|
|
42
|
-
capture exists, is owned by the run, has the expected sink/network artifact,
|
|
43
|
-
or contains an independent oracle. It also does not validate capture
|
|
44
|
-
identity uniqueness or artifact references. This is a future real-host
|
|
45
|
-
harness/evidence-store requirement, not something these unit tests can
|
|
46
|
-
prove. `docs/testing.md:99-116` and `docs/spec/plan.md:37` require actual
|
|
47
|
-
restricted captures and oracles.
|
|
48
|
-
|
|
49
|
-
3. **Evidence truth is explicitly unverified** — the module header
|
|
50
|
-
(`tests/support/qualification.ts:2-5`) correctly says it does not verify
|
|
51
|
-
hashes, contents, assertions, or completeness. Consequently, passing
|
|
52
|
-
`tests/unit/qualification.test.ts:19-23` demonstrates only bookkeeping with
|
|
53
|
-
synthetic records; it must never be reported as capture-truth or artifact
|
|
54
|
-
qualification. The real runner must inspect actual sink/network bytes and
|
|
55
|
-
keep raw evidence out of diagnostics, per `docs/testing.md:99-104`.
|
|
56
|
-
|
|
57
|
-
4. **No actual smoke execution or implementation-status binding** —
|
|
58
|
-
`tests/unit/qualification.test.ts:5-17` fabricates two records and never
|
|
59
|
-
launches a pinned host/provider/plugin. The statuses tested at lines 31-40
|
|
60
|
-
are correctly rejected, but there is no test that a case is bound to a real
|
|
61
|
-
executable, host/build/checksum identity, or observed execution. This is a
|
|
62
|
-
future runner requirement; TODO/skipped/scaffold passes cannot be security
|
|
63
|
-
evidence (`AGENTS.md:17-20`, `docs/testing.md:26-30,73-78`).
|
|
64
|
-
|
|
65
|
-
## Positive coverage
|
|
66
|
-
|
|
67
|
-
- Duplicate required IDs and unexpected evidence are rejected
|
|
68
|
-
(`tests/unit/qualification.test.ts:95-99`).
|
|
69
|
-
- Run/build/profile/platform/expectation mismatches and zero assertions or
|
|
70
|
-
captures are rejected (`tests/unit/qualification.test.ts:51-63`).
|
|
71
|
-
- `expected-gap` is isolated to active-only and requires `observed-gap`; it
|
|
72
|
-
cannot satisfy enforced (`tests/unit/qualification.test.ts:65-83`,
|
|
73
|
-
`tests/support/qualification.ts:66,90-91`).
|
|
74
|
-
- Result diagnostics contain failure codes only; the invalid ID is not echoed
|
|
75
|
-
(`tests/unit/qualification.test.ts:86-93`).
|
|
76
|
-
|
|
77
|
-
## Checks run
|
|
78
|
-
|
|
79
|
-
- `node --test tests/unit/qualification.test.ts`: **pass**, 13/13.
|
|
80
|
-
- `npm.cmd run typecheck`: **fails in unrelated existing scope** at
|
|
81
|
-
`tests/unit/recording-endpoint.test.ts:3` because
|
|
82
|
-
`../support/recording-endpoint.ts` is missing. No qualification-file type
|
|
83
|
-
error was reported.
|
|
84
|
-
|
|
85
|
-
## Revision: 2026-10-13 — repaired helper re-review
|
|
86
|
-
|
|
87
|
-
Scope expanded for this revision to the four files named by the review request:
|
|
88
|
-
`tests/support/qualification.ts`, `tests/unit/qualification.test.ts`,
|
|
89
|
-
`tests/support/recording-endpoint.ts`, and `tests/unit/recording-endpoint.test.ts`.
|
|
90
|
-
|
|
91
|
-
### Revised verdict
|
|
92
|
-
|
|
93
|
-
**Usable as test helpers only; not source/host qualification.** The prior
|
|
94
|
-
qualification malformed-input finding is resolved: `assessCases` now accepts
|
|
95
|
-
unknown inputs, validates bounded plain-data descriptors and array elements,
|
|
96
|
-
rejects accessors without invoking them, catches reflection failures, and
|
|
97
|
-
returns the fixed `INVALID_INPUT` result (`qualification.ts:47-101`). The
|
|
98
|
-
focused tests cover malformed values and accessor behavior
|
|
99
|
-
(`qualification.test.ts:102-128`).
|
|
100
|
-
|
|
101
|
-
The recording fixture is also suitable synthetic loopback infrastructure: it
|
|
102
|
-
validates options with fixed errors (`recording-endpoint.ts:34-80`), bounds
|
|
103
|
-
request/response data, tracks sockets and pending buffers, separates parsed
|
|
104
|
-
request counts from malformed connections, and has idempotent bounded close
|
|
105
|
-
cleanup (`:83-211`). The nine focused tests exercise those repaired behaviors,
|
|
106
|
-
including malformed options, incomplete bodies, and active-socket close.
|
|
107
|
-
|
|
108
|
-
### Remaining concrete observations
|
|
109
|
-
|
|
110
|
-
- **No new must-fix defect found in these four files.** The assessor still
|
|
111
|
-
intentionally accepts a caller-selected, syntactically valid case set and
|
|
112
|
-
opaque capture IDs (`qualification.ts:2-5,109-151`). The smoke runner must
|
|
113
|
-
supply authoritative inventory binding, completeness, capture ownership and
|
|
114
|
-
capture/oracle truth. This is a qualification limitation, not evidence that
|
|
115
|
-
the helper validates artifact hashes or capture contents.
|
|
116
|
-
- The recording fixture retains successful request bodies until `close()`;
|
|
117
|
-
its configured maxima permit up to 64 requests × 1 MiB (plus copies made by
|
|
118
|
-
`captures()`) (`recording-endpoint.ts:71-79,141-145,175-178`). This is bounded,
|
|
119
|
-
and not a current correctness/security finding for a test-only helper, but a
|
|
120
|
-
future harness should set an explicit aggregate capture budget if it runs
|
|
121
|
-
adversarial workloads.
|
|
122
|
-
- `counts().attempted` deliberately counts parsed HTTP requests, while
|
|
123
|
-
malformed connections are reported only by `malformed`
|
|
124
|
-
(`recording-endpoint.ts:28,87-90,157-178`). It is therefore not a total
|
|
125
|
-
connection-attempt or zero-egress oracle; callers must not interpret it as
|
|
126
|
-
one.
|
|
127
|
-
|
|
128
|
-
### Focused verification
|
|
129
|
-
|
|
130
|
-
- `node --test tests/unit/qualification.test.ts tests/unit/recording-endpoint.test.ts`:
|
|
131
|
-
**pass, 24/24** (15 qualification, 9 recording-endpoint).
|
|
132
|
-
- No full typecheck was run in this revision because unrelated agents are
|
|
133
|
-
editing adjacent support files; the focused result is the primary evidence.
|