@piagent/platform 1.5.5 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +166 -0
- package/README.md +25 -21
- package/README.vi.md +34 -5
- package/adapters/web-frontend/profile.json +2 -4
- package/architecture/layers.json +18 -3
- package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
- package/benchmarks/deep-logic-v1/grade.mjs +272 -10
- package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
- package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
- package/benchmarks/deep-logic-v1/project/package.json +1 -1
- package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
- package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
- package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
- package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
- package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
- package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
- package/benchmarks/deep-logic-v1/suite.json +51 -3
- package/benchmarks/deep-logic-v1/variant.mjs +22 -1
- package/benchmarks/production-v1/spend-control.v1.json +92 -0
- package/benchmarks/production-v1/suite.json +46 -3
- package/catalog/capabilities.json +18 -18
- package/docs/authority-manifest.md +1 -1
- package/docs/auto-delegation-policy.md +38 -73
- package/docs/command-reference-vietnamese.md +27 -35
- package/docs/context-engine.md +12 -4
- package/docs/context-window-policy.md +37 -1
- package/docs/distribution-standard.md +7 -7
- package/docs/en/architecture.md +27 -13
- package/docs/languages.json +4 -4
- package/docs/model-options.md +8 -5
- package/docs/operator-manual-vietnamese.md +27 -45
- package/docs/project-adapters.md +2 -2
- package/docs/publishing-for-teams.md +10 -0
- package/docs/quality-benchmark.md +427 -62
- package/docs/release-install-policy.md +10 -9
- package/docs/runtime-harness-standard.md +3 -3
- package/docs/runtime-policy-design.md +4 -4
- package/docs/runtime-quality-baseline.md +13 -6
- package/docs/security-threat-model.md +2 -2
- package/docs/subagent-orchestration-capabilities.md +19 -51
- package/docs/subagents-and-multiagent.md +21 -47
- package/docs/task-implementation-contract.md +3 -3
- package/docs/task-lifecycle-vietnamese.md +3 -3
- package/docs/team-onboarding.md +2 -2
- package/docs/usage-observability.md +7 -2
- package/docs/vi/architecture.md +27 -13
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +89 -95
- package/docs-site/commands.html +1 -1
- package/docs-site/content/benchmark.html +88 -94
- package/docs-site/content/en/benchmark.html +134 -90
- package/docs-site/content/en/index.html +19 -19
- package/docs-site/content/en/runtime.html +4 -4
- package/docs-site/content/en/whats-new.html +12 -1
- package/docs-site/content/en/workflows.html +2 -2
- package/docs-site/content/index.html +19 -19
- package/docs-site/content/runtime.html +4 -4
- package/docs-site/content/whats-new.html +12 -1
- package/docs-site/content/workflows.html +2 -2
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +135 -91
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +20 -20
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +5 -5
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +13 -2
- package/docs-site/en/workflows.html +3 -3
- package/docs-site/index.html +20 -20
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +5 -5
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +13 -2
- package/docs-site/workflows.html +3 -3
- package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
- package/evals/fixtures/codex-relative-efficiency-v1.invalid.json +4 -0
- package/evals/fixtures/codex-relative-efficiency-v1.valid.json +94 -0
- package/evals/fixtures/helper-request.invalid.json +1 -1
- package/evals/fixtures/helper-request.valid.json +1 -1
- package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
- package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
- package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +7 -0
- package/evals/fixtures/task-authority-snapshot.valid.json +4 -4
- package/evals/fs4-readiness-matrix.v1.json +2 -2
- package/evals/fs5-causal-arm.v1.json +3 -3
- package/evals/fs5-pilot-protocol.v1.json +3 -3
- package/evals/fs5-pilot-protocol.v2.json +8 -8
- package/evals/fs5-pilot-protocol.v3.json +8 -8
- package/evals/fs5-pilot-protocol.v4.json +7 -6
- package/evals/fs5-pilot-protocol.v5.json +9 -7
- package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
- package/evals/runtime-conformance-v1/README.md +43 -0
- package/evals/runtime-conformance-v1/evaluate-paid-canary.mjs +198 -0
- package/evals/runtime-conformance-v1/lane.json +57 -0
- package/evals/runtime-conformance-v1/paid-canary.json +31 -0
- package/evals/runtime-conformance-v1/runner.mjs +456 -0
- package/package.json +3 -1
- package/packages/piagent-core/README.md +13 -4
- package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
- package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
- package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
- package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +698 -0
- package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
- package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
- package/packages/piagent-core/benchmark/benchmark-core.js +736 -664
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
- package/packages/piagent-core/benchmark/benchmark-forensics.js +441 -4
- package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
- package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
- package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
- package/packages/piagent-core/benchmark/benchmark-preflight.js +5 -1
- package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
- package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +345 -0
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +252 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +130 -12
- package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
- package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
- package/packages/piagent-core/benchmark/benchmark-runtime-causal.js +244 -0
- package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +979 -0
- package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
- package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
- package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
- package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
- package/packages/piagent-core/benchmark/benchmark-suite.js +149 -2
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +380 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
- package/packages/piagent-core/benchmark/benchmark-usage.js +322 -0
- package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
- package/packages/piagent-core/capabilities/runtime-integrity.js +3 -0
- package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
- package/packages/piagent-core/extensions/acceptance-behavior-proof.js +806 -0
- package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
- package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
- package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
- package/packages/piagent-core/extensions/acceptance-receipt.js +123 -59
- package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
- package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
- package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
- package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
- package/packages/piagent-core/extensions/context-engine.js +149 -156
- package/packages/piagent-core/extensions/context-evidence.js +48 -0
- package/packages/piagent-core/extensions/context-import-links.js +296 -0
- package/packages/piagent-core/extensions/context-index-policy.js +4 -0
- package/packages/piagent-core/extensions/context-query-paths.js +57 -0
- package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
- package/packages/piagent-core/extensions/criterion-context-pack.js +435 -7
- package/packages/piagent-core/extensions/criterion-graph.js +82 -9
- package/packages/piagent-core/extensions/fallback-base-policy.ts +101 -0
- package/packages/piagent-core/extensions/guard-types.ts +6 -0
- package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +420 -260
- package/packages/piagent-core/extensions/task-contract-view.js +17 -3
- package/packages/piagent-core/extensions/task-lifecycle.js +39 -2
- package/packages/piagent-core/extensions/task-state.js +109 -142
- package/packages/piagent-core/extensions/verification-intelligence.js +52 -13
- package/packages/piagent-core/extensions/workspace-evidence-roots.js +193 -0
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/policies/base-policy.json +44 -2
- package/packages/piagent-core/policy/authority-manifest.v1.json +3 -3
- package/packages/piagent-core/prompts/be-to-fe.md +2 -8
- package/packages/piagent-core/prompts/plan.md +1 -1
- package/packages/piagent-core/prompts/platform-improve.md +2 -6
- package/packages/piagent-core/prompts/review.md +2 -7
- package/packages/piagent-core/prompts/scout.md +1 -1
- package/packages/piagent-core/prompts/task.md +4 -3
- package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
- package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
- package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
- package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
- package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
- package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
- package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
- package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
- package/packages/piagent-core/runtime/hooks/completion-hook.ts +12 -12
- package/packages/piagent-core/runtime/hooks/input-hook.ts +17 -1
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +107 -3
- package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +134 -166
- package/packages/piagent-core/runtime/hooks/tool-result-value-helpers.ts +66 -0
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
- package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
- package/packages/piagent-core/runtime/inspection/bounded-emission-guard.ts +286 -0
- package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +37 -7
- package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +27 -4
- package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +70 -0
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +73 -9
- package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
- package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
- package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
- package/packages/piagent-core/runtime/orchestration/helper-lifecycle.ts +16 -12
- package/packages/piagent-core/runtime/orchestration/minimal-delegation-policy.ts +71 -0
- package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +28 -20
- package/packages/piagent-core/runtime/orchestration/role-policy.ts +27 -9
- package/packages/piagent-core/runtime/orchestration/subagent-tool-policy.ts +329 -0
- package/packages/piagent-core/runtime/policy/block-remedy.ts +0 -4
- package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +7 -2
- package/packages/piagent-core/runtime/quality/edit-freshness-guard.ts +102 -0
- package/packages/piagent-core/runtime/quality/exact-output-contract.ts +22 -11
- package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
- package/packages/piagent-core/runtime/quality/performance-assurance.ts +9 -5
- package/packages/piagent-core/runtime/recovery/continuation-budget.ts +1 -1
- package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
- package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
- package/packages/piagent-core/runtime/recovery/handoff-projection.ts +4 -1
- package/packages/piagent-core/runtime/recovery/pristine-task-policy-refresh.ts +91 -0
- package/packages/piagent-core/runtime/recovery/recovery-policy.ts +7 -4
- package/packages/piagent-core/runtime/recovery/resume-state.ts +112 -14
- package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +60 -13
- package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
- package/packages/piagent-core/runtime/recovery/task-evidence-coverage-refresh.ts +217 -0
- package/packages/piagent-core/runtime/registration/context-commands.ts +82 -7
- package/packages/piagent-core/runtime/registration/knowledge-tools.ts +9 -5
- package/packages/piagent-core/runtime/registration/operator-request-intake.ts +49 -0
- package/packages/piagent-core/runtime/registration/policy-tools.ts +50 -15
- package/packages/piagent-core/runtime/registration/session-commands.ts +1 -1
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +61 -25
- package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +21 -12
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +169 -0
- package/packages/piagent-core/runtime/registration/task-start-manifest.ts +54 -0
- package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +108 -103
- package/packages/piagent-core/runtime/runtime-limits.ts +16 -2
- package/packages/piagent-core/runtime/session/adaptive-context-analysis.ts +461 -0
- package/packages/piagent-core/runtime/session/adaptive-context-governor.ts +464 -0
- package/packages/piagent-core/runtime/session/adaptive-context-ledger.ts +265 -0
- package/packages/piagent-core/runtime/session/message-signals.ts +7 -3
- package/packages/piagent-core/runtime/session/operator-request-carry.ts +44 -0
- package/packages/piagent-core/runtime/session/runtime-state.ts +161 -5
- package/packages/piagent-core/runtime/session/source-checkout-read-grants.ts +35 -0
- package/packages/piagent-core/runtime/session/system-prompt.ts +76 -14
- package/packages/piagent-core/runtime/session/task-contract-presentation.ts +39 -0
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
- package/packages/piagent-core/runtime/tools/phase-tools.ts +8 -8
- package/packages/piagent-core/runtime/tools/tool-groups.ts +12 -2
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
- package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +101 -0
- package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +164 -0
- package/packages/piagent-core/runtime/workflows/task-intake.ts +207 -38
- package/packages/piagent-core/security/sensitive-data.js +13 -218
- package/packages/piagent-core/security/sensitive-project-file.js +42 -0
- package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
- package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
- package/packages/piagent-core/security/sensitive-text.js +234 -0
- package/packages/piagent-core/subagents/piagent-oracle.md +5 -3
- package/packages/piagent-core/subagents/piagent-planner.md +6 -4
- package/packages/piagent-core/subagents/piagent-reviewer.md +5 -3
- package/packages/piagent-core/subagents/piagent-scout.md +4 -2
- package/packages/piagent-core/subagents/piagent-worker.md +7 -5
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-B4XehTCU.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/extension/piagent-webui.ts +3 -1
- package/packages/piagent-webui/extension/same-session-bridge.ts +1 -1
- package/packages/piagent-webui/extension/session-stream-adapter.ts +33 -10
- package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
- package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +122 -20
- package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
- package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
- package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
- package/packages/piagent-webui/gateway/session-operation-lifecycle.ts +237 -0
- package/packages/piagent-webui/gateway/session-operation-retry-control.ts +38 -0
- package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
- package/packages/piagent-webui/gateway/session-operation-watchdog.ts +165 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +141 -125
- package/packages/piagent-webui/ownership/session-lease-store.ts +5 -2
- package/packages/piagent-webui/server/core-inspection-provider.ts +2 -1
- package/packages/piagent-webui/server/loopback-server.ts +8 -0
- package/packages/piagent-webui/server/transcript-projection.ts +113 -9
- package/packages/piagent-webui/shared/text-visibility.ts +10 -0
- package/schemas/codex-relative-efficiency-v1.schema.json +155 -0
- package/schemas/piagent-webui/catalog-v1.json +9 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
- package/schemas/piagent-webui/runtime-event-v2.schema.json +15 -5
- package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
- package/schemas/piagent-webui/subagent-tree-v1.schema.json +11 -1
- package/schemas/project-profile.schema.json +1 -1
- package/schemas/task-contract.schema.json +27 -1
- package/scripts/benchmark-runner-core.mjs +367 -363
- package/scripts/benchmark-runner-finalization.mjs +313 -0
- package/scripts/benchmark-runner-host-readiness.mjs +94 -0
- package/scripts/benchmark-runner-support.mjs +200 -0
- package/scripts/benchmark-session.mjs +95 -41
- package/scripts/configure-model-scope.sh +4 -3
- package/scripts/configure-subagents.sh +42 -34
- package/scripts/helper-evaluation.mjs +2 -2
- package/scripts/install-global.sh +2 -2
- package/scripts/pi-usage-history.mjs +37 -10
- package/scripts/setup.sh +2 -2
- package/scripts/team-doctor.sh +1 -1
- package/scripts/verify-local.sh +10 -1
- package/templates/global/settings.json +2 -1
- package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import {
|
|
2
|
+
REDACTION,
|
|
3
|
+
keyLooksSensitive,
|
|
4
|
+
redactSensitiveTextInternal
|
|
5
|
+
} from "./sensitive-text.js";
|
|
6
|
+
import {
|
|
7
|
+
balancedSourceExpression,
|
|
8
|
+
hasStandaloneKeywordSourceLiteral,
|
|
9
|
+
hasStandaloneNumericSourceLiteral,
|
|
10
|
+
maskSourceLookupStrings,
|
|
11
|
+
rewriteSensitiveSegment,
|
|
12
|
+
rewriteSensitiveStarts,
|
|
13
|
+
sourceReference
|
|
14
|
+
} from "./sensitive-source-expression.js";
|
|
15
|
+
|
|
16
|
+
function nextSourceComment(source, cursor, { hashComments }) {
|
|
17
|
+
let quote = "", escaped = false;
|
|
18
|
+
for (let index = cursor; index < source.length; index += 1) {
|
|
19
|
+
const character = source[index], next = source[index + 1] ?? "";
|
|
20
|
+
if (quote) {
|
|
21
|
+
if (escaped) escaped = false;
|
|
22
|
+
else if (character === "\\") escaped = true;
|
|
23
|
+
else if (character === quote) quote = "";
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
27
|
+
quote = character;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (character === "/" && next === "*") return { index, kind: "block" };
|
|
31
|
+
if (character === "/" && next === "/") return { index, kind: "line" };
|
|
32
|
+
if (((hashComments && character === "#") || (character === "-" && next === "-"))
|
|
33
|
+
&& (index === cursor || /\s/.test(source[index - 1] ?? ""))) return { index, kind: "line" };
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function shieldExecutableSourceReferences(input, { shellOnly = false, hashComments = true } = {}) {
|
|
39
|
+
const references = [];
|
|
40
|
+
let nonce = 0;
|
|
41
|
+
let markerPrefix;
|
|
42
|
+
do {
|
|
43
|
+
markerPrefix = `__PIAGENT_DSR_${nonce}_`;
|
|
44
|
+
nonce += 1;
|
|
45
|
+
} while (String(input ?? "").includes(markerPrefix));
|
|
46
|
+
const placeholder = (value) => {
|
|
47
|
+
const id = `${markerPrefix}${references.length}__`;
|
|
48
|
+
references.push({ id, value });
|
|
49
|
+
return id;
|
|
50
|
+
};
|
|
51
|
+
const rewriteCode = (segment) => rewriteSensitiveSegment(segment, {
|
|
52
|
+
allowDynamic: true, shellOnly, placeholder
|
|
53
|
+
});
|
|
54
|
+
const rewriteComment = (segment) => rewriteSensitiveSegment(segment, {
|
|
55
|
+
allowDynamic: false, shellOnly, placeholder
|
|
56
|
+
});
|
|
57
|
+
const source = String(input ?? "");
|
|
58
|
+
let result = "", cursor = 0, blockComment = false;
|
|
59
|
+
while (cursor < source.length) {
|
|
60
|
+
if (blockComment) {
|
|
61
|
+
const end = source.indexOf("*/", cursor);
|
|
62
|
+
if (end < 0) {
|
|
63
|
+
result += rewriteComment(source.slice(cursor));
|
|
64
|
+
cursor = source.length;
|
|
65
|
+
} else {
|
|
66
|
+
const body = rewriteComment(source.slice(cursor, end));
|
|
67
|
+
result += `${body}*/`;
|
|
68
|
+
cursor = end + 2;
|
|
69
|
+
blockComment = false;
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const comment = nextSourceComment(source, cursor, { hashComments });
|
|
74
|
+
if (!comment) {
|
|
75
|
+
result += rewriteCode(source.slice(cursor));
|
|
76
|
+
cursor = source.length;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
result += rewriteCode(source.slice(cursor, comment.index));
|
|
80
|
+
if (comment.kind === "line") {
|
|
81
|
+
const lineEnd = source.indexOf("\n", comment.index);
|
|
82
|
+
const end = lineEnd < 0 ? source.length : lineEnd;
|
|
83
|
+
result += rewriteComment(source.slice(comment.index, end));
|
|
84
|
+
if (lineEnd >= 0) result += "\n";
|
|
85
|
+
cursor = lineEnd < 0 ? source.length : lineEnd + 1;
|
|
86
|
+
} else {
|
|
87
|
+
result += "/*";
|
|
88
|
+
cursor = comment.index + 2;
|
|
89
|
+
blockComment = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
text: result,
|
|
94
|
+
restore(value) {
|
|
95
|
+
let restored = value;
|
|
96
|
+
for (const reference of references) restored = restored.replaceAll(reference.id, reference.value);
|
|
97
|
+
return restored;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const SENSITIVE_SOURCE_QUOTED_HEREDOC_PATTERN = /(^[ \t]*(?:(?:const|let|var)\s+)?([$@%]?[A-Za-z_$][A-Za-z0-9_$]*)\s*(?:=|<-|:=)\s*)<<[-~]?(["'])([A-Za-z_][A-Za-z0-9_]*)\3[^\r\n]*(?:\r\n|\n|\r)([\s\S]*?)(^[ \t]*\4[ \t]*$)/gm;
|
|
103
|
+
const SENSITIVE_SOURCE_BARE_HEREDOC_PATTERN = /(^[ \t]*(?:(?:const|let|var)\s+)?([$@%]?[A-Za-z_$][A-Za-z0-9_$]*)\s*(?:=|<-|:=)\s*)<<[-~]?([A-Za-z_][A-Za-z0-9_]*)[^\r\n]*(?:\r\n|\n|\r)([\s\S]*?)(^[ \t]*\3[ \t]*$)/gm;
|
|
104
|
+
|
|
105
|
+
function redactSensitiveSourceHeredocs(input) {
|
|
106
|
+
const redactMatch = (match, prefix, key) => {
|
|
107
|
+
if (!keyLooksSensitive(key)) return match;
|
|
108
|
+
const secretPayload = match.slice(prefix.length);
|
|
109
|
+
const lineEndings = secretPayload.match(/\r\n|\n|\r/g) ?? [];
|
|
110
|
+
return `${prefix}${REDACTION}${lineEndings.join("")}`;
|
|
111
|
+
};
|
|
112
|
+
const quoted = input.replace(SENSITIVE_SOURCE_QUOTED_HEREDOC_PATTERN, redactMatch);
|
|
113
|
+
return quoted.replace(SENSITIVE_SOURCE_BARE_HEREDOC_PATTERN, redactMatch);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function redactSourceText(input, options) {
|
|
117
|
+
if (typeof input !== "string") return { text: "", redacted: false };
|
|
118
|
+
const heredocRedacted = options?.shellOnly ? input : redactSensitiveSourceHeredocs(input);
|
|
119
|
+
const shielded = shieldExecutableSourceReferences(heredocRedacted, options);
|
|
120
|
+
const redacted = redactSensitiveTextInternal(shielded.text);
|
|
121
|
+
const text = shielded.restore(redacted.text);
|
|
122
|
+
return { text, redacted: text !== input };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function restorableMarkers(input, domain) {
|
|
126
|
+
const references = [];
|
|
127
|
+
let nonce = 0;
|
|
128
|
+
let prefix;
|
|
129
|
+
do {
|
|
130
|
+
prefix = `__PIAGENT_${domain}_${nonce}_`;
|
|
131
|
+
nonce += 1;
|
|
132
|
+
} while (input.includes(prefix));
|
|
133
|
+
return {
|
|
134
|
+
protect(value) {
|
|
135
|
+
const id = `${prefix}${references.length}__`;
|
|
136
|
+
references.push({ id, value });
|
|
137
|
+
return id;
|
|
138
|
+
},
|
|
139
|
+
restore(value) {
|
|
140
|
+
let restored = value;
|
|
141
|
+
for (const reference of references) restored = restored.replaceAll(reference.id, reference.value);
|
|
142
|
+
return restored;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function unquotedConfigurationValue(value) {
|
|
148
|
+
const clean = String(value ?? "").trim();
|
|
149
|
+
if (clean.length >= 2 && ((clean.startsWith("\"") && clean.endsWith("\""))
|
|
150
|
+
|| (clean.startsWith("'") && clean.endsWith("'")))) return clean.slice(1, -1).trim();
|
|
151
|
+
return clean;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function pureConfigurationReference(value, { allowBareIdentifier = false } = {}) {
|
|
155
|
+
const clean = unquotedConfigurationValue(value);
|
|
156
|
+
if (!clean) return false;
|
|
157
|
+
if (/^(?:\$[A-Za-z_][A-Za-z0-9_]*|\$\{[A-Za-z_][A-Za-z0-9_]*\}|\*[A-Za-z_][A-Za-z0-9_.-]*|!Ref\s+[A-Za-z_][A-Za-z0-9_.:-]*)$/.test(clean)) return true;
|
|
158
|
+
const template = /^(?:\$?\{\{)([\s\S]+)\}\}$/.exec(clean);
|
|
159
|
+
if (template) return sourceReference(template[1], false);
|
|
160
|
+
if (/^(?:var|env|attr)\(\s*(?:--)?[A-Za-z_$][A-Za-z0-9_$.-]*\s*\)$/i.test(clean)) return true;
|
|
161
|
+
if (!sourceReference(clean, false)) return false;
|
|
162
|
+
return allowBareIdentifier || /(?:\.|->|::|\?\.|\(|\[)/.test(clean)
|
|
163
|
+
|| /^(?:await\s+|this\b|self\b|super\b|[$@%])/.test(clean)
|
|
164
|
+
|| /_(?:REF|VAR|ENV)$/.test(clean);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function yamlValueParts(value) {
|
|
168
|
+
let quote = "", escaped = false;
|
|
169
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
170
|
+
const character = value[index];
|
|
171
|
+
if (quote) {
|
|
172
|
+
if (escaped) escaped = false;
|
|
173
|
+
else if (character === "\\") escaped = true;
|
|
174
|
+
else if (character === quote) quote = "";
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (character === "\"" || character === "'") quote = character;
|
|
178
|
+
else if (character === "#" && (index === 0 || /\s/.test(value[index - 1]))) {
|
|
179
|
+
return { value: value.slice(0, index).trimEnd(), comment: value.slice(index) };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return { value: value.trimEnd(), comment: "" };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function redactSensitiveYamlText(input) {
|
|
186
|
+
const markers = restorableMarkers(input, "YAML_REF");
|
|
187
|
+
const parts = input.split(/(\r\n|\n|\r)/);
|
|
188
|
+
let blockIndent = -1;
|
|
189
|
+
for (let index = 0; index < parts.length; index += 2) {
|
|
190
|
+
const line = parts[index];
|
|
191
|
+
const indentation = (line.match(/^[ \t]*/) ?? [""])[0].replaceAll("\t", " ").length;
|
|
192
|
+
if (blockIndent >= 0) {
|
|
193
|
+
if (!line.trim() || indentation > blockIndent) {
|
|
194
|
+
parts[index] = line.trim() ? (line.match(/^[ \t]*/) ?? [""])[0] : line;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
blockIndent = -1;
|
|
198
|
+
}
|
|
199
|
+
const match = /^([ \t]*(?:-[ \t]+)?((?:"(?:\\.|[^"])*"|'(?:''|[^'])*'|[A-Za-z_$][A-Za-z0-9_$.-]*))[ \t]*:[ \t]*)(.*)$/.exec(line);
|
|
200
|
+
if (!match || !keyLooksSensitive(match[2])) continue;
|
|
201
|
+
const rhs = yamlValueParts(match[3]);
|
|
202
|
+
if (rhs.value && pureConfigurationReference(rhs.value)) {
|
|
203
|
+
const comment = rhs.comment ? ` ${redactSensitiveTextInternal(rhs.comment.trimStart()).text}` : "";
|
|
204
|
+
parts[index] = `${markers.protect(`${match[1]}${rhs.value}`)}${comment}`;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
parts[index] = `${match[1]}${REDACTION}${rhs.comment ? ` ${rhs.comment.trimStart()}` : ""}`;
|
|
208
|
+
if (!rhs.value || /^[>|][+-]?(?:\d+)?$/.test(rhs.value.trim())) blockIndent = indentation;
|
|
209
|
+
}
|
|
210
|
+
const structured = parts.join("");
|
|
211
|
+
const generic = redactSensitiveTextInternal(structured);
|
|
212
|
+
const text = markers.restore(generic.text);
|
|
213
|
+
return { text, redacted: text !== input };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function markupLookupKey(attributes) {
|
|
217
|
+
const match = /\b(?:key|name)\s*=\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^\s>]+))/i.exec(attributes);
|
|
218
|
+
return match ? (match[1] ?? match[2] ?? match[3] ?? "") : "";
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function redactMarkupAttributes(tag, markers) {
|
|
222
|
+
if (/^<\s*\//.test(tag)) return tag;
|
|
223
|
+
const lookupKey = markupLookupKey(tag);
|
|
224
|
+
return tag.replace(/(\s)([A-Za-z_:][A-Za-z0-9_.:-]*)(\s*=\s*)(?:(["'])((?:\\.|(?!\4)[\s\S])*?)\4|([^\s>]+))/g,
|
|
225
|
+
(match, spacing, key, separator, quote, quotedValue, bareValue) => {
|
|
226
|
+
const value = quotedValue ?? bareValue ?? "";
|
|
227
|
+
const sensitive = keyLooksSensitive(key)
|
|
228
|
+
|| (keyLooksSensitive(lookupKey) && ["value", "content"].includes(key.toLowerCase()));
|
|
229
|
+
if (!sensitive) return match;
|
|
230
|
+
const expressionBinding = key.startsWith(":") || key.toLowerCase().startsWith("v-bind:");
|
|
231
|
+
if (pureConfigurationReference(value, { allowBareIdentifier: expressionBinding })) {
|
|
232
|
+
return `${spacing}${markers.protect(match.slice(spacing.length))}`;
|
|
233
|
+
}
|
|
234
|
+
return `${spacing}${key}${separator}${quote ? `${quote}${REDACTION}${quote}` : REDACTION}`;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function markupTags(input) {
|
|
239
|
+
const tags = [];
|
|
240
|
+
for (let start = input.indexOf("<"); start >= 0; start = input.indexOf("<", start + 1)) {
|
|
241
|
+
let quote = "", escaped = false, end = start + 1;
|
|
242
|
+
for (; end < input.length; end += 1) {
|
|
243
|
+
const character = input[end];
|
|
244
|
+
if (quote) {
|
|
245
|
+
if (escaped) escaped = false;
|
|
246
|
+
else if (character === "\\") escaped = true;
|
|
247
|
+
else if (character === quote) quote = "";
|
|
248
|
+
} else if (character === "\"" || character === "'") quote = character;
|
|
249
|
+
else if (character === ">") break;
|
|
250
|
+
}
|
|
251
|
+
if (end >= input.length) break;
|
|
252
|
+
const text = input.slice(start, end + 1);
|
|
253
|
+
const parsed = /^<\s*(\/)?\s*([A-Za-z_][A-Za-z0-9_.:-]*)\b([\s\S]*?)>$/.exec(text);
|
|
254
|
+
if (parsed) tags.push({ start, end: end + 1, text, closing: Boolean(parsed[1]), name: parsed[2], attributes: parsed[3] });
|
|
255
|
+
start = end;
|
|
256
|
+
}
|
|
257
|
+
return tags;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function rewriteMarkupTags(input, rewriter) {
|
|
261
|
+
let result = "", cursor = 0;
|
|
262
|
+
for (const tag of markupTags(input)) {
|
|
263
|
+
result += `${input.slice(cursor, tag.start)}${rewriter(tag.text)}`;
|
|
264
|
+
cursor = tag.end;
|
|
265
|
+
}
|
|
266
|
+
return `${result}${input.slice(cursor)}`;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function redactMarkupPairs(input, markers) {
|
|
270
|
+
const stack = [];
|
|
271
|
+
const replacements = [];
|
|
272
|
+
for (const tag of markupTags(input)) {
|
|
273
|
+
const tagName = tag.name.toLowerCase();
|
|
274
|
+
if (!tag.closing && !/\/\s*>$/.test(tag.text)) {
|
|
275
|
+
stack.push({
|
|
276
|
+
tagName,
|
|
277
|
+
contentStart: tag.end,
|
|
278
|
+
sensitive: keyLooksSensitive(tagName.split(":").at(-1) ?? tagName)
|
|
279
|
+
|| keyLooksSensitive(markupLookupKey(tag.attributes))
|
|
280
|
+
});
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (!tag.closing) continue;
|
|
284
|
+
let openIndex = stack.length - 1;
|
|
285
|
+
while (openIndex >= 0 && stack[openIndex].tagName !== tagName) openIndex -= 1;
|
|
286
|
+
if (openIndex < 0) continue;
|
|
287
|
+
const open = stack[openIndex];
|
|
288
|
+
stack.length = openIndex;
|
|
289
|
+
if (!open.sensitive) continue;
|
|
290
|
+
const content = input.slice(open.contentStart, tag.start);
|
|
291
|
+
replacements.push({
|
|
292
|
+
start: open.contentStart,
|
|
293
|
+
end: tag.start,
|
|
294
|
+
value: pureConfigurationReference(content)
|
|
295
|
+
? markers.protect(content)
|
|
296
|
+
: `${REDACTION}${(content.match(/\r\n|\n|\r/g) ?? []).join("")}`
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// An outer sensitive element supersedes any replacement wholly inside it.
|
|
301
|
+
const selected = replacements.filter((candidate) => !replacements.some((other) => other !== candidate
|
|
302
|
+
&& other.start <= candidate.start && other.end >= candidate.end));
|
|
303
|
+
let result = input;
|
|
304
|
+
for (const replacement of selected.sort((left, right) => right.start - left.start)) {
|
|
305
|
+
result = `${result.slice(0, replacement.start)}${replacement.value}${result.slice(replacement.end)}`;
|
|
306
|
+
}
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function redactSensitiveMarkupText(input) {
|
|
311
|
+
const markers = restorableMarkers(input, "MARKUP_REF");
|
|
312
|
+
const paired = redactMarkupPairs(input, markers);
|
|
313
|
+
const structured = rewriteMarkupTags(paired, (tag) => redactMarkupAttributes(tag, markers));
|
|
314
|
+
const generic = redactSensitiveTextInternal(structured);
|
|
315
|
+
const text = markers.restore(generic.text);
|
|
316
|
+
return { text, redacted: text !== input };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function redactSensitiveCssText(input) {
|
|
320
|
+
const markers = restorableMarkers(input, "CSS_REF");
|
|
321
|
+
const structured = input.replace(/(^|[;{}\r\n])([ \t]*(--)?([A-Za-z_$][A-Za-z0-9_$-]*)[ \t]*:[ \t\r\n]*)([^;}]*)(?=;|}|$)/g,
|
|
322
|
+
(match, boundary, prefix, _custom, key, value) => {
|
|
323
|
+
if (!keyLooksSensitive(key)) return match;
|
|
324
|
+
if (pureConfigurationReference(value)) return `${boundary}${markers.protect(`${prefix}${value}`)}`;
|
|
325
|
+
return `${boundary}${prefix}${REDACTION}${(value.match(/\r\n|\n|\r/g) ?? []).join("")}`;
|
|
326
|
+
});
|
|
327
|
+
const generic = redactSensitiveTextInternal(structured);
|
|
328
|
+
const text = markers.restore(generic.text);
|
|
329
|
+
return { text, redacted: text !== input };
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const SOURCE_OBJECTIVE_C_TYPED_ASSIGNMENT_START_PATTERN = /(^|[\r\n;{])([ \t]*(?:(?:const|static|extern|volatile|__strong|__weak|nullable|nonnull|unsigned|signed|long|short)\s+)*(?:[A-Za-z_$][A-Za-z0-9_$]*(?:\s*<[^>\r\n;=]+>)?\s+)*[A-Za-z_$][A-Za-z0-9_$]*(?:\s*<[^>\r\n;=]+>)?\s*\*+\s*(#?[A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*)/g;
|
|
333
|
+
const SOURCE_OBJECTIVE_C_DICTIONARY_START_PATTERN = /(^|[\s{[(;,])((?:@")([A-Za-z_$][A-Za-z0-9_$.-]*)(?:"\s*:\s*))/g;
|
|
334
|
+
|
|
335
|
+
function objectiveCReference(value) {
|
|
336
|
+
if (sourceReference(value, false)) return true;
|
|
337
|
+
const clean = String(value ?? "").trim();
|
|
338
|
+
const masked = maskSourceLookupStrings(clean);
|
|
339
|
+
return Boolean(masked && /^\[[A-Za-z_$]/.test(masked)
|
|
340
|
+
&& /^[A-Za-z0-9_$@%?.()[\]{},!:\s|&+*/<>=-]+$/.test(masked)
|
|
341
|
+
&& balancedSourceExpression(masked)
|
|
342
|
+
&& !hasStandaloneNumericSourceLiteral(masked)
|
|
343
|
+
&& !hasStandaloneKeywordSourceLiteral(masked));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function redactSensitiveObjectiveCText(input) {
|
|
347
|
+
let source = rewriteSensitiveStarts(input, SOURCE_OBJECTIVE_C_TYPED_ASSIGNMENT_START_PATTERN, {
|
|
348
|
+
allowDynamic: true,
|
|
349
|
+
shellOnly: false,
|
|
350
|
+
placeholder: (value) => value,
|
|
351
|
+
reference: objectiveCReference
|
|
352
|
+
});
|
|
353
|
+
source = rewriteSensitiveStarts(source, SOURCE_OBJECTIVE_C_DICTIONARY_START_PATTERN, {
|
|
354
|
+
allowDynamic: true,
|
|
355
|
+
shellOnly: false,
|
|
356
|
+
placeholder: (value) => value,
|
|
357
|
+
reference: objectiveCReference
|
|
358
|
+
});
|
|
359
|
+
source = source.replace(/(^|[^A-Za-z0-9_$])((#?[A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*)@"((?:\\.|[^"\\\r\n])*)"/g,
|
|
360
|
+
(match, boundary, prefix, key) => keyLooksSensitive(key)
|
|
361
|
+
? `${boundary}${prefix}@"${REDACTION}"`
|
|
362
|
+
: match);
|
|
363
|
+
source = source.replace(/(^|[^A-Za-z0-9_$])((#?[A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*)(@?(?:0[xX][0-9A-Fa-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|YES|NO|nil|NULL))(?=[\s;,)])/g,
|
|
364
|
+
(match, boundary, prefix, key) => keyLooksSensitive(key)
|
|
365
|
+
? `${boundary}${prefix}${REDACTION}`
|
|
366
|
+
: match);
|
|
367
|
+
source = source.replace(/(@"((?:\\.|[^"\\\r\n])*)"\s*:\s*)@"((?:\\.|[^"\\\r\n])*)"/g,
|
|
368
|
+
(match, prefix, key) => keyLooksSensitive(key)
|
|
369
|
+
? `${prefix}@"${REDACTION}"`
|
|
370
|
+
: match);
|
|
371
|
+
source = source.replace(/(@"((?:\\.|[^"\\\r\n])*)"\s*:\s*)(@?(?:0[xX][0-9A-Fa-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|YES|NO|nil|NULL))(?=[\s,}])/g,
|
|
372
|
+
(match, prefix, key) => keyLooksSensitive(key)
|
|
373
|
+
? `${prefix}${REDACTION}`
|
|
374
|
+
: match);
|
|
375
|
+
const result = redactSourceText(source, { shellOnly: false, hashComments: false });
|
|
376
|
+
return { text: result.text, redacted: result.text !== input };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export function redactSensitiveSourceText(input) {
|
|
380
|
+
return redactSourceText(input, { shellOnly: false, hashComments: true });
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export function redactSensitiveShellSourceText(input) {
|
|
384
|
+
return redactSourceText(input, { shellOnly: true });
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
export {
|
|
389
|
+
redactSensitiveCssText,
|
|
390
|
+
redactSensitiveMarkupText,
|
|
391
|
+
redactSensitiveObjectiveCText,
|
|
392
|
+
redactSensitiveYamlText,
|
|
393
|
+
redactSourceText
|
|
394
|
+
};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
const REDACTION = "[REDACTED_SECRET]";
|
|
2
|
+
|
|
3
|
+
const TOKEN_PATTERNS = [
|
|
4
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
5
|
+
/\bAKIA[0-9A-Z]{16}\b/g,
|
|
6
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
|
|
7
|
+
/\bgh[opsru]_[A-Za-z0-9_]{20,}\b/g,
|
|
8
|
+
/\bsk-(?:(?:proj|svcacct|admin|ant)-)?[A-Za-z0-9_-]{20,}\b/g,
|
|
9
|
+
/\bsk_(?:live|test)_[A-Za-z0-9]{16,}\b/g,
|
|
10
|
+
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,
|
|
11
|
+
// An npm token was recognised only where something named it -- `NPM_TOKEN=...`
|
|
12
|
+
// caught the assignment, a field called `token` caught the field -- so the one
|
|
13
|
+
// place it actually appears was missed: `//registry.npmjs.org/:_authToken=npm_…`
|
|
14
|
+
// is the whole of an `.npmrc`, and a `cat` of that file or a failing publish log
|
|
15
|
+
// carried the credential through unredacted. Every other provider here is
|
|
16
|
+
// recognised by the shape of its token; npm was the gap.
|
|
17
|
+
/\bnpm_[A-Za-z0-9]{30,}\b/g,
|
|
18
|
+
/\bAIza[0-9A-Za-z_-]{20,}\b/g,
|
|
19
|
+
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const CONNECTION_URL_PATTERN = /\b((?:https?|ftp|postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/"']+:)([^@\s/"']+)(@[^\s"'<>]+)/gi;
|
|
23
|
+
const BEARER_PATTERN = /\b(Bearer\s+)([A-Za-z0-9._~+/=-]{20,})\b/gi;
|
|
24
|
+
const BASIC_AUTH_PATTERN = /\b(Basic\s+)([A-Za-z0-9+/]{12,}={0,2})(?=$|[\s,;}])/gi;
|
|
25
|
+
// The value is one whitespace-free token, not the rest of the line. Taking the
|
|
26
|
+
// rest of the line made the result depend on where the header sat among the
|
|
27
|
+
// arguments: `curl URL -H "Authorization: Token abc123"` yielded `abc123"`, short
|
|
28
|
+
// enough to keep, while moving the header before the URL swept the URL into the
|
|
29
|
+
// value and pushed it past the length bar. Same header, same credential, opposite
|
|
30
|
+
// outcome. Credentials carry no spaces, so stopping at the first one also keeps
|
|
31
|
+
// prose like "Authorization: not required for local runs" intact.
|
|
32
|
+
const AUTHORIZATION_HEADER_PATTERN = /\b(Authorization\s*:\s*)([A-Za-z][A-Za-z0-9_-]{0,31})(\s+)([^\s\r\n"'`]+)/gi;
|
|
33
|
+
|
|
34
|
+
// A credential passed as a command-line option, which is how most CLIs take one.
|
|
35
|
+
// The assignment patterns below require a key starting with a letter, so every
|
|
36
|
+
// `--token=...` and `--token ...` walked straight past them.
|
|
37
|
+
const CLI_OPTION_SECRET_PATTERN = /(^|[\s({[])(--[A-Za-z][A-Za-z0-9_.-]{0,80})(=|\s+)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'`;,)}]+)/g;
|
|
38
|
+
|
|
39
|
+
// Under one of these schemes the header carries an opaque credential, so its
|
|
40
|
+
// length says nothing. Anything else after `Authorization:` is more likely prose
|
|
41
|
+
// — "Authorization: not required" — and keeps the ambiguous-syntax length bar.
|
|
42
|
+
const AUTHORIZATION_SCHEMES = new Set([
|
|
43
|
+
"bearer", "basic", "token", "digest", "negotiate", "ntlm",
|
|
44
|
+
"oauth", "hawk", "signature", "apikey", "jwt", "aws4-hmac-sha256"
|
|
45
|
+
]);
|
|
46
|
+
const QUERY_SECRET_PATTERN = /([?&])([A-Za-z][A-Za-z0-9_.-]{0,80})(=)([^&#\s]+)/gi;
|
|
47
|
+
const DOUBLE_QUOTED_SECRET_ASSIGNMENT_PATTERN = /(^|[\s{[,(;])((?:"|')?[$@%]?[A-Za-z][A-Za-z0-9_.-]{0,80}(?:"|')?\s*)(:=|:|=(?!=))\s*"((?:\\.|[^"\\\r\n])*)"/gim;
|
|
48
|
+
const SINGLE_QUOTED_SECRET_ASSIGNMENT_PATTERN = /(^|[\s{[,(;])((?:"|')?[$@%]?[A-Za-z][A-Za-z0-9_.-]{0,80}(?:"|')?\s*)(:=|:|=(?!=))\s*'((?:\\.|[^'\\\r\n])*)'/gim;
|
|
49
|
+
const SECRET_ASSIGNMENT_PATTERN = /(^|[\s{[,(;])((?:"|')?[$@%]?[A-Za-z][A-Za-z0-9_.-]{0,80}(?:"|')?\s*)(:=|:|=(?!=))\s*([^"'\s,;}]+)/gim;
|
|
50
|
+
const WHITESPACE_SECRET_ASSIGNMENT_PATTERN = /(^|[\s{[,(;])((?:"|')?(?:aws_)?secret_access_key(?:"|')?\s+)(["']?)([A-Za-z0-9/+=]{20,})/gim;
|
|
51
|
+
|
|
52
|
+
const SENSITIVE_KEY_TERMS = [
|
|
53
|
+
"api_key",
|
|
54
|
+
"token",
|
|
55
|
+
"password",
|
|
56
|
+
"passwd",
|
|
57
|
+
"pwd",
|
|
58
|
+
"secret",
|
|
59
|
+
"credential",
|
|
60
|
+
"client_secret",
|
|
61
|
+
"access_token",
|
|
62
|
+
"refresh_token",
|
|
63
|
+
"secret_access_key",
|
|
64
|
+
"passphrase",
|
|
65
|
+
"private_key",
|
|
66
|
+
"signing_key",
|
|
67
|
+
"authorization"
|
|
68
|
+
];
|
|
69
|
+
const SENSITIVE_PLURAL_KEYS = new Set([
|
|
70
|
+
"tokens",
|
|
71
|
+
"api_keys",
|
|
72
|
+
"passwords",
|
|
73
|
+
"secrets",
|
|
74
|
+
"credentials",
|
|
75
|
+
"client_secrets",
|
|
76
|
+
"access_tokens",
|
|
77
|
+
"refresh_tokens",
|
|
78
|
+
"session_tokens",
|
|
79
|
+
"passphrases",
|
|
80
|
+
"private_keys",
|
|
81
|
+
"signing_keys",
|
|
82
|
+
"authorizations"
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
function normalizeSecretValue(value) {
|
|
86
|
+
return String(value ?? "")
|
|
87
|
+
.trim()
|
|
88
|
+
.replace(/^[`"']|[`"']$/g, "")
|
|
89
|
+
.replace(/[.;)]+$/g, "");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function patternMatches(pattern, value) {
|
|
93
|
+
pattern.lastIndex = 0;
|
|
94
|
+
return pattern.test(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function looksLikeKnownSecret(value) {
|
|
98
|
+
return TOKEN_PATTERNS.some((pattern) => patternMatches(pattern, value))
|
|
99
|
+
|| patternMatches(CONNECTION_URL_PATTERN, value)
|
|
100
|
+
|| patternMatches(BEARER_PATTERN, value);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function normalizeSecretKey(key) {
|
|
104
|
+
return String(key ?? "")
|
|
105
|
+
.trim()
|
|
106
|
+
.replace(/^["']|["']$/g, "")
|
|
107
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
108
|
+
.replace(/[^A-Za-z0-9]+/g, "_")
|
|
109
|
+
.replace(/^_+|_+$/g, "")
|
|
110
|
+
.toLowerCase();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function keyLooksSensitive(key) {
|
|
114
|
+
const normalized = normalizeSecretKey(key);
|
|
115
|
+
return SENSITIVE_PLURAL_KEYS.has(normalized) || SENSITIVE_KEY_TERMS.some((term) => normalized === term
|
|
116
|
+
|| normalized.endsWith(`_${term}`));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function valueLooksPlaceholder(value) {
|
|
120
|
+
const clean = normalizeSecretValue(value);
|
|
121
|
+
if (!clean) return true;
|
|
122
|
+
if (/^(?:null|undefined|none|false|true|0|""|'')$/i.test(clean)) return true;
|
|
123
|
+
if (/^<[^>\n]{1,80}>$/.test(clean)) return true;
|
|
124
|
+
if (/^\[REDACTED_SECRET\]$/i.test(clean)) return true;
|
|
125
|
+
if (/^(?:not-set|unset|placeholder|example|changeme|change-me|redacted|xxx|\*{3,})$/i.test(clean)) return true;
|
|
126
|
+
if (/^your[-_][a-z0-9][a-z0-9_-]*$/i.test(clean)) return true;
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Length is only evidence where the syntax is ambiguous, and `=` is not.
|
|
131
|
+
//
|
|
132
|
+
// A short value used to be kept in the clear whatever the syntax, so `TOKEN=hunter2`
|
|
133
|
+
// and `PASSWORD=short7` went into the ledger verbatim. Every name in
|
|
134
|
+
// SENSITIVE_KEY_TERMS states outright what it holds — there is no `key` or `id`
|
|
135
|
+
// among them — so under an `=`, or inside quotes, a non-placeholder value is the
|
|
136
|
+
// secret the key says it is, at any length.
|
|
137
|
+
//
|
|
138
|
+
// A bare `:` is the ambiguous case, because English uses it too: `password: short`
|
|
139
|
+
// and `The secret: always run tests` are prose, and `Authorization: Token abc123`
|
|
140
|
+
// puts the scheme name where a value would go. Those keep a length bar.
|
|
141
|
+
const SHORT_VALUE_MIN_LENGTH = 8;
|
|
142
|
+
const AMBIGUOUS_VALUE_MIN_LENGTH = 12;
|
|
143
|
+
|
|
144
|
+
function valueLooksSensitive(key, value, syntax = "unquoted-colon") {
|
|
145
|
+
const clean = normalizeSecretValue(value);
|
|
146
|
+
if (!clean || valueLooksPlaceholder(clean)) return false;
|
|
147
|
+
if (looksLikeKnownSecret(clean)) return true;
|
|
148
|
+
if (!keyLooksSensitive(key)) return false;
|
|
149
|
+
if (syntax !== "unquoted-colon") return true;
|
|
150
|
+
return clean.length >= (keyNamesASecretOutright(key) ? SHORT_VALUE_MIN_LENGTH : AMBIGUOUS_VALUE_MIN_LENGTH);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Under a bare `:`, these names carry enough intent on their own to redact a short
|
|
154
|
+
// value; the broader terms wait for length before touching prose.
|
|
155
|
+
function keyNamesASecretOutright(key) {
|
|
156
|
+
const normalized = normalizeSecretKey(key);
|
|
157
|
+
return ["password", "passwd", "pwd", "secret", "credential", "passphrase", "private_key", "signing_key"]
|
|
158
|
+
.some((term) => normalized === term || normalized.endsWith(`_${term}`))
|
|
159
|
+
|| ["passwords", "secrets", "credentials", "passphrases", "private_keys", "signing_keys"].includes(normalized);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function assignmentSyntax(separator) {
|
|
163
|
+
return separator.includes("=") || separator.includes("<-") ? "assignment" : "unquoted-colon";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function redactSensitiveTextInternal(input) {
|
|
167
|
+
if (typeof input !== "string") return { text: "", redacted: false };
|
|
168
|
+
let text = input;
|
|
169
|
+
|
|
170
|
+
text = text.replace(CONNECTION_URL_PATTERN, (_match, prefix, _password, suffix) => `${prefix}${REDACTION}${suffix}`);
|
|
171
|
+
text = text.replace(BEARER_PATTERN, (_match, prefix) => `${prefix}${REDACTION}`);
|
|
172
|
+
text = text.replace(BASIC_AUTH_PATTERN, (_match, prefix) => `${prefix}${REDACTION}`);
|
|
173
|
+
text = text.replace(AUTHORIZATION_HEADER_PATTERN, (match, prefix, scheme, spacing, value) => {
|
|
174
|
+
const syntax = AUTHORIZATION_SCHEMES.has(scheme.toLowerCase()) ? "assignment" : "unquoted-colon";
|
|
175
|
+
if (!valueLooksSensitive("authorization", value, syntax)) return match;
|
|
176
|
+
return `${prefix}${scheme}${spacing}${REDACTION}`;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Over-redaction is the safe direction here: a flag whose name says "secret"
|
|
180
|
+
// and whose argument is a plain name — `docker service create --secret build` —
|
|
181
|
+
// loses that name from the record and cannot serve as verify evidence. Reading
|
|
182
|
+
// the name as the credential it is called is the cheaper mistake.
|
|
183
|
+
text = text.replace(CLI_OPTION_SECRET_PATTERN, (match, prefix, flag, separator, value) => {
|
|
184
|
+
// A following option is the next flag, not this flag's argument.
|
|
185
|
+
if (separator !== "=" && value.startsWith("-")) return match;
|
|
186
|
+
if (!keyLooksSensitive(flag) || !valueLooksSensitive(flag, value, "assignment")) return match;
|
|
187
|
+
return `${prefix}${flag}${separator === "=" ? "= " : " "}${REDACTION}`;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
for (const pattern of TOKEN_PATTERNS) text = text.replace(pattern, REDACTION);
|
|
191
|
+
|
|
192
|
+
text = text.replace(QUERY_SECRET_PATTERN, (match, prefix, key, separator, value) => {
|
|
193
|
+
if (!keyLooksSensitive(key) || !valueLooksSensitive(key, value, "assignment")) return match;
|
|
194
|
+
return `${prefix}${key}${separator}${REDACTION}`;
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
text = text.replace(DOUBLE_QUOTED_SECRET_ASSIGNMENT_PATTERN, (match, prefix, key, separator, value) => {
|
|
198
|
+
if (!keyLooksSensitive(key) || !valueLooksSensitive(key, value, "quoted")) return match;
|
|
199
|
+
return `${prefix}${key}${separator} "${REDACTION}"`;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
text = text.replace(SINGLE_QUOTED_SECRET_ASSIGNMENT_PATTERN, (match, prefix, key, separator, value) => {
|
|
203
|
+
if (!keyLooksSensitive(key) || !valueLooksSensitive(key, value, "quoted")) return match;
|
|
204
|
+
return `${prefix}${key}${separator} '${REDACTION}'`;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
text = text.replace(SECRET_ASSIGNMENT_PATTERN, (match, prefix, key, separator, value) => {
|
|
208
|
+
if (!keyLooksSensitive(key) || !valueLooksSensitive(key, value, assignmentSyntax(separator))) return match;
|
|
209
|
+
return `${prefix}${key}${separator} ${REDACTION}`;
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
text = text.replace(WHITESPACE_SECRET_ASSIGNMENT_PATTERN, (match, prefix, key, quote, value) => {
|
|
213
|
+
if (!valueLooksSensitive(key, value)) return match;
|
|
214
|
+
return `${prefix}${key}${quote}${REDACTION}`;
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
return { text, redacted: text !== input };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function redactSensitiveText(input) {
|
|
221
|
+
return redactSensitiveTextInternal(input);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
REDACTION,
|
|
226
|
+
SENSITIVE_KEY_TERMS,
|
|
227
|
+
SENSITIVE_PLURAL_KEYS,
|
|
228
|
+
keyLooksSensitive,
|
|
229
|
+
looksLikeKnownSecret,
|
|
230
|
+
normalizeSecretKey,
|
|
231
|
+
redactSensitiveTextInternal,
|
|
232
|
+
valueLooksPlaceholder,
|
|
233
|
+
valueLooksSensitive
|
|
234
|
+
};
|
|
@@ -4,13 +4,15 @@ description: Piagent second-opinion advisor for risky plans and architecture dec
|
|
|
4
4
|
tools: read, grep, find, ls
|
|
5
5
|
thinking: high
|
|
6
6
|
systemPromptMode: replace
|
|
7
|
-
inheritProjectContext:
|
|
7
|
+
inheritProjectContext: false
|
|
8
8
|
inheritSkills: false
|
|
9
|
-
defaultContext:
|
|
9
|
+
defaultContext: fresh
|
|
10
|
+
turnBudget: {"maxTurns":8,"graceTurns":0}
|
|
10
11
|
defaultProgress: true
|
|
11
12
|
acceptance: {"level":"attested"}
|
|
12
13
|
acceptanceRole: read-only
|
|
13
14
|
rolePolicyVersion: role-policy-v1
|
|
15
|
+
helperRequestSchemaVersion: 2
|
|
14
16
|
outputSchema: oracle-result-v1
|
|
15
17
|
---
|
|
16
18
|
|
|
@@ -18,7 +20,7 @@ You are `piagent-oracle`, a second-opinion subagent.
|
|
|
18
20
|
|
|
19
21
|
Your job is to challenge assumptions before implementation. Do not edit files. Focus on risks, missed constraints, simpler alternatives, and verification strategy.
|
|
20
22
|
|
|
21
|
-
The parent must supply a bounded HelperRequest
|
|
23
|
+
The parent must supply a bounded HelperRequest v2 with `isolated-minimal` context transfer. This is the sole optional helper, not a mandatory phase. Stay inside its read/tool/budget/stopping boundaries and never perform or request external writes, destructive actions, permission expansion, another helper, or a retry.
|
|
22
24
|
|
|
23
25
|
Return a concise recommendation:
|
|
24
26
|
|