@sema-agent/server 7.147.0 → 7.148.0
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/MIGRATION.md +1039 -24
- package/README.md +20 -7
- package/README.zh-CN.md +14 -8
- package/USAGE.md +380 -163
- package/deploy/sema-up/README.md +16 -5
- package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
- package/deploy/sema-up/chart/templates/_helpers.tpl +20 -4
- package/deploy/sema-up/chart/values.yaml +3 -2
- package/deploy/sema-up/cluster-up.sh +74 -176
- package/deploy/sema-up/kube-up.sh +29 -49
- package/deploy/sema-up/lib/chart-run.sh +23 -0
- package/deploy/sema-up/lib/dataroot.sh +3 -3
- package/deploy/sema-up/lib/health.sh +62 -13
- package/deploy/sema-up/lib/helm-values-cluster.py +18 -0
- package/deploy/sema-up/lib/helm-values-kube.py +35 -0
- package/deploy/sema-up/lib/regcred.py +8 -0
- package/deploy/sema-up/lib/remote/helm-install.sh +3 -0
- package/deploy/sema-up/lib/remote/image-import.sh +6 -0
- package/deploy/sema-up/lib/remote/machine-precheck.sh +11 -0
- package/deploy/sema-up/lib/remote/region-probe.sh +3 -0
- package/deploy/sema-up/lib/remote/stack-ready.sh +26 -0
- package/deploy/sema-up/lib/remote/vxlan-guard.sh +8 -0
- package/deploy/sema-up/lib/render-stack.py +17 -0
- package/deploy/sema-up/lib/shell-text.sh +87 -0
- package/deploy/sema-up/lib/usage-flags.txt +10 -0
- package/deploy/sema-up/lib/usage-head.txt +1 -0
- package/deploy/sema-up/lib/usage-tail.txt +13 -0
- package/deploy/sema-up/preflight.sh +10 -8
- package/deploy/sema-up/sema-up.sh +14 -39
- package/deploy/sema-up/smoke.sh +7 -6
- package/deploy/sema-up/stack/compose.dataroot.yaml +3 -0
- package/deploy/sema-up/stack/compose.yaml +13 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +21 -0
- package/dist/adoption/plan.d.ts +24 -0
- package/dist/adoption/plan.js +53 -1
- package/dist/adoption/runner.d.ts +10 -1
- package/dist/adoption/runner.js +36 -16
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +28 -30
- package/dist/approval-gate-currency.js +3 -2
- package/dist/approval-reconciler.d.ts +4 -13
- package/dist/approval-reconciler.js +2 -2
- package/dist/approval.d.ts +13 -11
- package/dist/approval.js +3 -3
- package/dist/audit.d.ts +10 -3
- package/dist/audit.js +15 -7
- package/dist/auth-bridge.d.ts +0 -14
- package/dist/auth-bridge.js +0 -7
- package/dist/auto-mode-face.d.ts +10 -7
- package/dist/auto-mode-face.js +7 -4
- package/dist/background-agent-name.d.ts +19 -1
- package/dist/background-agent-name.js +12 -2
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/bake-runner/main.js +9 -6
- package/dist/bench/s1/arms.js +6 -5
- package/dist/bench/s1/live-deps.js +5 -2
- package/dist/bench/s1/run-firm.js +6 -5
- package/dist/bind-host.d.ts +25 -0
- package/dist/bind-host.js +25 -0
- package/dist/boot/adoption.d.ts +3 -0
- package/dist/boot/adoption.js +1 -0
- package/dist/boot/deployment-mods.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +17 -7
- package/dist/boot/execution-env.js +37 -31
- package/dist/boot/exit-boundary.d.ts +2 -2
- package/dist/boot/exit-boundary.js +6 -5
- package/dist/boot/fatal-exit.d.ts +3 -5
- package/dist/boot/fatal-exit.js +2 -2
- package/dist/boot/leader.d.ts +15 -0
- package/dist/boot/leader.js +17 -15
- package/dist/boot/memory-consolidation.d.ts +37 -29
- package/dist/boot/memory-consolidation.js +11 -5
- package/dist/boot/org-memory.js +1 -1
- package/dist/boot/parked-revive-gate.js +2 -2
- package/dist/boot/reapers.d.ts +4 -3
- package/dist/boot/reapers.js +19 -16
- package/dist/boot/resolve-spec.d.ts +5 -3
- package/dist/boot/resolve-spec.js +55 -67
- package/dist/boot/retention-lane.d.ts +4 -4
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +28 -7
- package/dist/boot/runner-deps.js +11 -4
- package/dist/boot/runtime-caps.d.ts +2 -2
- package/dist/boot/runtime-caps.js +16 -2
- package/dist/boot/session-faces.d.ts +16 -7
- package/dist/boot/session-faces.js +114 -94
- package/dist/boot/shutdown.d.ts +5 -4
- package/dist/boot/shutdown.js +6 -4
- package/dist/boot/stage-01-config.js +9 -1
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
- package/dist/boot/stage-02-web-admin-pull.js +6 -1
- package/dist/boot/stage-03-store-backend.d.ts +3 -0
- package/dist/boot/stage-03-store-backend.js +4 -3
- package/dist/boot/stage-04-stores.d.ts +2 -0
- package/dist/boot/stage-04-stores.js +2 -2
- package/dist/boot/stage-05-execution-env.d.ts +7 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +10 -12
- package/dist/boot/stage-06-runners.js +23 -15
- package/dist/boot/stage-07-capability-layer.d.ts +11 -8
- package/dist/boot/stage-07-capability-layer.js +5 -3
- package/dist/boot/stage-08-reapers.d.ts +11 -8
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +12 -15
- package/dist/boot/stage-09-leader.js +12 -4
- package/dist/boot/stage-10-http-server.d.ts +12 -15
- package/dist/boot/stage-10-http-server.js +7 -4
- package/dist/boot/store-evidence.d.ts +20 -0
- package/dist/boot/store-evidence.js +13 -0
- package/dist/boot/stores.d.ts +3 -0
- package/dist/boot/stores.js +21 -10
- package/dist/boot/task-list-lane.d.ts +4 -4
- package/dist/boot/web-admin.d.ts +4 -2
- package/dist/boot/web-admin.js +55 -35
- package/dist/boot/webfetch-summarize-lane.d.ts +1 -1
- package/dist/boot-reclaim.d.ts +3 -1
- package/dist/boot-reclaim.js +1 -1
- package/dist/brain.d.ts +7 -18
- package/dist/brain.js +5 -17
- package/dist/budget.js +6 -6
- package/dist/capabilities/center-plugins.d.ts +7 -1
- package/dist/capabilities/center-plugins.js +32 -10
- package/dist/capabilities/center-wiring.js +1 -1
- package/dist/capabilities/composite-members.d.ts +2 -2
- package/dist/capabilities/composite-members.js +2 -2
- package/dist/capabilities/repo-tools.d.ts +2 -0
- package/dist/capabilities/repo-tools.js +14 -12
- package/dist/capabilities/scenarios.d.ts +6 -15
- package/dist/capabilities/scenarios.js +11 -16
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +38 -11
- package/dist/capability-facts.js +47 -8
- package/dist/card-void.d.ts +4 -4
- package/dist/card-void.js +1 -1
- package/dist/center-credential-renewer.d.ts +6 -2
- package/dist/center-credential-renewer.js +7 -3
- package/dist/config-catalog.d.ts +16 -1
- package/dist/config-catalog.js +62 -56
- package/dist/config-dir-trust.d.ts +37 -4
- package/dist/config-dir-trust.js +88 -44
- package/dist/config-invariants.d.ts +42 -3
- package/dist/config-invariants.js +69 -5
- package/dist/config-lkg.d.ts +23 -1
- package/dist/config-lkg.js +17 -3
- package/dist/config-provider.d.ts +9 -9
- package/dist/config-provider.js +25 -110
- package/dist/config-pull-failure.d.ts +50 -0
- package/dist/config-pull-failure.js +48 -0
- package/dist/config-types.d.ts +26 -17
- package/dist/config.d.ts +8 -16
- package/dist/config.js +113 -47
- package/dist/delegated-session-owner.d.ts +1 -1
- package/dist/deleted-session-ids.d.ts +3 -2
- package/dist/deployment-governance.d.ts +3 -3
- package/dist/deployment-shape.d.ts +30 -4
- package/dist/deployment-shape.js +7 -0
- package/dist/egress-redirect.d.ts +25 -7
- package/dist/egress-redirect.js +20 -2
- package/dist/elicitation.d.ts +6 -5
- package/dist/elicitation.js +23 -22
- package/dist/engine-identity.d.ts +28 -0
- package/dist/engine-identity.js +10 -0
- package/dist/entry-problems.d.ts +5 -7
- package/dist/entry-problems.js +1 -1
- package/dist/env-facts.js +2 -1
- package/dist/env-witness.d.ts +7 -0
- package/dist/env-witness.js +16 -0
- package/dist/execution-lane-caps.d.ts +5 -18
- package/dist/execution-lane-caps.js +0 -22
- package/dist/execution-placement.d.ts +58 -18
- package/dist/execution-placement.js +41 -2
- package/dist/field-conflict.d.ts +7 -11
- package/dist/field-conflict.js +3 -3
- package/dist/file-history-capture.d.ts +3 -3
- package/dist/file-history-disclosure.js +1 -0
- package/dist/fleet/fleet-bus.d.ts +21 -3
- package/dist/fleet/fleet-bus.js +35 -25
- package/dist/fleet/fleet-reconciler.js +2 -2
- package/dist/fleet/serving-lease.js +3 -3
- package/dist/fleet-client.js +3 -3
- package/dist/fleet-lease.d.ts +0 -1
- package/dist/fleet-lease.js +4 -5
- package/dist/history-anchor.d.ts +23 -3
- package/dist/history-anchor.js +24 -4
- package/dist/hitl-delivery.d.ts +90 -0
- package/dist/hitl-delivery.js +98 -0
- package/dist/hooks/classic-stations.d.ts +8 -11
- package/dist/hooks/classic-stations.js +0 -7
- package/dist/hooks/hook-llm.d.ts +5 -1
- package/dist/hooks/hook-llm.js +24 -15
- package/dist/hooks/hook-runner.d.ts +67 -57
- package/dist/hooks/hook-runner.js +260 -186
- package/dist/host-lsp-manager.d.ts +22 -8
- package/dist/host-lsp-manager.js +4 -1
- package/dist/http/active-run-conflict.d.ts +2 -43
- package/dist/http/active-run-conflict.js +3 -7
- package/dist/http/admission.d.ts +4 -18
- package/dist/http/admission.js +75 -78
- package/dist/http/approval-sweeps.d.ts +3 -3
- package/dist/http/approval-sweeps.js +54 -30
- package/dist/http/caller-trust.d.ts +8 -10
- package/dist/http/caller-trust.js +1 -2
- package/dist/http/claim-heartbeat.d.ts +49 -0
- package/dist/http/claim-heartbeat.js +46 -0
- package/dist/http/claimed-run.d.ts +4 -3
- package/dist/http/dispatch.d.ts +8 -1
- package/dist/http/dispatch.js +76 -30
- package/dist/http/durable-run-leg.d.ts +3 -3
- package/dist/http/durable-run-leg.js +17 -12
- package/dist/http/execution-context.d.ts +17 -43
- package/dist/http/execution-context.js +7 -5
- package/dist/http/health-reader.d.ts +36 -0
- package/dist/http/health-reader.js +21 -0
- package/dist/http/health-self-report.d.ts +9 -9
- package/dist/http/health-self-report.js +4 -4
- package/dist/http/idempotency.d.ts +9 -5
- package/dist/http/idempotency.js +4 -4
- package/dist/http/memory-compliance-failure-reply.d.ts +15 -16
- package/dist/http/memory-compliance-failure-reply.js +4 -2
- package/dist/http/memory-face-fault-reply.d.ts +67 -0
- package/dist/http/memory-face-fault-reply.js +71 -0
- package/dist/http/memory-store-refusal-reply.d.ts +1 -1
- package/dist/http/memory-store-refusal-reply.js +3 -0
- package/dist/http/owner-access.d.ts +391 -67
- package/dist/http/owner-access.js +371 -35
- package/dist/http/principal-gate.d.ts +24 -81
- package/dist/http/principal-gate.js +24 -68
- package/dist/http/refusal-body.d.ts +35 -2
- package/dist/http/refusal-body.js +34 -0
- package/dist/http/request-guards.d.ts +9 -13
- package/dist/http/request-guards.js +34 -68
- package/dist/http/resume-composition.d.ts +37 -0
- package/dist/http/resume-composition.js +18 -0
- package/dist/http/resume-ctx-read.d.ts +35 -12
- package/dist/http/resume-ctx-read.js +25 -6
- package/dist/http/resume-legs.d.ts +21 -18
- package/dist/http/resume-legs.js +189 -129
- package/dist/http/retired-skill-manifest.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +25 -32
- package/dist/http/routes/a2a-serve.d.ts +43 -5
- package/dist/http/routes/a2a-serve.js +58 -37
- package/dist/http/routes/admin-config-refresh.js +2 -2
- package/dist/http/routes/admin-drain.js +2 -2
- package/dist/http/routes/admin-memory-optout.js +4 -3
- package/dist/http/routes/adoption.d.ts +3 -0
- package/dist/http/routes/adoption.js +17 -10
- package/dist/http/routes/agents-roster.js +13 -7
- package/dist/http/routes/approvals-assistant.js +70 -65
- package/dist/http/routes/attachments.js +2 -2
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/background.js +9 -17
- package/dist/http/routes/capabilities.js +15 -18
- package/dist/http/routes/config-catalog.js +2 -2
- package/dist/http/routes/devices.d.ts +3 -3
- package/dist/http/routes/devices.js +4 -4
- package/dist/http/routes/diagnostics.d.ts +27 -3
- package/dist/http/routes/diagnostics.js +27 -21
- package/dist/http/routes/engine.js +2 -2
- package/dist/http/routes/fleet.js +5 -3
- package/dist/http/routes/images.js +10 -6
- package/dist/http/routes/leader.d.ts +7 -2
- package/dist/http/routes/leader.js +12 -3
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +7 -15
- package/dist/http/routes/memory-bundle.js +4 -7
- package/dist/http/routes/memory-compliance.js +4 -4
- package/dist/http/routes/memory-consolidation.js +6 -9
- package/dist/http/routes/memory-origin.d.ts +2 -0
- package/dist/http/routes/memory-origin.js +7 -8
- package/dist/http/routes/memory-policy.js +17 -12
- package/dist/http/routes/notify-wake.js +10 -19
- package/dist/http/routes/observability.js +3 -3
- package/dist/http/routes/principal-inbox.d.ts +1 -1
- package/dist/http/routes/principal-inbox.js +2 -2
- package/dist/http/routes/projects.d.ts +1 -1
- package/dist/http/routes/projects.js +3 -2
- package/dist/http/routes/retention-ops.js +6 -9
- package/dist/http/routes/rules.js +20 -5
- package/dist/http/routes/run-memory-capture.d.ts +2 -2
- package/dist/http/routes/run-memory-capture.js +6 -12
- package/dist/http/routes/run-permission-mode.d.ts +2 -2
- package/dist/http/routes/run-permission-mode.js +10 -17
- package/dist/http/routes/runs.js +146 -231
- package/dist/http/routes/session-memory-sync.d.ts +2 -2
- package/dist/http/routes/session-memory-sync.js +7 -13
- package/dist/http/routes/session-sync.d.ts +4 -2
- package/dist/http/routes/session-sync.js +21 -20
- package/dist/http/routes/sessions-list.d.ts +3 -3
- package/dist/http/routes/sessions-list.js +9 -9
- package/dist/http/routes/sessions.js +87 -124
- package/dist/http/routes/shared-memory.js +6 -6
- package/dist/http/routes/side-query.js +2 -2
- package/dist/http/routes/tasks.js +136 -120
- package/dist/http/routes/trace-usage.d.ts +0 -12
- package/dist/http/routes/trace-usage.js +40 -46
- package/dist/http/routes/workflows.d.ts +39 -4
- package/dist/http/routes/workflows.js +42 -14
- package/dist/http/run-concurrency-cap.d.ts +20 -12
- package/dist/http/run-concurrency-cap.js +39 -26
- package/dist/http/run-read-face.d.ts +3 -5
- package/dist/http/run-read-face.js +8 -13
- package/dist/http/send.d.ts +12 -3
- package/dist/http/send.js +42 -6
- package/dist/http/server.d.ts +39 -40
- package/dist/http/server.js +36 -11
- package/dist/http/sse-log.d.ts +17 -10
- package/dist/http/sse-log.js +7 -7
- package/dist/http/stored-body-replay.d.ts +12 -0
- package/dist/http/stored-body-replay.js +2 -2
- package/dist/http/submit-ctx.d.ts +16 -8
- package/dist/http/submit-ctx.js +6 -2
- package/dist/http/submit-replay.d.ts +19 -6
- package/dist/http/submit-replay.js +18 -6
- package/dist/http/sync-submit-body.d.ts +3 -4
- package/dist/http/sync-submit-body.js +4 -5
- package/dist/http/wire-types.d.ts +4 -3
- package/dist/identity-source.d.ts +36 -5
- package/dist/identity-source.js +27 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/key-resolver.d.ts +32 -0
- package/dist/key-resolver.js +23 -9
- package/dist/leader/diffup.js +2 -1
- package/dist/leader/endpoint.d.ts +26 -5
- package/dist/leader/endpoint.js +154 -14
- package/dist/leader/fanout.d.ts +3 -0
- package/dist/leader/fanout.js +78 -63
- package/dist/leader/leader.d.ts +16 -0
- package/dist/leader/leader.js +43 -3
- package/dist/leader/merge.d.ts +9 -1
- package/dist/leader/merge.js +16 -1
- package/dist/leader/repair-wire.js +1 -1
- package/dist/leader/wire.d.ts +36 -3
- package/dist/leader/wire.js +59 -18
- package/dist/lsp-evict.d.ts +6 -4
- package/dist/lsp-evict.js +2 -3
- package/dist/memory-operator-faces.d.ts +5 -4
- package/dist/memory-operator-faces.js +1 -1
- package/dist/memory-scope.d.ts +29 -2
- package/dist/memory-scope.js +64 -15
- package/dist/memory-store-refusal.d.ts +5 -2
- package/dist/memory-sync-client.d.ts +3 -2
- package/dist/memory-sync-client.js +6 -3
- package/dist/model-compat.d.ts +17 -8
- package/dist/model-compat.js +6 -2
- package/dist/model-context-window.d.ts +18 -0
- package/dist/model-context-window.js +2 -0
- package/dist/model-entry-headers.d.ts +46 -4
- package/dist/model-entry-headers.js +2 -2
- package/dist/model-entry-refusal.d.ts +35 -16
- package/dist/model-entry-refusal.js +40 -27
- package/dist/model-plane-face.d.ts +19 -11
- package/dist/model-plane-face.js +9 -1
- package/dist/model-plane-probe.d.ts +2 -0
- package/dist/model-plane-probe.js +17 -0
- package/dist/model-provider.d.ts +3 -3
- package/dist/model-route-endpoint.d.ts +9 -5
- package/dist/model-route-endpoint.js +29 -7
- package/dist/model-select.d.ts +16 -0
- package/dist/model-select.js +4 -0
- package/dist/mountinfo.d.ts +37 -0
- package/dist/mountinfo.js +47 -0
- package/dist/namespaced-rule-name.d.ts +23 -14
- package/dist/namespaced-rule-name.js +8 -11
- package/dist/net-address.d.ts +1 -1
- package/dist/observability/corrupt-read-seat.d.ts +4 -4
- package/dist/observability/corrupt-read-seat.js +5 -3
- package/dist/observability/fail-open.d.ts +58 -38
- package/dist/observability/fail-open.js +60 -38
- package/dist/observability/logger.d.ts +22 -1
- package/dist/observability/logger.js +89 -12
- package/dist/observability/metrics.js +3 -4
- package/dist/observability/otel-exporter.js +2 -1
- package/dist/observability/principal-context.d.ts +14 -7
- package/dist/observability/principal-context.js +8 -3
- package/dist/observability/run-terminal.d.ts +7 -1
- package/dist/observability/run-terminal.js +5 -2
- package/dist/orchestration/hardened-vm-runner.d.ts +1 -0
- package/dist/orchestration/hardened-vm-runner.js +11 -5
- package/dist/orchestration/hardened-vm-worker-runner.d.ts +0 -14
- package/dist/orchestration/hardened-vm-worker-runner.js +5 -0
- package/dist/orchestration/hardened-vm-worker.js +2 -1
- package/dist/orchestration/workflow-completion-inbox.d.ts +3 -3
- package/dist/orchestration/workflow-completion-inbox.js +3 -2
- package/dist/org-delivery-gate.d.ts +5 -4
- package/dist/org-delivery-gate.js +7 -6
- package/dist/outbound-dispatcher.d.ts +1 -1
- package/dist/outbound-dispatcher.js +6 -12
- package/dist/owner-brands.d.ts +81 -0
- package/dist/owner-brands.js +42 -0
- package/dist/owner-faces.d.ts +531 -0
- package/dist/owner-faces.js +126 -0
- package/dist/parked-decide.d.ts +67 -5
- package/dist/parked-decide.js +127 -5
- package/dist/parked-revive-surface.d.ts +14 -4
- package/dist/parked-revive-surface.js +5 -4
- package/dist/peer-directory.d.ts +6 -8
- package/dist/peer-directory.js +3 -2
- package/dist/permission-rule-vocab.d.ts +53 -8
- package/dist/permission-rule-vocab.js +30 -2
- package/dist/plugins/adoption-log-sql.d.ts +0 -22
- package/dist/plugins/adoption-log-sql.js +5 -3
- package/dist/plugins/approval-ask-retired-delete-by-task-m50.d.ts +7 -0
- package/dist/plugins/approval-ask-retired-delete-by-task-m50.js +17 -0
- package/dist/plugins/approval-ask-store-file.d.ts +18 -7
- package/dist/plugins/approval-ask-store-file.js +37 -14
- package/dist/plugins/approval-ask-store-memory.d.ts +12 -4
- package/dist/plugins/approval-ask-store-memory.js +24 -10
- package/dist/plugins/approval-ask-store-sql.d.ts +39 -20
- package/dist/plugins/approval-ask-store-sql.js +41 -10
- package/dist/plugins/approval-exemption-skill-m46.d.ts +20 -0
- package/dist/plugins/approval-exemption-skill-m46.js +25 -0
- package/dist/plugins/approval-exemption-store.d.ts +6 -1
- package/dist/plugins/approval-exemption-store.js +14 -0
- package/dist/plugins/approval-nonce-store.d.ts +39 -12
- package/dist/plugins/approval-nonce-store.js +72 -23
- package/dist/plugins/blob-backend.d.ts +2 -0
- package/dist/plugins/blob-backend.js +9 -6
- package/dist/plugins/caching-session-store.d.ts +13 -1
- package/dist/plugins/caching-session-store.js +43 -4
- package/dist/plugins/checkpoint-index-columns.d.ts +32 -5
- package/dist/plugins/checkpoint-index-columns.js +36 -1
- package/dist/plugins/checkpoint-store-face.d.ts +83 -10
- package/dist/plugins/checkpoint-store-face.js +18 -1
- package/dist/plugins/device-store-sql.js +1 -0
- package/dist/plugins/ensure-index.d.ts +13 -1
- package/dist/plugins/ensure-index.js +154 -21
- package/dist/plugins/ensure-schema-lock-policy.d.ts +0 -15
- package/dist/plugins/ensure-schema-lock-policy.js +3 -2
- package/dist/plugins/file-run-store.d.ts +63 -23
- package/dist/plugins/file-run-store.js +138 -83
- package/dist/plugins/host-platform.d.ts +24 -3
- package/dist/plugins/host-platform.js +15 -1
- package/dist/plugins/image-bake-store-sql.js +2 -0
- package/dist/plugins/imported-layer-root-retirement.d.ts +2 -2
- package/dist/plugins/k8s-pod-reaper.d.ts +1 -3
- package/dist/plugins/k8s-pod-reaper.js +0 -1
- package/dist/plugins/leader-run-store-sql.d.ts +22 -0
- package/dist/plugins/leader-run-store-sql.js +34 -4
- package/dist/plugins/local-checkpoint-store.d.ts +58 -23
- package/dist/plugins/local-checkpoint-store.js +195 -76
- package/dist/plugins/local-data-dir-modes-m39.js +2 -1
- package/dist/plugins/local-docker-capacity.d.ts +93 -0
- package/dist/plugins/local-docker-capacity.js +194 -0
- package/dist/plugins/local-docker-reaper.d.ts +92 -0
- package/dist/plugins/local-docker-reaper.js +102 -0
- package/dist/plugins/local-engine-high-water.d.ts +4 -2
- package/dist/plugins/local-engine-high-water.js +4 -1
- package/dist/plugins/local-session-store.d.ts +358 -125
- package/dist/plugins/local-session-store.js +824 -251
- package/dist/plugins/local-session-window.d.ts +3 -2
- package/dist/plugins/local-session-window.js +3 -2
- package/dist/plugins/local-sidecar-quarantine.js +3 -2
- package/dist/plugins/local-task-attachment-store.d.ts +18 -1
- package/dist/plugins/local-task-attachment-store.js +22 -1
- package/dist/plugins/memory-embedder.js +9 -7
- package/dist/plugins/memory-engine-pg.d.ts +3 -2
- package/dist/plugins/memory-engine-pg.js +14 -5
- package/dist/plugins/memory-engine-sql-apply.d.ts +8 -4
- package/dist/plugins/memory-engine-sql-apply.js +6 -8
- package/dist/plugins/memory-engine-tidb.d.ts +4 -2
- package/dist/plugins/memory-engine-tidb.js +11 -2
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +1 -1
- package/dist/plugins/memory-optout-grant-store-sql.js +3 -3
- package/dist/plugins/memory-run-store.d.ts +39 -27
- package/dist/plugins/memory-run-store.js +72 -70
- package/dist/plugins/one-time-migration-marker.d.ts +10 -0
- package/dist/plugins/one-time-migration-marker.js +7 -0
- package/dist/plugins/one-time-migrations.d.ts +186 -45
- package/dist/plugins/one-time-migrations.js +442 -119
- package/dist/plugins/org-delivery-quota-store.js +2 -1
- package/dist/plugins/permission-rule-store-file.d.ts +3 -3
- package/dist/plugins/permission-rule-store-sql.d.ts +4 -63
- package/dist/plugins/permission-rule-store-sql.js +6 -86
- package/dist/plugins/pg-pool.d.ts +1 -31
- package/dist/plugins/pg-pool.js +16 -7
- package/dist/plugins/remote-env-e2b.d.ts +7 -25
- package/dist/plugins/remote-env-e2b.js +34 -25
- package/dist/plugins/remote-env-host.d.ts +2 -9
- package/dist/plugins/remote-env-host.js +34 -22
- package/dist/plugins/remote-env-k8s.d.ts +40 -45
- package/dist/plugins/remote-env-k8s.js +107 -58
- package/dist/plugins/remote-env-local-docker.d.ts +148 -14
- package/dist/plugins/remote-env-local-docker.js +367 -72
- package/dist/plugins/remote-scratchpad.js +4 -0
- package/dist/plugins/retention-deployment.d.ts +49 -17
- package/dist/plugins/retention-deployment.js +39 -8
- package/dist/plugins/run-preview-m45.d.ts +11 -0
- package/dist/plugins/run-preview-m45.js +19 -0
- package/dist/plugins/run-store-sql.d.ts +56 -68
- package/dist/plugins/run-store-sql.js +127 -116
- package/dist/plugins/s3-answer.d.ts +2 -1
- package/dist/plugins/sandbox-reaper.d.ts +26 -0
- package/dist/plugins/sandbox-reaper.js +2 -0
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +54 -0
- package/dist/plugins/scenario-prefix-switch-m42.js +55 -0
- package/dist/plugins/scheduler-support.d.ts +16 -1
- package/dist/plugins/scheduler-support.js +22 -2
- package/dist/plugins/schema-consistency.d.ts +42 -9
- package/dist/plugins/schema-consistency.js +212 -11
- package/dist/plugins/schema-drift-sentence.d.ts +4 -1
- package/dist/plugins/schema-drift-sentence.js +4 -4
- package/dist/plugins/schema-ensure-legs.d.ts +9 -0
- package/dist/plugins/schema-ensure-legs.js +1 -1
- package/dist/plugins/schema-indexes.js +3 -0
- package/dist/plugins/schema-live-columns.d.ts +14 -5
- package/dist/plugins/schema-live-columns.js +10 -10
- package/dist/plugins/send-user-file.js +2 -1
- package/dist/plugins/session-birth.d.ts +37 -0
- package/dist/plugins/session-birth.js +38 -0
- package/dist/plugins/session-epoch-anchor.d.ts +40 -12
- package/dist/plugins/session-epoch-anchor.js +33 -11
- package/dist/plugins/session-ext-table.d.ts +27 -3
- package/dist/plugins/session-ext-table.js +19 -6
- package/dist/plugins/session-fork.d.ts +15 -1
- package/dist/plugins/session-fork.js +3 -0
- package/dist/plugins/session-ownership.d.ts +1 -1
- package/dist/plugins/session-placement.d.ts +22 -16
- package/dist/plugins/session-placement.js +15 -12
- package/dist/plugins/session-row-sql.d.ts +12 -0
- package/dist/plugins/session-row-sql.js +3 -3
- package/dist/plugins/session-run-rollup.d.ts +29 -0
- package/dist/plugins/session-run-rollup.js +40 -0
- package/dist/plugins/session-store-sql.d.ts +38 -12
- package/dist/plugins/session-store-sql.js +130 -30
- package/dist/plugins/session-withdraw-sql.d.ts +36 -0
- package/dist/plugins/session-withdraw-sql.js +42 -0
- package/dist/plugins/shared-memory-store-sql.d.ts +0 -69
- package/dist/plugins/shared-memory-store-sql.js +2 -1
- package/dist/plugins/shell-sentinel-owner-m48.d.ts +20 -0
- package/dist/plugins/shell-sentinel-owner-m48.js +3 -0
- package/dist/plugins/snapshot-bucket-presence.d.ts +2 -1
- package/dist/plugins/sql-driver.d.ts +1 -1
- package/dist/plugins/sql-driver.js +2 -1
- package/dist/plugins/sql-errors.d.ts +32 -5
- package/dist/plugins/sql-errors.js +55 -7
- package/dist/plugins/sql-json-column.d.ts +8 -7
- package/dist/plugins/sql-json-column.js +10 -6
- package/dist/plugins/store-backend.d.ts +84 -15
- package/dist/plugins/store-backend.js +186 -55
- package/dist/plugins/store-contracts.d.ts +90 -30
- package/dist/plugins/store-contracts.js +22 -1
- package/dist/plugins/store-fault.d.ts +28 -2
- package/dist/plugins/store-fault.js +20 -2
- package/dist/plugins/task-attachment-store.d.ts +15 -3
- package/dist/plugins/task-attachment-store.js +22 -9
- package/dist/plugins/tidb-pool.js +23 -8
- package/dist/plugins/web-search.js +5 -3
- package/dist/plugins/workflow-run-store-sql.d.ts +6 -1
- package/dist/plugins/workflow-run-store-sql.js +11 -5
- package/dist/principal-jwt.d.ts +4 -4
- package/dist/principal-jwt.js +20 -5
- package/dist/principal-shape.d.ts +41 -0
- package/dist/principal-shape.js +19 -0
- package/dist/question.d.ts +13 -23
- package/dist/question.js +21 -39
- package/dist/request-declaration-refusal.d.ts +35 -12
- package/dist/request-declaration-refusal.js +21 -9
- package/dist/request-form.d.ts +58 -0
- package/dist/request-form.js +72 -0
- package/dist/request-image-urls.d.ts +8 -2
- package/dist/request-image-urls.js +2 -1
- package/dist/request-images.d.ts +20 -0
- package/dist/request-images.js +59 -0
- package/dist/request-key-closure.d.ts +6 -7
- package/dist/request-key-closure.js +15 -2
- package/dist/resource-suspend.d.ts +7 -16
- package/dist/resource-suspend.js +1 -1
- package/dist/retired-name-host-notice.d.ts +21 -0
- package/dist/retired-name-host-notice.js +12 -0
- package/dist/rule-entry-list.d.ts +2 -2
- package/dist/rule-entry-list.js +3 -4
- package/dist/rule-issue-reading.d.ts +58 -0
- package/dist/rule-issue-reading.js +14 -0
- package/dist/rules-consent.d.ts +5 -3
- package/dist/rules-consent.js +1 -0
- package/dist/run-acceptance.d.ts +3 -1
- package/dist/run-acceptance.js +3 -0
- package/dist/run-local.d.ts +14 -6
- package/dist/run-local.js +92 -80
- package/dist/run-stale-default.d.ts +7 -0
- package/dist/run-stale-default.js +2 -0
- package/dist/runs.d.ts +26 -15
- package/dist/runs.js +39 -27
- package/dist/runtime-caps-resolver.d.ts +21 -6
- package/dist/runtime-caps-resolver.js +17 -4
- package/dist/runtime-governance.d.ts +2 -2
- package/dist/runtime-governance.js +5 -3
- package/dist/sealed-key-layout.d.ts +12 -5
- package/dist/sealed-key-layout.js +5 -0
- package/dist/sealed-key.d.ts +12 -2
- package/dist/sealed-key.js +115 -27
- package/dist/security.d.ts +128 -158
- package/dist/security.js +163 -59
- package/dist/sema-config-dir.d.ts +20 -0
- package/dist/sema-config-dir.js +25 -0
- package/dist/server-secret-env.d.ts +21 -5
- package/dist/server-secret-env.js +14 -4
- package/dist/session-children-retire.d.ts +7 -5
- package/dist/session-children-retire.js +7 -2
- package/dist/session-deletion.d.ts +88 -0
- package/dist/session-deletion.js +8 -0
- package/dist/session-erase.d.ts +145 -0
- package/dist/session-erase.js +115 -0
- package/dist/session-error-wire.d.ts +5 -5
- package/dist/session-error-wire.js +1 -1
- package/dist/session-incarnation.d.ts +52 -5
- package/dist/session-incarnation.js +19 -2
- package/dist/session-policy-wire.d.ts +6 -3
- package/dist/session-policy-wire.js +11 -1
- package/dist/session-resident-background.d.ts +0 -71
- package/dist/session-resident-background.js +4 -3
- package/dist/session-row.d.ts +2 -1
- package/dist/session-rules-seat.d.ts +12 -0
- package/dist/session-rules-seat.js +19 -0
- package/dist/session-titler.d.ts +7 -15
- package/dist/session-titler.js +1 -1
- package/dist/spec-fields.d.ts +57 -3
- package/dist/spec-fields.js +72 -51
- package/dist/store-posture.d.ts +136 -20
- package/dist/store-posture.js +188 -3
- package/dist/stored-request-hooks-m20.js +2 -2
- package/dist/stores-sql/background-agent-store-sql.d.ts +11 -2
- package/dist/stores-sql/background-agent-store-sql.js +73 -20
- package/dist/stores-sql/checkpoint-store-sql.d.ts +33 -28
- package/dist/stores-sql/checkpoint-store-sql.js +75 -44
- package/dist/stores-sql/mailbox-store-sql.d.ts +7 -4
- package/dist/stores-sql/mailbox-store-sql.js +31 -32
- package/dist/stores-sql/pg-session-storage.d.ts +7 -5
- package/dist/stores-sql/pg-session-storage.js +54 -46
- package/dist/stores-sql/retention-store-sql.d.ts +87 -19
- package/dist/stores-sql/retention-store-sql.js +92 -27
- package/dist/stores-sql/session-policy-store-sql.d.ts +32 -10
- package/dist/stores-sql/session-policy-store-sql.js +44 -36
- package/dist/stores-sql/session-write-hooks.d.ts +12 -6
- package/dist/stores-sql/tidb-session-storage.d.ts +4 -4
- package/dist/stores-sql/tidb-session-storage.js +13 -8
- package/dist/stores-sql/tidb-session-store.d.ts +36 -17
- package/dist/stores-sql/tidb-session-store.js +69 -39
- package/dist/stores-sql/windowed-session-storage.d.ts +5 -0
- package/dist/stores-sql/windowed-session-storage.js +9 -0
- package/dist/submission-exit.d.ts +50 -0
- package/dist/submission-exit.js +108 -0
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-a2a.js +3 -3
- package/dist/task-cwd.d.ts +20 -0
- package/dist/task-cwd.js +8 -0
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-mcp.js +3 -3
- package/dist/task-settings.d.ts +14 -10
- package/dist/task-settings.js +18 -7
- package/dist/terminal.d.ts +25 -43
- package/dist/terminal.js +31 -11
- package/dist/tool-approval.d.ts +131 -129
- package/dist/tool-approval.js +189 -193
- package/dist/trace/core-keyset-guard.d.ts +13 -6
- package/dist/trace/core-vocab-wire.d.ts +95 -0
- package/dist/trace/core-vocab-wire.js +15 -0
- package/dist/trace/exit-seat.d.ts +30 -4
- package/dist/trace/exit-seat.js +40 -36
- package/dist/trace/extension-call-face.d.ts +3 -2
- package/dist/trace/extension-call-face.js +3 -1
- package/dist/trace/ledger-events.d.ts +4 -7
- package/dist/trace/ledger-sink.d.ts +1 -30
- package/dist/trace/ledger-sink.js +0 -11
- package/dist/trace/model-segment.d.ts +5 -5
- package/dist/trace/model-segment.js +5 -5
- package/dist/trace/project.d.ts +55 -42
- package/dist/trace/project.js +52 -19
- package/dist/trace/redact.d.ts +123 -27
- package/dist/trace/redact.js +880 -260
- package/dist/trace/self-minted-wire.d.ts +487 -19
- package/dist/trace/self-minted-wire.js +172 -23
- package/dist/trace/wire-projection-faces.d.ts +5 -6
- package/dist/trace/wire-projection-faces.js +2 -2
- package/dist/upstream-body.d.ts +23 -0
- package/dist/upstream-body.js +16 -0
- package/dist/url-refusal.d.ts +3 -3
- package/dist/url-refusal.js +11 -4
- package/dist/user-authored-text.d.ts +1 -1
- package/dist/user-input-ledger.d.ts +7 -8
- package/dist/user-input-ledger.js +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +6 -3
- package/dist/web-admin-client/apply-effective.js +13 -16
- package/dist/web-admin-client/apply-ledger.d.ts +16 -7
- package/dist/web-admin-client/apply-ledger.js +5 -2
- package/dist/web-admin-client/center-request.d.ts +2 -2
- package/dist/web-admin-client/center-request.js +15 -15
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.js +1 -1
- package/dist/web-admin-client/entry-metadata.d.ts +8 -0
- package/dist/web-admin-client/entry-metadata.js +13 -0
- package/dist/web-admin-client/http-client.d.ts +1 -1
- package/dist/web-admin-client/http-client.js +23 -4
- package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
- package/dist/web-admin-client/mcp-revocation.js +2 -1
- package/dist/web-admin-client/read-warnings.d.ts +1 -0
- package/dist/web-admin-client/read-warnings.js +1 -0
- package/dist/web-admin-client/restart-signal.js +8 -4
- package/dist/web-admin-client/skills-mcp.d.ts +2 -2
- package/dist/web-admin-client/types.d.ts +1 -2
- package/dist/workspace-space.d.ts +3 -2
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +4 -4
- package/package.json +6 -3
- package/scripts/drain-check-local.mjs +118 -147
- package/scripts/drain-check.mysql.sql +22 -2
- package/scripts/drain-check.pg.sql +22 -2
- package/wire-changes/server@7.148.0.json +1517 -0
- package/dist/http/memory-control-plane-corrupt-reply.d.ts +0 -25
- package/dist/http/memory-control-plane-corrupt-reply.js +0 -19
- package/dist/http/memory-layer-reply.d.ts +0 -30
- package/dist/http/memory-layer-reply.js +0 -24
- package/dist/lsp/e2b-bridge.d.ts +0 -57
- package/dist/lsp/e2b-bridge.js +0 -139
- package/dist/lsp/e2b-manager.d.ts +0 -93
- package/dist/lsp/e2b-manager.js +0 -178
- package/dist/lsp/lsp-frames.d.ts +0 -14
- package/dist/lsp/lsp-frames.js +0 -25
- package/dist/lsp/manager.d.ts +0 -129
- package/dist/lsp/manager.js +0 -127
- package/dist/lsp/types.d.ts +0 -12
- package/dist/lsp/types.js +0 -2
- package/dist/lsp/ws-transport.d.ts +0 -40
- package/dist/lsp/ws-transport.js +0 -210
package/dist/trace/redact.js
CHANGED
|
@@ -29,6 +29,7 @@ export function mapNormalizedToOriginal(text, normalized) {
|
|
|
29
29
|
return map;
|
|
30
30
|
}
|
|
31
31
|
const SPELLED_FORMAT = 1, SPELLED_CONTROL = 2, RAW_CONTROL = 4, RAW_WHITESPACE = 8;
|
|
32
|
+
const RAW_IGNORABLE = 16, SPELLED_IGNORABLE = 32;
|
|
32
33
|
const INVISIBLE_UNIT_CLASS = (() => {
|
|
33
34
|
const inSet = new RegExp(`[${CONTROL_AND_BIDI_CHARS}]`);
|
|
34
35
|
const table = new Uint8Array(0x10000);
|
|
@@ -39,32 +40,72 @@ const INVISIBLE_UNIT_CLASS = (() => {
|
|
|
39
40
|
}
|
|
40
41
|
return table;
|
|
41
42
|
})();
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
const READING_IGNORABLE_CLASS = String.raw `\p{Default_Ignorable_Code_Point}\p{Mn}\p{Cc}`;
|
|
44
|
+
const READING_IGNORABLE_RE = new RegExp(`^[${READING_IGNORABLE_CLASS}]$`, "u");
|
|
45
|
+
function isReadingIgnorable(cp) {
|
|
46
|
+
if (cp < 0 || cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff))
|
|
47
|
+
return false;
|
|
48
|
+
return READING_IGNORABLE_RE.test(String.fromCodePoint(cp));
|
|
49
|
+
}
|
|
50
|
+
export function isReadingIgnorableForTest(cp) {
|
|
51
|
+
return isReadingIgnorable(cp);
|
|
52
|
+
}
|
|
53
|
+
const RAW_UNIT_CLASS = (() => {
|
|
54
|
+
const table = new Uint8Array(0x10000);
|
|
55
|
+
for (let unit = 0; unit < table.length; unit++) {
|
|
56
|
+
const cls = INVISIBLE_UNIT_CLASS[unit];
|
|
57
|
+
if (cls !== 0)
|
|
58
|
+
table[unit] = cls === 2 ? RAW_WHITESPACE : RAW_CONTROL;
|
|
59
|
+
}
|
|
60
|
+
const units = [];
|
|
61
|
+
for (let c = 0; c < 0x10000; c++)
|
|
62
|
+
if (c < 0xd800 || c > 0xdfff)
|
|
63
|
+
units.push(String.fromCharCode(c));
|
|
64
|
+
for (const m of units.join("").matchAll(new RegExp(`[${READING_IGNORABLE_CLASS}]`, "gu"))) {
|
|
65
|
+
const unit = m[0].charCodeAt(0);
|
|
66
|
+
if (table[unit] === 0)
|
|
67
|
+
table[unit] = RAW_IGNORABLE;
|
|
68
|
+
}
|
|
69
|
+
return table;
|
|
55
70
|
})();
|
|
71
|
+
const ASTRAL_IGNORABLE_MEMO = new Map();
|
|
72
|
+
function astralIgnorableAt(cp) {
|
|
73
|
+
let hit = ASTRAL_IGNORABLE_MEMO.get(cp);
|
|
74
|
+
if (hit === undefined) {
|
|
75
|
+
hit = isReadingIgnorable(cp);
|
|
76
|
+
if (ASTRAL_IGNORABLE_MEMO.size < 4096)
|
|
77
|
+
ASTRAL_IGNORABLE_MEMO.set(cp, hit);
|
|
78
|
+
}
|
|
79
|
+
return hit;
|
|
80
|
+
}
|
|
56
81
|
function collectRawControlCuts(s, allowed) {
|
|
57
82
|
const cuts = [];
|
|
58
83
|
let present = 0;
|
|
59
|
-
if ((allowed & (RAW_CONTROL | RAW_WHITESPACE)) === 0)
|
|
84
|
+
if ((allowed & (RAW_CONTROL | RAW_WHITESPACE | RAW_IGNORABLE)) === 0)
|
|
60
85
|
return { cuts, present };
|
|
61
|
-
|
|
62
|
-
for (let
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
const n = s.length;
|
|
87
|
+
for (let i = 0; i < n; i++) {
|
|
88
|
+
const unit = s.charCodeAt(i);
|
|
89
|
+
let cls = RAW_UNIT_CLASS[unit];
|
|
90
|
+
let len = 1;
|
|
91
|
+
if (cls === 0) {
|
|
92
|
+
if ((unit & 0xfc00) !== 0xd800 || i + 1 >= n)
|
|
93
|
+
continue;
|
|
94
|
+
const low = s.charCodeAt(i + 1);
|
|
95
|
+
if ((low & 0xfc00) !== 0xdc00)
|
|
96
|
+
continue;
|
|
97
|
+
if (!astralIgnorableAt(((unit - 0xd800) << 10) + (low - 0xdc00) + 0x10000)) {
|
|
98
|
+
i += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
cls = RAW_IGNORABLE;
|
|
102
|
+
len = 2;
|
|
103
|
+
}
|
|
104
|
+
if ((cls & allowed) !== 0) {
|
|
105
|
+
cuts.push(i, i + len, cls);
|
|
106
|
+
present |= cls;
|
|
107
|
+
}
|
|
108
|
+
i += len - 1;
|
|
68
109
|
}
|
|
69
110
|
return { cuts, present };
|
|
70
111
|
}
|
|
@@ -83,7 +124,8 @@ function collectSpelledCuts(s) {
|
|
|
83
124
|
const cp = readSpelledCodePoint(s, body, read);
|
|
84
125
|
if (cp === ESCAPE_TRUNCATED)
|
|
85
126
|
return { cuts, present, open: i };
|
|
86
|
-
const
|
|
127
|
+
const unitClass = cp >= 0 && cp < 0x10000 ? INVISIBLE_UNIT_CLASS[cp] : 0;
|
|
128
|
+
const cls = cp < 0 ? 0 : isFormatCodePoint(cp) ? SPELLED_FORMAT : unitClass === 1 ? SPELLED_CONTROL : unitClass === 2 ? 0 : isReadingIgnorable(cp) ? SPELLED_IGNORABLE : 0;
|
|
87
129
|
if (cls !== 0) {
|
|
88
130
|
cuts.push(i, read.end, cls);
|
|
89
131
|
present |= cls;
|
|
@@ -465,6 +507,88 @@ let anyValueArm;
|
|
|
465
507
|
function anyValueArmRe() {
|
|
466
508
|
return (anyValueArm ??= new RegExp(`(?:${VALUE_ARM_BODIES.join("|")})`, "y"));
|
|
467
509
|
}
|
|
510
|
+
const SCAN_UNATTEMPTED = -1;
|
|
511
|
+
class ScanReader {
|
|
512
|
+
#t;
|
|
513
|
+
#n;
|
|
514
|
+
#reg = SCAN_UNATTEMPTED;
|
|
515
|
+
#hit = false;
|
|
516
|
+
#open;
|
|
517
|
+
#unattributed = false;
|
|
518
|
+
constructor(t) {
|
|
519
|
+
this.#t = t;
|
|
520
|
+
this.#n = t.length;
|
|
521
|
+
this.#open = t.length;
|
|
522
|
+
}
|
|
523
|
+
#mark() {
|
|
524
|
+
this.#hit = true;
|
|
525
|
+
if (this.#reg === SCAN_UNATTEMPTED) {
|
|
526
|
+
this.#unattributed = true;
|
|
527
|
+
this.#open = 0;
|
|
528
|
+
}
|
|
529
|
+
else if (this.#reg < this.#open)
|
|
530
|
+
this.#open = this.#reg;
|
|
531
|
+
}
|
|
532
|
+
charCodeAt(i) {
|
|
533
|
+
if (i < this.#n)
|
|
534
|
+
return this.#t.charCodeAt(i);
|
|
535
|
+
this.#mark();
|
|
536
|
+
return NaN;
|
|
537
|
+
}
|
|
538
|
+
atEnd(i) {
|
|
539
|
+
if (i < this.#n)
|
|
540
|
+
return false;
|
|
541
|
+
this.#mark();
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
readEnd() {
|
|
545
|
+
this.#mark();
|
|
546
|
+
return this.#n;
|
|
547
|
+
}
|
|
548
|
+
startsWith(lit, at) {
|
|
549
|
+
if (at + lit.length <= this.#n)
|
|
550
|
+
return this.#t.startsWith(lit, at);
|
|
551
|
+
for (let k = 0; at + k < this.#n; k++)
|
|
552
|
+
if (this.#t.charCodeAt(at + k) !== lit.charCodeAt(k))
|
|
553
|
+
return false;
|
|
554
|
+
this.#mark();
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
slice(a, b) {
|
|
558
|
+
if (b > this.#n)
|
|
559
|
+
this.#mark();
|
|
560
|
+
return this.#t.slice(a, b);
|
|
561
|
+
}
|
|
562
|
+
indexOf(lit, from = 0) {
|
|
563
|
+
return this.#t.indexOf(lit, from);
|
|
564
|
+
}
|
|
565
|
+
search(re, from) {
|
|
566
|
+
re.lastIndex = from;
|
|
567
|
+
return re.exec(this.#t);
|
|
568
|
+
}
|
|
569
|
+
lastIndexOf(lit) {
|
|
570
|
+
return this.#t.lastIndexOf(lit);
|
|
571
|
+
}
|
|
572
|
+
attempt(from) {
|
|
573
|
+
this.#reg = from;
|
|
574
|
+
this.#hit = false;
|
|
575
|
+
}
|
|
576
|
+
reachedEnd() {
|
|
577
|
+
return this.#hit;
|
|
578
|
+
}
|
|
579
|
+
begin() {
|
|
580
|
+
this.#reg = SCAN_UNATTEMPTED;
|
|
581
|
+
this.#hit = false;
|
|
582
|
+
}
|
|
583
|
+
get open() {
|
|
584
|
+
return this.#open;
|
|
585
|
+
}
|
|
586
|
+
get unattributed() {
|
|
587
|
+
return this.#unattributed;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const VIEW_END = 0x3fffffff;
|
|
591
|
+
const segmentEnds = (s, i, limit) => i >= limit || s.atEnd(i);
|
|
468
592
|
const ARM_RANK = { structural: 0, keyword: 1, shape: 2, fragment: 3 };
|
|
469
593
|
let poolSpanCount = 0;
|
|
470
594
|
let poolArmCount = 0;
|
|
@@ -737,6 +861,112 @@ function deriveLiteralHead(re) {
|
|
|
737
861
|
first: unionMembers(per.map((p) => p.first)),
|
|
738
862
|
};
|
|
739
863
|
}
|
|
864
|
+
function expandHeadUnits(src, flags) {
|
|
865
|
+
if (/[iuv]/.test(flags))
|
|
866
|
+
throw new Error(`redact: head-unit expansion does not support the i/u/v flags (/${src}/${flags})`);
|
|
867
|
+
const fail = (at, why) => {
|
|
868
|
+
throw new Error(`redact: head-unit expansion cannot read ${why} at ${at} in /${src}/`);
|
|
869
|
+
};
|
|
870
|
+
const LIMIT = 4096;
|
|
871
|
+
const seqOf = (from) => {
|
|
872
|
+
let seqs = [[]];
|
|
873
|
+
let i = from;
|
|
874
|
+
while (i < src.length && src[i] !== "|" && src[i] !== ")") {
|
|
875
|
+
let atom;
|
|
876
|
+
const c = src[i];
|
|
877
|
+
if (c === "(") {
|
|
878
|
+
if (!src.startsWith("(?:", i))
|
|
879
|
+
return fail(i, "a group other than a non-capturing one");
|
|
880
|
+
const inner = altsOf(i + 3);
|
|
881
|
+
if (src[inner.next] !== ")")
|
|
882
|
+
return fail(i, "an unbalanced group");
|
|
883
|
+
atom = inner.seqs;
|
|
884
|
+
i = inner.next + 1;
|
|
885
|
+
}
|
|
886
|
+
else if (c === "[") {
|
|
887
|
+
let k = i + 1;
|
|
888
|
+
while (k < src.length && src[k] !== "]")
|
|
889
|
+
k += src[k] === "\\" ? 2 : 1;
|
|
890
|
+
if (k >= src.length)
|
|
891
|
+
return fail(i, "an unterminated character class");
|
|
892
|
+
atom = [[codeUnitMembers(src.slice(i, k + 1))]];
|
|
893
|
+
i = k + 1;
|
|
894
|
+
}
|
|
895
|
+
else if (c === "\\") {
|
|
896
|
+
const e = src[i + 1];
|
|
897
|
+
if (e === undefined || !(HEAD_CLASS_ESCAPES.has(e) || HEAD_LITERAL_ESCAPES.has(e)))
|
|
898
|
+
return fail(i, "an escape that is not one code unit");
|
|
899
|
+
atom = [[codeUnitMembers(src.slice(i, i + 2))]];
|
|
900
|
+
i += 2;
|
|
901
|
+
}
|
|
902
|
+
else if (c === "." || c === "^" || c === "$" || c === "*" || c === "+" || c === "?" || c === "{") {
|
|
903
|
+
return fail(i, JSON.stringify(c));
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
atom = [[codeUnitMembers(c)]];
|
|
907
|
+
i += 1;
|
|
908
|
+
}
|
|
909
|
+
let lo = 1;
|
|
910
|
+
let hi = 1;
|
|
911
|
+
if (src[i] === "?") {
|
|
912
|
+
lo = 0;
|
|
913
|
+
i += 1;
|
|
914
|
+
}
|
|
915
|
+
else if (src[i] === "{") {
|
|
916
|
+
const m = /^\{(\d+)(?:,(\d+))?\}/.exec(src.slice(i));
|
|
917
|
+
if (m === null)
|
|
918
|
+
return fail(i, "an unbounded quantifier");
|
|
919
|
+
lo = Number(m[1]);
|
|
920
|
+
hi = m[2] === undefined ? lo : Number(m[2]);
|
|
921
|
+
i += m[0].length;
|
|
922
|
+
}
|
|
923
|
+
else if (src[i] === "*" || src[i] === "+")
|
|
924
|
+
return fail(i, "an unbounded quantifier");
|
|
925
|
+
let reps = [];
|
|
926
|
+
let power = [[]];
|
|
927
|
+
for (let k = 0; k <= hi; k++) {
|
|
928
|
+
if (k >= lo)
|
|
929
|
+
reps = reps.concat(power);
|
|
930
|
+
if (k < hi)
|
|
931
|
+
power = power.flatMap((p) => atom.map((a) => [...p, ...a]));
|
|
932
|
+
}
|
|
933
|
+
seqs = seqs.flatMap((s) => reps.map((r) => [...s, ...r]));
|
|
934
|
+
if (seqs.length > LIMIT)
|
|
935
|
+
return fail(i, "a head with too many spellings");
|
|
936
|
+
}
|
|
937
|
+
return { seqs, next: i };
|
|
938
|
+
};
|
|
939
|
+
const altsOf = (from) => {
|
|
940
|
+
const seqs = [];
|
|
941
|
+
let i = from;
|
|
942
|
+
for (;;) {
|
|
943
|
+
const one = seqOf(i);
|
|
944
|
+
seqs.push(...one.seqs);
|
|
945
|
+
i = one.next;
|
|
946
|
+
if (src[i] !== "|")
|
|
947
|
+
break;
|
|
948
|
+
i += 1;
|
|
949
|
+
}
|
|
950
|
+
return { seqs, next: i };
|
|
951
|
+
};
|
|
952
|
+
const all = altsOf(0);
|
|
953
|
+
if (all.next !== src.length)
|
|
954
|
+
return fail(all.next, "trailing syntax");
|
|
955
|
+
if (all.seqs.some((s) => s.length === 0))
|
|
956
|
+
return fail(0, "an empty head spelling (every position would be feasible)");
|
|
957
|
+
return all.seqs;
|
|
958
|
+
}
|
|
959
|
+
function headFeasibleAt(seqs, text, p) {
|
|
960
|
+
const room = text.length - p;
|
|
961
|
+
outer: for (const seq of seqs) {
|
|
962
|
+
const m = Math.min(seq.length, room);
|
|
963
|
+
for (let k = 0; k < m; k++)
|
|
964
|
+
if (unitBit(seq[k], text.charCodeAt(p + k)) === 0)
|
|
965
|
+
continue outer;
|
|
966
|
+
return true;
|
|
967
|
+
}
|
|
968
|
+
return false;
|
|
969
|
+
}
|
|
740
970
|
const repeatLen = (k, len) => (k === 0 ? 0 : k * len);
|
|
741
971
|
function readReachAlternatives(src, from) {
|
|
742
972
|
const alts = [];
|
|
@@ -921,17 +1151,56 @@ function resolveSpanOverlaps(spans) {
|
|
|
921
1151
|
}
|
|
922
1152
|
return kept;
|
|
923
1153
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
let
|
|
1154
|
+
const NO_JOINTS = Object.freeze([]);
|
|
1155
|
+
const sortedJoints = (joints) => [...new Set(joints)].sort((a, b) => a - b);
|
|
1156
|
+
function firstJointAfter(at, start) {
|
|
1157
|
+
let lo = 0;
|
|
1158
|
+
let hi = at.length;
|
|
1159
|
+
while (lo < hi) {
|
|
1160
|
+
const mid = (lo + hi) >>> 1;
|
|
1161
|
+
if (at[mid] <= start)
|
|
1162
|
+
lo = mid + 1;
|
|
1163
|
+
else
|
|
1164
|
+
hi = mid;
|
|
1165
|
+
}
|
|
1166
|
+
return lo;
|
|
1167
|
+
}
|
|
1168
|
+
function jointsCrossedBy(spans, joints) {
|
|
1169
|
+
if (joints.length === 0)
|
|
1170
|
+
return [];
|
|
1171
|
+
const at = sortedJoints(joints);
|
|
1172
|
+
const crossed = new Set();
|
|
1173
|
+
for (const s of spans)
|
|
1174
|
+
for (let i = firstJointAfter(at, s.start); i < at.length && at[i] < s.end; i++)
|
|
1175
|
+
crossed.add(at[i]);
|
|
1176
|
+
return [...crossed].sort((a, b) => a - b);
|
|
1177
|
+
}
|
|
1178
|
+
function cutAtJoints(spans, joints) {
|
|
1179
|
+
const at = sortedJoints(joints);
|
|
1180
|
+
const out = [];
|
|
929
1181
|
for (const s of spans) {
|
|
930
|
-
|
|
931
|
-
|
|
1182
|
+
let start = s.start;
|
|
1183
|
+
for (let i = firstJointAfter(at, s.start); i < at.length && at[i] < s.end; i++) {
|
|
1184
|
+
out.push({ ...s, start, end: at[i] });
|
|
1185
|
+
start = at[i];
|
|
1186
|
+
}
|
|
1187
|
+
out.push(start === s.start ? s : { ...s, start });
|
|
932
1188
|
}
|
|
933
|
-
|
|
934
|
-
|
|
1189
|
+
return out;
|
|
1190
|
+
}
|
|
1191
|
+
const poolTie = (a, b) => a.rank - b.rank || a.order - b.order;
|
|
1192
|
+
export function mergeRedactionSpans(spans, tie = () => 0, joints = NO_JOINTS) {
|
|
1193
|
+
const order = (joints.length === 0 ? [...spans] : cutAtJoints(spans, joints)).sort((a, b) => a.start - b.start || b.end - a.end || tie(a, b));
|
|
1194
|
+
const committed = joints.length === 0 ? undefined : new Set(joints);
|
|
1195
|
+
const out = [];
|
|
1196
|
+
for (const s of order) {
|
|
1197
|
+
const last = out[out.length - 1];
|
|
1198
|
+
if (last === undefined || s.start > last.end || (s.start === last.end && committed?.has(s.start) === true))
|
|
1199
|
+
out.push(s);
|
|
1200
|
+
else if (s.end > last.end)
|
|
1201
|
+
out[out.length - 1] = { ...last, end: s.end };
|
|
1202
|
+
}
|
|
1203
|
+
return out;
|
|
935
1204
|
}
|
|
936
1205
|
function collectValueArmSpans(arm, text, out) {
|
|
937
1206
|
const { g, y, back, repl, rank, order } = arm;
|
|
@@ -1163,7 +1432,7 @@ const SHAPE_SECRET_PATTERNS = [
|
|
|
1163
1432
|
[new RegExp(String.raw `xox[baprs]-${atLeast("[A-Za-z0-9-]", 10)}`, "g"), "«redacted:slack-token»"],
|
|
1164
1433
|
[new RegExp(String.raw `AKIA${atLeast("[0-9A-Z]", 16)}`, "g"), "«redacted:aws-key»"],
|
|
1165
1434
|
[new RegExp(String.raw `ASIA${atLeast("[0-9A-Z]", 16)}`, "g"), "«redacted:aws-key»"],
|
|
1166
|
-
[new RegExp(String.raw `(?:gl(?:pat|dt|rt|rtr|cbt|ptt|oas|ft|imt|agent|wt|soat|ffct)-${atLeast("[A-Za-z0-9_-]", 20)}|(?:sk|rk)_(?:live|test|org)_${atLeast("[A-Za-z0-9]", 24)}|pypi-${atLeast("[A-Za-z0-9_-]", 85)})`, "g"), "«redacted:key»"],
|
|
1435
|
+
[new RegExp(String.raw `(?:gl(?:pat|dt|rt|rtr|cbt|ptt|oas|ft|imt|agent|wt|soat|ffct)-${atLeast("[A-Za-z0-9_-]", 20)}|(?:sk|rk)_(?:live|test|org)_${atLeast("[A-Za-z0-9]", 24)}|pypi-${atLeast("[A-Za-z0-9_-]", 85)}|(?<![A-Za-z0-9])(?:npm_${atLeast("[A-Za-z0-9]", 36)}|hf_${atLeast("[A-Za-z0-9]", 34)}|ya29\.${atLeast("[A-Za-z0-9._-]", 30)}))`, "g"), "«redacted:key»"],
|
|
1167
1436
|
[new RegExp(String.raw `xapp-\d-${atLeast("[A-Za-z0-9-]", 20)}`, "g"), "«redacted:slack-token»"],
|
|
1168
1437
|
[valueArm("sk-", "[A-Za-z0-9_-]", SK_FULL_ARM_MIN, "self-evident"), "«redacted:key»"],
|
|
1169
1438
|
];
|
|
@@ -1176,16 +1445,16 @@ const isIdentStartCode = (c) => (c >= CH_A && c <= CH_Z) || (c >= CH_a && c <= C
|
|
|
1176
1445
|
const isIdentCode = (c) => isIdentStartCode(c) || (c >= CH_0 && c <= CH_9) || c === CH_UNDERSCORE || c === CH_MINUS;
|
|
1177
1446
|
function pemEscapeLetterAt(s, i, limit) {
|
|
1178
1447
|
let j = i;
|
|
1179
|
-
while (j
|
|
1448
|
+
while (!segmentEnds(s, j, limit) && s.charCodeAt(j) === CH_BACKSLASH)
|
|
1180
1449
|
j += 1;
|
|
1181
|
-
if (j === i || j
|
|
1450
|
+
if (j === i || segmentEnds(s, j, limit))
|
|
1182
1451
|
return -1;
|
|
1183
1452
|
const n = s.charCodeAt(j);
|
|
1184
1453
|
return n === CH_r || n === CH_n || n === CH_t ? j : -1;
|
|
1185
1454
|
}
|
|
1186
1455
|
function skipPemSeps(scan, s, i, limit) {
|
|
1187
1456
|
for (;;) {
|
|
1188
|
-
if (i
|
|
1457
|
+
if (segmentEnds(s, i, limit))
|
|
1189
1458
|
return i;
|
|
1190
1459
|
if (tokenEnd(scan, i) >= 0)
|
|
1191
1460
|
return i;
|
|
@@ -1205,7 +1474,7 @@ function skipPemSeps(scan, s, i, limit) {
|
|
|
1205
1474
|
}
|
|
1206
1475
|
}
|
|
1207
1476
|
function pemLineBreakLen(s, i, limit) {
|
|
1208
|
-
if (i
|
|
1477
|
+
if (segmentEnds(s, i, limit))
|
|
1209
1478
|
return 0;
|
|
1210
1479
|
const c = s.charCodeAt(i);
|
|
1211
1480
|
if (c === CH_CR || c === CH_LF)
|
|
@@ -1218,7 +1487,7 @@ function pemLineBreakLen(s, i, limit) {
|
|
|
1218
1487
|
return 0;
|
|
1219
1488
|
}
|
|
1220
1489
|
function pemInlineSepLen(s, i, limit) {
|
|
1221
|
-
if (i
|
|
1490
|
+
if (segmentEnds(s, i, limit))
|
|
1222
1491
|
return 0;
|
|
1223
1492
|
const c = s.charCodeAt(i);
|
|
1224
1493
|
if (c === CH_SPACE || c === CH_TAB)
|
|
@@ -1231,16 +1500,20 @@ function pemInlineSepLen(s, i, limit) {
|
|
|
1231
1500
|
return 0;
|
|
1232
1501
|
}
|
|
1233
1502
|
function probePemHeaderToken(scan, s, p, limit) {
|
|
1234
|
-
if (
|
|
1503
|
+
if (segmentEnds(s, p, limit))
|
|
1504
|
+
return -1;
|
|
1505
|
+
if (tokenEnd(scan, p) >= 0 || !isIdentStartCode(s.charCodeAt(p)))
|
|
1235
1506
|
return -1;
|
|
1236
1507
|
p += 1;
|
|
1237
1508
|
let identLen = 1;
|
|
1238
|
-
while (identLen < PEM_HEADER_IDENT_MAX && p
|
|
1509
|
+
while (identLen < PEM_HEADER_IDENT_MAX && !segmentEnds(s, p, limit) && tokenEnd(scan, p) < 0 && isIdentCode(s.charCodeAt(p))) {
|
|
1239
1510
|
p += 1;
|
|
1240
1511
|
identLen += 1;
|
|
1241
1512
|
}
|
|
1242
1513
|
for (;;) {
|
|
1243
|
-
if (
|
|
1514
|
+
if (segmentEnds(s, p, limit))
|
|
1515
|
+
return -1;
|
|
1516
|
+
if (tokenEnd(scan, p) >= 0)
|
|
1244
1517
|
return -1;
|
|
1245
1518
|
const c = s.charCodeAt(p);
|
|
1246
1519
|
if (c === CH_SPACE || c === CH_TAB) {
|
|
@@ -1261,7 +1534,7 @@ function setPemHdr(scan, search, contentEnd, next, hitLimit, jsonEnd = false) {
|
|
|
1261
1534
|
}
|
|
1262
1535
|
function parsePemHeaderLine(scan, s, i, limit, allowBare, json) {
|
|
1263
1536
|
const start = skipPemSeps(scan, s, i, limit);
|
|
1264
|
-
if (start
|
|
1537
|
+
if (segmentEnds(s, start, limit))
|
|
1265
1538
|
return false;
|
|
1266
1539
|
const afterToken = probePemHeaderToken(scan, s, start, limit);
|
|
1267
1540
|
if (afterToken < 0 && !allowBare)
|
|
@@ -1270,7 +1543,7 @@ function parsePemHeaderLine(scan, s, i, limit, allowBare, json) {
|
|
|
1270
1543
|
if (afterToken >= 0 && probePemHeaderToken(scan, s, p, limit) >= 0)
|
|
1271
1544
|
return setPemHdr(scan, start, p, p, false);
|
|
1272
1545
|
for (;;) {
|
|
1273
|
-
if (p
|
|
1546
|
+
if (segmentEnds(s, p, limit))
|
|
1274
1547
|
return setPemHdr(scan, start, p, p, true);
|
|
1275
1548
|
const unit = crossEnd(scan, p);
|
|
1276
1549
|
if (unit >= 0) {
|
|
@@ -1292,9 +1565,9 @@ function parsePemHeaderLine(scan, s, i, limit, allowBare, json) {
|
|
|
1292
1565
|
return setPemHdr(scan, start, p, p + 1, false);
|
|
1293
1566
|
if (c === CH_BACKSLASH) {
|
|
1294
1567
|
let j = p;
|
|
1295
|
-
while (j
|
|
1568
|
+
while (!segmentEnds(s, j, limit) && s.charCodeAt(j) === CH_BACKSLASH)
|
|
1296
1569
|
j += 1;
|
|
1297
|
-
const n = j
|
|
1570
|
+
const n = segmentEnds(s, j, limit) ? -1 : s.charCodeAt(j);
|
|
1298
1571
|
if (n !== CH_r && n !== CH_n && n !== CH_t) {
|
|
1299
1572
|
p = json && (j - p) % 2 === 0 && n === CH_QUOTE ? j : Math.min(limit, j + 1);
|
|
1300
1573
|
continue;
|
|
@@ -1316,7 +1589,7 @@ function parsePemHeaderLine(scan, s, i, limit, allowBare, json) {
|
|
|
1316
1589
|
break;
|
|
1317
1590
|
q += u;
|
|
1318
1591
|
}
|
|
1319
|
-
if (q
|
|
1592
|
+
if (segmentEnds(s, q, limit))
|
|
1320
1593
|
return setPemHdr(scan, start, p, q, true);
|
|
1321
1594
|
if (probePemHeaderToken(scan, s, q, limit) >= 0)
|
|
1322
1595
|
return setPemHdr(scan, start, p, q, false);
|
|
@@ -1329,7 +1602,7 @@ function parsePemBody(scan, s, i, limit) {
|
|
|
1329
1602
|
for (;;) {
|
|
1330
1603
|
const q = skipPemSeps(scan, s, p, limit);
|
|
1331
1604
|
let r = q;
|
|
1332
|
-
while (r
|
|
1605
|
+
while (!segmentEnds(s, r, limit) && tokenEnd(scan, r) < 0 && isBase64Code(s.charCodeAt(r)))
|
|
1333
1606
|
r += 1;
|
|
1334
1607
|
if (r - q < PEM_BODY_RUN_MIN)
|
|
1335
1608
|
break;
|
|
@@ -1439,13 +1712,24 @@ function findPemFence(scan, text, from) {
|
|
|
1439
1712
|
}
|
|
1440
1713
|
const SSH2_FENCE_OPEN = "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----";
|
|
1441
1714
|
const SSH2_FENCE_CLOSE = "---- END SSH2 ENCRYPTED PRIVATE KEY ----";
|
|
1442
|
-
const
|
|
1715
|
+
const ARMOR_BODY_MAX = (() => {
|
|
1716
|
+
const caps = STRUCTURAL_SECRET_PATTERNS.flatMap(([re]) => {
|
|
1717
|
+
const m = /\[\\s\\S\]\{0,(\d+)\}\?/.exec(re.source);
|
|
1718
|
+
return m === null ? [] : [Number(m[1])];
|
|
1719
|
+
});
|
|
1720
|
+
const first = caps[0];
|
|
1721
|
+
if (caps.length !== 2 || first === undefined || caps.some((c) => c !== first)) {
|
|
1722
|
+
throw new Error(`redact: the PEM and SSH2 armor rows of the structural table must each declare one body cap of the same size (read ${JSON.stringify(caps)})`);
|
|
1723
|
+
}
|
|
1724
|
+
return first;
|
|
1725
|
+
})();
|
|
1726
|
+
export const MAX_RECOGNITION_SPAN = SSH2_FENCE_OPEN.length + ARMOR_BODY_MAX + SSH2_FENCE_CLOSE.length;
|
|
1443
1727
|
function armorCloseAt(scan, text, kind, bodyFrom, max) {
|
|
1444
|
-
const near = firstDelim(scan,
|
|
1728
|
+
const near = firstDelim(scan, kind, bodyFrom, false);
|
|
1445
1729
|
if (near < 0)
|
|
1446
1730
|
return -1;
|
|
1447
|
-
const free = firstDelim(scan,
|
|
1448
|
-
const far = free >= 0 ? free : lastNotHiddenDelim(scan,
|
|
1731
|
+
const free = firstDelim(scan, kind, bodyFrom, true);
|
|
1732
|
+
const far = free >= 0 ? free : lastNotHiddenDelim(scan, kind, near, VIEW_END);
|
|
1449
1733
|
if (far > near && blockWithin(scan, text, kind, bodyFrom, far, max))
|
|
1450
1734
|
return far;
|
|
1451
1735
|
return blockWithin(scan, text, kind, bodyFrom, near, max) ? near : -1;
|
|
@@ -1459,8 +1743,8 @@ function blockWithin(scan, text, kind, bodyFrom, close, max) {
|
|
|
1459
1743
|
}
|
|
1460
1744
|
function collectSsh2FenceSpans(scan, text, json, span, isHead) {
|
|
1461
1745
|
const fam = familyCode("ssh2-armor");
|
|
1462
|
-
const opens = delimPositions(scan,
|
|
1463
|
-
const closes = delimPositions(scan,
|
|
1746
|
+
const opens = delimPositions(scan, "ssh2-open");
|
|
1747
|
+
const closes = delimPositions(scan, "ssh2-close");
|
|
1464
1748
|
const blockEnds = [];
|
|
1465
1749
|
let firstLive = 0;
|
|
1466
1750
|
let freshFrom = -1;
|
|
@@ -1475,13 +1759,13 @@ function collectSsh2FenceSpans(scan, text, json, span, isHead) {
|
|
|
1475
1759
|
}
|
|
1476
1760
|
if (rooted && prevEnd >= 0) {
|
|
1477
1761
|
scan.self = readingKey(fam, c);
|
|
1478
|
-
while (firstLive < blockEnds.length && uncoveredWithin(scan, blockEnds[firstLive], c + SSH2_FENCE_CLOSE.length) >
|
|
1762
|
+
while (firstLive < blockEnds.length && uncoveredWithin(scan, blockEnds[firstLive], c + SSH2_FENCE_CLOSE.length) > ARMOR_BODY_MAX + SSH2_FENCE_CLOSE.length)
|
|
1479
1763
|
firstLive += 1;
|
|
1480
1764
|
for (let j = firstLive; j < blockEnds.length; j++) {
|
|
1481
1765
|
const from = blockEnds[j];
|
|
1482
1766
|
if (from > c)
|
|
1483
1767
|
break;
|
|
1484
|
-
if ((from === freshFrom && blockWithin(scan, text, "ssh2-close", freshEnd, c,
|
|
1768
|
+
if ((from === freshFrom && blockWithin(scan, text, "ssh2-close", freshEnd, c, ARMOR_BODY_MAX - 1)) || blockWithin(scan, text, "ssh2-close", from, c, ARMOR_BODY_MAX)) {
|
|
1485
1769
|
span(from, c + SSH2_FENCE_CLOSE.length, c, NOT_CLOSED);
|
|
1486
1770
|
freshFrom = from;
|
|
1487
1771
|
freshEnd = c + SSH2_FENCE_CLOSE.length;
|
|
@@ -1506,7 +1790,7 @@ function collectSsh2FenceSpans(scan, text, json, span, isHead) {
|
|
|
1506
1790
|
openAt = k < opens.length ? opens[k] : -1;
|
|
1507
1791
|
return openAt;
|
|
1508
1792
|
};
|
|
1509
|
-
const truncatedEnd = createTruncatedBlockEnd(scan, text, json, (from) => firstDelim(scan,
|
|
1793
|
+
const truncatedEnd = createTruncatedBlockEnd(scan, text, json, (from) => firstDelim(scan, "ssh2-close", from, true));
|
|
1510
1794
|
for (let oi = 0; oi < opens.length;) {
|
|
1511
1795
|
const fence = opens[oi];
|
|
1512
1796
|
const bodyFrom = fence + SSH2_FENCE_OPEN.length;
|
|
@@ -1515,30 +1799,31 @@ function collectSsh2FenceSpans(scan, text, json, span, isHead) {
|
|
|
1515
1799
|
continue;
|
|
1516
1800
|
}
|
|
1517
1801
|
scan.self = readingKey(fam, fence);
|
|
1518
|
-
|
|
1519
|
-
|
|
1802
|
+
text.attempt(fence);
|
|
1803
|
+
if (isHead && measureWithin(scan, bodyFrom, text.readEnd(), ARMOR_BODY_MAX)) {
|
|
1804
|
+
span(fence, text.readEnd(), fence, NOT_CLOSED, true);
|
|
1520
1805
|
return;
|
|
1521
1806
|
}
|
|
1522
1807
|
let resume = fence + 1;
|
|
1523
1808
|
if (!isHead) {
|
|
1524
1809
|
const open = nextFreeOpen(bodyFrom);
|
|
1525
|
-
const limit = open < 0 ?
|
|
1810
|
+
const limit = open < 0 ? VIEW_END : open;
|
|
1526
1811
|
const readEnd = (crossEndsRun) => {
|
|
1527
1812
|
const t = truncatedEnd(bodyFrom, limit, crossEndsRun);
|
|
1528
1813
|
const bodyEnd = t < 0 ? -1 : armorBodyEnd(scan, text, json, bodyFrom, limit, false, crossEndsRun);
|
|
1529
1814
|
return bodyEnd < 0 ? -1 : Math.max(bodyEnd, t);
|
|
1530
1815
|
};
|
|
1531
1816
|
const far = readEnd(false);
|
|
1532
|
-
const near = far >= 0 && !measureWithin(scan, bodyFrom, far,
|
|
1817
|
+
const near = far >= 0 && !measureWithin(scan, bodyFrom, far, ARMOR_BODY_MAX) ? readEnd(true) : -1;
|
|
1533
1818
|
const end = near >= 0 && near < far ? near : far;
|
|
1534
|
-
if (end >= 0 && measureWithin(scan, bodyFrom, end,
|
|
1819
|
+
if (end >= 0 && measureWithin(scan, bodyFrom, end, ARMOR_BODY_MAX)) {
|
|
1535
1820
|
span(fence, end, fence, NOT_CLOSED);
|
|
1536
1821
|
resume = end;
|
|
1537
1822
|
}
|
|
1538
1823
|
}
|
|
1539
|
-
const close = armorCloseAt(scan, text, "ssh2-close", bodyFrom,
|
|
1824
|
+
const close = armorCloseAt(scan, text, "ssh2-close", bodyFrom, ARMOR_BODY_MAX);
|
|
1540
1825
|
if (close < 0) {
|
|
1541
|
-
if (isHead && firstDelim(scan,
|
|
1826
|
+
if (isHead && firstDelim(scan, "ssh2-close", bodyFrom, false) < 0)
|
|
1542
1827
|
return;
|
|
1543
1828
|
oi = lowerBound(opens, resume);
|
|
1544
1829
|
continue;
|
|
@@ -1549,16 +1834,16 @@ function collectSsh2FenceSpans(scan, text, json, span, isHead) {
|
|
|
1549
1834
|
}
|
|
1550
1835
|
}
|
|
1551
1836
|
const PEM_END_OPEN = "-----END";
|
|
1552
|
-
const PEM_FENCE_BODY_MAX = 8192;
|
|
1553
1837
|
const PEM_LINE_INVALID = -1;
|
|
1554
1838
|
const PEM_LINE_OPEN = -2;
|
|
1555
1839
|
function pemFenceLineEnd(text, labelFrom) {
|
|
1556
1840
|
const close = text.indexOf(PEM_FENCE_CLOSE, labelFrom);
|
|
1557
1841
|
if (close < 0) {
|
|
1558
|
-
|
|
1842
|
+
const n = text.readEnd();
|
|
1843
|
+
let to = n;
|
|
1559
1844
|
while (to > labelFrom && text.charCodeAt(to - 1) === 45)
|
|
1560
1845
|
to -= 1;
|
|
1561
|
-
const stillPossible =
|
|
1846
|
+
const stillPossible = n - to >= 2 ? isPemFenceLabel(text, labelFrom, to) : !pemLabelDashRuleBroken(text, labelFrom, to);
|
|
1562
1847
|
return stillPossible ? PEM_LINE_OPEN : PEM_LINE_INVALID;
|
|
1563
1848
|
}
|
|
1564
1849
|
return isPemFenceLabel(text, labelFrom, close) ? close + PEM_FENCE_CLOSE.length : PEM_LINE_INVALID;
|
|
@@ -1569,23 +1854,24 @@ function collectPemFenceSpans(scan, text, span, isHead) {
|
|
|
1569
1854
|
const fence = text.indexOf(PEM_FENCE_OPEN, from);
|
|
1570
1855
|
if (fence < 0)
|
|
1571
1856
|
return;
|
|
1857
|
+
text.attempt(fence);
|
|
1572
1858
|
const bodyFrom = pemFenceLineEnd(text, fence + PEM_FENCE_OPEN.length);
|
|
1573
1859
|
if (bodyFrom === PEM_LINE_INVALID) {
|
|
1574
1860
|
from = fence + 1;
|
|
1575
1861
|
continue;
|
|
1576
1862
|
}
|
|
1577
|
-
if (lineHeld(scan, fence, bodyFrom === PEM_LINE_OPEN ? text.
|
|
1863
|
+
if (lineHeld(scan, fence, bodyFrom === PEM_LINE_OPEN ? text.readEnd() : bodyFrom, readingKey(fam, fence))) {
|
|
1578
1864
|
from = fence + 1;
|
|
1579
1865
|
continue;
|
|
1580
1866
|
}
|
|
1581
1867
|
scan.self = readingKey(fam, fence);
|
|
1582
|
-
const near = bodyFrom === PEM_LINE_OPEN ? -1 : firstDelim(scan,
|
|
1583
|
-
if (near < 0 || (isHead && firstDelim(scan,
|
|
1868
|
+
const near = bodyFrom === PEM_LINE_OPEN ? -1 : firstDelim(scan, "pem-end", bodyFrom, false);
|
|
1869
|
+
if (near < 0 || (isHead && firstDelim(scan, "pem-end", bodyFrom, true) < 0)) {
|
|
1584
1870
|
if (isHead)
|
|
1585
|
-
span(fence, text.
|
|
1871
|
+
span(fence, text.readEnd(), fence, NOT_CLOSED, true);
|
|
1586
1872
|
return;
|
|
1587
1873
|
}
|
|
1588
|
-
const endAt = armorCloseAt(scan, text, "pem-end", bodyFrom,
|
|
1874
|
+
const endAt = armorCloseAt(scan, text, "pem-end", bodyFrom, ARMOR_BODY_MAX);
|
|
1589
1875
|
if (endAt < 0) {
|
|
1590
1876
|
from = fence + 1;
|
|
1591
1877
|
continue;
|
|
@@ -1597,8 +1883,8 @@ function collectPemFenceSpans(scan, text, span, isHead) {
|
|
|
1597
1883
|
}
|
|
1598
1884
|
function truncationWindowEnd(text, from, json) {
|
|
1599
1885
|
if (!json)
|
|
1600
|
-
return text.
|
|
1601
|
-
for (let i = from;
|
|
1886
|
+
return text.readEnd();
|
|
1887
|
+
for (let i = from; !text.atEnd(i); i++) {
|
|
1602
1888
|
const c = text.charCodeAt(i);
|
|
1603
1889
|
if (c === CH_BACKSLASH) {
|
|
1604
1890
|
i += 1;
|
|
@@ -1607,7 +1893,7 @@ function truncationWindowEnd(text, from, json) {
|
|
|
1607
1893
|
if (c === CH_QUOTE)
|
|
1608
1894
|
return i;
|
|
1609
1895
|
}
|
|
1610
|
-
return text.
|
|
1896
|
+
return text.readEnd();
|
|
1611
1897
|
}
|
|
1612
1898
|
function armorBodyEnd(scan, text, json, from, limit, allowBare, crossEndsRun) {
|
|
1613
1899
|
let pos = from;
|
|
@@ -1649,13 +1935,19 @@ function collectPemFragmentSpans(scan, text, json, span, isHead) {
|
|
|
1649
1935
|
const fam = familyCode("pem-armor");
|
|
1650
1936
|
let cur = findPemFence(scan, text, 0);
|
|
1651
1937
|
let inherited = false;
|
|
1652
|
-
const truncatedEnd = createTruncatedBlockEnd(scan, text, json, (from) => firstDelim(scan,
|
|
1938
|
+
const truncatedEnd = createTruncatedBlockEnd(scan, text, json, (from) => firstDelim(scan, "pem-end", from, true));
|
|
1653
1939
|
while (cur !== undefined) {
|
|
1654
1940
|
const next = findPemFence(scan, text, cur.after);
|
|
1655
|
-
const limit = next === undefined ?
|
|
1941
|
+
const limit = next === undefined ? VIEW_END : next.fence;
|
|
1656
1942
|
scan.self = readingKey(fam, cur.fence);
|
|
1943
|
+
text.attempt(cur.fence);
|
|
1657
1944
|
const bodyEnd = armorBodyEnd(scan, text, json, cur.after, limit, inherited, false);
|
|
1658
1945
|
inherited = scan.hdr.hitLimit;
|
|
1946
|
+
if (isHead && text.reachedEnd()) {
|
|
1947
|
+
span(cur.fence, text.readEnd(), cur.fence, NOT_CLOSED, bodyEnd < 0);
|
|
1948
|
+
cur = next;
|
|
1949
|
+
continue;
|
|
1950
|
+
}
|
|
1659
1951
|
const end = isHead || bodyEnd < 0 ? bodyEnd : Math.max(bodyEnd, truncatedEnd(cur.after, limit, false));
|
|
1660
1952
|
if (end >= 0)
|
|
1661
1953
|
span(cur.fence, end, cur.fence, NOT_CLOSED);
|
|
@@ -1664,22 +1956,21 @@ function collectPemFragmentSpans(scan, text, json, span, isHead) {
|
|
|
1664
1956
|
}
|
|
1665
1957
|
function collectHeadlessPpkSpans(scan, text, span, isHead) {
|
|
1666
1958
|
const KEY = PPK_LINES_FIELD;
|
|
1667
|
-
const n = text.length;
|
|
1668
1959
|
const LINE_NONE = -1;
|
|
1669
1960
|
const LINE_OPEN = -2;
|
|
1670
1961
|
const openAt = (i) => {
|
|
1671
1962
|
if (!isHead)
|
|
1672
1963
|
return false;
|
|
1673
1964
|
let k = i;
|
|
1674
|
-
while (k
|
|
1965
|
+
while (!text.atEnd(k) && tokenEnd(scan, k) < 0 && text.charCodeAt(k) === 92)
|
|
1675
1966
|
k += 1;
|
|
1676
|
-
return k
|
|
1967
|
+
return text.atEnd(k);
|
|
1677
1968
|
};
|
|
1678
1969
|
const isB64 = (c) => (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 43 || c === 47 || c === 61;
|
|
1679
1970
|
const b64At = (i) => tokenEnd(scan, i) < 0 && isB64(text.charCodeAt(i));
|
|
1680
|
-
const skipHs = (i) => { while (i
|
|
1971
|
+
const skipHs = (i) => { while (!text.atEnd(i) && tokenEnd(scan, i) < 0 && (text.charCodeAt(i) === 32 || text.charCodeAt(i) === 9))
|
|
1681
1972
|
i += 1; return i; };
|
|
1682
|
-
const lineEndHidden = (i) => i
|
|
1973
|
+
const lineEndHidden = (i) => !text.atEnd(i) && delimClass(scan, i) === DELIM_HIDDEN;
|
|
1683
1974
|
const skipNewlines = (i) => {
|
|
1684
1975
|
let q = skipHs(i);
|
|
1685
1976
|
let seen = false;
|
|
@@ -1722,7 +2013,7 @@ function collectHeadlessPpkSpans(scan, text, span, isHead) {
|
|
|
1722
2013
|
if (lineEndHidden(i))
|
|
1723
2014
|
return 0;
|
|
1724
2015
|
let k = i;
|
|
1725
|
-
while (k
|
|
2016
|
+
while (!text.atEnd(k) && text.charCodeAt(k) === 92)
|
|
1726
2017
|
k += 1;
|
|
1727
2018
|
if (k === i)
|
|
1728
2019
|
return 0;
|
|
@@ -1731,7 +2022,7 @@ function collectHeadlessPpkSpans(scan, text, span, isHead) {
|
|
|
1731
2022
|
};
|
|
1732
2023
|
const atLineEnd = (i) => {
|
|
1733
2024
|
const b = skipHs(i);
|
|
1734
|
-
if (b
|
|
2025
|
+
if (text.atEnd(b) || openAt(b))
|
|
1735
2026
|
return true;
|
|
1736
2027
|
if (tokenEnd(scan, b) >= 0 || lineEndHidden(b))
|
|
1737
2028
|
return false;
|
|
@@ -1747,13 +2038,13 @@ function collectHeadlessPpkSpans(scan, text, span, isHead) {
|
|
|
1747
2038
|
if (mk === 43 || mk === 45)
|
|
1748
2039
|
q = skipHs(q + 1);
|
|
1749
2040
|
let r = q;
|
|
1750
|
-
while (r
|
|
2041
|
+
while (!text.atEnd(r) && b64At(r))
|
|
1751
2042
|
r += 1;
|
|
1752
2043
|
if (r - q < 4) {
|
|
1753
|
-
if (isHead && r
|
|
2044
|
+
if (isHead && text.atEnd(r))
|
|
1754
2045
|
return LINE_OPEN;
|
|
1755
2046
|
r = q0;
|
|
1756
|
-
while (r
|
|
2047
|
+
while (!text.atEnd(r) && b64At(r))
|
|
1757
2048
|
r += 1;
|
|
1758
2049
|
if (r - q0 < 4)
|
|
1759
2050
|
return LINE_NONE;
|
|
@@ -1765,11 +2056,12 @@ function collectHeadlessPpkSpans(scan, text, span, isHead) {
|
|
|
1765
2056
|
const at = text.indexOf(KEY, search);
|
|
1766
2057
|
if (at === -1)
|
|
1767
2058
|
break;
|
|
2059
|
+
text.attempt(at);
|
|
1768
2060
|
let p = at + KEY.length;
|
|
1769
2061
|
const d0 = p;
|
|
1770
|
-
while (p
|
|
2062
|
+
while (!text.atEnd(p) && tokenEnd(scan, p) < 0 && text.charCodeAt(p) >= 48 && text.charCodeAt(p) <= 57)
|
|
1771
2063
|
p += 1;
|
|
1772
|
-
if (p === d0 && p
|
|
2064
|
+
if (p === d0 && !text.atEnd(p)) {
|
|
1773
2065
|
search = at + KEY.length;
|
|
1774
2066
|
continue;
|
|
1775
2067
|
}
|
|
@@ -1784,7 +2076,7 @@ function collectHeadlessPpkSpans(scan, text, span, isHead) {
|
|
|
1784
2076
|
const r = bodyLineAt(from);
|
|
1785
2077
|
if (r === LINE_NONE)
|
|
1786
2078
|
break;
|
|
1787
|
-
end = r === LINE_OPEN ?
|
|
2079
|
+
end = r === LINE_OPEN ? text.readEnd() : r;
|
|
1788
2080
|
if (r === LINE_OPEN) {
|
|
1789
2081
|
open = true;
|
|
1790
2082
|
break;
|
|
@@ -1806,7 +2098,7 @@ const FRAGMENT_SECRET_PATTERNS = [
|
|
|
1806
2098
|
[valueArm("xox[baprs]-", "[A-Za-z0-9-]", 4, "needs-left-boundary"), "«redacted:slack-token:partial»"],
|
|
1807
2099
|
[valueArm("AKIA", "[0-9A-Z]", 6, "needs-left-boundary"), "«redacted:aws-key:partial»"],
|
|
1808
2100
|
[valueArm("ASIA", "[0-9A-Z]", 8, "needs-left-boundary"), "«redacted:aws-key:partial»"],
|
|
1809
|
-
[valueArm("(?:gl(?:pat|dt|rt|rtr|cbt|ptt|oas|ft|imt|agent|wt|soat|ffct)-|(?:sk|rk)_(?:live|test|org)_|pypi
|
|
2101
|
+
[valueArm("(?:gl(?:pat|dt|rt|rtr|cbt|ptt|oas|ft|imt|agent|wt|soat|ffct)-|(?:sk|rk)_(?:live|test|org)_|pypi-|npm_|hf_|ya29\\.)", "[A-Za-z0-9_-]", 8, "needs-left-boundary"), "«redacted:key:partial»"],
|
|
1810
2102
|
[valueArm("xapp-\\d-", "[A-Za-z0-9-]", 4, "needs-left-boundary"), "«redacted:slack-token:partial»"],
|
|
1811
2103
|
];
|
|
1812
2104
|
const DISPLAY_SAFE_URL_TOKEN = "«redacted:url»";
|
|
@@ -1890,7 +2182,7 @@ const isControlCode = (c) => c < 0x20 || c === 0x7f;
|
|
|
1890
2182
|
const TOKEN_UNIT_Y = new RegExp(REDACTION_TOKEN_RE_SRC, "y");
|
|
1891
2183
|
function credentialParamValueStart(text, p, json) {
|
|
1892
2184
|
let encoded = false;
|
|
1893
|
-
for (let i = p;
|
|
2185
|
+
for (let i = p; !text.atEnd(i); i++) {
|
|
1894
2186
|
const c = text.charCodeAt(i);
|
|
1895
2187
|
if (c === CH_EQ) {
|
|
1896
2188
|
if (i === p)
|
|
@@ -2374,7 +2666,8 @@ function reachAt(ix, d, self) {
|
|
|
2374
2666
|
return ix.dEnd2[d] < 0 ? -1 : ix.reach2[d];
|
|
2375
2667
|
}
|
|
2376
2668
|
const FOOT_NONE = 0x7fffffff;
|
|
2377
|
-
|
|
2669
|
+
const NO_DELIM_POSITIONS = new Int32Array(0);
|
|
2670
|
+
function buildForensicScan(tokens, rows, armCount, positionsOf) {
|
|
2378
2671
|
return {
|
|
2379
2672
|
rows,
|
|
2380
2673
|
tokens,
|
|
@@ -2385,6 +2678,7 @@ function buildForensicScan(tokens, rows, armCount) {
|
|
|
2385
2678
|
footLo: FOOT_NONE,
|
|
2386
2679
|
footHi: -1,
|
|
2387
2680
|
armFoot: new Int32Array(2 * armCount),
|
|
2681
|
+
execs: [],
|
|
2388
2682
|
lastAt: -1,
|
|
2389
2683
|
headsRead: { a: NO_URL_SEGMENTS, n: 0 },
|
|
2390
2684
|
headsWrite: { a: NO_URL_SEGMENTS, n: 0 },
|
|
@@ -2394,6 +2688,7 @@ function buildForensicScan(tokens, rows, armCount) {
|
|
|
2394
2688
|
opsWrite: { a: NO_URL_SEGMENTS, n: 0, cut: OPS_UNCUT },
|
|
2395
2689
|
hdr: { search: 0, contentEnd: 0, next: 0, hitLimit: false, jsonEnd: false },
|
|
2396
2690
|
delimPos: new Map(),
|
|
2691
|
+
positionsOf,
|
|
2397
2692
|
delimIx: new Map(),
|
|
2398
2693
|
delimIxRows: rows,
|
|
2399
2694
|
};
|
|
@@ -2404,6 +2699,11 @@ function noteEvidenceRead(scan, p) {
|
|
|
2404
2699
|
if (p > scan.footHi)
|
|
2405
2700
|
scan.footHi = p;
|
|
2406
2701
|
}
|
|
2702
|
+
function noteExecution(scan, lo, hi, from) {
|
|
2703
|
+
if (lo > hi)
|
|
2704
|
+
return;
|
|
2705
|
+
scan.execs.push(lo, hi, from);
|
|
2706
|
+
}
|
|
2407
2707
|
function footprintClean(dirty, lo, hi) {
|
|
2408
2708
|
if (lo > hi)
|
|
2409
2709
|
return true;
|
|
@@ -2660,16 +2960,21 @@ export function unitCountsWithinForTest(table, queries) {
|
|
|
2660
2960
|
anchor: Int32Array.from(sorted, keyOf),
|
|
2661
2961
|
closeAt: new Int32Array(sorted.length).fill(NOT_CLOSED),
|
|
2662
2962
|
};
|
|
2663
|
-
const scan = buildForensicScan(NO_TOKEN_UNITS, rows, 1);
|
|
2963
|
+
const scan = buildForensicScan(NO_TOKEN_UNITS, rows, 1, () => NO_DELIM_POSITIONS);
|
|
2664
2964
|
return queries.map(([from, to, max, self]) => {
|
|
2665
2965
|
scan.self = self === undefined ? NO_SELF : readingKey(familyCode("prose"), self);
|
|
2666
2966
|
return measureWithin(scan, from, to, max);
|
|
2667
2967
|
});
|
|
2668
2968
|
}
|
|
2669
|
-
function delimPositions(scan,
|
|
2969
|
+
function delimPositions(scan, kind) {
|
|
2670
2970
|
const hit = scan.delimPos.get(kind);
|
|
2671
2971
|
if (hit !== undefined)
|
|
2672
2972
|
return hit;
|
|
2973
|
+
const pos = scan.positionsOf(kind);
|
|
2974
|
+
scan.delimPos.set(kind, pos);
|
|
2975
|
+
return pos;
|
|
2976
|
+
}
|
|
2977
|
+
function delimPositionsOf(text, kind) {
|
|
2673
2978
|
const out = [];
|
|
2674
2979
|
switch (kind) {
|
|
2675
2980
|
case "ssh2-open":
|
|
@@ -2680,11 +2985,13 @@ function delimPositions(scan, text, kind) {
|
|
|
2680
2985
|
ssh2ScanBytes += text.length;
|
|
2681
2986
|
break;
|
|
2682
2987
|
}
|
|
2683
|
-
case "pem-end":
|
|
2988
|
+
case "pem-end": {
|
|
2989
|
+
const lines = new ScanReader(text);
|
|
2684
2990
|
for (let b = text.indexOf(PEM_END_OPEN); b >= 0; b = text.indexOf(PEM_END_OPEN, b + 1))
|
|
2685
|
-
if (pemFenceLineEnd(
|
|
2991
|
+
if (pemFenceLineEnd(lines, b + PEM_END_OPEN.length) >= 0)
|
|
2686
2992
|
out.push(b);
|
|
2687
2993
|
break;
|
|
2994
|
+
}
|
|
2688
2995
|
case "at":
|
|
2689
2996
|
case "at-json":
|
|
2690
2997
|
for (let p = text.indexOf("@"); p >= 0; p = text.indexOf("@", p + 1)) {
|
|
@@ -2699,11 +3006,9 @@ function delimPositions(scan, text, kind) {
|
|
|
2699
3006
|
}
|
|
2700
3007
|
break;
|
|
2701
3008
|
}
|
|
2702
|
-
|
|
2703
|
-
scan.delimPos.set(kind, pos);
|
|
2704
|
-
return pos;
|
|
3009
|
+
return Int32Array.from(out);
|
|
2705
3010
|
}
|
|
2706
|
-
function delimIndexOf(scan,
|
|
3011
|
+
function delimIndexOf(scan, kind) {
|
|
2707
3012
|
const t = scan.rows;
|
|
2708
3013
|
if (scan.delimIxRows !== t) {
|
|
2709
3014
|
scan.delimIx = new Map();
|
|
@@ -2713,7 +3018,7 @@ function delimIndexOf(scan, text, kind) {
|
|
|
2713
3018
|
const hit = byKind.get(kind);
|
|
2714
3019
|
if (hit !== undefined)
|
|
2715
3020
|
return hit;
|
|
2716
|
-
const pos = delimPositions(scan,
|
|
3021
|
+
const pos = delimPositions(scan, kind);
|
|
2717
3022
|
const n = pos.length;
|
|
2718
3023
|
const nextNotHidden = new Int32Array(n + 1);
|
|
2719
3024
|
const nextFree = new Int32Array(n + 1);
|
|
@@ -2773,9 +3078,9 @@ function bucketFirstFrom(b, i, n) {
|
|
|
2773
3078
|
const k = lowerBound(b, i);
|
|
2774
3079
|
return k < b.length ? b[k] : n;
|
|
2775
3080
|
}
|
|
2776
|
-
function firstDelim(scan,
|
|
3081
|
+
function firstDelim(scan, kind, from, wantFree) {
|
|
2777
3082
|
noteEvidenceRead(scan, from);
|
|
2778
|
-
const di = delimIndexOf(scan,
|
|
3083
|
+
const di = delimIndexOf(scan, kind);
|
|
2779
3084
|
const n = di.pos.length;
|
|
2780
3085
|
const bucket = (wantFree ? di.onlyCoveredBy : di.onlyHiddenBy).get(scan.self);
|
|
2781
3086
|
const firstAt = (i) => (i >= n ? n : Math.min(wantFree ? di.nextFree[i] : di.nextNotHidden[i], bucketFirstFrom(bucket, i, n)));
|
|
@@ -2789,11 +3094,11 @@ function firstDelim(scan, text, kind, from, wantFree) {
|
|
|
2789
3094
|
j = firstAt(lowerBound(di.pos, own.maxClose[k]));
|
|
2790
3095
|
}
|
|
2791
3096
|
const at = j >= n ? -1 : di.pos[j];
|
|
2792
|
-
noteEvidenceRead(scan, at < 0 ?
|
|
3097
|
+
noteEvidenceRead(scan, at < 0 ? VIEW_END : at);
|
|
2793
3098
|
return at;
|
|
2794
3099
|
}
|
|
2795
|
-
function lastNotHiddenDelim(scan,
|
|
2796
|
-
const di = delimIndexOf(scan,
|
|
3100
|
+
function lastNotHiddenDelim(scan, kind, a, b) {
|
|
3101
|
+
const di = delimIndexOf(scan, kind);
|
|
2797
3102
|
const bucket = di.onlyHiddenBy.get(scan.self);
|
|
2798
3103
|
const lastAt = (j) => {
|
|
2799
3104
|
let best = di.prevNotHidden[j];
|
|
@@ -2820,13 +3125,12 @@ function lastNotHiddenDelim(scan, text, kind, a, b) {
|
|
|
2820
3125
|
return best >= 0 && di.pos[best] >= a ? di.pos[best] : -1;
|
|
2821
3126
|
}
|
|
2822
3127
|
function scanUrlRun(scan, text, i, kind, json) {
|
|
2823
|
-
const n = text.length;
|
|
2824
3128
|
noteEvidenceRead(scan, i);
|
|
2825
3129
|
scan.lastAt = -1;
|
|
2826
|
-
run: while (i
|
|
3130
|
+
run: while (!text.atEnd(i)) {
|
|
2827
3131
|
const unit = crossEndAt(scan, i);
|
|
2828
3132
|
if (unit >= 0) {
|
|
2829
|
-
const at = lastNotHiddenDelim(scan,
|
|
3133
|
+
const at = lastNotHiddenDelim(scan, json ? "at-json" : "at", i, unit);
|
|
2830
3134
|
if (at > scan.lastAt)
|
|
2831
3135
|
scan.lastAt = at;
|
|
2832
3136
|
i = unit;
|
|
@@ -2834,7 +3138,7 @@ function scanUrlRun(scan, text, i, kind, json) {
|
|
|
2834
3138
|
}
|
|
2835
3139
|
const c = text.charCodeAt(i);
|
|
2836
3140
|
if (json && c === 92) {
|
|
2837
|
-
if (i + 1
|
|
3141
|
+
if (!text.atEnd(i + 1) && !isLineTerminator(text.charCodeAt(i + 1))) {
|
|
2838
3142
|
i += 2;
|
|
2839
3143
|
continue;
|
|
2840
3144
|
}
|
|
@@ -2871,7 +3175,7 @@ function matchUserinfoAt(scan, text, p, json, isHead) {
|
|
|
2871
3175
|
const probeEnd = scanUrlRun(scan, text, p, "plain-user", json);
|
|
2872
3176
|
const keyId = probeEnd > p && text.charCodeAt(probeEnd) === 58 && readableCover(scan, p, probeEnd);
|
|
2873
3177
|
const runEnd = scanUrlRun(scan, text, p, keyId ? "token-pass" : "plain-pass", json);
|
|
2874
|
-
if (isHead && runEnd
|
|
3178
|
+
if (isHead && runEnd > p && text.atEnd(runEnd))
|
|
2875
3179
|
return runEnd;
|
|
2876
3180
|
const at = scan.lastAt;
|
|
2877
3181
|
if (at <= p)
|
|
@@ -2879,6 +3183,7 @@ function matchUserinfoAt(scan, text, p, json, isHead) {
|
|
|
2879
3183
|
return at;
|
|
2880
3184
|
}
|
|
2881
3185
|
const URL_SEG_STRIDE = 4;
|
|
3186
|
+
const URL_PARAM_DELIMS = /[?&#]/g;
|
|
2882
3187
|
const URL_SEG_MAX_INTS = 3 * 1_048_576;
|
|
2883
3188
|
const NO_URL_SEGMENTS = new Int32Array(0);
|
|
2884
3189
|
const ANCHOR_SEG_STRIDE = 4;
|
|
@@ -2908,12 +3213,12 @@ function collectUrlCredentialSpans(scan, text, json, span, isHead) {
|
|
|
2908
3213
|
const phn = dirty === undefined ? 0 : hr.n;
|
|
2909
3214
|
let pc = 0;
|
|
2910
3215
|
for (let from = 0;;) {
|
|
2911
|
-
|
|
2912
|
-
const m = head.exec(text);
|
|
3216
|
+
const m = text.search(head, from);
|
|
2913
3217
|
if (m === null)
|
|
2914
3218
|
break;
|
|
2915
3219
|
const colon = m.index;
|
|
2916
3220
|
const start = colon + 3;
|
|
3221
|
+
text.attempt(start);
|
|
2917
3222
|
while (pc < phn && ph[pc] < colon)
|
|
2918
3223
|
pc += URL_SEG_STRIDE;
|
|
2919
3224
|
const known = pc < phn && ph[pc] === colon;
|
|
@@ -2934,8 +3239,9 @@ function collectUrlCredentialSpans(scan, text, json, span, isHead) {
|
|
|
2934
3239
|
lo = scan.footLo;
|
|
2935
3240
|
hi = scan.footHi;
|
|
2936
3241
|
urlSegmentRuns += 1;
|
|
3242
|
+
noteExecution(scan, lo, hi, start);
|
|
2937
3243
|
if (at >= 0 && at !== (known ? ph[pc + 1] : -2)) {
|
|
2938
|
-
const undecided = isHead &&
|
|
3244
|
+
const undecided = isHead && text.atEnd(at);
|
|
2939
3245
|
span(start, at, colon, undecided ? NOT_CLOSED : at, undecided);
|
|
2940
3246
|
}
|
|
2941
3247
|
}
|
|
@@ -2957,13 +3263,15 @@ function collectUrlCredentialSpans(scan, text, json, span, isHead) {
|
|
|
2957
3263
|
const pp = pr.a;
|
|
2958
3264
|
const ppn = dirty === undefined ? 0 : pr.n;
|
|
2959
3265
|
let qc = 0;
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
3266
|
+
let resume = 0;
|
|
3267
|
+
for (let m = text.search(URL_PARAM_DELIMS, 0); m !== null; m = text.search(URL_PARAM_DELIMS, resume)) {
|
|
3268
|
+
const i = m.index;
|
|
3269
|
+
resume = i + 1;
|
|
3270
|
+
text.attempt(i + 1);
|
|
2964
3271
|
const valueStart = credentialParamValueStart(text, i + 1, json);
|
|
2965
3272
|
if (valueStart < 0)
|
|
2966
3273
|
continue;
|
|
3274
|
+
text.attempt(valueStart);
|
|
2967
3275
|
while (qc < ppn && pp[qc] < i)
|
|
2968
3276
|
qc += URL_SEG_STRIDE;
|
|
2969
3277
|
const known = qc < ppn && pp[qc] === i;
|
|
@@ -2984,6 +3292,7 @@ function collectUrlCredentialSpans(scan, text, json, span, isHead) {
|
|
|
2984
3292
|
lo = scan.footLo;
|
|
2985
3293
|
hi = scan.footHi;
|
|
2986
3294
|
urlSegmentRuns += 1;
|
|
3295
|
+
noteExecution(scan, lo, hi, valueStart);
|
|
2987
3296
|
if (valueEnd > valueStart && valueEnd !== (known ? pp[qc + 1] : -2))
|
|
2988
3297
|
span(valueStart, valueEnd, i, NOT_CLOSED);
|
|
2989
3298
|
}
|
|
@@ -3000,7 +3309,7 @@ function collectUrlCredentialSpans(scan, text, json, span, isHead) {
|
|
|
3000
3309
|
armLo = lo;
|
|
3001
3310
|
if (hi > armHi)
|
|
3002
3311
|
armHi = hi;
|
|
3003
|
-
|
|
3312
|
+
resume = valueEnd;
|
|
3004
3313
|
}
|
|
3005
3314
|
scan.headsRead = hw;
|
|
3006
3315
|
scan.headsWrite = hr;
|
|
@@ -3013,10 +3322,9 @@ const JSON_FIELD_ANCHOR = '"';
|
|
|
3013
3322
|
const JSON_FIELD_HEAD_MAX = Math.max(...JSON_FIELD_QUOTE_FORMS.map((f) => f.length));
|
|
3014
3323
|
function jsonSecretFieldValueQuoteAt(text, p, depth) {
|
|
3015
3324
|
const form = JSON_FIELD_QUOTE_FORMS[depth];
|
|
3016
|
-
const n = text.length;
|
|
3017
3325
|
const nameFrom = p + form.length;
|
|
3018
3326
|
let i = nameFrom;
|
|
3019
|
-
for (; i
|
|
3327
|
+
for (; !text.atEnd(i); i++) {
|
|
3020
3328
|
const c = text.charCodeAt(i);
|
|
3021
3329
|
if (!isJsonFieldNameCode(c))
|
|
3022
3330
|
break;
|
|
@@ -3024,12 +3332,12 @@ function jsonSecretFieldValueQuoteAt(text, p, depth) {
|
|
|
3024
3332
|
if (i === nameFrom || !text.startsWith(form, i) || credentialNameAnchor(text.slice(nameFrom, i)) === undefined)
|
|
3025
3333
|
return -1;
|
|
3026
3334
|
i += form.length;
|
|
3027
|
-
while (i
|
|
3335
|
+
while (!text.atEnd(i) && isRegexSpace(text.charCodeAt(i)))
|
|
3028
3336
|
i += 1;
|
|
3029
3337
|
if (text.charCodeAt(i) !== CH_COLON)
|
|
3030
3338
|
return -1;
|
|
3031
3339
|
i += 1;
|
|
3032
|
-
while (i
|
|
3340
|
+
while (!text.atEnd(i) && isRegexSpace(text.charCodeAt(i)))
|
|
3033
3341
|
i += 1;
|
|
3034
3342
|
return text.startsWith(form, i) ? i : -1;
|
|
3035
3343
|
}
|
|
@@ -3044,7 +3352,7 @@ const packUnit8 = (kind, next) => next * 8 + kind;
|
|
|
3044
3352
|
const unit8Kind = (u) => (u % 8);
|
|
3045
3353
|
const unit8Next = (u) => (u - (u % 8)) / 8;
|
|
3046
3354
|
function escapedUnitAt(text, i, depth) {
|
|
3047
|
-
if (
|
|
3355
|
+
if (text.atEnd(i))
|
|
3048
3356
|
return packUnit8(U_END, i);
|
|
3049
3357
|
if (depth === 0) {
|
|
3050
3358
|
const c = text.charCodeAt(i);
|
|
@@ -3111,12 +3419,13 @@ function collectJsonSecretFieldSpans(text, span, isHead) {
|
|
|
3111
3419
|
const start = p - (form.length - 1);
|
|
3112
3420
|
if (start < p - run)
|
|
3113
3421
|
continue;
|
|
3422
|
+
text.attempt(start);
|
|
3114
3423
|
const q = jsonSecretFieldValueQuoteAt(text, start, d);
|
|
3115
3424
|
const found = q < 0 ? -1 : jsonStringEndAt(text, q + form.length, d, isHead);
|
|
3116
3425
|
if (found === -1)
|
|
3117
3426
|
continue;
|
|
3118
3427
|
const open = found === STRING_OPEN;
|
|
3119
|
-
const end = open ? text.
|
|
3428
|
+
const end = open ? text.readEnd() : found;
|
|
3120
3429
|
span(q, end, q, open ? NOT_CLOSED : end - form.length, open, JSON_FIELD_VALUE_REPLS[d]);
|
|
3121
3430
|
from = scanResumeAfterHit(start, end, end - q);
|
|
3122
3431
|
next = text.indexOf(JSON_FIELD_ANCHOR, from);
|
|
@@ -3171,7 +3480,7 @@ function readTextUnit(text, i, json) {
|
|
|
3171
3480
|
return packUnit(c, 1);
|
|
3172
3481
|
if (c === CH_QUOTE)
|
|
3173
3482
|
return packUnit(JSON_STRING_END, 1);
|
|
3174
|
-
if (c !== CH_BACKSLASH || i + 1
|
|
3483
|
+
if (c !== CH_BACKSLASH || text.atEnd(i + 1))
|
|
3175
3484
|
return packUnit(c, 1);
|
|
3176
3485
|
switch (text.charCodeAt(i + 1)) {
|
|
3177
3486
|
case CH_n: return packUnit(CH_LF, 2);
|
|
@@ -3281,9 +3590,8 @@ function anchorHeadAt(scan, text, op, json) {
|
|
|
3281
3590
|
return { strength, quotedName: quote !== 0, spacedLeft, listSep, runStart };
|
|
3282
3591
|
}
|
|
3283
3592
|
function quotedValueEnd(text, cs, quote, json, isHead) {
|
|
3284
|
-
const n = text.length;
|
|
3285
3593
|
let i = cs;
|
|
3286
|
-
while (i
|
|
3594
|
+
while (!text.atEnd(i)) {
|
|
3287
3595
|
const unit = readAnchorUnit(text, i, json);
|
|
3288
3596
|
const ch = unitChOf(unit);
|
|
3289
3597
|
if (ch === quote)
|
|
@@ -3292,7 +3600,7 @@ function quotedValueEnd(text, cs, quote, json, isHead) {
|
|
|
3292
3600
|
return -1;
|
|
3293
3601
|
i += unitLenOf(unit);
|
|
3294
3602
|
if (ch === CH_BACKSLASH && quote !== JSON_STRING_END) {
|
|
3295
|
-
if (i
|
|
3603
|
+
if (text.atEnd(i))
|
|
3296
3604
|
break;
|
|
3297
3605
|
const escaped = readAnchorUnit(text, i, json);
|
|
3298
3606
|
if (unitChOf(escaped) === JSON_STRING_END)
|
|
@@ -3307,6 +3615,7 @@ function buildBareValueMemo() {
|
|
|
3307
3615
|
return {
|
|
3308
3616
|
from: new Int32Array(4),
|
|
3309
3617
|
at: new Int32Array(4).fill(-1),
|
|
3618
|
+
end: new Uint8Array(4),
|
|
3310
3619
|
netFrom: new Int32Array(4).fill(NO_MEMO_GROUP),
|
|
3311
3620
|
net: new Int32Array(16),
|
|
3312
3621
|
runFrom: new Int32Array(4).fill(NO_MEMO_GROUP),
|
|
@@ -3315,14 +3624,17 @@ function buildBareValueMemo() {
|
|
|
3315
3624
|
}
|
|
3316
3625
|
const listSepSlot = (listSep) => (listSep === 0 ? 0 : listSep === CH_AMP ? 1 : listSep === CH_SEMI ? 2 : 3);
|
|
3317
3626
|
function bareValueEnd(text, s, json, listSep, memo) {
|
|
3318
|
-
const n = text.length;
|
|
3319
3627
|
const k = listSepSlot(listSep);
|
|
3320
3628
|
let i;
|
|
3321
|
-
if (memo.from[k] <= s && s <= memo.at[k])
|
|
3629
|
+
if (memo.from[k] <= s && s <= memo.at[k]) {
|
|
3322
3630
|
i = memo.at[k];
|
|
3631
|
+
if (memo.end[k] === 1)
|
|
3632
|
+
text.readEnd();
|
|
3633
|
+
}
|
|
3323
3634
|
else {
|
|
3324
3635
|
i = s;
|
|
3325
|
-
|
|
3636
|
+
let reachedEnd = false;
|
|
3637
|
+
while (!(reachedEnd = text.atEnd(i))) {
|
|
3326
3638
|
const unit = readAnchorUnit(text, i, json);
|
|
3327
3639
|
const ch = unitChOf(unit);
|
|
3328
3640
|
if (ch === JSON_STRING_END || isRegexSpace(ch))
|
|
@@ -3331,7 +3643,7 @@ function bareValueEnd(text, s, json, listSep, memo) {
|
|
|
3331
3643
|
break;
|
|
3332
3644
|
const next = i + unitLenOf(unit);
|
|
3333
3645
|
if (isQuoteUnit(ch)) {
|
|
3334
|
-
if (
|
|
3646
|
+
if ((reachedEnd = text.atEnd(next)))
|
|
3335
3647
|
break;
|
|
3336
3648
|
if (endsValueUnit(unitChOf(readAnchorUnit(text, next, json))))
|
|
3337
3649
|
break;
|
|
@@ -3340,6 +3652,7 @@ function bareValueEnd(text, s, json, listSep, memo) {
|
|
|
3340
3652
|
}
|
|
3341
3653
|
memo.from[k] = s;
|
|
3342
3654
|
memo.at[k] = i;
|
|
3655
|
+
memo.end[k] = reachedEnd ? 1 : 0;
|
|
3343
3656
|
memo.netFrom[k] = NO_MEMO_GROUP;
|
|
3344
3657
|
memo.runFrom[k] = NO_MEMO_GROUP;
|
|
3345
3658
|
}
|
|
@@ -3392,21 +3705,20 @@ function bareValueEnd(text, s, json, listSep, memo) {
|
|
|
3392
3705
|
return e;
|
|
3393
3706
|
}
|
|
3394
3707
|
function literalValueAt(text, s, json, bare, listSep, isHead, memo) {
|
|
3395
|
-
|
|
3396
|
-
if (s >= n)
|
|
3708
|
+
if (text.atEnd(s))
|
|
3397
3709
|
return undefined;
|
|
3398
3710
|
const firstUnit = readAnchorUnit(text, s, json);
|
|
3399
3711
|
const first = unitChOf(firstUnit);
|
|
3400
3712
|
let vs = s;
|
|
3401
3713
|
if (isQuoteUnit(first) || first === JSON_STRING_END) {
|
|
3402
3714
|
vs = s + unitLenOf(firstUnit);
|
|
3403
|
-
if (vs
|
|
3715
|
+
if (text.atEnd(vs))
|
|
3404
3716
|
return undefined;
|
|
3405
3717
|
if (!isAsciiAlnumCode(unitChOf(readAnchorUnit(text, vs, json))))
|
|
3406
3718
|
return undefined;
|
|
3407
3719
|
const close = quotedValueEnd(text, vs, first, json, isHead);
|
|
3408
3720
|
if (close === STRING_OPEN)
|
|
3409
|
-
return { start: vs, end:
|
|
3721
|
+
return { start: vs, end: text.readEnd(), quoted: true, open: true };
|
|
3410
3722
|
if (close >= 0)
|
|
3411
3723
|
return { start: vs, end: close, quoted: true };
|
|
3412
3724
|
}
|
|
@@ -3429,11 +3741,11 @@ function literalValueAt(text, s, json, bare, listSep, isHead, memo) {
|
|
|
3429
3741
|
}
|
|
3430
3742
|
if (isProgramIdentStartCode(text.charCodeAt(vs))) {
|
|
3431
3743
|
let k = vs;
|
|
3432
|
-
while (k
|
|
3744
|
+
while (!text.atEnd(k) && isProgramIdentCode(text.charCodeAt(k)))
|
|
3433
3745
|
k += 1;
|
|
3434
3746
|
anchoredScanUnits += k - vs;
|
|
3435
3747
|
const after = text.charCodeAt(k);
|
|
3436
|
-
if (after === CH_LPAREN || after === CH_LBRACKET || (after === CH_DOT && k + 1
|
|
3748
|
+
if (after === CH_LPAREN || after === CH_LBRACKET || (after === CH_DOT && !text.atEnd(k + 1) && isProgramIdentStartCode(text.charCodeAt(k + 1))))
|
|
3437
3749
|
return undefined;
|
|
3438
3750
|
}
|
|
3439
3751
|
const e = bareValueEnd(text, vs, json, listSep, memo);
|
|
@@ -3452,7 +3764,7 @@ function literalValueAt(text, s, json, bare, listSep, isHead, memo) {
|
|
|
3452
3764
|
case "goes-on":
|
|
3453
3765
|
return undefined;
|
|
3454
3766
|
case "undecided":
|
|
3455
|
-
return { start: vs, end: text.
|
|
3767
|
+
return { start: vs, end: text.readEnd(), quoted: false, open: true };
|
|
3456
3768
|
default: {
|
|
3457
3769
|
const unhandled = rest;
|
|
3458
3770
|
throw new Error(`redact: unhandled line-key rest ${String(unhandled)}`);
|
|
@@ -3462,9 +3774,8 @@ function literalValueAt(text, s, json, bare, listSep, isHead, memo) {
|
|
|
3462
3774
|
return { start: vs, end: e, quoted: false };
|
|
3463
3775
|
}
|
|
3464
3776
|
function lineKeyRestAt(text, e, json, isHead) {
|
|
3465
|
-
const n = text.length;
|
|
3466
3777
|
let i = e;
|
|
3467
|
-
while (i
|
|
3778
|
+
while (!text.atEnd(i)) {
|
|
3468
3779
|
const unit = readAnchorUnit(text, i, json);
|
|
3469
3780
|
const ch = unitChOf(unit);
|
|
3470
3781
|
if (isInlineSpaceUnit(ch) || (ch >= 0 && INVISIBLE_UNIT_CLASS[ch] === 1)) {
|
|
@@ -3526,9 +3837,8 @@ function declarativeBareAt(text, head, spacedRight, json) {
|
|
|
3526
3837
|
return spacedRight && lineHeadBefore(text, head.runStart, json) ? "line-key" : "never";
|
|
3527
3838
|
}
|
|
3528
3839
|
function schemeValueAt(text, s, json) {
|
|
3529
|
-
const n = text.length;
|
|
3530
3840
|
let i = s;
|
|
3531
|
-
if (i
|
|
3841
|
+
if (text.atEnd(i))
|
|
3532
3842
|
return undefined;
|
|
3533
3843
|
const opening = readAnchorUnit(text, i, json);
|
|
3534
3844
|
if (isQuoteUnit(unitChOf(opening)) || unitChOf(opening) === JSON_STRING_END)
|
|
@@ -3540,14 +3850,14 @@ function schemeValueAt(text, s, json) {
|
|
|
3540
3850
|
anchoredScanUnits += REDACTION_MARK.length;
|
|
3541
3851
|
}
|
|
3542
3852
|
else {
|
|
3543
|
-
while (i
|
|
3853
|
+
while (!text.atEnd(i) && i - w <= STRONG_AUTH_SCHEME_MAX && (isIdentStartCode(text.charCodeAt(i))))
|
|
3544
3854
|
i += 1;
|
|
3545
3855
|
anchoredScanUnits += i - w;
|
|
3546
3856
|
if (i - w > STRONG_AUTH_SCHEME_MAX || !STRONG_AUTH_SCHEMES.has(text.slice(w, i).toLowerCase()))
|
|
3547
3857
|
return undefined;
|
|
3548
3858
|
}
|
|
3549
3859
|
let separated = false;
|
|
3550
|
-
while (i
|
|
3860
|
+
while (!text.atEnd(i)) {
|
|
3551
3861
|
const unit = readAnchorUnit(text, i, json);
|
|
3552
3862
|
const ch = unitChOf(unit);
|
|
3553
3863
|
if (!isInlineSpaceUnit(ch) && !isSchemeDelimiterCode(ch))
|
|
@@ -3560,30 +3870,30 @@ function schemeValueAt(text, s, json) {
|
|
|
3560
3870
|
const vs = i;
|
|
3561
3871
|
if (engineMarked) {
|
|
3562
3872
|
let k = i;
|
|
3563
|
-
while (k
|
|
3873
|
+
while (!text.atEnd(k) && isToken68Code(text.charCodeAt(k)))
|
|
3564
3874
|
k += 1;
|
|
3565
|
-
while (k
|
|
3875
|
+
while (!text.atEnd(k) && text.charCodeAt(k) === CH_EQ)
|
|
3566
3876
|
k += 1;
|
|
3567
3877
|
if (k - vs >= BEARER_VALUE_MIN) {
|
|
3568
3878
|
anchoredScanUnits += k - vs;
|
|
3569
3879
|
return { start: vs, end: k, quoted: false };
|
|
3570
3880
|
}
|
|
3571
3881
|
}
|
|
3572
|
-
if (i
|
|
3882
|
+
if (text.atEnd(i) || !isAsciiAlnumCode(text.charCodeAt(i)))
|
|
3573
3883
|
return undefined;
|
|
3574
|
-
while (i
|
|
3884
|
+
while (!text.atEnd(i) && isToken68Code(text.charCodeAt(i)))
|
|
3575
3885
|
i += 1;
|
|
3576
|
-
while (i
|
|
3886
|
+
while (!text.atEnd(i) && text.charCodeAt(i) === CH_EQ)
|
|
3577
3887
|
i += 1;
|
|
3578
3888
|
anchoredScanUnits += i - vs;
|
|
3579
3889
|
const e = i;
|
|
3580
|
-
while (i
|
|
3890
|
+
while (!text.atEnd(i)) {
|
|
3581
3891
|
const unit = readAnchorUnit(text, i, json);
|
|
3582
3892
|
if (!isInlineSpaceUnit(unitChOf(unit)))
|
|
3583
3893
|
break;
|
|
3584
3894
|
i += unitLenOf(unit);
|
|
3585
3895
|
}
|
|
3586
|
-
if (i
|
|
3896
|
+
if (!text.atEnd(i) && !endsHeaderValueUnit(unitChOf(readAnchorUnit(text, i, json))))
|
|
3587
3897
|
return undefined;
|
|
3588
3898
|
return { start: vs, end: e, quoted: false };
|
|
3589
3899
|
}
|
|
@@ -3591,10 +3901,9 @@ function anchoredValueAt(scan, text, op, json, span, isHead, memo) {
|
|
|
3591
3901
|
const head = anchorHeadAt(scan, text, op, json);
|
|
3592
3902
|
if (head === undefined)
|
|
3593
3903
|
return;
|
|
3594
|
-
const n = text.length;
|
|
3595
3904
|
let s = op + 1;
|
|
3596
3905
|
let spacedRight = false;
|
|
3597
|
-
while (s
|
|
3906
|
+
while (!text.atEnd(s)) {
|
|
3598
3907
|
const unit = readAnchorUnit(text, s, json);
|
|
3599
3908
|
if (!isInlineSpaceUnit(unitChOf(unit)))
|
|
3600
3909
|
break;
|
|
@@ -3661,6 +3970,7 @@ function collectAnchoredValueSpans(scan, text, json, span, isHead) {
|
|
|
3661
3970
|
if (!known && dirty !== undefined && op < rd.cut)
|
|
3662
3971
|
continue;
|
|
3663
3972
|
scan.self = readingKey(anchorFamily, op);
|
|
3973
|
+
text.attempt(op + 1);
|
|
3664
3974
|
let lo;
|
|
3665
3975
|
let hi;
|
|
3666
3976
|
let answer;
|
|
@@ -3676,6 +3986,7 @@ function collectAnchoredValueSpans(scan, text, json, span, isHead) {
|
|
|
3676
3986
|
hi = scan.footHi;
|
|
3677
3987
|
if (lo > hi)
|
|
3678
3988
|
continue;
|
|
3989
|
+
noteExecution(scan, lo, hi, op + 1);
|
|
3679
3990
|
answer = nameBoundAt(scan, lo, hi);
|
|
3680
3991
|
}
|
|
3681
3992
|
if (wr.cut === OPS_UNCUT) {
|
|
@@ -3730,10 +4041,9 @@ export function resetDiagnosticScanUnitsForTest() {
|
|
|
3730
4041
|
diagnosticScanUnits = 0;
|
|
3731
4042
|
}
|
|
3732
4043
|
function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
|
|
3733
|
-
const n = text.length;
|
|
3734
4044
|
const readRun = (from, isValue) => {
|
|
3735
4045
|
let i = from;
|
|
3736
|
-
while (i
|
|
4046
|
+
while (!text.atEnd(i)) {
|
|
3737
4047
|
const unit = readTextUnit(text, i, json);
|
|
3738
4048
|
diagnosticScanUnits += 1;
|
|
3739
4049
|
if (!isValue(unitChOf(unit)))
|
|
@@ -3782,6 +4092,7 @@ function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
|
|
|
3782
4092
|
}
|
|
3783
4093
|
if (nameStart < 0)
|
|
3784
4094
|
continue;
|
|
4095
|
+
text.attempt(nameStart);
|
|
3785
4096
|
let s;
|
|
3786
4097
|
let end;
|
|
3787
4098
|
if (inValue) {
|
|
@@ -3790,14 +4101,14 @@ function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
|
|
|
3790
4101
|
}
|
|
3791
4102
|
else {
|
|
3792
4103
|
s = skipBlank(op + 1);
|
|
3793
|
-
if (s
|
|
4104
|
+
if (!text.atEnd(s)) {
|
|
3794
4105
|
const unit = readTextUnit(text, s, json);
|
|
3795
4106
|
if (unitChOf(unit) === CH_QUOTE)
|
|
3796
4107
|
s += unitLenOf(unit);
|
|
3797
4108
|
}
|
|
3798
|
-
if (s
|
|
4109
|
+
if (text.atEnd(s)) {
|
|
3799
4110
|
if (isHead)
|
|
3800
|
-
span(nameStart,
|
|
4111
|
+
span(nameStart, text.readEnd(), op, NOT_CLOSED, true);
|
|
3801
4112
|
continue;
|
|
3802
4113
|
}
|
|
3803
4114
|
end = readRun(s, isDiagnosticValueUnit);
|
|
@@ -3805,11 +4116,11 @@ function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
|
|
|
3805
4116
|
}
|
|
3806
4117
|
if (end > s && nameTier === "auth-scheme" && readRun(s, isAsciiLetterCode) === end) {
|
|
3807
4118
|
const k = skipBlank(end);
|
|
3808
|
-
if (k > end &&
|
|
3809
|
-
span(nameStart,
|
|
4119
|
+
if (k > end && isHead && text.atEnd(k)) {
|
|
4120
|
+
span(nameStart, text.readEnd(), op, NOT_CLOSED, true);
|
|
3810
4121
|
continue;
|
|
3811
4122
|
}
|
|
3812
|
-
if (k > end && k
|
|
4123
|
+
if (k > end && !text.atEnd(k)) {
|
|
3813
4124
|
const credEnd = readRun(k, isDiagnosticSchemeValueUnit);
|
|
3814
4125
|
if (credEnd > k)
|
|
3815
4126
|
end = credEnd;
|
|
@@ -3821,10 +4132,10 @@ function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
|
|
|
3821
4132
|
}
|
|
3822
4133
|
}
|
|
3823
4134
|
let schemeEnd = 0;
|
|
3824
|
-
DIAGNOSTIC_SCHEME_RE
|
|
3825
|
-
for (let m = DIAGNOSTIC_SCHEME_RE.exec(text); m !== null; m = DIAGNOSTIC_SCHEME_RE.exec(text)) {
|
|
4135
|
+
for (let m = text.search(DIAGNOSTIC_SCHEME_RE, 0); m !== null; m = text.search(DIAGNOSTIC_SCHEME_RE, m.index + m[0].length)) {
|
|
3826
4136
|
const at = m.index;
|
|
3827
4137
|
const q = at + m[0].length;
|
|
4138
|
+
text.attempt(at);
|
|
3828
4139
|
if (q < schemeEnd)
|
|
3829
4140
|
continue;
|
|
3830
4141
|
if (at > 0 && isRegexWordCode(text.charCodeAt(at - 1)) && deletedAt(at) === "none")
|
|
@@ -3832,9 +4143,9 @@ function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
|
|
|
3832
4143
|
const k = skipBlank(q);
|
|
3833
4144
|
if (k === q && deletedAt(q) !== "blank")
|
|
3834
4145
|
continue;
|
|
3835
|
-
if (k
|
|
4146
|
+
if (text.atEnd(k)) {
|
|
3836
4147
|
if (isHead)
|
|
3837
|
-
span(at,
|
|
4148
|
+
span(at, text.readEnd(), at, NOT_CLOSED, true);
|
|
3838
4149
|
continue;
|
|
3839
4150
|
}
|
|
3840
4151
|
const end = readRun(k, isDiagnosticSchemeValueUnit);
|
|
@@ -3852,12 +4163,14 @@ export function structuralScannerForTest(arm) {
|
|
|
3852
4163
|
};
|
|
3853
4164
|
switch (arm) {
|
|
3854
4165
|
case "json-secret-field":
|
|
3855
|
-
return { declared: new RegExp(JSON_SECRET_FIELD_PATTERN[0].source, JSON_SECRET_FIELD_PATTERN[0].flags), spans: collect(collectJsonSecretFieldSpans) };
|
|
4166
|
+
return { declared: new RegExp(JSON_SECRET_FIELD_PATTERN[0].source, JSON_SECRET_FIELD_PATTERN[0].flags), spans: collect((text, span, isHead) => collectJsonSecretFieldSpans(new ScanReader(text), span, isHead)) };
|
|
3856
4167
|
case "pem-fence":
|
|
3857
|
-
return { declared: new RegExp(PEM_FENCE_PATTERN[0].source, PEM_FENCE_PATTERN[0].flags), spans: collect((text, span, isHead) => collectPemFenceSpans(buildForensicScan(NO_TOKEN_UNITS, NO_ROWS, 1), text, span, isHead)) };
|
|
4168
|
+
return { declared: new RegExp(PEM_FENCE_PATTERN[0].source, PEM_FENCE_PATTERN[0].flags), spans: collect((text, span, isHead) => collectPemFenceSpans(buildForensicScan(NO_TOKEN_UNITS, NO_ROWS, 1, (kind) => delimPositionsOf(text, kind)), new ScanReader(text), span, isHead)) };
|
|
3858
4169
|
}
|
|
3859
4170
|
}
|
|
3860
4171
|
let ppkScanBytes = 0;
|
|
4172
|
+
const TO_END = -1;
|
|
4173
|
+
const EACH_HEAD = -1;
|
|
3861
4174
|
export function ppkScanBytesForTest() { return ppkScanBytes; }
|
|
3862
4175
|
export function resetPpkScanBytesForTest() { ppkScanBytes = 0; }
|
|
3863
4176
|
function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
@@ -3872,14 +4185,14 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3872
4185
|
if (c !== undefined && c >= from)
|
|
3873
4186
|
return c;
|
|
3874
4187
|
const p = text.indexOf(needle, from);
|
|
3875
|
-
ppkScanBytes +=
|
|
4188
|
+
ppkScanBytes += p === -1 ? 0 : p - from;
|
|
3876
4189
|
const v = p === -1 ? Number.POSITIVE_INFINITY : p;
|
|
3877
4190
|
cache.set(needle, v);
|
|
3878
4191
|
return v;
|
|
3879
4192
|
};
|
|
3880
4193
|
const versionEnd = (at) => {
|
|
3881
4194
|
let p = at + HEAD.length;
|
|
3882
|
-
while (
|
|
4195
|
+
while (!text.atEnd(p) && tokenEnd(scan, p) < 0) {
|
|
3883
4196
|
const c = text.charCodeAt(p);
|
|
3884
4197
|
if (c >= 48 && c <= 57)
|
|
3885
4198
|
p += 1;
|
|
@@ -3894,11 +4207,12 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3894
4207
|
};
|
|
3895
4208
|
const isOpenHead = (at) => {
|
|
3896
4209
|
const p = versionEnd(at);
|
|
3897
|
-
return
|
|
4210
|
+
return text.atEnd(p) || (text.atEnd(p + 1) && p > at + HEAD.length && text.charCodeAt(p) === 58);
|
|
3898
4211
|
};
|
|
3899
|
-
const nextVersionedHead = (from) => {
|
|
4212
|
+
const nextVersionedHead = (from, attemptAt) => {
|
|
3900
4213
|
let p = find(HEAD, from);
|
|
3901
4214
|
for (; p !== Number.POSITIVE_INFINITY; p = find(HEAD, p + HEAD.length)) {
|
|
4215
|
+
text.attempt(attemptAt === EACH_HEAD ? p : attemptAt);
|
|
3902
4216
|
const lineEnd = versionedHeadEnd(p);
|
|
3903
4217
|
if (lineEnd >= 0 && !lineHeld(scan, p, lineEnd, readingKey(fam, p)))
|
|
3904
4218
|
break;
|
|
@@ -3907,7 +4221,7 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3907
4221
|
};
|
|
3908
4222
|
const hexRunEnd = (from) => {
|
|
3909
4223
|
let e = from;
|
|
3910
|
-
while (
|
|
4224
|
+
while (!text.atEnd(e) && tokenEnd(scan, e) < 0) {
|
|
3911
4225
|
const c = text.charCodeAt(e);
|
|
3912
4226
|
if ((c >= 48 && c <= 57) || (c >= 97 && c <= 102) || (c >= 65 && c <= 70))
|
|
3913
4227
|
e += 1;
|
|
@@ -3916,12 +4230,13 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3916
4230
|
}
|
|
3917
4231
|
return e;
|
|
3918
4232
|
};
|
|
3919
|
-
let at = nextVersionedHead(0);
|
|
4233
|
+
let at = nextVersionedHead(0, EACH_HEAD);
|
|
3920
4234
|
while (at !== Number.POSITIVE_INFINITY) {
|
|
3921
4235
|
scan.self = readingKey(fam, at);
|
|
4236
|
+
text.attempt(at);
|
|
3922
4237
|
let pos = at + HEAD.length + 1;
|
|
3923
4238
|
let closeAt = NOT_CLOSED;
|
|
3924
|
-
let end =
|
|
4239
|
+
let end = TO_END;
|
|
3925
4240
|
let ateToEnd = !isHead;
|
|
3926
4241
|
let open = false;
|
|
3927
4242
|
for (;;) {
|
|
@@ -3942,7 +4257,7 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3942
4257
|
pos = hexStart;
|
|
3943
4258
|
continue;
|
|
3944
4259
|
}
|
|
3945
|
-
const limit = nextVersionedHead(hexEnd);
|
|
4260
|
+
const limit = nextVersionedHead(hexEnd, at);
|
|
3946
4261
|
const straggler = Math.min(find(LINES, hexEnd), find(MAC, hexEnd), find(HASH, hexEnd));
|
|
3947
4262
|
let gapBlank = true;
|
|
3948
4263
|
if (limit !== Number.POSITIVE_INFINITY) {
|
|
@@ -3956,7 +4271,7 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3956
4271
|
}
|
|
3957
4272
|
const undecided = isHead && limit === Number.POSITIVE_INFINITY;
|
|
3958
4273
|
ateToEnd = straggler < limit || !gapBlank;
|
|
3959
|
-
end = ateToEnd || undecided ?
|
|
4274
|
+
end = ateToEnd || undecided ? TO_END : hexEnd;
|
|
3960
4275
|
open = undecided;
|
|
3961
4276
|
if (end === hexEnd)
|
|
3962
4277
|
closeAt = term;
|
|
@@ -3964,14 +4279,24 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
|
|
|
3964
4279
|
}
|
|
3965
4280
|
if (ateToEnd && eat !== undefined && eat.from < 0) {
|
|
3966
4281
|
eat.from = at;
|
|
3967
|
-
eat.len = text.
|
|
4282
|
+
eat.len = text.readEnd();
|
|
3968
4283
|
}
|
|
3969
|
-
span(at, end, at, closeAt, open);
|
|
3970
|
-
at = end
|
|
4284
|
+
span(at, end === TO_END ? text.readEnd() : end, at, closeAt, open);
|
|
4285
|
+
at = end === TO_END ? Number.POSITIVE_INFINITY : nextVersionedHead(end, EACH_HEAD);
|
|
3971
4286
|
}
|
|
3972
4287
|
const last = isHead ? text.lastIndexOf(HEAD) : -1;
|
|
3973
|
-
if (last >= 0
|
|
3974
|
-
|
|
4288
|
+
if (last >= 0)
|
|
4289
|
+
text.attempt(last);
|
|
4290
|
+
if (last >= 0 && isOpenHead(last) && !lineHeld(scan, last, text.readEnd(), readingKey(fam, last)))
|
|
4291
|
+
span(last, text.readEnd(), last, NOT_CLOSED, true);
|
|
4292
|
+
}
|
|
4293
|
+
function anchoredHeadOf(prior) {
|
|
4294
|
+
switch (prior.kind) {
|
|
4295
|
+
case "anchored":
|
|
4296
|
+
return { kind: "anchors", anchors: prior.anchors };
|
|
4297
|
+
case "bounded":
|
|
4298
|
+
throw new Error("redact: a bounded arm declares no anchor literal to read its head from");
|
|
4299
|
+
}
|
|
3975
4300
|
}
|
|
3976
4301
|
const NO_GAP = (_unit) => false;
|
|
3977
4302
|
const armPool = (() => {
|
|
@@ -3981,6 +4306,9 @@ const armPool = (() => {
|
|
|
3981
4306
|
throw new Error(`redact: arm-pool replacement ${JSON.stringify(token)} may only use a leading $1 (the run kept outside the span)`);
|
|
3982
4307
|
return body;
|
|
3983
4308
|
};
|
|
4309
|
+
const headUnderivable = (re) => {
|
|
4310
|
+
throw new Error(`redact: regex arm /${re.source}/ has no derivable head — the live frontier cannot tell where an attempt that reads past the end of the text starts`);
|
|
4311
|
+
};
|
|
3984
4312
|
const regexMember = ([re, token], rank, order) => {
|
|
3985
4313
|
if (token.startsWith("$1"))
|
|
3986
4314
|
throw new Error(`redact: regex arm /${re.source}/ cannot carry an outside-span $1 prefix — that form belongs to the structural scanners`);
|
|
@@ -4003,7 +4331,7 @@ const armPool = (() => {
|
|
|
4003
4331
|
phase: 1,
|
|
4004
4332
|
lexical: LEXICAL_KEYWORD_ARMS.has(re),
|
|
4005
4333
|
diagnosticOnly: false,
|
|
4006
|
-
collect: (text, _json, _eat, out, isHead) => {
|
|
4334
|
+
collect: (text, _view, _json, _eat, out, isHead) => {
|
|
4007
4335
|
if (boundary === undefined)
|
|
4008
4336
|
collectRegexSpans(arm, text, out);
|
|
4009
4337
|
else
|
|
@@ -4020,9 +4348,10 @@ const armPool = (() => {
|
|
|
4020
4348
|
family: "prose",
|
|
4021
4349
|
reach: regexDecisionReach(re, LEXICAL_KEYWORD_ARMS.has(re)),
|
|
4022
4350
|
prior: { kind: "bounded", gap: keywordTail === undefined ? NO_GAP : (c) => keywordTail.isSeparator(String.fromCharCode(c)) },
|
|
4351
|
+
head: { kind: "units", seqs: keywordTail !== undefined ? keywordTail.forms.map((f) => [...f].map((ch) => codeUnitMembers(ch))) : d.src !== undefined ? expandHeadUnits(d.src, re.flags) : headUnderivable(re) },
|
|
4023
4352
|
};
|
|
4024
4353
|
};
|
|
4025
|
-
const scannerMember = (token, order, arm, reach, family, prior, rank = ARM_RANK.structural, lexical = false, diagnosticOnly = false) => {
|
|
4354
|
+
const scannerMember = (token, order, arm, reach, family, prior, head, rank = ARM_RANK.structural, lexical = false, diagnosticOnly = false) => {
|
|
4026
4355
|
const repl = spanRepl(token);
|
|
4027
4356
|
return {
|
|
4028
4357
|
token,
|
|
@@ -4031,16 +4360,17 @@ const armPool = (() => {
|
|
|
4031
4360
|
phase: 1,
|
|
4032
4361
|
lexical,
|
|
4033
4362
|
diagnosticOnly,
|
|
4034
|
-
collect: (
|
|
4363
|
+
collect: (_text, view, json, eat, out, isHead, deletedAt) => arm(view, json, eat, (start, end, anchor, closeAt, undecided, r = repl) => out.push(undecided === true ? { start, end, repl: r, rank, order, undecided, anchor, closeAt } : { start, end, repl: r, rank, order, anchor, closeAt }), isHead, deletedAt),
|
|
4035
4364
|
retry: undefined,
|
|
4036
4365
|
headSrc: undefined,
|
|
4037
4366
|
headFirst: undefined,
|
|
4038
4367
|
family,
|
|
4039
4368
|
reach,
|
|
4040
4369
|
prior,
|
|
4370
|
+
head,
|
|
4041
4371
|
};
|
|
4042
4372
|
};
|
|
4043
|
-
const forensicMember = (token, order, arm, reach, family, prior, rank = ARM_RANK.structural, lexical = false) => {
|
|
4373
|
+
const forensicMember = (token, order, arm, reach, family, grain, prior, head, rank = ARM_RANK.structural, lexical = false) => {
|
|
4044
4374
|
const repl = spanRepl(token);
|
|
4045
4375
|
return {
|
|
4046
4376
|
token,
|
|
@@ -4049,41 +4379,47 @@ const armPool = (() => {
|
|
|
4049
4379
|
phase: 2,
|
|
4050
4380
|
lexical,
|
|
4051
4381
|
diagnosticOnly: false,
|
|
4052
|
-
collect: (scan,
|
|
4382
|
+
collect: (scan, view, json, eat, out, isHead) => arm(scan, view, json, eat, (start, end, anchor, closeAt, undecided, r = repl) => out.push(undecided === true ? { start, end, repl: r, rank, order, undecided, anchor, closeAt } : { start, end, repl: r, rank, order, anchor, closeAt }), isHead),
|
|
4053
4383
|
retry: undefined,
|
|
4054
4384
|
headSrc: undefined,
|
|
4055
4385
|
headFirst: undefined,
|
|
4056
4386
|
family,
|
|
4057
4387
|
repl,
|
|
4388
|
+
grain,
|
|
4058
4389
|
reach,
|
|
4059
4390
|
prior,
|
|
4391
|
+
head,
|
|
4060
4392
|
};
|
|
4061
4393
|
};
|
|
4394
|
+
const PEM_ARMOR_PRIOR = { kind: "anchored", anchors: [PEM_FENCE_OPEN, PEM_END_OPEN] };
|
|
4395
|
+
const SSH2_ARMOR_PRIOR = { kind: "anchored", anchors: [SSH2_FENCE_OPEN, SSH2_FENCE_CLOSE] };
|
|
4396
|
+
const PPK_CONTAINER_PRIOR = { kind: "anchored", anchors: [PPK_FILE_HEAD] };
|
|
4397
|
+
const HEADLESS_PPK_PRIOR = { kind: "anchored", anchors: [PPK_LINES_FIELD] };
|
|
4062
4398
|
const structuralScannerMember = (row, order) => {
|
|
4063
4399
|
if (row === PEM_FENCE_PATTERN)
|
|
4064
|
-
return forensicMember(row[1], order, (scan, text, _json, _eat, span, isHead) => collectPemFenceSpans(scan, text, span, isHead), PEM_FENCE_OPEN.length, "pem-armor",
|
|
4400
|
+
return forensicMember(row[1], order, (scan, text, _json, _eat, span, isHead) => collectPemFenceSpans(scan, text, span, isHead), PEM_FENCE_OPEN.length, "pem-armor", "arm", PEM_ARMOR_PRIOR, anchoredHeadOf(PEM_ARMOR_PRIOR));
|
|
4065
4401
|
if (row === SSH2_FENCE_PATTERN)
|
|
4066
|
-
return forensicMember(row[1], order, (scan, text, json, _eat, span, isHead) => collectSsh2FenceSpans(scan, text, json, span, isHead), SSH2_FENCE_OPEN.length, "ssh2-armor",
|
|
4402
|
+
return forensicMember(row[1], order, (scan, text, json, _eat, span, isHead) => collectSsh2FenceSpans(scan, text, json, span, isHead), SSH2_FENCE_OPEN.length, "ssh2-armor", "arm", SSH2_ARMOR_PRIOR, anchoredHeadOf(SSH2_ARMOR_PRIOR));
|
|
4067
4403
|
if (row === URL_CREDENTIAL_PATTERN)
|
|
4068
|
-
return forensicMember(row[1], order, (scan, text, json, _eat, span, isHead) => collectUrlCredentialSpans(scan, text, json, span, isHead), "://".length, "url", { kind: "bounded", gap: NO_GAP });
|
|
4404
|
+
return forensicMember(row[1], order, (scan, text, json, _eat, span, isHead) => collectUrlCredentialSpans(scan, text, json, span, isHead), "://".length, "url", "segment", { kind: "bounded", gap: NO_GAP }, { kind: "anchors", anchors: ["://"] });
|
|
4069
4405
|
if (row === JSON_SECRET_FIELD_PATTERN)
|
|
4070
|
-
return scannerMember(row[1], order, (text, _json, _eat, span, isHead) => collectJsonSecretFieldSpans(text, span, isHead), JSON_FIELD_HEAD_MAX, "json-field", { kind: "bounded", gap: isRegexSpace });
|
|
4406
|
+
return scannerMember(row[1], order, (text, _json, _eat, span, isHead) => collectJsonSecretFieldSpans(text, span, isHead), JSON_FIELD_HEAD_MAX, "json-field", { kind: "bounded", gap: isRegexSpace }, { kind: "anchors", anchors: [JSON_FIELD_ANCHOR] });
|
|
4071
4407
|
throw new Error(`redact: structural row /${row[0].source}/ has no hand-written scanner — structural grammars are declared as regexes but never executed as one (S-102 / S-265)`);
|
|
4072
4408
|
};
|
|
4073
4409
|
const members = [];
|
|
4074
4410
|
for (const row of STRUCTURAL_SECRET_PATTERNS)
|
|
4075
4411
|
members.push(structuralScannerMember(row, members.length));
|
|
4076
|
-
members.push(forensicMember(PPK_CONTAINER_TOKEN, members.length, (scan, text, _json, eat, span, isHead) => collectPpkContainerSpans(scan, text, eat, span, isHead), PPK_FILE_HEAD.length, "putty-ppk",
|
|
4077
|
-
members.push(forensicMember(PEM_FRAGMENT_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectPemFragmentSpans(scan, text, json, span, isHead), PEM_FENCE_OPEN.length, "pem-armor",
|
|
4078
|
-
members.push(forensicMember(HEADLESS_PPK_TOKEN, members.length, (scan, text, _json, _eat, span, isHead) => collectHeadlessPpkSpans(scan, text, span, isHead), PPK_LINES_FIELD.length, "putty-ppk",
|
|
4079
|
-
members.push(forensicMember(ANCHORED_VALUE_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectAnchoredValueSpans(scan, text, json, span, isHead), Math.max(BEARER_VALUE_MIN, BARE_WORD_MAX + 1, STRONG_AUTH_SCHEME_MAX + 1), "anchor", { kind: "bounded", gap: (c) => isInlineSpaceUnit(c) || isSchemeDelimiterCode(c) }, ARM_RANK.keyword, true));
|
|
4412
|
+
members.push(forensicMember(PPK_CONTAINER_TOKEN, members.length, (scan, text, _json, eat, span, isHead) => collectPpkContainerSpans(scan, text, eat, span, isHead), PPK_FILE_HEAD.length, "putty-ppk", "arm", PPK_CONTAINER_PRIOR, anchoredHeadOf(PPK_CONTAINER_PRIOR)));
|
|
4413
|
+
members.push(forensicMember(PEM_FRAGMENT_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectPemFragmentSpans(scan, text, json, span, isHead), PEM_FENCE_OPEN.length, "pem-armor", "arm", PEM_ARMOR_PRIOR, anchoredHeadOf(PEM_ARMOR_PRIOR)));
|
|
4414
|
+
members.push(forensicMember(HEADLESS_PPK_TOKEN, members.length, (scan, text, _json, _eat, span, isHead) => collectHeadlessPpkSpans(scan, text, span, isHead), PPK_LINES_FIELD.length, "putty-ppk", "arm", HEADLESS_PPK_PRIOR, anchoredHeadOf(HEADLESS_PPK_PRIOR)));
|
|
4415
|
+
members.push(forensicMember(ANCHORED_VALUE_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectAnchoredValueSpans(scan, text, json, span, isHead), Math.max(BEARER_VALUE_MIN, BARE_WORD_MAX + 1, STRONG_AUTH_SCHEME_MAX + 1), "anchor", "segment", { kind: "bounded", gap: (c) => isInlineSpaceUnit(c) || isSchemeDelimiterCode(c) }, { kind: "anchors", anchors: ["=", ":"] }, ARM_RANK.keyword, true));
|
|
4080
4416
|
for (const row of KEYWORD_SECRET_PATTERNS)
|
|
4081
4417
|
members.push(regexMember(row, ARM_RANK.keyword, members.length));
|
|
4082
4418
|
for (const row of SHAPE_SECRET_PATTERNS)
|
|
4083
4419
|
members.push(regexMember(row, ARM_RANK.shape, members.length));
|
|
4084
4420
|
for (const row of FRAGMENT_SECRET_PATTERNS)
|
|
4085
4421
|
members.push(regexMember(row, ARM_RANK.fragment, members.length));
|
|
4086
|
-
members.push(scannerMember(ANCHORED_VALUE_TOKEN, members.length, (text, json, _eat, span, isHead, deletedAt) => collectDiagnosticValueSpans(text, json, span, isHead, deletedAt), Math.max(CREDENTIAL_NAME_MAX, STRONG_AUTH_SCHEME_MAX) + 2, "prose", { kind: "bounded", gap: isRegexSpace }, ARM_RANK.keyword, true, true));
|
|
4422
|
+
members.push(scannerMember(ANCHORED_VALUE_TOKEN, members.length, (text, json, _eat, span, isHead, deletedAt) => collectDiagnosticValueSpans(text, json, span, isHead, deletedAt), Math.max(CREDENTIAL_NAME_MAX, STRONG_AUTH_SCHEME_MAX) + 2, "prose", { kind: "bounded", gap: isRegexSpace }, { kind: "anchors", anchors: ["=", ":"] }, ARM_RANK.keyword, true, true));
|
|
4087
4423
|
for (const [re] of KEYWORD_SECRET_PATTERNS) {
|
|
4088
4424
|
if (!LEXICAL_KEYWORD_ARMS.has(re))
|
|
4089
4425
|
throw new Error(`redact: keyword arm /${re.source}/ is not registered as lexical — build it with keywordArm() so the bounded-unit scope can exclude it`);
|
|
@@ -4116,11 +4452,51 @@ const armPool = (() => {
|
|
|
4116
4452
|
poolArmCount = members.length;
|
|
4117
4453
|
poolBoundaryArmCount = retryMembers.length;
|
|
4118
4454
|
const reaches = members.map((m) => ({ token: m.token, order: m.order, reach: m.reach }));
|
|
4455
|
+
const viewOpenOf = (text, lane, spans, scanned) => {
|
|
4456
|
+
const n = text.length;
|
|
4457
|
+
let open = scanned;
|
|
4458
|
+
const visit = (m) => {
|
|
4459
|
+
const h = m.head;
|
|
4460
|
+
switch (h.kind) {
|
|
4461
|
+
case "units":
|
|
4462
|
+
for (let p = Math.max(0, n - m.reach); p < open; p++) {
|
|
4463
|
+
if (headFeasibleAt(h.seqs, text, p)) {
|
|
4464
|
+
open = p;
|
|
4465
|
+
break;
|
|
4466
|
+
}
|
|
4467
|
+
}
|
|
4468
|
+
return;
|
|
4469
|
+
case "anchors":
|
|
4470
|
+
for (const a of h.anchors) {
|
|
4471
|
+
for (let k = Math.min(a.length - 1, n); k > 0 && n - k < open; k--) {
|
|
4472
|
+
if (text.endsWith(a.slice(0, k))) {
|
|
4473
|
+
open = n - k;
|
|
4474
|
+
break;
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
}
|
|
4478
|
+
return;
|
|
4479
|
+
default: {
|
|
4480
|
+
const unhandled = h;
|
|
4481
|
+
throw new Error(`redact: unhandled head reading ${String(unhandled)}`);
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
};
|
|
4485
|
+
for (const m of lane.phase1)
|
|
4486
|
+
visit(m);
|
|
4487
|
+
for (const m of lane.phase2)
|
|
4488
|
+
visit(m);
|
|
4489
|
+
for (const sp of spans)
|
|
4490
|
+
if (sp.end >= n && sp.start < open && members[sp.order].head.kind === "units")
|
|
4491
|
+
open = sp.start;
|
|
4492
|
+
return open;
|
|
4493
|
+
};
|
|
4119
4494
|
const run = (text, wantCount, json, eat, scope, reach, engineMarked, deletedAt) => {
|
|
4120
4495
|
readings += 1;
|
|
4121
4496
|
const isHead = reach !== undefined;
|
|
4122
4497
|
const lane = LANES[scope];
|
|
4123
4498
|
const spans = [];
|
|
4499
|
+
const view = new ScanReader(text);
|
|
4124
4500
|
let tried;
|
|
4125
4501
|
const untriedFrom = (nu, p) => {
|
|
4126
4502
|
let q = p;
|
|
@@ -4170,11 +4546,14 @@ const armPool = (() => {
|
|
|
4170
4546
|
at = freshCovered(before);
|
|
4171
4547
|
}
|
|
4172
4548
|
};
|
|
4173
|
-
for (const m of lane.phase1)
|
|
4174
|
-
|
|
4549
|
+
for (const m of lane.phase1) {
|
|
4550
|
+
view.begin();
|
|
4551
|
+
m.collect(text, view, json, eat, spans, isHead, deletedAt);
|
|
4552
|
+
}
|
|
4175
4553
|
closeCoveragePositions(0);
|
|
4554
|
+
let evidence;
|
|
4176
4555
|
if (lane.phase2.length > 0) {
|
|
4177
|
-
const scan = buildForensicScan(tokenUnits(text), buildEvidenceRows(text), lane.phase2.length);
|
|
4556
|
+
const scan = buildForensicScan(tokenUnits(text), buildEvidenceRows(text), lane.phase2.length, (kind) => delimPositionsOf(text, kind));
|
|
4178
4557
|
const reuse = forensicRescanMode === "incremental";
|
|
4179
4558
|
const foot = scan.armFoot;
|
|
4180
4559
|
let dirty;
|
|
@@ -4193,15 +4572,29 @@ const armPool = (() => {
|
|
|
4193
4572
|
scan.self = NO_SELF;
|
|
4194
4573
|
scan.footLo = FOOT_NONE;
|
|
4195
4574
|
scan.footHi = -1;
|
|
4196
|
-
lane.phase2[j]
|
|
4575
|
+
const arm = lane.phase2[j];
|
|
4576
|
+
view.begin();
|
|
4577
|
+
arm.collect(scan, view, json, level === 0 ? eat : undefined, spans, isHead);
|
|
4197
4578
|
foot[2 * j] = scan.footLo;
|
|
4198
4579
|
foot[2 * j + 1] = scan.footHi;
|
|
4199
4580
|
forensicRuns += 1;
|
|
4581
|
+
switch (arm.grain) {
|
|
4582
|
+
case "arm":
|
|
4583
|
+
noteExecution(scan, scan.footLo, scan.footHi, scan.footLo);
|
|
4584
|
+
break;
|
|
4585
|
+
case "segment":
|
|
4586
|
+
break;
|
|
4587
|
+
default: {
|
|
4588
|
+
const unhandled = arm.grain;
|
|
4589
|
+
throw new Error(`redact: unhandled evidence grain ${String(unhandled)}`);
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4200
4592
|
}
|
|
4201
4593
|
closeCoveragePositions(before);
|
|
4202
4594
|
forensicLevels += 1;
|
|
4203
4595
|
const grown = foldEvidenceRows(scan.rows, spans, folded, (o) => familyCodeOfOrder[o]);
|
|
4204
4596
|
folded = spans.length;
|
|
4597
|
+
evidence = { execs: scan.execs, rows: grown.next };
|
|
4205
4598
|
if (grown.dirty.starts.length === 0)
|
|
4206
4599
|
break;
|
|
4207
4600
|
if (level + 1 >= FORENSIC_LEVEL_MAX) {
|
|
@@ -4224,9 +4617,12 @@ const armPool = (() => {
|
|
|
4224
4617
|
}
|
|
4225
4618
|
poolSpanCount += spans.length;
|
|
4226
4619
|
const survives = (sp) => !engineMarked(sp.start, sp.end, sp.repl) && (sp.undecided !== true || reach === undefined || reach(sp.start));
|
|
4227
|
-
const
|
|
4620
|
+
const cover = spans.filter(survives);
|
|
4621
|
+
const kept = resolveSpanOverlaps(cover);
|
|
4622
|
+
const open = isHead ? viewOpenOf(text, lane, spans, view.open) : text.length;
|
|
4623
|
+
const unattributed = view.unattributed;
|
|
4228
4624
|
if (!wantCount || kept.length === 0)
|
|
4229
|
-
return { hits: NO_HITS, kept };
|
|
4625
|
+
return { hits: NO_HITS, kept, cover, evidence, open, unattributed };
|
|
4230
4626
|
const tokenOf = (sp) => members[sp.order].token;
|
|
4231
4627
|
const strong = spans.filter((sp) => armOfToken(tokenOf(sp)) === "full" && survives(sp)).sort((a, b) => a.start - b.start);
|
|
4232
4628
|
const byArmedToken = new Map();
|
|
@@ -4248,9 +4644,9 @@ const armPool = (() => {
|
|
|
4248
4644
|
cur.count += 1;
|
|
4249
4645
|
stamped.push({ ...sp, hit: { token, arm } });
|
|
4250
4646
|
}
|
|
4251
|
-
return { hits: [...byArmedToken.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm })), kept: stamped };
|
|
4647
|
+
return { hits: [...byArmedToken.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm })), kept: stamped, cover, evidence, open, unattributed };
|
|
4252
4648
|
};
|
|
4253
|
-
return Object.assign(run, { reaches,
|
|
4649
|
+
return Object.assign(run, { reaches, maxDecisionReach: Math.max(...reaches.map((r) => r.reach)), priors: members.map((m) => m.prior) });
|
|
4254
4650
|
})();
|
|
4255
4651
|
let onRedaction;
|
|
4256
4652
|
export function setRedactionObserver(fn) {
|
|
@@ -4274,9 +4670,9 @@ export const WHOLE_EXTENT = { kind: "whole" };
|
|
|
4274
4670
|
function invisibleClassesOf(layout) {
|
|
4275
4671
|
switch (layout) {
|
|
4276
4672
|
case "multi-line":
|
|
4277
|
-
return SPELLED_FORMAT | SPELLED_CONTROL | RAW_CONTROL;
|
|
4673
|
+
return SPELLED_FORMAT | SPELLED_CONTROL | RAW_CONTROL | RAW_IGNORABLE;
|
|
4278
4674
|
case "single-line":
|
|
4279
|
-
return SPELLED_FORMAT | SPELLED_CONTROL | RAW_CONTROL | RAW_WHITESPACE;
|
|
4675
|
+
return SPELLED_FORMAT | SPELLED_CONTROL | RAW_CONTROL | RAW_WHITESPACE | RAW_IGNORABLE;
|
|
4280
4676
|
default: {
|
|
4281
4677
|
const unhandled = layout;
|
|
4282
4678
|
throw new Error(`redact: unhandled layout ${String(unhandled)}`);
|
|
@@ -4317,14 +4713,19 @@ export function readingHeadEnd(text, layout, units, from = 0) {
|
|
|
4317
4713
|
}
|
|
4318
4714
|
return text.length;
|
|
4319
4715
|
}
|
|
4320
|
-
function runRedaction(text, observe, json, wantHits, scope, layout, extent, observeFrom = 0) {
|
|
4716
|
+
function runRedaction(text, observe, json, wantHits, scope, layout, extent, observeFrom = 0, joints = NO_JOINTS) {
|
|
4321
4717
|
scannedUnits += text.length;
|
|
4322
4718
|
const wantCount = wantHits || (onRedaction !== undefined && observe);
|
|
4323
4719
|
const eat = observe ? { from: -1, len: 0, capFrom: -1, capLen: 0 } : undefined;
|
|
4324
4720
|
let spans = [];
|
|
4721
|
+
const cover = [];
|
|
4325
4722
|
let hits = NO_HITS;
|
|
4326
4723
|
let readsSoFar = 0;
|
|
4327
4724
|
let unioned = false;
|
|
4725
|
+
const evidence = [];
|
|
4726
|
+
let lattice = text.length;
|
|
4727
|
+
let viewOpen = text.length;
|
|
4728
|
+
let unattributed = false;
|
|
4328
4729
|
const read = (layers, view) => {
|
|
4329
4730
|
const toOriginal = createViewToOriginal(layers);
|
|
4330
4731
|
const reach = extent.kind === "head" ? (viewStart) => toOriginal.start(viewStart) < extent.emitEnd : undefined;
|
|
@@ -4343,7 +4744,17 @@ function runRedaction(text, observe, json, wantHits, scope, layout, extent, obse
|
|
|
4343
4744
|
};
|
|
4344
4745
|
const r = applyRules(view, wantCount, json, eat, scope, reach, engineMarked, deletedAt);
|
|
4345
4746
|
forgetEscapedSeparatorTails();
|
|
4747
|
+
if (r.evidence !== undefined && (r.evidence.execs.length > 0 || r.evidence.rows.starts.length > 0)) {
|
|
4748
|
+
const viewLength = view.length;
|
|
4749
|
+
evidence.push({ execs: r.evidence.execs, rows: r.evidence.rows, at: (v) => (v >= viewLength ? text.length : toOriginal.start(v)) });
|
|
4750
|
+
}
|
|
4751
|
+
if (r.open < view.length)
|
|
4752
|
+
viewOpen = Math.min(viewOpen, toOriginal.start(r.open));
|
|
4753
|
+
if (r.unattributed)
|
|
4754
|
+
unattributed = true;
|
|
4346
4755
|
readsSoFar += 1;
|
|
4756
|
+
for (const sp of toOriginal.spans(r.cover))
|
|
4757
|
+
cover.push(sp);
|
|
4347
4758
|
if (readsSoFar === 1) {
|
|
4348
4759
|
spans = toOriginal.spans(r.kept);
|
|
4349
4760
|
hits = r.hits;
|
|
@@ -4360,6 +4771,7 @@ function runRedaction(text, observe, json, wantHits, scope, layout, extent, obse
|
|
|
4360
4771
|
const rfold = deleteInvisibleCharacters(text, raw, rmask);
|
|
4361
4772
|
const normalized = normalizeForRedaction(rfold.text);
|
|
4362
4773
|
const spelled = collectSpelledCuts(normalized);
|
|
4774
|
+
lattice = Math.min(lattice, latticeOpenOf(text.length, rfold, normalized, spelled.open));
|
|
4363
4775
|
for (let smask = 0;; smask = (smask - spelled.present) & spelled.present) {
|
|
4364
4776
|
const sfold = deleteInvisibleCharacters(normalized, spelled, smask);
|
|
4365
4777
|
read([{ fold: sfold }, { input: rfold.text, view: normalized }, { fold: rfold }], sfold.text);
|
|
@@ -4375,9 +4787,21 @@ function runRedaction(text, observe, json, wantHits, scope, layout, extent, obse
|
|
|
4375
4787
|
recordFailOpen("server.redact.ppk-eat-to-end", `from=${eat.from} len=${eat.len}`);
|
|
4376
4788
|
if (eat !== undefined && eat.capFrom >= 0)
|
|
4377
4789
|
recordFailOpen("server.redact.forensic-level-cap", `from=${eat.capFrom} len=${eat.capLen}`);
|
|
4790
|
+
if (observe && unattributed)
|
|
4791
|
+
recordFailOpen("server.redact.scan-view-unattributed", `len=${text.length}`);
|
|
4378
4792
|
if (observe)
|
|
4379
4793
|
reportHits(observeFrom === 0 ? hits : hitsOfSpans(spans.filter((sp) => sp.end > observeFrom)));
|
|
4380
|
-
|
|
4794
|
+
const groups = mergeRedactionSpans(cover, poolTie, joints);
|
|
4795
|
+
return { text: renderRedactionSpans(text, groups, 0, text.length), hits, spans: groups, crossed: jointsCrossedBy(spans, joints), evidence, lattice, view: viewOpen };
|
|
4796
|
+
}
|
|
4797
|
+
function latticeOpenOf(n, rfold, normalized, open) {
|
|
4798
|
+
let at = n;
|
|
4799
|
+
if (open >= 0)
|
|
4800
|
+
at = createViewToOriginal([{ input: rfold.text, view: normalized }, { fold: rfold }]).start(open);
|
|
4801
|
+
const last = rfold.text.length - 1;
|
|
4802
|
+
if (last >= 0 && (rfold.text.charCodeAt(last) & 0xfc00) === 0xd800)
|
|
4803
|
+
at = Math.min(at, createViewToOriginal([{ fold: rfold }]).start(last));
|
|
4804
|
+
return at;
|
|
4381
4805
|
}
|
|
4382
4806
|
function hitsOfSpans(spans) {
|
|
4383
4807
|
const by = new Map();
|
|
@@ -4415,8 +4839,8 @@ export function redactSecrets(text, opts) {
|
|
|
4415
4839
|
if (before === "")
|
|
4416
4840
|
return runRedaction(text, opts?.observe ?? true, opts?.json === true, false, "free-text", "multi-line", WHOLE_EXTENT).text;
|
|
4417
4841
|
const whole = before + text;
|
|
4418
|
-
const r = runRedaction(whole, opts?.observe ?? true, opts?.json === true, false, "free-text", "multi-line", WHOLE_EXTENT, before.length);
|
|
4419
|
-
return
|
|
4842
|
+
const r = runRedaction(whole, opts?.observe ?? true, opts?.json === true, false, "free-text", "multi-line", WHOLE_EXTENT, before.length, [before.length]);
|
|
4843
|
+
return renderRedactionSpans(whole, r.spans, before.length, whole.length);
|
|
4420
4844
|
}
|
|
4421
4845
|
export function redactSecretsWithArms(text, opts) {
|
|
4422
4846
|
const r = runRedaction(text, opts?.observe ?? true, opts?.json === true, true, "free-text", "multi-line", WHOLE_EXTENT);
|
|
@@ -4426,21 +4850,136 @@ export function redactionSpansForTest(text, opts) {
|
|
|
4426
4850
|
const r = runRedaction(text, false, opts?.json === true, false, opts?.scope ?? "free-text", "multi-line", WHOLE_EXTENT);
|
|
4427
4851
|
return { text: r.text, spans: r.spans.map((sp) => ({ start: sp.start, end: sp.end })) };
|
|
4428
4852
|
}
|
|
4429
|
-
export function proposeRedactionSpans(text, scope, layout, extent) {
|
|
4430
|
-
return runRedaction(text, true,
|
|
4853
|
+
export function proposeRedactionSpans(text, scope, layout, extent, json) {
|
|
4854
|
+
return runRedaction(text, true, json, false, scope, layout, extent).spans.map((sp) => ({ start: sp.start, end: sp.end, repl: sp.repl }));
|
|
4431
4855
|
}
|
|
4432
|
-
export const
|
|
4856
|
+
export const MAX_DECISION_REACH = armPool.maxDecisionReach;
|
|
4433
4857
|
export function regexDecisionReachForTest(re, lexical) {
|
|
4434
4858
|
return regexDecisionReach(re, lexical);
|
|
4435
4859
|
}
|
|
4436
|
-
export function
|
|
4860
|
+
export function decisionReachForTest() {
|
|
4437
4861
|
return armPool.reaches;
|
|
4438
4862
|
}
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4863
|
+
const FRONTIER_TERMS = {
|
|
4864
|
+
view: (m) => m.view,
|
|
4865
|
+
lattice: (m) => m.lattice,
|
|
4866
|
+
token: (m) => m.token,
|
|
4867
|
+
evidence: (m, f) => m.evidence(f),
|
|
4868
|
+
coverage: (m) => m.n,
|
|
4869
|
+
};
|
|
4870
|
+
const READ_PORTS = Object.keys(FRONTIER_TERMS);
|
|
4871
|
+
function settledFrontier(m) {
|
|
4872
|
+
let f = m.n;
|
|
4873
|
+
for (;;) {
|
|
4874
|
+
let next = f;
|
|
4875
|
+
for (const k of READ_PORTS)
|
|
4876
|
+
next = Math.min(next, FRONTIER_TERMS[k](m, next));
|
|
4877
|
+
if (next >= f)
|
|
4878
|
+
return f;
|
|
4879
|
+
f = next;
|
|
4880
|
+
}
|
|
4442
4881
|
}
|
|
4443
|
-
function
|
|
4882
|
+
function tokenTailOpen(text) {
|
|
4883
|
+
const n = text.length;
|
|
4884
|
+
const p = text.lastIndexOf("«");
|
|
4885
|
+
if (p < 0)
|
|
4886
|
+
return n;
|
|
4887
|
+
const e = tokenUnitEnd(text, p);
|
|
4888
|
+
if (e < 0)
|
|
4889
|
+
return n - p < TOKEN_UNIT_REACH && text.indexOf("»", p) < 0 ? p : n;
|
|
4890
|
+
if (e !== n)
|
|
4891
|
+
return n;
|
|
4892
|
+
let start = p;
|
|
4893
|
+
while (start > 0) {
|
|
4894
|
+
const q = text.lastIndexOf("«", start - 1);
|
|
4895
|
+
if (q < 0 || tokenUnitEnd(text, q) < start)
|
|
4896
|
+
break;
|
|
4897
|
+
start = q;
|
|
4898
|
+
}
|
|
4899
|
+
return start;
|
|
4900
|
+
}
|
|
4901
|
+
const TOKEN_UNIT_REACH = regexDecisionReach(TOKEN_UNIT_Y, false);
|
|
4902
|
+
function createEvidenceFrontier(readings) {
|
|
4903
|
+
const prepared = readings.filter((r) => r.execs.length > 0).map((r) => {
|
|
4904
|
+
const E = r.execs.length / 3;
|
|
4905
|
+
const order = Array.from({ length: E }, (_, i) => i);
|
|
4906
|
+
const hi = Float64Array.from(order, (i) => r.at(r.execs[3 * i + 1]));
|
|
4907
|
+
const from = Float64Array.from(order, (i) => r.at(r.execs[3 * i + 2]));
|
|
4908
|
+
order.sort((x, y) => hi[y] - hi[x]);
|
|
4909
|
+
const t = r.rows;
|
|
4910
|
+
const iv = [];
|
|
4911
|
+
for (let k = 0; k < t.starts.length; k++) {
|
|
4912
|
+
const s = r.at(t.starts[k]);
|
|
4913
|
+
const c = t.closeAt[k];
|
|
4914
|
+
const d = Math.max(r.at(t.ends[k] - 1) + 1, c >= 0 ? r.at(c) + 1 : 0);
|
|
4915
|
+
if (d - s >= 2)
|
|
4916
|
+
iv.push([s, d]);
|
|
4917
|
+
}
|
|
4918
|
+
iv.sort((a, b) => a[0] - b[0]);
|
|
4919
|
+
const segS = [];
|
|
4920
|
+
const segE = [];
|
|
4921
|
+
for (const [s, d] of iv) {
|
|
4922
|
+
const last = segE.length - 1;
|
|
4923
|
+
if (last >= 0 && s < segE[last])
|
|
4924
|
+
segE[last] = Math.max(segE[last], d);
|
|
4925
|
+
else {
|
|
4926
|
+
segS.push(s);
|
|
4927
|
+
segE.push(d);
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
const horizon = (f) => {
|
|
4931
|
+
let a = 0;
|
|
4932
|
+
let b = segS.length;
|
|
4933
|
+
while (a < b) {
|
|
4934
|
+
const mid = (a + b) >>> 1;
|
|
4935
|
+
if (segS[mid] < f)
|
|
4936
|
+
a = mid + 1;
|
|
4937
|
+
else
|
|
4938
|
+
b = mid;
|
|
4939
|
+
}
|
|
4940
|
+
return a > 0 && f < segE[a - 1] ? segS[a - 1] : f;
|
|
4941
|
+
};
|
|
4942
|
+
return { order, hi, from, horizon };
|
|
4943
|
+
});
|
|
4944
|
+
if (prepared.length === 0)
|
|
4945
|
+
return (f) => f;
|
|
4946
|
+
return (f) => {
|
|
4947
|
+
let out = f;
|
|
4948
|
+
for (const p of prepared) {
|
|
4949
|
+
let cur = f;
|
|
4950
|
+
let least = Infinity;
|
|
4951
|
+
for (let k = 0;;) {
|
|
4952
|
+
const fev = p.horizon(cur);
|
|
4953
|
+
while (k < p.order.length && p.hi[p.order[k]] >= fev)
|
|
4954
|
+
least = Math.min(least, p.from[p.order[k++]]);
|
|
4955
|
+
if (least >= cur)
|
|
4956
|
+
break;
|
|
4957
|
+
cur = least;
|
|
4958
|
+
}
|
|
4959
|
+
out = Math.min(out, cur);
|
|
4960
|
+
}
|
|
4961
|
+
return out;
|
|
4962
|
+
};
|
|
4963
|
+
}
|
|
4964
|
+
export function evidenceFrontierForTest(execs, rows, f) {
|
|
4965
|
+
const t = {
|
|
4966
|
+
starts: Int32Array.from(rows, (r) => r[0]),
|
|
4967
|
+
ends: Int32Array.from(rows, (r) => r[1]),
|
|
4968
|
+
family: new Uint8Array(rows.length),
|
|
4969
|
+
anchor: Int32Array.from(rows, (r) => r[0]),
|
|
4970
|
+
closeAt: Int32Array.from(rows, (r) => r[2]),
|
|
4971
|
+
};
|
|
4972
|
+
return createEvidenceFrontier([{ execs: execs.flat(), rows: t, at: (v) => v }])(f);
|
|
4973
|
+
}
|
|
4974
|
+
export function forensicExecutionsForTest(text) {
|
|
4975
|
+
const out = [];
|
|
4976
|
+
for (const r of runRedaction(text, false, false, false, "free-text", "multi-line", { kind: "head", emitEnd: text.length }).evidence) {
|
|
4977
|
+
for (let k = 0; k < r.execs.length; k += 3)
|
|
4978
|
+
out.push([r.at(r.execs[k]), r.at(r.execs[k + 1]), r.at(r.execs[k + 2])]);
|
|
4979
|
+
}
|
|
4980
|
+
return out;
|
|
4981
|
+
}
|
|
4982
|
+
export function renderRedactionSpans(text, spans, from, until) {
|
|
4444
4983
|
if (from >= until)
|
|
4445
4984
|
return "";
|
|
4446
4985
|
const parts = [];
|
|
@@ -4459,9 +4998,11 @@ function renderRange(text, spans, from, until) {
|
|
|
4459
4998
|
parts.push(text.slice(at, until));
|
|
4460
4999
|
return parts.join("");
|
|
4461
5000
|
}
|
|
4462
|
-
const
|
|
4463
|
-
const streamRescanStep = (n) => Math.max(STREAM_RESCAN_MIN, n >>> 5);
|
|
5001
|
+
const streamRescanStep = (n) => Math.max(1, n >>> 5);
|
|
4464
5002
|
const STREAM_WINDOW_HORIZON = 2;
|
|
5003
|
+
if (STREAM_WINDOW_HORIZON * MAX_DECISION_REACH > MAX_RECOGNITION_SPAN) {
|
|
5004
|
+
throw new Error(`redact: the horizon of the scan window (${STREAM_WINDOW_HORIZON} × ${MAX_DECISION_REACH} units) exceeds the longest recognition span (${MAX_RECOGNITION_SPAN}) — the exit seat's margin would be shorter than what a decision reads`);
|
|
5005
|
+
}
|
|
4465
5006
|
const STREAM_WINDOW_MIN = 2048;
|
|
4466
5007
|
function deriveStreamWindowAlphabets(priors) {
|
|
4467
5008
|
const blank = new Uint8Array(0x10000);
|
|
@@ -4481,7 +5022,7 @@ function deriveStreamWindowAlphabets(priors) {
|
|
|
4481
5022
|
throw new Error("redact: an anchored arm declares an empty anchor literal");
|
|
4482
5023
|
for (let i = 0; i < anchor.length; i++) {
|
|
4483
5024
|
const c = anchor.charCodeAt(i);
|
|
4484
|
-
if (INVISIBLE_UNIT_CLASS[c] !== 0 || FORMAT_CODEPOINT_TABLE[c] === 1 || (c & 0xf800) === 0xd800 || c === CH_BACKSLASH) {
|
|
5025
|
+
if (INVISIBLE_UNIT_CLASS[c] !== 0 || FORMAT_CODEPOINT_TABLE[c] === 1 || isReadingIgnorable(c) || (c & 0xf800) === 0xd800 || c === CH_BACKSLASH) {
|
|
4485
5026
|
throw new Error(`redact: anchor literal ${JSON.stringify(anchor)} holds a unit some reading deletes or reads as an escape (index ${i}) — its presence is not monotone under deletion, so the stream window's delimiter check on the most-deleted reading would be incomplete`);
|
|
4486
5027
|
}
|
|
4487
5028
|
}
|
|
@@ -4545,15 +5086,70 @@ function windowAdvancePoint(text, units, alphabets = STREAM_WINDOW_ALPHABETS) {
|
|
|
4545
5086
|
return at <= 0 ? 0 : text.lastIndexOf("\n", at - 1) + 1;
|
|
4546
5087
|
}
|
|
4547
5088
|
function windowIndependentAt(text, q) {
|
|
4548
|
-
|
|
5089
|
+
return windowVerdictAt(text, q) === "independent";
|
|
5090
|
+
}
|
|
5091
|
+
function windowVerdictAt(text, q) {
|
|
5092
|
+
const fullRun = runRedaction(text, false, false, false, "free-text", "multi-line", { kind: "head", emitEnd: text.length });
|
|
5093
|
+
const full = fullRun.spans;
|
|
4549
5094
|
if (full.some((s) => s.start < q && s.end > q))
|
|
4550
|
-
return
|
|
5095
|
+
return "span-straddles";
|
|
5096
|
+
if (fullRun.evidence.some((r) => footprintStraddles(r, q)))
|
|
5097
|
+
return "footprint-straddles";
|
|
5098
|
+
if (fullRun.evidence.some((r) => rowStraddles(r, q)))
|
|
5099
|
+
return "row-straddles";
|
|
4551
5100
|
const after = full.filter((s) => s.start >= q);
|
|
4552
5101
|
const tail = text.slice(q);
|
|
4553
|
-
const
|
|
5102
|
+
const aloneRun = runRedaction(tail, false, false, false, "free-text", "multi-line", { kind: "head", emitEnd: tail.length });
|
|
5103
|
+
const alone = aloneRun.spans;
|
|
4554
5104
|
if (after.length !== alone.length)
|
|
5105
|
+
return "spans-differ";
|
|
5106
|
+
if (!after.every((a, i) => a.start - q === alone[i].start && a.end - q === alone[i].end && a.repl === alone[i].repl))
|
|
5107
|
+
return "spans-differ";
|
|
5108
|
+
if (!sameRowSet(rowKeysFrom(fullRun.evidence, q), rowKeysFrom(aloneRun.evidence, 0)))
|
|
5109
|
+
return "rows-differ";
|
|
5110
|
+
return fullRun.view < q ? "view-straddles" : "independent";
|
|
5111
|
+
}
|
|
5112
|
+
export function windowVerdictAtForTest(text, q) {
|
|
5113
|
+
return windowVerdictAt(text, q);
|
|
5114
|
+
}
|
|
5115
|
+
function footprintStraddles(r, q) {
|
|
5116
|
+
for (let k = 0; k < r.execs.length; k += 3)
|
|
5117
|
+
if (r.at(r.execs[k]) < q && r.at(r.execs[k + 1]) >= q)
|
|
5118
|
+
return true;
|
|
5119
|
+
return false;
|
|
5120
|
+
}
|
|
5121
|
+
function rowStraddles(r, q) {
|
|
5122
|
+
const t = r.rows;
|
|
5123
|
+
for (let k = 0; k < t.starts.length; k++) {
|
|
5124
|
+
if (r.at(t.starts[k]) >= q)
|
|
5125
|
+
continue;
|
|
5126
|
+
const c = t.closeAt[k];
|
|
5127
|
+
if (Math.max(r.at(t.ends[k] - 1) + 1, c >= 0 ? r.at(c) + 1 : 0) > q)
|
|
5128
|
+
return true;
|
|
5129
|
+
}
|
|
5130
|
+
return false;
|
|
5131
|
+
}
|
|
5132
|
+
function rowKeysFrom(readings, q) {
|
|
5133
|
+
const keys = new Set();
|
|
5134
|
+
for (const r of readings) {
|
|
5135
|
+
const t = r.rows;
|
|
5136
|
+
for (let k = 0; k < t.starts.length; k++) {
|
|
5137
|
+
const s = r.at(t.starts[k]);
|
|
5138
|
+
if (s < q)
|
|
5139
|
+
continue;
|
|
5140
|
+
const c = t.closeAt[k];
|
|
5141
|
+
keys.add(`${s - q},${r.at(t.ends[k] - 1) + 1 - q},${t.family[k]},${r.at(t.anchor[k]) - q},${c >= 0 ? r.at(c) - q : -1}`);
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
return keys;
|
|
5145
|
+
}
|
|
5146
|
+
function sameRowSet(a, b) {
|
|
5147
|
+
if (a.size !== b.size)
|
|
4555
5148
|
return false;
|
|
4556
|
-
|
|
5149
|
+
for (const k of a)
|
|
5150
|
+
if (!b.has(k))
|
|
5151
|
+
return false;
|
|
5152
|
+
return true;
|
|
4557
5153
|
}
|
|
4558
5154
|
export function windowAdvancePointForTest(text, units, extra = []) {
|
|
4559
5155
|
return windowAdvancePoint(text, units, extra.length === 0 ? STREAM_WINDOW_ALPHABETS : deriveStreamWindowAlphabets([...armPool.priors, ...extra]));
|
|
@@ -4562,18 +5158,53 @@ export function windowIndependentAtForTest(text, q) {
|
|
|
4562
5158
|
return windowIndependentAt(text, q);
|
|
4563
5159
|
}
|
|
4564
5160
|
export function createRedactionStream() {
|
|
4565
|
-
return openRedactionStream(
|
|
5161
|
+
return openRedactionStream();
|
|
4566
5162
|
}
|
|
4567
5163
|
export function createRedactionStreamWithoutWindowForTest() {
|
|
4568
|
-
return openRedactionStream(
|
|
5164
|
+
return openRedactionStream(false);
|
|
4569
5165
|
}
|
|
4570
5166
|
export function createRedactionStreamWithCertifierForTest(certify) {
|
|
4571
|
-
return openRedactionStream(
|
|
4572
|
-
}
|
|
4573
|
-
export function
|
|
4574
|
-
return openRedactionStream(
|
|
4575
|
-
}
|
|
4576
|
-
function
|
|
5167
|
+
return openRedactionStream(true, certify);
|
|
5168
|
+
}
|
|
5169
|
+
export function createRedactionStreamWithFrontierForTest(adjust) {
|
|
5170
|
+
return openRedactionStream(true, windowIndependentAt, adjust);
|
|
5171
|
+
}
|
|
5172
|
+
function settledCut(win, joints = NO_JOINTS) {
|
|
5173
|
+
const n = win.length;
|
|
5174
|
+
let rounds = 1;
|
|
5175
|
+
let r = runRedaction(win, false, false, false, "free-text", "multi-line", { kind: "head", emitEnd: n }, 0, joints);
|
|
5176
|
+
const lattice = r.lattice;
|
|
5177
|
+
const token = tokenTailOpen(win);
|
|
5178
|
+
let scanned = n;
|
|
5179
|
+
for (let tail = Math.min(lattice, token), back = 1; tail < scanned; back *= 2) {
|
|
5180
|
+
scanned = Math.max(0, Math.min(tail, scanned - back));
|
|
5181
|
+
const head = win.slice(0, scanned);
|
|
5182
|
+
r = runRedaction(head, false, false, false, "free-text", "multi-line", { kind: "head", emitEnd: scanned }, 0, joints);
|
|
5183
|
+
rounds += 1;
|
|
5184
|
+
tail = Math.min(r.lattice, tokenTailOpen(head));
|
|
5185
|
+
}
|
|
5186
|
+
const spans = r.spans;
|
|
5187
|
+
const inputs = { n, view: r.view, lattice, token, evidence: createEvidenceFrontier(r.evidence) };
|
|
5188
|
+
const frontier = settledFrontier(inputs);
|
|
5189
|
+
let cut = frontier;
|
|
5190
|
+
for (const s of spans)
|
|
5191
|
+
if (s.start < cut && (s.end >= cut || s.end >= scanned))
|
|
5192
|
+
cut = s.start;
|
|
5193
|
+
return { cut, spans, inputs, frontier, rounds };
|
|
5194
|
+
}
|
|
5195
|
+
export function settledCutsForTest(text) {
|
|
5196
|
+
const s = settledCut(text);
|
|
5197
|
+
const terms = Object.fromEntries(READ_PORTS.map((k) => [k, FRONTIER_TERMS[k](s.inputs, s.frontier)]));
|
|
5198
|
+
return { cut: s.cut, settled: renderRedactionSpans(text, s.spans, 0, s.cut), frontier: s.frontier, terms, rounds: s.rounds };
|
|
5199
|
+
}
|
|
5200
|
+
export function createScanViewForTest(text) {
|
|
5201
|
+
const r = new ScanReader(text);
|
|
5202
|
+
return { view: r, open: () => r.open, unattributed: () => r.unattributed };
|
|
5203
|
+
}
|
|
5204
|
+
export function expandHeadUnitsForTest(src, flags = "g") {
|
|
5205
|
+
return expandHeadUnits(src, flags).length;
|
|
5206
|
+
}
|
|
5207
|
+
function openRedactionStream(windowed = true, certify = windowIndependentAt, adjust = 0) {
|
|
4577
5208
|
let past = [];
|
|
4578
5209
|
let total = 0;
|
|
4579
5210
|
let win = "";
|
|
@@ -4584,6 +5215,8 @@ function openRedactionStream(pendingTail, windowed = true, certify = windowIndep
|
|
|
4584
5215
|
let sent = "";
|
|
4585
5216
|
let scannedAt = 0;
|
|
4586
5217
|
let evaluatedAt = -1;
|
|
5218
|
+
const commits = [];
|
|
5219
|
+
const jointsInWindow = () => (commits.length === 0 ? NO_JOINTS : commits.filter((c) => c > base).map((c) => c - base));
|
|
4587
5220
|
let retryAt = 0;
|
|
4588
5221
|
const whole = () => (past.length === 0 ? win : past.join("") + win);
|
|
4589
5222
|
const advanceWindow = () => {
|
|
@@ -4592,7 +5225,7 @@ function openRedactionStream(pendingTail, windowed = true, certify = windowIndep
|
|
|
4592
5225
|
evaluatedAt = total;
|
|
4593
5226
|
retryAt = win.length + (win.length >> 1);
|
|
4594
5227
|
windowEvaluations += 1;
|
|
4595
|
-
const q = windowAdvancePoint(win, STREAM_WINDOW_HORIZON *
|
|
5228
|
+
const q = windowAdvancePoint(win, STREAM_WINDOW_HORIZON * MAX_DECISION_REACH);
|
|
4596
5229
|
if (q < 0) {
|
|
4597
5230
|
retryAt = 0;
|
|
4598
5231
|
return;
|
|
@@ -4615,25 +5248,18 @@ function openRedactionStream(pendingTail, windowed = true, certify = windowIndep
|
|
|
4615
5248
|
total += chunk.length;
|
|
4616
5249
|
},
|
|
4617
5250
|
takeSettled() {
|
|
4618
|
-
if (total -
|
|
4619
|
-
return "";
|
|
4620
|
-
if (total - scannedAt < streamRescanStep(total))
|
|
5251
|
+
if (released === total || total - scannedAt < streamRescanStep(total))
|
|
4621
5252
|
return "";
|
|
4622
5253
|
scannedAt = total;
|
|
4623
|
-
const emitEnd = pendingTailStart(win, pendingTail);
|
|
4624
5254
|
const from = released - base;
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
let cut = emitEnd;
|
|
4629
|
-
for (const s of spans)
|
|
4630
|
-
if (s.start < cut && s.end > cut)
|
|
4631
|
-
cut = s.start;
|
|
5255
|
+
const settled = settledCut(win, jointsInWindow());
|
|
5256
|
+
const spans = settled.spans;
|
|
5257
|
+
let cut = Math.min(win.length, settled.cut + adjust);
|
|
4632
5258
|
if (cut > 0 && cut < win.length && (win.charCodeAt(cut - 1) & 0xfc00) === 0xd800 && (win.charCodeAt(cut) & 0xfc00) === 0xdc00)
|
|
4633
5259
|
cut -= 1;
|
|
4634
5260
|
if (cut <= from)
|
|
4635
5261
|
return "";
|
|
4636
|
-
const out =
|
|
5262
|
+
const out = renderRedactionSpans(win, spans, from, cut);
|
|
4637
5263
|
released = base + cut;
|
|
4638
5264
|
sent += out;
|
|
4639
5265
|
return out;
|
|
@@ -4641,9 +5267,10 @@ function openRedactionStream(pendingTail, windowed = true, certify = windowIndep
|
|
|
4641
5267
|
takeAll() {
|
|
4642
5268
|
if (released === total)
|
|
4643
5269
|
return "";
|
|
4644
|
-
const spans = runRedaction(win, false, false, false, "free-text", "multi-line", WHOLE_EXTENT).spans;
|
|
4645
|
-
const out =
|
|
5270
|
+
const spans = runRedaction(win, false, false, false, "free-text", "multi-line", WHOLE_EXTENT, 0, jointsInWindow()).spans;
|
|
5271
|
+
const out = renderRedactionSpans(win, spans, released - base, win.length);
|
|
4646
5272
|
released = scannedAt = total;
|
|
5273
|
+
commits.push(total);
|
|
4647
5274
|
sent += out;
|
|
4648
5275
|
return out;
|
|
4649
5276
|
},
|
|
@@ -4651,12 +5278,13 @@ function openRedactionStream(pendingTail, windowed = true, certify = windowIndep
|
|
|
4651
5278
|
if (deliveredFrom === total)
|
|
4652
5279
|
return { rest: "", diverged: false };
|
|
4653
5280
|
const buf = whole();
|
|
4654
|
-
const spans = runRedaction(buf, false, false, false, "free-text", "multi-line", WHOLE_EXTENT)
|
|
4655
|
-
const split = released > deliveredFrom && spans.some((s) => s.start < released && s.end > released);
|
|
4656
|
-
return { rest:
|
|
5281
|
+
const { spans, crossed } = runRedaction(buf, false, false, false, "free-text", "multi-line", WHOLE_EXTENT, 0, commits);
|
|
5282
|
+
const split = released > deliveredFrom && (spans.some((s) => s.start < released && s.end > released) || crossed.some((j) => j > deliveredFrom));
|
|
5283
|
+
return { rest: renderRedactionSpans(buf, spans, released, buf.length), diverged: split || renderRedactionSpans(buf, spans, deliveredFrom, released) !== sent };
|
|
4657
5284
|
},
|
|
4658
5285
|
skip() {
|
|
4659
5286
|
released = deliveredFrom = scannedAt = total;
|
|
5287
|
+
commits.push(total);
|
|
4660
5288
|
sent = "";
|
|
4661
5289
|
},
|
|
4662
5290
|
endBlock() {
|
|
@@ -4824,10 +5452,6 @@ function shapeLawCredentialInQueryOrFragment(canonical) {
|
|
|
4824
5452
|
}
|
|
4825
5453
|
return false;
|
|
4826
5454
|
}
|
|
4827
|
-
let displaySafeFailClosedWarned = false;
|
|
4828
|
-
export function resetDisplaySafeFailClosedWarnForTest() {
|
|
4829
|
-
displaySafeFailClosedWarned = false;
|
|
4830
|
-
}
|
|
4831
5455
|
export function buildDisplaySafeUrl(raw, positionalLaw = displayUrlOf) {
|
|
4832
5456
|
return buildDisplaySafeUrlChecked(raw, positionalLaw).text;
|
|
4833
5457
|
}
|
|
@@ -4863,10 +5487,6 @@ export function buildDisplaySafeRefusal(text, sourceUrls) {
|
|
|
4863
5487
|
const REFUSAL_WITHHELD_TEXT = "[route refusal text withheld: it quotes a configured URL that carries a credential, and the upstream wording cannot be re-redacted safely once the URL has been rewritten for display. " +
|
|
4864
5488
|
"The machine-readable verdict is on the pairing field beside this one; fix the configuration so the credential is not in the URL.]";
|
|
4865
5489
|
function noteDisplaySafeFailClosed(level) {
|
|
4866
|
-
|
|
4867
|
-
return;
|
|
4868
|
-
displaySafeFailClosedWarned = true;
|
|
4869
|
-
process.emitWarning(`display-safe URL composition fell back to fail-closed (${level}): a part of the configured URL was judged to carry a credential that the composition cannot redact at byte granularity, so that whole part is withheld. ` +
|
|
4870
|
-
`The product is safe, but this deployment has an input hitting the composition seam — report it upstream. No original bytes are logged.`, "SemaRedactionFailClosed");
|
|
5490
|
+
recordFailOpen("server.redact.display-safe-fail-closed", `level=${level}`);
|
|
4871
5491
|
}
|
|
4872
5492
|
//# sourceMappingURL=redact.js.map
|