tamperward 2.16.3 → 2.16.5

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/README.md CHANGED
@@ -220,11 +220,34 @@ BROKEN platform posture rather than misdiagnosing it as a missing Python install
220
220
  `--agent-budget <seconds>`
221
221
  adds an operator-owned wall-clock boundary around the same lifecycle (separate from the
222
222
  verifier's `--budget`). A clean timeout is `AGENT_TIMEOUT` / exit 124; enforcement or
223
- cannot-adjudicate still outranks it. Windows retains `taskkill /T /F`; other non-Linux
224
- platforms retain process-group/fingerprint/quiescence safeguards but do not claim the Linux
225
- subreaper boundary. A detached process that escapes those weaker platform controls remains
226
- an explicit residual tracked in **#379**, not part of the Linux guarantee.
227
- Dependency-attestation reuse remains disabled on all platforms.
223
+ cannot-adjudicate still outranks it. **From 2.16.4, `tamperward run` is Linux-only
224
+ for authoritative lifecycle certification.** Windows, macOS and other non-Linux platforms
225
+ fail closed before the agent starts because this release has no OS primitive there that can
226
+ prove the detached execution domain is drained. From **2.16.5**, checkpointed-local
227
+ `tamperward verify` also has an explicit host-shell contract: Linux, macOS and the
228
+ supported POSIX Node platforms use `/bin/sh -c`; Windows local verification fails closed
229
+ before candidate execution rather than depending on an incidental MSYS/Git-for-Windows
230
+ `sh` on PATH. A digest-pinned container verifier is a separate backend and must pass its
231
+ own Docker authority preflight. Dependency-attestation reuse remains disabled on all
232
+ platforms.
233
+
234
+ ### Platform support
235
+
236
+ | Capability | Linux | macOS | Windows |
237
+ | --- | --- | --- | --- |
238
+ | `check` / policy evaluation | Supported | Supported | Supported |
239
+ | Claude hook / Stop adapter | Supported where Claude Code command hooks are available | Same | Same |
240
+ | `watch` / observer telemetry | Supported; backend health is reported | Supported/degraded according to `fs.watch` health | Supported/degraded according to `fs.watch` health |
241
+ | checkpointed-local `verify` | Supported via `/bin/sh` | Supported via `/bin/sh` | **Unsupported; fails before candidate execution** |
242
+ | isolated-container `verify` | Supported when Docker authority preflight passes | Not claimed beyond Docker preflight | Not claimed beyond Docker preflight |
243
+ | authoritative `run` | **Supported only with trusted non-root subreaper backend** | **Unsupported; fails before agent start** | **Unsupported; fails before agent start** |
244
+ | CI coverage for this contract | Full suite + platform contract | Platform-contract job | Platform-contract job |
245
+
246
+ The platform-contract CI job runs on real `ubuntu-latest`, `macos-latest` and
247
+ `windows-latest` hosts. It verifies the declared shell/lifecycle selection and proves
248
+ that Windows local verification refuses before a candidate command can produce a side
249
+ effect. This matrix is intentionally narrower than the Linux adversarial suite; it tests
250
+ the support boundary rather than implying feature parity where none is claimed.
228
251
 
229
252
  `tamperward verify` materialises two temporary copies — they are **not
230
253
  sandboxes**, and both execute agent-controlled code. The visible copy runs the
package/dist/cli/index.js CHANGED
@@ -10218,15 +10218,37 @@ function suiteEnv(scratch) {
10218
10218
  env.YARN_IGNORE_PATH = "1";
10219
10219
  return env;
10220
10220
  }
10221
+ function localVerifierShell(platform = process.platform, command) {
10222
+ switch (platform) {
10223
+ case "linux":
10224
+ case "darwin":
10225
+ case "freebsd":
10226
+ case "openbsd":
10227
+ case "aix":
10228
+ case "sunos":
10229
+ return { executable: "/bin/sh", args: ["-c", command] };
10230
+ default:
10231
+ return null;
10232
+ }
10233
+ }
10221
10234
  function runLocalSuite(dir, cmd, budgetSecs) {
10222
10235
  const t0 = Date.now();
10236
+ const shell = localVerifierShell(process.platform, cmd);
10237
+ if (!shell) {
10238
+ return {
10239
+ exit: null,
10240
+ secs: 0,
10241
+ failure: "backend",
10242
+ reason: `checkpointed-local verifier is unsupported on ${process.platform}; no trusted local shell contract is defined`
10243
+ };
10244
+ }
10223
10245
  const scratch = mkdtempSync3(join16(tmpdir3(), "tw-verify-run-"));
10224
10246
  try {
10225
- const r = runCapturedProcessSync("sh", ["-c", cmd], {
10247
+ const r = runCapturedProcessSync(shell.executable, shell.args, {
10226
10248
  cwd: dir,
10227
10249
  env: suiteEnv(scratch),
10228
10250
  timeoutMs: budgetSecs * 1e3,
10229
- detached: process.platform !== "win32",
10251
+ detached: true,
10230
10252
  killGroupOnFinish: true,
10231
10253
  backstopMs: 3e4
10232
10254
  });
@@ -10339,6 +10361,22 @@ function runVerify(opts) {
10339
10361
  return 2;
10340
10362
  }
10341
10363
  const isolated = verifierBackend.kind === "container";
10364
+ if (!isolated && !localVerifierShell(process.platform, cmd)) {
10365
+ if (opts.json) {
10366
+ out2(JSON.stringify({
10367
+ verdict: "CANNOT_VERIFY",
10368
+ reason: "LOCAL_VERIFIER_UNSUPPORTED_PLATFORM",
10369
+ platform: process.platform,
10370
+ verifier_backend: backendReport(),
10371
+ oracle_assurance: oracleAssuranceReport()
10372
+ }));
10373
+ } else {
10374
+ out2(
10375
+ `verify: checkpointed-local verifier is unsupported on ${process.platform}; no trusted local shell contract is defined. Failing closed before candidate execution.`
10376
+ );
10377
+ }
10378
+ return 2;
10379
+ }
10342
10380
  const dependencyEnvironment = isolated ? null : opts.dependencyEnvironment ?? discoverDependencyEnvironment(cwd, cmd);
10343
10381
  const dependencyReport = () => dependencyEnvironment ? dependencyEnvironmentReport(dependencyEnvironment) : {
10344
10382
  status: "verifier-owned",
@@ -10601,6 +10639,15 @@ function parseVerify(args) {
10601
10639
  // src/cli/run.ts
10602
10640
  var out = (s) => process.stdout.write(s + "\n");
10603
10641
  var err = (s) => process.stderr.write(s + "\n");
10642
+ function authoritativeRunLifecyclePlatform(platform = process.platform) {
10643
+ return platform === "linux";
10644
+ }
10645
+ function waitForSettleSync(seconds) {
10646
+ if (!Number.isFinite(seconds) || seconds <= 0) return;
10647
+ const ms = Math.ceil(seconds * 1e3);
10648
+ const word = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
10649
+ Atomics.wait(word, 0, 0, ms);
10650
+ }
10604
10651
  function canReuseAdjacentDependencyAttestation(_lifecycleOwned, _platform = process.platform) {
10605
10652
  return false;
10606
10653
  }
@@ -11211,6 +11258,14 @@ function runEnvelope(opts) {
11211
11258
  return 2;
11212
11259
  }
11213
11260
  }
11261
+ const lifecyclePlatform = opts.lifecyclePlatformOverride ?? process.platform;
11262
+ if (!authoritativeRunLifecyclePlatform(lifecyclePlatform)) {
11263
+ const alternative = lifecyclePlatform === "win32" ? "Use standalone tamperward check; checkpointed-local verify is unsupported on Windows, while container verify must pass its own Docker authority preflight." : "Use standalone tamperward check/verify or an isolated execution domain.";
11264
+ err(
11265
+ `tamperward run: authoritative agent lifecycle ownership is unavailable on ${lifecyclePlatform}; this release only certifies run on Linux with the trusted subreaper/ECHILD backend. Failing closed before the agent starts. ${alternative}`
11266
+ );
11267
+ return 2;
11268
+ }
11214
11269
  const verifierBackend = prepareVerifierBackend(frozenPolicy.verify);
11215
11270
  out(`tamperward run \u2014 trusted base ${base.slice(0, 10)}; agent exit is untrusted.`);
11216
11271
  out(`tamperward run \u2014 verifier backend: ${verifierBackendSummary(verifierBackend)}`);
@@ -11329,10 +11384,7 @@ tamperward run \u2014 agent exit ${agentExit}; DEPENDENCY_DRIFT \u2192 ENFORCEME
11329
11384
  verifierBackend
11330
11385
  });
11331
11386
  if (opts.settle && opts.settle > 0) {
11332
- try {
11333
- execFileSync9("sleep", [String(opts.settle)]);
11334
- } catch {
11335
- }
11387
+ waitForSettleSync(opts.settle);
11336
11388
  }
11337
11389
  const mutatedDuringAdjudication = treeFingerprint(cwd, protectedIgnored) !== fpBefore;
11338
11390
  if (mutatedDuringAdjudication) {
@@ -11427,14 +11479,14 @@ function lifecyclePlatformCheck(platform = process.platform, linuxPython = platf
11427
11479
  if (platform === "win32") {
11428
11480
  return {
11429
11481
  id: "platform",
11430
- state: "WARN",
11431
- detail: "Windows: taskkill /T /F is a best-effort tree fallback, not the Linux subreaper/ECHILD boundary; detached-domain residual tracked in #379 and verifier-entry attestation reuse stays disabled"
11482
+ state: "BROKEN",
11483
+ detail: "Windows: authoritative tamperward run lifecycle ownership is unavailable; taskkill /T /F is only a best-effort tree fallback, so run fails closed before agent start. Standalone check remains available; checkpointed-local verify is unsupported because this release defines verifier command semantics only through POSIX /bin/sh. A container verifier must pass its own Docker authority preflight."
11432
11484
  };
11433
11485
  }
11434
11486
  return {
11435
11487
  id: "platform",
11436
- state: "WARN",
11437
- detail: `${platform}: POSIX process-group/fingerprint/quiescence safeguards are available, but the Linux subreaper/ECHILD detached-domain boundary is unavailable; residual tracked in #379 and verifier-entry attestation reuse stays disabled`
11488
+ state: "BROKEN",
11489
+ detail: `${platform}: authoritative tamperward run lifecycle ownership is unavailable because this release has no subreaper/ECHILD-equivalent backend; run fails closed before agent start. Standalone check/verify remain available.`
11438
11490
  };
11439
11491
  }
11440
11492
  var VERIFY_COMMAND = /\btamperward(?:@\S+)?\s+verify\b/;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.16.3",
3
+ "version": "2.16.5",
4
4
  "description": "The deterministic agent-integrity gate. One ruleset, evaluated on the actual diff/commands as a verdict, enforced everywhere a change can be made.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "hexrift",