@miller-tech/uap 2.21.3 → 2.36.1
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 +22 -10
- package/config/model-profiles/qwen38-coder390.json +46 -0
- package/config/model-profiles/qwen38.json +3 -2
- package/config/model-registry.json +110 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/benchmarks/paired/types.d.ts +2 -2
- package/dist/bin/cli.js +315 -20
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/attention.d.ts +6 -0
- package/dist/cli/attention.d.ts.map +1 -0
- package/dist/cli/attention.js +115 -0
- package/dist/cli/attention.js.map +1 -0
- package/dist/cli/bench-report.d.ts +82 -0
- package/dist/cli/bench-report.d.ts.map +1 -0
- package/dist/cli/bench-report.js +237 -0
- package/dist/cli/bench-report.js.map +1 -0
- package/dist/cli/clients.d.ts +6 -0
- package/dist/cli/clients.d.ts.map +1 -0
- package/dist/cli/clients.js +142 -0
- package/dist/cli/clients.js.map +1 -0
- package/dist/cli/dashboard-grants.d.ts +26 -0
- package/dist/cli/dashboard-grants.d.ts.map +1 -0
- package/dist/cli/dashboard-grants.js +69 -0
- package/dist/cli/dashboard-grants.js.map +1 -0
- package/dist/cli/dashboard-pace.d.ts +31 -0
- package/dist/cli/dashboard-pace.d.ts.map +1 -0
- package/dist/cli/dashboard-pace.js +42 -0
- package/dist/cli/dashboard-pace.js.map +1 -0
- package/dist/cli/dashboard-session.d.ts +25 -0
- package/dist/cli/dashboard-session.d.ts.map +1 -0
- package/dist/cli/dashboard-session.js +814 -0
- package/dist/cli/dashboard-session.js.map +1 -0
- package/dist/cli/dashboard-types.d.ts +18 -0
- package/dist/cli/dashboard-types.d.ts.map +1 -0
- package/dist/cli/dashboard-types.js +9 -0
- package/dist/cli/dashboard-types.js.map +1 -0
- package/dist/cli/dashboard.d.ts +2 -18
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +43 -793
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/deliver.d.ts +35 -0
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +93 -9
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/diff.d.ts +85 -0
- package/dist/cli/diff.d.ts.map +1 -0
- package/dist/cli/diff.js +293 -0
- package/dist/cli/diff.js.map +1 -0
- package/dist/cli/eta.d.ts +35 -0
- package/dist/cli/eta.d.ts.map +1 -0
- package/dist/cli/eta.js +101 -0
- package/dist/cli/eta.js.map +1 -0
- package/dist/cli/handsfree.d.ts +7 -0
- package/dist/cli/handsfree.d.ts.map +1 -1
- package/dist/cli/handsfree.js +27 -0
- package/dist/cli/handsfree.js.map +1 -1
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +126 -5
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/loops.d.ts +24 -5
- package/dist/cli/loops.d.ts.map +1 -1
- package/dist/cli/loops.js +92 -12
- package/dist/cli/loops.js.map +1 -1
- package/dist/cli/models.d.ts +62 -0
- package/dist/cli/models.d.ts.map +1 -0
- package/dist/cli/models.js +567 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/plan.d.ts +9 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +57 -4
- package/dist/cli/plan.js.map +1 -1
- package/dist/cli/proxy-relay.d.ts +55 -0
- package/dist/cli/proxy-relay.d.ts.map +1 -0
- package/dist/cli/proxy-relay.js +116 -0
- package/dist/cli/proxy-relay.js.map +1 -0
- package/dist/cli/proxy.d.ts +4 -0
- package/dist/cli/proxy.d.ts.map +1 -1
- package/dist/cli/proxy.js +26 -1
- package/dist/cli/proxy.js.map +1 -1
- package/dist/cli/sandbox.d.ts +101 -4
- package/dist/cli/sandbox.d.ts.map +1 -1
- package/dist/cli/sandbox.js +393 -44
- package/dist/cli/sandbox.js.map +1 -1
- package/dist/cli/self.d.ts +13 -0
- package/dist/cli/self.d.ts.map +1 -0
- package/dist/cli/self.js +94 -0
- package/dist/cli/self.js.map +1 -0
- package/dist/cli/systemd-services.d.ts +2 -8
- package/dist/cli/systemd-services.d.ts.map +1 -1
- package/dist/cli/systemd-services.js +5 -20
- package/dist/cli/systemd-services.js.map +1 -1
- package/dist/cli/task.js +1 -1
- package/dist/cli/task.js.map +1 -1
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +31 -2
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/config/settings-registry.d.ts +1 -1
- package/dist/config/settings-registry.d.ts.map +1 -1
- package/dist/config/settings-registry.js +108 -0
- package/dist/config/settings-registry.js.map +1 -1
- package/dist/coordination/capability-router.js +2 -2
- package/dist/coordination/capability-router.js.map +1 -1
- package/dist/coordination/database.d.ts +13 -0
- package/dist/coordination/database.d.ts.map +1 -1
- package/dist/coordination/database.js +63 -7
- package/dist/coordination/database.js.map +1 -1
- package/dist/coordination/eta-inject.d.ts +32 -0
- package/dist/coordination/eta-inject.d.ts.map +1 -0
- package/dist/coordination/eta-inject.js +64 -0
- package/dist/coordination/eta-inject.js.map +1 -0
- package/dist/coordination/reactor.d.ts.map +1 -1
- package/dist/coordination/reactor.js +14 -0
- package/dist/coordination/reactor.js.map +1 -1
- package/dist/coordination/service.d.ts +18 -8
- package/dist/coordination/service.d.ts.map +1 -1
- package/dist/coordination/service.js +38 -28
- package/dist/coordination/service.js.map +1 -1
- package/dist/dashboard/client-registry.d.ts +163 -0
- package/dist/dashboard/client-registry.d.ts.map +1 -0
- package/dist/dashboard/client-registry.js +549 -0
- package/dist/dashboard/client-registry.js.map +1 -0
- package/dist/dashboard/controls.d.ts.map +1 -1
- package/dist/dashboard/controls.js +33 -4
- package/dist/dashboard/controls.js.map +1 -1
- package/dist/dashboard/data-seeder.d.ts +10 -7
- package/dist/dashboard/data-seeder.d.ts.map +1 -1
- package/dist/dashboard/data-seeder.js +31 -75
- package/dist/dashboard/data-seeder.js.map +1 -1
- package/dist/dashboard/data-service.d.ts +9 -0
- package/dist/dashboard/data-service.d.ts.map +1 -1
- package/dist/dashboard/data-service.js +32 -3
- package/dist/dashboard/data-service.js.map +1 -1
- package/dist/dashboard/placement-routes.d.ts +119 -0
- package/dist/dashboard/placement-routes.d.ts.map +1 -0
- package/dist/dashboard/placement-routes.js +331 -0
- package/dist/dashboard/placement-routes.js.map +1 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +408 -2
- package/dist/dashboard/server.js.map +1 -1
- package/dist/delivery/attention.d.ts +130 -0
- package/dist/delivery/attention.d.ts.map +1 -0
- package/dist/delivery/attention.js +341 -0
- package/dist/delivery/attention.js.map +1 -0
- package/dist/delivery/decompose.d.ts +18 -0
- package/dist/delivery/decompose.d.ts.map +1 -1
- package/dist/delivery/decompose.js +22 -1
- package/dist/delivery/decompose.js.map +1 -1
- package/dist/delivery/eta-estimate.d.ts +111 -0
- package/dist/delivery/eta-estimate.d.ts.map +1 -0
- package/dist/delivery/eta-estimate.js +171 -0
- package/dist/delivery/eta-estimate.js.map +1 -0
- package/dist/delivery/eta.d.ts +23 -0
- package/dist/delivery/eta.d.ts.map +1 -0
- package/dist/delivery/eta.js +59 -0
- package/dist/delivery/eta.js.map +1 -0
- package/dist/delivery/orchestrated-mission.d.ts +10 -0
- package/dist/delivery/orchestrated-mission.d.ts.map +1 -1
- package/dist/delivery/orchestrated-mission.js +15 -1
- package/dist/delivery/orchestrated-mission.js.map +1 -1
- package/dist/delivery/plan-check.d.ts +7 -1
- package/dist/delivery/plan-check.d.ts.map +1 -1
- package/dist/delivery/plan-check.js +23 -2
- package/dist/delivery/plan-check.js.map +1 -1
- package/dist/delivery/run-state.d.ts +1 -1
- package/dist/delivery/run-state.d.ts.map +1 -1
- package/dist/delivery/run-state.js +8 -1
- package/dist/delivery/run-state.js.map +1 -1
- package/dist/delivery/task-orchestrator.d.ts +8 -3
- package/dist/delivery/task-orchestrator.d.ts.map +1 -1
- package/dist/delivery/task-orchestrator.js +75 -43
- package/dist/delivery/task-orchestrator.js.map +1 -1
- package/dist/delivery/task-sync.d.ts +21 -0
- package/dist/delivery/task-sync.d.ts.map +1 -1
- package/dist/delivery/task-sync.js +44 -8
- package/dist/delivery/task-sync.js.map +1 -1
- package/dist/delivery/task-workspace.d.ts +3 -3
- package/dist/delivery/task-workspace.js +3 -3
- package/dist/generators/self-card.d.ts +65 -0
- package/dist/generators/self-card.d.ts.map +1 -0
- package/dist/generators/self-card.js +256 -0
- package/dist/generators/self-card.js.map +1 -0
- package/dist/inference/probe.js +1 -1
- package/dist/inference/probe.js.map +1 -1
- package/dist/memory/prepopulate.d.ts.map +1 -1
- package/dist/memory/prepopulate.js +2 -0
- package/dist/memory/prepopulate.js.map +1 -1
- package/dist/models/analytics.d.ts +32 -0
- package/dist/models/analytics.d.ts.map +1 -1
- package/dist/models/analytics.js +68 -5
- package/dist/models/analytics.js.map +1 -1
- package/dist/models/plan-readability.d.ts +55 -0
- package/dist/models/plan-readability.d.ts.map +1 -0
- package/dist/models/plan-readability.js +339 -0
- package/dist/models/plan-readability.js.map +1 -0
- package/dist/placement/admission.d.ts +59 -0
- package/dist/placement/admission.d.ts.map +1 -0
- package/dist/placement/admission.js +197 -0
- package/dist/placement/admission.js.map +1 -0
- package/dist/placement/auto.d.ts +44 -0
- package/dist/placement/auto.d.ts.map +1 -0
- package/dist/placement/auto.js +212 -0
- package/dist/placement/auto.js.map +1 -0
- package/dist/placement/enforce.d.ts +128 -0
- package/dist/placement/enforce.d.ts.map +1 -0
- package/dist/placement/enforce.js +655 -0
- package/dist/placement/enforce.js.map +1 -0
- package/dist/placement/idle.d.ts +50 -0
- package/dist/placement/idle.d.ts.map +1 -0
- package/dist/placement/idle.js +213 -0
- package/dist/placement/idle.js.map +1 -0
- package/dist/placement/ledger.d.ts +323 -0
- package/dist/placement/ledger.d.ts.map +1 -0
- package/dist/placement/ledger.js +263 -0
- package/dist/placement/ledger.js.map +1 -0
- package/dist/placement/preview.d.ts +51 -0
- package/dist/placement/preview.d.ts.map +1 -0
- package/dist/placement/preview.js +61 -0
- package/dist/placement/preview.js.map +1 -0
- package/dist/placement/probes.d.ts +47 -0
- package/dist/placement/probes.d.ts.map +1 -0
- package/dist/placement/probes.js +207 -0
- package/dist/placement/probes.js.map +1 -0
- package/dist/placement/proxy-env.d.ts +21 -0
- package/dist/placement/proxy-env.d.ts.map +1 -0
- package/dist/placement/proxy-env.js +42 -0
- package/dist/placement/proxy-env.js.map +1 -0
- package/dist/placement/registry.d.ts +1038 -0
- package/dist/placement/registry.d.ts.map +1 -0
- package/dist/placement/registry.js +274 -0
- package/dist/placement/registry.js.map +1 -0
- package/dist/policies/liveness.d.ts +6 -8
- package/dist/policies/liveness.d.ts.map +1 -1
- package/dist/policies/liveness.js +6 -25
- package/dist/policies/liveness.js.map +1 -1
- package/dist/policies/sandbox-anchor.d.ts +91 -0
- package/dist/policies/sandbox-anchor.d.ts.map +1 -0
- package/dist/policies/sandbox-anchor.js +187 -0
- package/dist/policies/sandbox-anchor.js.map +1 -0
- package/dist/policies/sandbox-grants.d.ts +131 -0
- package/dist/policies/sandbox-grants.d.ts.map +1 -0
- package/dist/policies/sandbox-grants.js +562 -0
- package/dist/policies/sandbox-grants.js.map +1 -0
- package/dist/state/manifest.d.ts +4 -2
- package/dist/state/manifest.d.ts.map +1 -1
- package/dist/state/manifest.js +32 -16
- package/dist/state/manifest.js.map +1 -1
- package/dist/utils/checkout-root.d.ts +2 -0
- package/dist/utils/checkout-root.d.ts.map +1 -0
- package/dist/utils/checkout-root.js +43 -0
- package/dist/utils/checkout-root.js.map +1 -0
- package/dist/utils/resolve-uap-bin.d.ts +5 -0
- package/dist/utils/resolve-uap-bin.d.ts.map +1 -0
- package/dist/utils/resolve-uap-bin.js +33 -0
- package/dist/utils/resolve-uap-bin.js.map +1 -0
- package/dist/utils/terminal-safe.d.ts +12 -0
- package/dist/utils/terminal-safe.d.ts.map +1 -0
- package/dist/utils/terminal-safe.js +53 -0
- package/dist/utils/terminal-safe.js.map +1 -0
- package/docs/ATTRIBUTION.md +1 -0
- package/docs/DASHBOARD_UPLIFT_SPEC.md +8 -8
- package/docs/INDEX.md +6 -5
- package/docs/architecture/OVERVIEW.md +15 -3
- package/docs/architecture/PROTOCOL.md +7 -1
- package/docs/architecture/adr/0006-operator-directed-model-placement.md +86 -0
- package/docs/architecture/adr/0007-auto-displacement-allowlist-as-standing-consent.md +79 -0
- package/docs/architecture/adr/0008-fleet-clients-link-out.md +92 -0
- package/docs/architecture/adr/0009-completion-triggered-dispatch-and-per-leaf-model-dials.md +71 -0
- package/docs/architecture/adr/0010-attention-queue-and-afk-auto-decider.md +159 -0
- package/docs/architecture/adr/0011-sandbox-grants-and-network-egress-boundary.md +219 -0
- package/docs/architecture/adr/0012-operator-legibility-surfaces.md +175 -0
- package/docs/getting-started/INSTALLATION.md +1 -1
- package/docs/guides/AUTOMATIC_FEATURES.md +8 -0
- package/docs/guides/LOCAL_MODELS.md +1 -1
- package/docs/guides/PROXY.md +2 -1
- package/docs/guides/SANDBOX.md +91 -4
- package/docs/integrations/MCP_ROUTER.md +1 -1
- package/docs/plans/model-performance-proof-options.md +176 -0
- package/docs/reference/API.md +1 -1
- package/docs/reference/CLI.md +169 -4
- package/docs/reference/COMPARISON.md +1 -1
- package/docs/reference/CONFIGURATION.md +12 -3
- package/docs/reference/CONFIGURATION_REFERENCE.md +269 -14
- package/docs/reference/DATABASE_SCHEMA.md +1 -1
- package/docs/reference/FEATURES.md +15 -3
- package/docs/reference/PATTERNS.md +1 -1
- package/docs/reference/PLATFORMS.md +14 -1
- package/docs/specs/operator-model-placement.md +1314 -0
- package/docs/specs/operator-model-placement.review.md +339 -0
- package/package.json +2 -2
- package/scripts/maintenance/publish-npm.sh +23 -11
- package/scripts/version-bump.sh +6 -51
- package/src/policies/enforcers/__pycache__/_common.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-311.pyc +0 -0
- package/src/policies/schemas/policies/mandatory-testing-deployment.md +2 -5
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-311.pyc +0 -0
- package/templates/hooks/session-start.sh +44 -0
- package/tools/agents/UAP/cli.py +14 -3
- package/tools/agents/UAP/paths.py +50 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-311.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +1386 -99
- package/tools/agents/scripts/toolcall_path_normalizer.py +46 -1
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +29 -6
- package/tools/agents/tests/test_doubling_break.py +64 -5
- package/tools/agents/tests/test_error_loop_break.py +10 -4
- package/tools/agents/tests/test_error_loop_ignores_correctives.py +13 -2
- package/tools/agents/tests/test_lockstep_escalation.py +280 -9
- package/tools/agents/tests/test_path_containment.py +94 -0
- package/tools/agents/tests/test_proxy_unix_socket.py +162 -0
- package/tools/agents/tests/test_signature_quality.py +349 -0
- package/tools/agents/tests/test_uap_compliance.py +11 -1
- package/web/dash/core.js +1 -0
- package/web/dash/tab-clients.js +196 -0
- package/web/dash/tab-models.js +387 -8
- package/web/dash/tab-policies.js +87 -4
- package/web/dash/tabs.js +77 -73
- package/web/dashboard.html +6 -0
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/web/dash/tab-agents.js +0 -21
- package/web/dash/tab-deliver.js +0 -12
- package/web/dash/tab-memory.js +0 -12
- package/web/dash/tab-orchestration.js +0 -21
- package/web/dash/tab-overview.js +0 -21
- package/web/dash/tab-tasks.js +0 -21
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session sandbox grants (the D2 consent ledger).
|
|
3
|
+
*
|
|
4
|
+
* `uap sandbox` is all-or-nothing authority: the workdir + scratch are
|
|
5
|
+
* writable, everything else is EROFS. That default is right, but real work
|
|
6
|
+
* sometimes needs one more hole (a config dir, a build cache outside the
|
|
7
|
+
* tree) — and the legacy answer, `UAP_SANDBOX_ALLOW=path:path`, was
|
|
8
|
+
* UNRECORDED authority: an env var nobody audited, invisible to the
|
|
9
|
+
* operator, surviving in shell histories and hook templates forever.
|
|
10
|
+
*
|
|
11
|
+
* This ledger is the fix: every extra hole is a GRANT — bounded by a
|
|
12
|
+
* session, a TTL, and a stated reason, recorded with who consented, and
|
|
13
|
+
* audit-logged on use. "Every new authority must state who consented"
|
|
14
|
+
* (ADR 0011, the P4 bar).
|
|
15
|
+
*
|
|
16
|
+
* Design rules (inherited from the attention-queue store, review-hardened):
|
|
17
|
+
* - the ledger is shared-write state in `.uap/`, so every string is
|
|
18
|
+
* sanitized at INGEST and the load path re-applies the same sanitizer —
|
|
19
|
+
* a planted row must not become a kernel-writable hole or reach
|
|
20
|
+
* operator terminals;
|
|
21
|
+
* - atomic writes with unique tmp names (no fixed `.tmp` in shared dirs);
|
|
22
|
+
* - corrupt/unreadable ledger ⇒ EMPTY ledger: the safe direction for an
|
|
23
|
+
* authority store is least authority (the sandbox itself stays the real
|
|
24
|
+
* kernel boundary — a lost grant just means EROFS, not a breach);
|
|
25
|
+
* - every grant expires (default 8h, hard cap 7d): authority is bounded
|
|
26
|
+
* by construction, and revocation is a single command;
|
|
27
|
+
* - fail-OPEN for the sandbox, fail-CLOSED for the holes: load problems
|
|
28
|
+
* never crash a sandboxed run, they just yield no holes.
|
|
29
|
+
*/
|
|
30
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from 'fs';
|
|
31
|
+
import { randomBytes, randomUUID } from 'crypto';
|
|
32
|
+
import { homedir } from 'os';
|
|
33
|
+
import { dirname, join } from 'path';
|
|
34
|
+
import { mainCheckoutRoot } from '../utils/checkout-root.js';
|
|
35
|
+
import { ledgerHeadOf, pathCoversAnchorDir, readAnchor, verifyLedger, writeAnchor } from './sandbox-anchor.js';
|
|
36
|
+
/** Audit-log retention: the trail is append-only history, but an unbounded
|
|
37
|
+
* JSONL under the shared-write `.uap/` grows forever — past
|
|
38
|
+
* the trigger it is compacted to the newest AUDIT_MAX_LINES event lines
|
|
39
|
+
* (plus the triggering event and one `audit-compaction` marker), so the
|
|
40
|
+
* file lands at AUDIT_MAX_LINES + 2. The compaction is itself audited, so
|
|
41
|
+
* a pruned trail is an EXPECTED state, never a silent one. */
|
|
42
|
+
export const AUDIT_MAX_LINES = 10_000;
|
|
43
|
+
export const AUDIT_PRUNE_TRIGGER = 12_000;
|
|
44
|
+
/** Default grant TTL: 8h — long enough for a working session, short enough
|
|
45
|
+
* that a forgotten hole closes itself before the next one. */
|
|
46
|
+
export const DEFAULT_GRANT_TTL_SECS = 28_800;
|
|
47
|
+
/** Hard cap on grant TTL: authority must be re-consented weekly at most. */
|
|
48
|
+
export const MAX_GRANT_TTL_SECS = 604_800;
|
|
49
|
+
/** Paths per grant cap: a grant is a scoped exception, not a hole list. */
|
|
50
|
+
export const MAX_PATHS_PER_GRANT = 8;
|
|
51
|
+
/**
|
|
52
|
+
* Ledger file: `<mainCheckoutRoot>/.uap/sandbox-grants.json` — ONE ledger
|
|
53
|
+
* per checkout, not per cwd, anchored at the main checkout root like the
|
|
54
|
+
* attention queue (ADR 0010): the CLI can be invoked from any worktree
|
|
55
|
+
* subdir, and a per-cwd ledger would give the same session different
|
|
56
|
+
* authority depending on where the operator happened to stand. Today the
|
|
57
|
+
* CLI is the only consumer; the anchoring also keeps a future dashboard
|
|
58
|
+
* grants view (a natural P5 surface) reading the same file.
|
|
59
|
+
* `UAP_SANDBOX_GRANTS` pins an explicit file (tests, odd layouts).
|
|
60
|
+
*/
|
|
61
|
+
export function sandboxGrantsPath(projectRoot) {
|
|
62
|
+
const override = process.env.UAP_SANDBOX_GRANTS;
|
|
63
|
+
if (typeof override === 'string' && override.trim() !== '')
|
|
64
|
+
return override.trim();
|
|
65
|
+
return join(mainCheckoutRoot(projectRoot), '.uap', 'sandbox-grants.json');
|
|
66
|
+
}
|
|
67
|
+
/** Audit trail: append-only JSONL, one line per grant/revoke/sandbox-use. */
|
|
68
|
+
export function sandboxAuditPath(projectRoot) {
|
|
69
|
+
const override = process.env.UAP_SANDBOX_AUDIT;
|
|
70
|
+
if (typeof override === 'string' && override.trim() !== '')
|
|
71
|
+
return override.trim();
|
|
72
|
+
return join(mainCheckoutRoot(projectRoot), '.uap', 'sandbox-audit.jsonl');
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Sanitization — the ledger grants KERNEL-WRITABLE HOLES and feeds operator
|
|
76
|
+
// terminals; ingested strings are untrusted by construction.
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// eslint-disable-next-line no-control-regex -- stripping control characters IS the point
|
|
79
|
+
const CONTROL_CHARS = /[\x00-\x1f\x7f]/g;
|
|
80
|
+
function clean(s, max) {
|
|
81
|
+
if (typeof s !== 'string')
|
|
82
|
+
return '';
|
|
83
|
+
return s.replace(CONTROL_CHARS, ' ').trim().slice(0, max);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A grantable path must be ABSOLUTE, must exist (you grant a real hole, not
|
|
87
|
+
* a speculative one), and must not be an over-broad root — checked AFTER
|
|
88
|
+
* symlink resolution: `/tmp/link -> $HOME` passes a string-only refusal and
|
|
89
|
+
* bwrap's `--bind` follows the link, so the check that matters is against
|
|
90
|
+
* the REALPATH (`/`, `/home`, $HOME itself — the same refusal the sandbox
|
|
91
|
+
* applies to a too-broad workdir: an over-broad grant IS a sandbox escape).
|
|
92
|
+
* Returns the RESOLVED path (what the bind will actually target), or null.
|
|
93
|
+
*/
|
|
94
|
+
export function validateGrantPath(p) {
|
|
95
|
+
if (!p.startsWith('/'))
|
|
96
|
+
return null;
|
|
97
|
+
const home = process.env.HOME || homedir();
|
|
98
|
+
let resolved;
|
|
99
|
+
try {
|
|
100
|
+
if (!existsSync(p))
|
|
101
|
+
return null;
|
|
102
|
+
resolved = realpathSync(p);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
if (resolved === '/' || resolved === '/home' || resolved === home)
|
|
108
|
+
return null;
|
|
109
|
+
return resolved;
|
|
110
|
+
}
|
|
111
|
+
function sanitizeGrant(raw) {
|
|
112
|
+
// `id` goes through the SAME clean() as every other string field: the row is
|
|
113
|
+
// rendered on operator terminals (the grants listing, the dashboard section,
|
|
114
|
+
// the revoke command line), and a planted id carrying ANSI/OSC bytes would
|
|
115
|
+
// fire exactly when the operator is drawn to inspect a tamper alarm
|
|
116
|
+
// (review M1, 2026-10-11). trim() alone was the one gap.
|
|
117
|
+
const id = clean(raw.id, 64);
|
|
118
|
+
const sessionId = clean(raw.sessionId, 64);
|
|
119
|
+
const reason = clean(raw.reason, 300);
|
|
120
|
+
const grantedBy = clean(raw.grantedBy, 64);
|
|
121
|
+
if (!id ||
|
|
122
|
+
!sessionId ||
|
|
123
|
+
!reason || // a grant without a stated reason is exactly what this ledger exists to refuse
|
|
124
|
+
!grantedBy ||
|
|
125
|
+
typeof raw.grantedAt !== 'string' ||
|
|
126
|
+
typeof raw.expiresAt !== 'string') {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const paths = [];
|
|
130
|
+
const rawPaths = Array.isArray(raw.paths) ? raw.paths : [];
|
|
131
|
+
for (const rp of rawPaths) {
|
|
132
|
+
if (typeof rp !== 'string')
|
|
133
|
+
return null;
|
|
134
|
+
// The load path re-applies the FULL grantable-path validation, not just
|
|
135
|
+
// a string prefix: a planted well-formed row with `paths:["/"]` would
|
|
136
|
+
// otherwise become a real `--bind / /` hole (the bind follows the row,
|
|
137
|
+
// so the row must carry nothing the operator would have refused — the
|
|
138
|
+
// review's blocker finding). A row with ANY
|
|
139
|
+
// ungrantable path is dropped whole: least authority, and a half-row
|
|
140
|
+
// is a forged consent record.
|
|
141
|
+
const p = validateGrantPath(clean(rp, 512));
|
|
142
|
+
if (!p)
|
|
143
|
+
return null;
|
|
144
|
+
if (!paths.includes(p))
|
|
145
|
+
paths.push(p);
|
|
146
|
+
}
|
|
147
|
+
if (paths.length === 0)
|
|
148
|
+
return null; // a grant must grant something
|
|
149
|
+
// Timestamps must parse, and the expiry must respect the hard TTL bound —
|
|
150
|
+
// a planted `expiresAt: "9999"` never lapses under the lexicographic
|
|
151
|
+
// compare in listAuthority, which is exactly the "forever grant" this
|
|
152
|
+
// ledger exists to prevent. `grantedAt` is kept as written (history), but
|
|
153
|
+
// must be a parseable instant.
|
|
154
|
+
if (!Number.isFinite(Date.parse(raw.grantedAt)))
|
|
155
|
+
return null;
|
|
156
|
+
const expiresMs = Date.parse(raw.expiresAt);
|
|
157
|
+
if (!Number.isFinite(expiresMs) || expiresMs > Date.now() + MAX_GRANT_TTL_SECS * 1000)
|
|
158
|
+
return null;
|
|
159
|
+
return {
|
|
160
|
+
id,
|
|
161
|
+
sessionId,
|
|
162
|
+
paths,
|
|
163
|
+
reason,
|
|
164
|
+
grantedBy,
|
|
165
|
+
grantedAt: raw.grantedAt,
|
|
166
|
+
expiresAt: raw.expiresAt,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Store — least-authority load, atomic persist.
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
function loadGrants(projectRoot) {
|
|
173
|
+
try {
|
|
174
|
+
const path = sandboxGrantsPath(projectRoot);
|
|
175
|
+
if (!existsSync(path))
|
|
176
|
+
return [];
|
|
177
|
+
const parsed = JSON.parse(readFileSync(path, 'utf-8'));
|
|
178
|
+
if (!Array.isArray(parsed))
|
|
179
|
+
return [];
|
|
180
|
+
const grants = [];
|
|
181
|
+
for (const raw of parsed) {
|
|
182
|
+
if (typeof raw !== 'object' || raw === null)
|
|
183
|
+
continue;
|
|
184
|
+
const g = sanitizeGrant(raw);
|
|
185
|
+
if (g)
|
|
186
|
+
grants.push(g); // malformed rows are dropped, never fatal
|
|
187
|
+
}
|
|
188
|
+
return grants;
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
// Unreadable ledger = empty ledger: the SAFE direction for authority.
|
|
192
|
+
// The sandbox keeps its kernel boundary; only the extra holes vanish.
|
|
193
|
+
console.warn(`[sandbox-grants] ledger unreadable, treating as empty (no extra holes): ${err instanceof Error ? err.message : String(err)}`);
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function persistGrants(projectRoot, grants) {
|
|
198
|
+
try {
|
|
199
|
+
const path = sandboxGrantsPath(projectRoot);
|
|
200
|
+
// Create the TARGET's directory (not <cwd>/.uap): the ledger may live at
|
|
201
|
+
// the main checkout root while cwd is a worktree subdir, or at a
|
|
202
|
+
// UAP_SANDBOX_GRANTS override — mkdir-ing the wrong place fails the
|
|
203
|
+
// write it was supposed to enable.
|
|
204
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
205
|
+
// Unique tmp name: a fixed `.tmp` in shared-write .uap/ is an
|
|
206
|
+
// interleave-truncate and symlink-clobber target (review finding).
|
|
207
|
+
const tmp = `${path}.${process.pid}-${randomBytes(3).toString('hex')}.tmp`;
|
|
208
|
+
writeFileSync(tmp, JSON.stringify(grants, null, 2), 'utf-8');
|
|
209
|
+
renameSync(tmp, path);
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
// A failed persist is reported, never silent — but it must not throw:
|
|
214
|
+
// the caller (sandbox launch) treats "no persisted grants" as safe.
|
|
215
|
+
console.warn(`[sandbox-grants] ledger persist failed (grants NOT active for this session): ${err instanceof Error ? err.message : String(err)}`);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/** The last parseable seq in an audit line list (0 when none parse): seqs
|
|
220
|
+
* are monotonic, so the last parseable line IS the high-water. A malformed
|
|
221
|
+
* tail degrades to the last good seq, never to a collision. */
|
|
222
|
+
function scanHighWater(lines) {
|
|
223
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
224
|
+
try {
|
|
225
|
+
const last = JSON.parse(lines[i]);
|
|
226
|
+
if (typeof last.seq === 'number' && Number.isFinite(last.seq))
|
|
227
|
+
return last.seq;
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
/* keep scanning */
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
/** The audit file's high-water seq (0 when the file is absent, empty, or
|
|
236
|
+
* wholly malformed) — what anchorMutation witnesses after an operation's
|
|
237
|
+
* line has landed. */
|
|
238
|
+
function auditHighWater(projectRoot) {
|
|
239
|
+
try {
|
|
240
|
+
const path = sandboxAuditPath(projectRoot);
|
|
241
|
+
if (!existsSync(path))
|
|
242
|
+
return 0;
|
|
243
|
+
const text = readFileSync(path, 'utf-8');
|
|
244
|
+
if (text.length === 0)
|
|
245
|
+
return 0;
|
|
246
|
+
return scanHighWater(text.split('\n').filter((l) => l.length > 0));
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return 0;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** Append one audit line. Append-only, best-effort, never throws. Every line
|
|
253
|
+
* carries a monotonic `seq` — recovered as the max of the file's last
|
|
254
|
+
* parseable seq and the ANCHOR's witnessed high-water, so numbering
|
|
255
|
+
* survives compaction AND file deletion (a trail whose numbering can
|
|
256
|
+
* restart is a forgeable trail). The file is compacted past
|
|
257
|
+
* AUDIT_PRUNE_TRIGGER with the drop recorded in an `audit-compaction`
|
|
258
|
+
* marker. */
|
|
259
|
+
function audit(projectRoot, event) {
|
|
260
|
+
try {
|
|
261
|
+
const path = sandboxAuditPath(projectRoot);
|
|
262
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
263
|
+
let lines = [];
|
|
264
|
+
let fileHi = 0;
|
|
265
|
+
if (existsSync(path)) {
|
|
266
|
+
const text = readFileSync(path, 'utf-8');
|
|
267
|
+
if (text.length > 0) {
|
|
268
|
+
lines = text.split('\n').filter((l) => l.length > 0);
|
|
269
|
+
// Scan BACKWARDS for the last parseable line: after a compaction the
|
|
270
|
+
// file holds 10k lines with seqs up in the 12k+ range, so the old
|
|
271
|
+
// `lines.length` fallback could REUSE a live seq number. A malformed
|
|
272
|
+
// tail degrades to (last good seq + 1), never to a collision.
|
|
273
|
+
fileHi = scanHighWater(lines);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// The anchor's seqHi covers what the FILE cannot: deletion. The anchor
|
|
277
|
+
// only witnesses seqs at recorded mutations, so a file grown past the
|
|
278
|
+
// anchor (e.g. by sandbox-run lines) still numbers correctly — max of
|
|
279
|
+
// both.
|
|
280
|
+
const seq = Math.max(fileHi, readAnchor(projectRoot)?.seqHi ?? 0) + 1;
|
|
281
|
+
if (lines.length + 1 > AUDIT_PRUNE_TRIGGER) {
|
|
282
|
+
const kept = lines.slice(-AUDIT_MAX_LINES);
|
|
283
|
+
kept.push(JSON.stringify({ ...event, seq }));
|
|
284
|
+
kept.push(JSON.stringify({
|
|
285
|
+
ts: new Date().toISOString(),
|
|
286
|
+
action: 'audit-compaction',
|
|
287
|
+
dropped: lines.length + 1 - kept.length,
|
|
288
|
+
seq: seq + 1,
|
|
289
|
+
}));
|
|
290
|
+
const tmp = `${path}.${process.pid}-${randomBytes(3).toString('hex')}.tmp`;
|
|
291
|
+
writeFileSync(tmp, kept.map((l) => `${l}\n`).join(''), 'utf-8');
|
|
292
|
+
renameSync(tmp, path);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
appendFileSync(path, `${JSON.stringify({ ...event, seq })}\n`, 'utf-8');
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
console.warn(`[sandbox-grants] audit append failed (grant/revoke still applied): ${err instanceof Error ? err.message : String(err)}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
// Trust anchor (ADR 0011 follow-up, shipped): see sandbox-anchor.ts.
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
/** Verify the SANITIZED on-disk ledger against the out-of-checkout anchor.
|
|
305
|
+
* 'unanchored' is the pre-bootstrap state, not a failure. When `grants` is
|
|
306
|
+
* passed (an already-loaded sanitized snapshot), the SAME snapshot is
|
|
307
|
+
* verified and then acted on — the torn-read fix (a review finding):
|
|
308
|
+
* loading the file twice left a window where the hash saw one state and
|
|
309
|
+
* the resolver acted on another. */
|
|
310
|
+
export function verifyLedgerIntegrity(projectRoot, grants) {
|
|
311
|
+
const onDisk = grants ?? loadGrants(projectRoot);
|
|
312
|
+
return verifyLedger(projectRoot, ledgerHeadOf(onDisk));
|
|
313
|
+
}
|
|
314
|
+
/** Advance the anchor to a CONFIRMED on-disk state (called only after the
|
|
315
|
+
* lost-update guard proved the persist landed, and AFTER the operation's
|
|
316
|
+
* audit line is written, so the seq high-water the anchor witnesses
|
|
317
|
+
* includes it). A failed anchor write is loud but never fatal: the ledger
|
|
318
|
+
* stays operative; verification is simply not possible until the next
|
|
319
|
+
* recorded mutation succeeds. */
|
|
320
|
+
function anchorMutation(projectRoot, confirmed) {
|
|
321
|
+
const prior = readAnchor(projectRoot);
|
|
322
|
+
const seqHi = Math.max(prior?.seqHi ?? 0, auditHighWater(projectRoot));
|
|
323
|
+
if (!writeAnchor(projectRoot, ledgerHeadOf(confirmed), (prior?.mutations ?? 0) + 1, seqHi)) {
|
|
324
|
+
console.warn('[sandbox-grants] trust-anchor write failed — the ledger is active but NOT verifiable; ' +
|
|
325
|
+
'the next successful grant/renew/revoke will try to anchor it');
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
// Verify-after-write (review interleave finding): a concurrent writer's
|
|
329
|
+
// anchor landing between ours and the ledger read leaves a persistent
|
|
330
|
+
// false mismatch on a healthy ledger. Confirm ours is what the disk now
|
|
331
|
+
// holds; if not, say so — never a silent divergence.
|
|
332
|
+
const after = verifyLedgerIntegrity(projectRoot);
|
|
333
|
+
if (after.state !== 'ok') {
|
|
334
|
+
console.warn(`[sandbox-grants] the trust anchor moved to a concurrent writer's state after this mutation (${after.state}) — ` +
|
|
335
|
+
'if `uap sandbox grants` reports a mismatch you did not cause, re-run the last grant/revoke');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// ---------------------------------------------------------------------------
|
|
339
|
+
// Operations.
|
|
340
|
+
// ---------------------------------------------------------------------------
|
|
341
|
+
/** Create a grant. Returns the grant, or a refusal reason. */
|
|
342
|
+
export function grantAuthority(projectRoot, input) {
|
|
343
|
+
const sessionId = clean(input.sessionId, 64);
|
|
344
|
+
if (!sessionId)
|
|
345
|
+
return { ok: false, error: 'a grant requires --session <id> (the session this authority is scoped to)' };
|
|
346
|
+
const reason = clean(input.reason, 300);
|
|
347
|
+
if (!reason)
|
|
348
|
+
return { ok: false, error: 'a grant requires --reason "..." — consent must be stated, not implied' };
|
|
349
|
+
const paths = [];
|
|
350
|
+
for (const p of input.paths) {
|
|
351
|
+
const v = validateGrantPath(p);
|
|
352
|
+
if (!v)
|
|
353
|
+
return { ok: false, error: `not grantable: '${p}' (must be an existing absolute path, and not / , /home, or $HOME itself)` };
|
|
354
|
+
// The one hole that must never open: a grant covering the trust-anchor
|
|
355
|
+
// dir lets the sandboxed side delete or corrupt the tamper evidence
|
|
356
|
+
// itself (the anchor is ro-bound by default, but a hole
|
|
357
|
+
// over it makes it writable).
|
|
358
|
+
if (pathCoversAnchorDir(v)) {
|
|
359
|
+
return { ok: false, error: `not grantable: '${p}' covers the sandbox trust-anchor directory — a hole there could destroy the tamper evidence itself` };
|
|
360
|
+
}
|
|
361
|
+
if (!paths.includes(v))
|
|
362
|
+
paths.push(v);
|
|
363
|
+
if (paths.length > MAX_PATHS_PER_GRANT)
|
|
364
|
+
return { ok: false, error: `more than ${MAX_PATHS_PER_GRANT} paths in one grant — split it` };
|
|
365
|
+
}
|
|
366
|
+
if (paths.length === 0) {
|
|
367
|
+
return { ok: false, error: 'a grant grants something: pass at least one writable path' };
|
|
368
|
+
}
|
|
369
|
+
// TTL is FAIL-CLOSED on garbage: undefined → the 8h default, but a
|
|
370
|
+
// non-numeric or negative --ttl is REFUSED outright (the security
|
|
371
|
+
// review caught bad input silently meaning "give 8h anyway" — the wrong
|
|
372
|
+
// direction for authority). 0 floors to 1s: a
|
|
373
|
+
// zero-second grant is a recorded consent that expires immediately.
|
|
374
|
+
let ttl;
|
|
375
|
+
if (input.ttlSecs === undefined) {
|
|
376
|
+
ttl = DEFAULT_GRANT_TTL_SECS;
|
|
377
|
+
}
|
|
378
|
+
else if (!Number.isFinite(input.ttlSecs) || input.ttlSecs < 0) {
|
|
379
|
+
return { ok: false, error: `--ttl must be a non-negative number of seconds (got '${input.ttlSecs}')` };
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
ttl = Math.min(Math.max(1, Math.floor(input.ttlSecs)), MAX_GRANT_TTL_SECS);
|
|
383
|
+
}
|
|
384
|
+
const now = new Date();
|
|
385
|
+
const grant = {
|
|
386
|
+
id: `sbg-${randomUUID().slice(0, 8)}`,
|
|
387
|
+
sessionId,
|
|
388
|
+
paths,
|
|
389
|
+
reason,
|
|
390
|
+
grantedBy: process.env.USER || process.env.LOGNAME || 'unknown',
|
|
391
|
+
grantedAt: now.toISOString(),
|
|
392
|
+
expiresAt: new Date(now.getTime() + ttl * 1000).toISOString(),
|
|
393
|
+
};
|
|
394
|
+
for (let attempt = 0;; attempt++) {
|
|
395
|
+
// ONE load, ONE hash, one array to act on (the torn-read fix — a
|
|
396
|
+
// review finding): verifying a separate read left a window where the
|
|
397
|
+
// hash saw one state and the mint acted on another.
|
|
398
|
+
const loaded = loadGrants(projectRoot);
|
|
399
|
+
const integrity = verifyLedgerIntegrity(projectRoot, loaded);
|
|
400
|
+
if (integrity.state === 'mismatch') {
|
|
401
|
+
// A tampered ledger must not mint legitimacy: refuse to RECORD new
|
|
402
|
+
// consent on top of a state that failed integrity verification.
|
|
403
|
+
return {
|
|
404
|
+
ok: false,
|
|
405
|
+
error: `ledger failed integrity verification — ${integrity.detail}; refusing to record new consent until it is resolved`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
const existing = loaded.filter((g) => g.expiresAt > now.toISOString());
|
|
409
|
+
// Dedupe: an identical open grant (same session + same paths) is refreshed,
|
|
410
|
+
// not duplicated — a second `grant` for the same hole renews its TTL.
|
|
411
|
+
const twin = existing.find((g) => g.sessionId === grant.sessionId && g.paths.length === grant.paths.length && grant.paths.every((p) => g.paths.includes(p)));
|
|
412
|
+
if (twin) {
|
|
413
|
+
twin.expiresAt = grant.expiresAt;
|
|
414
|
+
twin.reason = grant.reason;
|
|
415
|
+
twin.grantedAt = grant.grantedAt;
|
|
416
|
+
// A failed persist must not be reported as a renewal: the OLD expiry
|
|
417
|
+
// stays active (the safe direction), and the operator keeps the truth.
|
|
418
|
+
if (!persistGrants(projectRoot, existing)) {
|
|
419
|
+
return { ok: false, error: 'ledger persist failed — the renewal is NOT active (the previous expiry stands)' };
|
|
420
|
+
}
|
|
421
|
+
// Lost-update guard: load→modify→persist has no lock, and the atomic
|
|
422
|
+
// rename prevents corruption, not lost updates — a concurrent writer
|
|
423
|
+
// landing after ours drops our renewal while we report success.
|
|
424
|
+
// Verify ours survived; retry once against the fresh state.
|
|
425
|
+
const confirmedAll = loadGrants(projectRoot);
|
|
426
|
+
const after = confirmedAll.find((g) => g.id === twin.id);
|
|
427
|
+
if (!after || after.expiresAt !== twin.expiresAt) {
|
|
428
|
+
if (attempt === 0)
|
|
429
|
+
continue;
|
|
430
|
+
return { ok: false, error: 'ledger changed under a concurrent writer — renewal not confirmed; retry the grant' };
|
|
431
|
+
}
|
|
432
|
+
// Audit FIRST, then anchor: the anchor witnesses the audit high-water,
|
|
433
|
+
// and it must include this operation's line (audit-then-anchor is what
|
|
434
|
+
// makes seq survive audit-file deletion — the anchor's seqHi is the
|
|
435
|
+
// floor the next line numbers from).
|
|
436
|
+
audit(projectRoot, { ts: grant.grantedAt, action: 'grant-renewed', grantId: twin.id, sessionId, paths, reason });
|
|
437
|
+
anchorMutation(projectRoot, confirmedAll);
|
|
438
|
+
return { ok: true, grant: twin };
|
|
439
|
+
}
|
|
440
|
+
const all = [...existing, grant];
|
|
441
|
+
if (!persistGrants(projectRoot, all)) {
|
|
442
|
+
return { ok: false, error: 'ledger persist failed — the grant is NOT active (refusing to report success)' };
|
|
443
|
+
}
|
|
444
|
+
// Lost-update guard (same shape as the renewal path): two concurrent
|
|
445
|
+
// grants can both read-modify-write and silently drop the loser's row
|
|
446
|
+
// while its CLI reports success — verify the row survived before
|
|
447
|
+
// claiming the grant active.
|
|
448
|
+
const confirmedAll = loadGrants(projectRoot);
|
|
449
|
+
if (!confirmedAll.some((g) => g.id === grant.id)) {
|
|
450
|
+
if (attempt === 0)
|
|
451
|
+
continue;
|
|
452
|
+
return { ok: false, error: 'ledger changed under a concurrent writer — the grant is NOT confirmed; retry' };
|
|
453
|
+
}
|
|
454
|
+
// Audit FIRST, then anchor — same reason as the renewal path above.
|
|
455
|
+
audit(projectRoot, { ts: grant.grantedAt, action: 'grant', grantId: grant.id, sessionId, paths, reason, ttlSecs: ttl });
|
|
456
|
+
anchorMutation(projectRoot, confirmedAll);
|
|
457
|
+
return { ok: true, grant };
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
/** List grants, optionally scoped to one session. Expired rows are inert. */
|
|
461
|
+
export function listAuthority(projectRoot, sessionId) {
|
|
462
|
+
const nowIso = new Date().toISOString();
|
|
463
|
+
const sid = sessionId ? clean(sessionId, 64) : '';
|
|
464
|
+
return loadGrants(projectRoot).filter((g) => g.expiresAt > nowIso && (!sid || g.sessionId === sid));
|
|
465
|
+
}
|
|
466
|
+
/** Revoke one grant by id. Returns true only when it was found AND removed
|
|
467
|
+
* from the ledger — a failed persist leaves the grant active, and reporting
|
|
468
|
+
* success over a live grant would be a false consent record. */
|
|
469
|
+
export function revokeAuthority(projectRoot, grantId) {
|
|
470
|
+
const id = clean(grantId, 64);
|
|
471
|
+
// A mismatched ledger may still LOSE authority (revoking is the safe
|
|
472
|
+
// direction) — but the revoke re-anchors the remaining rows as the new
|
|
473
|
+
// baseline, so a pre-existing mismatch is named loudly at the exact
|
|
474
|
+
// moment it stops being detectable.
|
|
475
|
+
const preIntegrity = verifyLedgerIntegrity(projectRoot);
|
|
476
|
+
for (let attempt = 0;; attempt++) {
|
|
477
|
+
const all = loadGrants(projectRoot);
|
|
478
|
+
const keep = all.filter((g) => g.id !== id);
|
|
479
|
+
if (keep.length === all.length)
|
|
480
|
+
return false;
|
|
481
|
+
if (!persistGrants(projectRoot, keep))
|
|
482
|
+
return false;
|
|
483
|
+
// Lost-update guard (security review): a concurrent writer landing
|
|
484
|
+
// after our persist can resurrect the row; verify the removal actually
|
|
485
|
+
// landed before reporting success, retrying once against fresh state.
|
|
486
|
+
const confirmedAll = loadGrants(projectRoot);
|
|
487
|
+
if (confirmedAll.some((g) => g.id === id)) {
|
|
488
|
+
if (attempt === 0)
|
|
489
|
+
continue;
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
// Audit FIRST, then anchor — same reason as the grant/renew paths.
|
|
493
|
+
audit(projectRoot, { ts: new Date().toISOString(), action: 'revoke', grantId: id });
|
|
494
|
+
anchorMutation(projectRoot, confirmedAll);
|
|
495
|
+
if (preIntegrity.state === 'mismatch') {
|
|
496
|
+
console.warn(`[sandbox-grants] NOTE: the ledger had failed integrity verification before this revoke — ${preIntegrity.detail}. ` +
|
|
497
|
+
'The remaining rows are now anchored as the new baseline; inspect them with `uap sandbox grants`.');
|
|
498
|
+
}
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Resolve the ACTIVE authority for a session — what `uap sandbox` will
|
|
504
|
+
* actually open. Expired or malformed rows are invisible here; the sandbox
|
|
505
|
+
* never has to reason about them.
|
|
506
|
+
*/
|
|
507
|
+
export function resolveSessionGrants(projectRoot, sessionId) {
|
|
508
|
+
// ONE load: the snapshot that gets verified is the SAME snapshot that
|
|
509
|
+
// resolves the holes (the torn-read fix).
|
|
510
|
+
const loaded = loadGrants(projectRoot);
|
|
511
|
+
// Fail-CLOSED on tamper evidence (ADR 0011): a ledger that fails anchor
|
|
512
|
+
// verification opens ZERO grant-derived holes. The sandbox's own kernel
|
|
513
|
+
// boundary is unaffected — only the extra holes close (the safe direction
|
|
514
|
+
// for authority, same rule as an unreadable ledger).
|
|
515
|
+
const integrity = verifyLedgerIntegrity(projectRoot, loaded);
|
|
516
|
+
if (integrity.state === 'mismatch') {
|
|
517
|
+
console.error(`[sandbox-grants] INTEGRITY MISMATCH — ${integrity.detail}. ` +
|
|
518
|
+
'Opening NO grant-derived writable holes for this session; the sandbox boundary itself is unaffected. ' +
|
|
519
|
+
'Run `uap sandbox grants` to inspect the ledger.');
|
|
520
|
+
return { grants: [], paths: [] };
|
|
521
|
+
}
|
|
522
|
+
if (integrity.state === 'unanchored' && loaded.length > 0) {
|
|
523
|
+
// The quiet dangerous state (review finding): grants exist but the anchor is
|
|
524
|
+
// gone/never written, so tamper evidence is OFF. Never silent.
|
|
525
|
+
console.warn(`[sandbox-grants] ${loaded.length} grant(s) on disk but NO trust anchor — tamper evidence is inactive; ` +
|
|
526
|
+
'the next successful grant/renew/revoke (re-)anchors the ledger');
|
|
527
|
+
}
|
|
528
|
+
const nowIso = new Date().toISOString();
|
|
529
|
+
const sid = clean(sessionId, 64);
|
|
530
|
+
const active = loaded.filter((g) => g.expiresAt > nowIso && (!sid || g.sessionId === sid));
|
|
531
|
+
const paths = [];
|
|
532
|
+
for (const g of active)
|
|
533
|
+
for (const p of g.paths)
|
|
534
|
+
if (!paths.includes(p))
|
|
535
|
+
paths.push(p);
|
|
536
|
+
return { grants: active, paths };
|
|
537
|
+
}
|
|
538
|
+
/** Record that a sandbox run USED its grants (the "who consented, when used" line).
|
|
539
|
+
* `netMode` is the network mode the run ACTUALLY engaged ('off' = the kernel
|
|
540
|
+
* egress boundary): the audit line is the consent record, so it must state
|
|
541
|
+
* the boundary that was really on. The legacy-env record states what the
|
|
542
|
+
* run actually OPENED (`legacyBound`, the resolved targets that were bound)
|
|
543
|
+
* separately from what plan time REFUSED (`legacyRefused`) — recording a
|
|
544
|
+
* refused entry as the run's allow would attribute authority the run never
|
|
545
|
+
* had, and the durable record must agree with the launch banner. */
|
|
546
|
+
export function auditSandboxUse(projectRoot, sessionId, used, legacyBound, legacyRefused, netMode) {
|
|
547
|
+
audit(projectRoot, {
|
|
548
|
+
ts: new Date().toISOString(),
|
|
549
|
+
action: 'sandbox-run',
|
|
550
|
+
sessionId: clean(sessionId, 64),
|
|
551
|
+
grantIds: used.grants.map((g) => g.id),
|
|
552
|
+
paths: used.paths,
|
|
553
|
+
netMode,
|
|
554
|
+
// The legacy env is still honored (backwards compatibility) but named in
|
|
555
|
+
// the audit: unrecorded authority is exactly what this ledger replaced.
|
|
556
|
+
// Control chars are cleaned here too — the audit line is operator-
|
|
557
|
+
// terminal output as much as JSONL.
|
|
558
|
+
unrecordedAllow: legacyBound.map((p) => clean(p, 512)),
|
|
559
|
+
unrecordedRefused: legacyRefused.map((p) => clean(p, 512)),
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
//# sourceMappingURL=sandbox-grants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-grants.js","sourceRoot":"","sources":["../../src/policies/sandbox-grants.ts"],"names":[],"mappings":"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"}
|
package/dist/state/manifest.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Implementation-State Manifest — a machine-generated snapshot of what this
|
|
3
3
|
* project IS and where its implementation actually stands, derived from
|
|
4
|
-
* ground truth (package.json,
|
|
4
|
+
* ground truth (package.json, git log, git branch, .factory registries)
|
|
5
5
|
* rather than hand-maintained docs that drift.
|
|
6
6
|
*
|
|
7
7
|
* Written to `.uap/state-manifest.json`; the reactor injects a one-line
|
|
@@ -14,7 +14,9 @@ export interface StateManifest {
|
|
|
14
14
|
version: string;
|
|
15
15
|
generatedAt: string;
|
|
16
16
|
branch?: string;
|
|
17
|
-
/** Latest
|
|
17
|
+
/** Latest commit subjects, newest first — the real "what shipped lately".
|
|
18
|
+
* UNTRUSTED input: commit subjects are contributor-authored text; they are
|
|
19
|
+
* stripped + single-lined at ingest and re-stripped at the digest boundary. */
|
|
18
20
|
recentChanges: string[];
|
|
19
21
|
/** Registry counts when the project has them (skills/droids/patterns). */
|
|
20
22
|
counts?: Record<string, number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/state/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/state/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;mFAE+E;IAC/E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAMD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAoDD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAkC/E;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAiB5E;AAED,qEAAqE;AACrE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAW/E;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CAmB9D"}
|