@kontourai/flow-agents 3.3.0 → 3.4.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/.github/workflows/add-to-project.yml +15 -0
- package/.github/workflows/ci.yml +161 -0
- package/CHANGELOG.md +48 -0
- package/CONTEXT.md +5 -1
- package/README.md +19 -8
- package/build/src/builder-flow-run-adapter.d.ts +80 -0
- package/build/src/builder-flow-run-adapter.js +241 -0
- package/build/src/builder-flow-runtime.d.ts +16 -0
- package/build/src/builder-flow-runtime.js +290 -0
- package/build/src/cli/builder-run.d.ts +1 -0
- package/build/src/cli/builder-run.js +27 -0
- package/build/src/cli/effective-backlog-settings.js +70 -2
- package/build/src/cli/init.d.ts +34 -0
- package/build/src/cli/init.js +341 -61
- package/build/src/cli/kit.js +55 -12
- package/build/src/cli/pull-work-provider.js +346 -5
- package/build/src/cli/skill-drift-check.d.ts +1 -0
- package/build/src/cli/skill-drift-check.js +165 -0
- package/build/src/cli/telemetry-doctor.d.ts +37 -0
- package/build/src/cli/telemetry-doctor.js +53 -6
- package/build/src/cli/validate-hook-influence.js +37 -7
- package/build/src/cli/workflow-sidecar.d.ts +93 -8
- package/build/src/cli/workflow-sidecar.js +1175 -158
- package/build/src/cli.js +5 -0
- package/build/src/flow-kit/validate.d.ts +54 -34
- package/build/src/flow-kit/validate.js +237 -26
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/lib/console-connect-options.d.ts +97 -0
- package/build/src/lib/console-connect-options.js +199 -0
- package/build/src/lib/console-telemetry-validate.d.ts +49 -0
- package/build/src/lib/console-telemetry-validate.js +91 -0
- package/build/src/lib/flow-resolver.d.ts +56 -3
- package/build/src/lib/flow-resolver.js +151 -11
- package/build/src/lib/fs.d.ts +17 -0
- package/build/src/lib/fs.js +172 -0
- package/build/src/lib/local-artifact-root.d.ts +44 -1
- package/build/src/lib/local-artifact-root.js +131 -3
- package/build/src/runtime-adapters.d.ts +39 -3
- package/build/src/runtime-adapters.js +77 -31
- package/build/src/tools/build-universal-bundles.js +40 -2
- package/build/src/tools/codex-agent-routing.d.ts +2 -0
- package/build/src/tools/codex-agent-routing.js +49 -0
- package/build/src/tools/generate-context-map.js +1 -0
- package/build/src/tools/validate-source-tree.js +27 -1
- package/context/scripts/hooks/lib/kit-catalog.js +235 -0
- package/context/scripts/hooks/lib/runnable-command.js +177 -0
- package/context/scripts/hooks/stop-goal-fit.js +278 -48
- package/context/scripts/hooks/workflow-steering.js +121 -21
- package/context/scripts/package.json +3 -0
- package/context/scripts/telemetry/install-console-config.sh +25 -4
- package/context/scripts/telemetry/lib/config.sh +102 -12
- package/context/scripts/telemetry/lib/pricing.sh +50 -0
- package/context/scripts/telemetry/lib/session.sh +3 -0
- package/context/scripts/telemetry/lib/transport.sh +87 -0
- package/context/scripts/telemetry/lib/usage.sh +205 -4
- package/context/scripts/telemetry/telemetry.conf +6 -0
- package/context/scripts/telemetry/telemetry.sh +48 -0
- package/context/settings/workspace-backlog-provider-settings.example.json +48 -0
- package/docs/agent-usage-feedback-loop.md +35 -0
- package/docs/architecture-engine-and-kits.md +110 -0
- package/docs/context-map.md +2 -0
- package/docs/decisions/embeddable-engine.md +152 -0
- package/docs/decisions/index.md +3 -1
- package/docs/decisions/trust-ledger-retention.md +88 -0
- package/docs/decisions/workflow-enforcement.md +31 -9
- package/docs/fixture-ownership.md +3 -0
- package/docs/implementing-trust-reconciliation.md +129 -0
- package/docs/index.md +19 -9
- package/docs/integrations/flow-agents-console.md +167 -0
- package/docs/kit-authoring-guide.md +52 -21
- package/docs/spec/builder-flow-runtime.md +80 -0
- package/docs/spec/runtime-hook-surface.md +45 -1
- package/docs/specs/economics-record-contract.md +270 -0
- package/docs/specs/harness-capability-matrix.md +74 -0
- package/docs/specs/learning-review-proposals-contract.md +340 -0
- package/docs/specs/routing-efficiency-review.md +59 -0
- package/docs/verifiable-trust.md +74 -25
- package/docs/workflow-usage-guide.md +10 -0
- package/evals/acceptance/prove-capture-teeth.sh +132 -0
- package/evals/ci/antigaming-suite.sh +1 -0
- package/evals/ci/run-baseline.sh +72 -4
- package/evals/fixtures/economics/acceptance.json +12 -0
- package/evals/fixtures/economics/agents/tool-worker-1/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-2/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-3/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-4/events.jsonl +1 -0
- package/evals/fixtures/economics/agents/tool-worker-5/events.jsonl +2 -0
- package/evals/fixtures/economics/critique.json +22 -0
- package/evals/fixtures/economics/expected-record.json +71 -0
- package/evals/fixtures/economics/session-usage-event.json +1 -0
- package/evals/fixtures/economics/state.json +11 -0
- package/evals/fixtures/economics/transcript.jsonl +3 -0
- package/evals/fixtures/hook-influence/cases.json +7 -7
- package/evals/fixtures/learning-review-proposals/balanced/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/economics.jsonl +5 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-1/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-2/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-3/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-4/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-5/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.json +30 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.md +66 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-5/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-6/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/repeat-window/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/under-threshold/economics.jsonl +3 -0
- package/evals/fixtures/telemetry/usage-transcript-sample.jsonl +4 -0
- package/evals/fixtures/trust-reconcile-exploits/mcp-degrade.json +42 -0
- package/evals/integration/test_builder_entry_enforcement.sh +241 -0
- package/evals/integration/test_builder_step_producers.sh +18 -10
- package/evals/integration/test_bundle_install.sh +172 -0
- package/evals/integration/test_console_tenant_isolation.sh +167 -0
- package/evals/integration/test_critique_supersession_roundtrip.sh +4 -1
- package/evals/integration/test_dual_emit_flow_step.sh +10 -4
- package/evals/integration/test_economics_record.sh +674 -0
- package/evals/integration/test_effective_backlog_settings.sh +1 -1
- package/evals/integration/test_evidence_capture_hook.sh +17 -2
- package/evals/integration/test_exemption_usage_review.sh +198 -0
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +83 -0
- package/evals/integration/test_flowdef_session_activation.sh +0 -1
- package/evals/integration/test_flowdef_session_history_preservation.sh +13 -3
- package/evals/integration/test_gate_lockdown.sh +7 -0
- package/evals/integration/test_gate_review_inquiry_records.sh +9 -1
- package/evals/integration/test_goal_fit_hook.sh +2031 -0
- package/evals/integration/test_hook_category_behaviors.sh +8 -1
- package/evals/integration/test_hook_influence_cases.sh +25 -1
- package/evals/integration/test_install_merge.sh +227 -2
- package/evals/integration/test_kit_conformance_levels.sh +6 -6
- package/evals/integration/test_learning_review_proposals.sh +329 -0
- package/evals/integration/test_liveness_conflict_injection.sh +26 -22
- package/evals/integration/test_liveness_console_relay.sh +166 -0
- package/evals/integration/test_liveness_heartbeat.sh +17 -17
- package/evals/integration/test_liveness_worktree_root.sh +575 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +6 -1
- package/evals/integration/test_publish_delivery.sh +331 -1
- package/evals/integration/test_pull_work_board.sh +200 -0
- package/evals/integration/test_pull_work_provider.sh +1 -1
- package/evals/integration/test_record_check.sh +378 -0
- package/evals/integration/test_routing_efficiency.sh +71 -0
- package/evals/integration/test_runtime_adapter_activation.sh +28 -0
- package/evals/integration/test_session_resume_roundtrip.sh +16 -19
- package/evals/integration/test_skill_drift_check.sh +870 -0
- package/evals/integration/test_telemetry.sh +445 -0
- package/evals/integration/test_telemetry_doctor.sh +66 -0
- package/evals/integration/test_telemetry_usage_pipeline.sh +228 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +30 -13
- package/evals/integration/test_trust_reconcile_trailer_diagnostic.sh +247 -0
- package/evals/integration/test_usage_cost.sh +61 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +1395 -0
- package/evals/integration/test_workflow_steering_hook.sh +157 -16
- package/evals/integration/test_workspace_settings.sh +176 -0
- package/evals/lib/env.sh +26 -0
- package/evals/lib/node.sh +8 -0
- package/evals/run.sh +29 -0
- package/evals/static/test_ci_integration_coverage.sh +115 -0
- package/evals/static/test_declared_scope_forms_documented.sh +114 -0
- package/evals/static/test_universal_bundles.sh +34 -0
- package/evals/static/test_validate_source_kit_asset_scope.sh +259 -0
- package/evals/static/test_workflow_skills.sh +1 -1
- package/kits/builder/flows/build.flow.json +9 -18
- package/kits/builder/flows/publish-learn.flow.json +5 -1
- package/kits/builder/kit.json +120 -0
- package/kits/builder/skills/deliver/SKILL.md +42 -0
- package/kits/builder/skills/evidence-gate/SKILL.md +12 -0
- package/kits/builder/skills/execute-plan/SKILL.md +9 -0
- package/kits/builder/skills/learning-review/SKILL.md +51 -0
- package/kits/builder/skills/plan-work/SKILL.md +17 -20
- package/kits/builder/skills/pull-work/SKILL.md +21 -0
- package/kits/builder/skills/release-readiness/SKILL.md +12 -0
- package/kits/knowledge/kit.json +9 -0
- package/kits/veritas-governance/docs/README.md +35 -7
- package/kits/veritas-governance/fixtures/exemption-review/mixed-fresh-stale.DECLARED.json +14 -0
- package/kits/veritas-governance/kit.json +14 -0
- package/kits/veritas-governance/skills/exemption-usage-review/SKILL.md +128 -0
- package/kits/veritas-governance/skills/exemption-usage-review/review-exemptions.mjs +231 -0
- package/package.json +2 -2
- package/packaging/manifest.json +29 -0
- package/schemas/backlog-provider-settings.schema.json +13 -0
- package/schemas/workflow-state.schema.json +44 -0
- package/scripts/README.md +4 -0
- package/scripts/check-content-boundary.cjs +8 -1
- package/scripts/ci/trust-reconcile.js +136 -0
- package/scripts/hooks/codex-hook-adapter.js +77 -2
- package/scripts/hooks/evidence-capture.js +38 -5
- package/scripts/hooks/lib/codex-exit-code.js +316 -0
- package/scripts/hooks/lib/kit-catalog.js +235 -0
- package/scripts/hooks/lib/liveness-write.js +28 -1
- package/scripts/hooks/lib/local-artifact-paths.js +97 -1
- package/scripts/hooks/lib/runnable-command.js +177 -0
- package/scripts/hooks/lib/skill-drift.js +350 -0
- package/scripts/hooks/stop-goal-fit.js +278 -48
- package/scripts/hooks/workflow-steering.js +121 -21
- package/scripts/install-codex-home.sh +97 -47
- package/scripts/install-merge.js +72 -14
- package/scripts/install-owned-files.js +178 -0
- package/scripts/liveness/relay.sh +84 -0
- package/scripts/telemetry/economics-record.schema.json +145 -0
- package/scripts/telemetry/economics-record.sh +331 -0
- package/scripts/telemetry/install-console-config.sh +25 -4
- package/scripts/telemetry/learning-review-decide.sh +124 -0
- package/scripts/telemetry/learning-review-proposals.schema.json +161 -0
- package/scripts/telemetry/learning-review-proposals.sh +484 -0
- package/scripts/telemetry/lib/config.sh +102 -12
- package/scripts/telemetry/lib/pricing.sh +14 -6
- package/scripts/telemetry/lib/session.sh +3 -0
- package/scripts/telemetry/lib/transport.sh +133 -15
- package/scripts/telemetry/lib/usage.sh +121 -28
- package/scripts/telemetry/routing-efficiency.sh +0 -0
- package/scripts/telemetry/telemetry.conf +6 -0
- package/scripts/telemetry/telemetry.sh +48 -0
- package/src/builder-flow-run-adapter.ts +357 -0
- package/src/builder-flow-runtime.ts +348 -0
- package/src/cli/builder-flow-run-adapter.test.mjs +495 -0
- package/src/cli/builder-flow-runtime.test.mjs +213 -0
- package/src/cli/builder-run.ts +28 -0
- package/src/cli/codex-agent-routing.test.mjs +44 -0
- package/src/cli/codex-exit-code.test.mjs +207 -0
- package/src/cli/console-connect-options.test.mjs +329 -0
- package/src/cli/console-telemetry-validate.test.mjs +157 -0
- package/src/cli/effective-backlog-settings.ts +68 -2
- package/src/cli/flow-resolver-composition.test.mjs +101 -0
- package/src/cli/init.test.mjs +161 -0
- package/src/cli/init.ts +407 -62
- package/src/cli/kit-metadata-security.test.mjs +443 -0
- package/src/cli/kit.ts +50 -12
- package/src/cli/pull-work-provider.ts +377 -3
- package/src/cli/sidecar-pure-helpers.test.mjs +64 -0
- package/src/cli/skill-drift-check.ts +196 -0
- package/src/cli/telemetry-doctor.test.mjs +53 -0
- package/src/cli/telemetry-doctor.ts +50 -7
- package/src/cli/validate-hook-influence.ts +37 -6
- package/src/cli/workflow-sidecar.ts +1150 -151
- package/src/cli.ts +5 -0
- package/src/flow-kit/validate.ts +277 -38
- package/src/index.ts +19 -0
- package/src/lib/console-connect-options.ts +261 -0
- package/src/lib/console-telemetry-validate.ts +88 -0
- package/src/lib/flow-resolver.ts +153 -10
- package/src/lib/fs.ts +160 -0
- package/src/lib/local-artifact-root.ts +129 -3
- package/src/runtime-adapters.ts +113 -33
- package/src/tools/build-universal-bundles.ts +36 -2
- package/src/tools/codex-agent-routing.ts +48 -0
- package/src/tools/generate-context-map.ts +1 -0
- package/src/tools/validate-source-tree.ts +26 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_liveness_console_relay.sh — optional console liveness relay (#295, ADR 0021 §4/§7).
|
|
3
|
+
#
|
|
4
|
+
# Proves the flow-agents EMIT half of the fleet relay: when opted in + configured, a liveness event
|
|
5
|
+
# is mirrored to the Console as a `kontour.console.liveness` record over the SAME transport core the
|
|
6
|
+
# telemetry mirror uses (Bearer + tenant auth). And — non-negotiable — local-first holds: with the
|
|
7
|
+
# relay off or unconfigured, or when the relay POST fails, the durable local `liveness/events.jsonl`
|
|
8
|
+
# write always succeeds and nothing propagates.
|
|
9
|
+
#
|
|
10
|
+
# Deterministic (a local stub HTTP server, no network/model spend, self-cleaning). The relay POST is
|
|
11
|
+
# detached+async, so the stub-received assertions poll with a timeout.
|
|
12
|
+
# Usage: bash evals/integration/test_liveness_console_relay.sh
|
|
13
|
+
|
|
14
|
+
set -uo pipefail
|
|
15
|
+
|
|
16
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
17
|
+
source "$ROOT/evals/lib/node.sh"
|
|
18
|
+
|
|
19
|
+
TMPDIR_EVAL="$(mktemp -d)"
|
|
20
|
+
trap 'rm -rf "$TMPDIR_EVAL"; [[ -n "${STUB_PID:-}" ]] && kill "$STUB_PID" 2>/dev/null' EXIT
|
|
21
|
+
PORT=38795
|
|
22
|
+
RECV="$TMPDIR_EVAL/recv.jsonl"
|
|
23
|
+
|
|
24
|
+
errors=0
|
|
25
|
+
pass() { echo " [PASS] $1"; }
|
|
26
|
+
fail() { echo " [FAIL] $1"; errors=$((errors + 1)); }
|
|
27
|
+
|
|
28
|
+
# Stub Console endpoint: append each received {method, headers, body} as one JSON line. `mode` env
|
|
29
|
+
# controls the response — "ok" (200) or "fail" (500) — to exercise the relay-failure path.
|
|
30
|
+
start_stub() {
|
|
31
|
+
local mode="$1"
|
|
32
|
+
STUB_MODE="$mode" node -e '
|
|
33
|
+
const http=require("http"),fs=require("fs");
|
|
34
|
+
const out=process.argv[1], mode=process.env.STUB_MODE||"ok";
|
|
35
|
+
const s=http.createServer((req,res)=>{let b="";req.on("data",d=>b+=d);req.on("end",()=>{
|
|
36
|
+
fs.appendFileSync(out, JSON.stringify({method:req.method,headers:req.headers,body:b})+"\n");
|
|
37
|
+
res.writeHead(mode==="fail"?500:200); res.end(mode==="fail"?"err":"ok");
|
|
38
|
+
});});
|
|
39
|
+
s.listen(Number(process.argv[2]),"127.0.0.1");
|
|
40
|
+
setTimeout(()=>process.exit(0),30000);
|
|
41
|
+
' "$RECV" "$PORT" >/dev/null 2>&1 &
|
|
42
|
+
STUB_PID=$!
|
|
43
|
+
# wait for bind
|
|
44
|
+
for _ in $(seq 1 20); do
|
|
45
|
+
if node -e 'const n=require("net");const s=n.connect(Number(process.argv[1]),"127.0.0.1");s.on("connect",()=>{s.end();process.exit(0)});s.on("error",()=>process.exit(1))' "$PORT" 2>/dev/null; then return 0; fi
|
|
46
|
+
sleep 0.2
|
|
47
|
+
done
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
stop_stub() { [[ -n "${STUB_PID:-}" ]] && kill "$STUB_PID" 2>/dev/null; STUB_PID=""; }
|
|
51
|
+
|
|
52
|
+
# Emit a liveness event through the REAL wire-in (appendLivenessEvent), inheriting the caller's env.
|
|
53
|
+
emit_event() {
|
|
54
|
+
local root="$1" evt_json="$2"
|
|
55
|
+
node -e 'const {appendLivenessEvent}=require(process.argv[1]);appendLivenessEvent(process.argv[2], JSON.parse(process.argv[3]));' \
|
|
56
|
+
"$ROOT/scripts/hooks/lib/liveness-write.js" "$root" "$evt_json"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Poll the stub's received file for at least one POST (the relay is detached/async).
|
|
60
|
+
wait_for_post() { for _ in $(seq 1 25); do [[ -s "$RECV" ]] && return 0; sleep 0.2; done; return 1; }
|
|
61
|
+
|
|
62
|
+
ENDPOINT="http://127.0.0.1:${PORT}/records"
|
|
63
|
+
|
|
64
|
+
echo "=== console liveness relay (#295) ==="
|
|
65
|
+
|
|
66
|
+
# ─── 1. Relay ON + configured: POST a kontour.console.liveness record with auth ────────────────
|
|
67
|
+
echo "--- 1. relay on+configured: liveness emit mirrors to the Console with Bearer + tenant ---"
|
|
68
|
+
: > "$RECV"; start_stub ok || { fail "stub server did not start"; }
|
|
69
|
+
ROOT_A="$TMPDIR_EVAL/a"
|
|
70
|
+
EVT1='{"type":"claim","subjectId":"relay-subj-1","actor":"claude-code:sessA:host","actor_key":"claude-code:sessA:host","at":"2026-07-05T00:00:00Z","ttlSeconds":1800,"host":"host","branch":"agent/a/relay-subj-1","artifact_dir":"relay-subj-1"}'
|
|
71
|
+
(
|
|
72
|
+
export FLOW_AGENTS_CONSOLE_LIVENESS_RELAY=1
|
|
73
|
+
export FLOW_AGENTS_CONSOLE_LIVENESS_ENDPOINT_URL="$ENDPOINT"
|
|
74
|
+
export CONSOLE_TELEMETRY_TOKEN="tok-abc123"
|
|
75
|
+
export CONSOLE_TENANT_ID="tenant-1"
|
|
76
|
+
emit_event "$ROOT_A" "$EVT1"
|
|
77
|
+
)
|
|
78
|
+
[[ -s "$ROOT_A/liveness/events.jsonl" ]] && pass "local liveness/events.jsonl written (local-first)" || fail "local liveness write did not happen"
|
|
79
|
+
if wait_for_post; then pass "relay POSTed to the Console endpoint"; else fail "relay did NOT POST within timeout"; fi
|
|
80
|
+
node -e '
|
|
81
|
+
const fs=require("fs"); const raw=fs.readFileSync(process.argv[1],"utf8").trim();
|
|
82
|
+
if(!raw){console.log("NO_POST");process.exit(0)}
|
|
83
|
+
const r=JSON.parse(raw.split("\n")[0]); const b=JSON.parse(r.body);
|
|
84
|
+
const checks=[
|
|
85
|
+
["method POST", r.method==="POST"],
|
|
86
|
+
["content-type json", (r.headers["content-type"]||"").includes("application/json")],
|
|
87
|
+
["authorization bearer", r.headers["authorization"]==="Bearer tok-abc123"],
|
|
88
|
+
["tenant header", r.headers["x-console-tenant-id"]==="tenant-1"],
|
|
89
|
+
["schema kontour.console.liveness", b.schema==="kontour.console.liveness"],
|
|
90
|
+
["version 0.1", b.version==="0.1"],
|
|
91
|
+
["type claim", b.type==="claim"],
|
|
92
|
+
["subjectId", b.subjectId==="relay-subj-1"],
|
|
93
|
+
["actor", b.actor==="claude-code:sessA:host"],
|
|
94
|
+
["branch", b.branch==="agent/a/relay-subj-1"],
|
|
95
|
+
];
|
|
96
|
+
for(const [name,ok] of checks) console.log((ok?"OK ":"BAD ")+name);
|
|
97
|
+
' "$RECV" > "$TMPDIR_EVAL/checks.txt" 2>&1
|
|
98
|
+
while IFS= read -r line; do
|
|
99
|
+
[[ "$line" == OK* ]] && pass "record ${line#OK }" || fail "record ${line#BAD } — $(cat "$TMPDIR_EVAL/checks.txt")"
|
|
100
|
+
done < <(grep -E '^(OK|BAD) ' "$TMPDIR_EVAL/checks.txt")
|
|
101
|
+
stop_stub
|
|
102
|
+
|
|
103
|
+
# ─── 2. Relay OFF (no flag): local write happens, NO POST (local-first) ────────────────────────
|
|
104
|
+
echo "--- 2. relay OFF: local write still happens, nothing is POSTed ---"
|
|
105
|
+
: > "$RECV"; start_stub ok
|
|
106
|
+
ROOT_B="$TMPDIR_EVAL/b"
|
|
107
|
+
( export FLOW_AGENTS_CONSOLE_LIVENESS_ENDPOINT_URL="$ENDPOINT"; unset FLOW_AGENTS_CONSOLE_LIVENESS_RELAY; emit_event "$ROOT_B" '{"type":"claim","subjectId":"off-1","actor":"a","at":"t"}' )
|
|
108
|
+
sleep 1
|
|
109
|
+
[[ -s "$ROOT_B/liveness/events.jsonl" ]] && pass "local write happened with relay OFF" || fail "local write missing with relay OFF"
|
|
110
|
+
[[ ! -s "$RECV" ]] && pass "NO POST when the relay flag is off (opt-in respected)" || fail "a POST happened with the relay off"
|
|
111
|
+
stop_stub
|
|
112
|
+
|
|
113
|
+
# ─── 3. Relay ON but NO endpoint configured: no-op, local write intact ──────────────────────────
|
|
114
|
+
echo "--- 3. relay on but unconfigured (no endpoint): no-op, local write intact ---"
|
|
115
|
+
: > "$RECV"; start_stub ok
|
|
116
|
+
ROOT_C="$TMPDIR_EVAL/c"
|
|
117
|
+
( export FLOW_AGENTS_CONSOLE_LIVENESS_RELAY=1; unset FLOW_AGENTS_CONSOLE_LIVENESS_ENDPOINT_URL FLOW_AGENTS_CONSOLE_URL CONSOLE_TELEMETRY_URL CONSOLE_URL; emit_event "$ROOT_C" '{"type":"claim","subjectId":"noep-1","actor":"a","at":"t"}' )
|
|
118
|
+
sleep 1
|
|
119
|
+
[[ -s "$ROOT_C/liveness/events.jsonl" ]] && pass "local write happened with no endpoint configured" || fail "local write missing with no endpoint"
|
|
120
|
+
[[ ! -s "$RECV" ]] && pass "NO POST when no console endpoint is configured (no-op)" || fail "a POST happened with no endpoint configured"
|
|
121
|
+
stop_stub
|
|
122
|
+
|
|
123
|
+
# ─── 4. Relay FAILURE (endpoint returns 500): local emit still succeeds, non-fatal ─────────────
|
|
124
|
+
echo "--- 4. relay failure (endpoint 500 / detached): local emit exit unaffected ---"
|
|
125
|
+
: > "$RECV"; start_stub fail
|
|
126
|
+
ROOT_D="$TMPDIR_EVAL/d"
|
|
127
|
+
(
|
|
128
|
+
export FLOW_AGENTS_CONSOLE_LIVENESS_RELAY=1
|
|
129
|
+
export FLOW_AGENTS_CONSOLE_LIVENESS_ENDPOINT_URL="$ENDPOINT"
|
|
130
|
+
emit_event "$ROOT_D" '{"type":"heartbeat","subjectId":"fail-1","actor":"a","at":"t"}'
|
|
131
|
+
)
|
|
132
|
+
rc=$?
|
|
133
|
+
[[ "$rc" -eq 0 ]] && pass "liveness emit exits 0 even when the relay endpoint fails (non-fatal)" || fail "liveness emit exited non-zero ($rc) on relay failure"
|
|
134
|
+
[[ -s "$ROOT_D/liveness/events.jsonl" ]] && pass "local write happened despite relay 500 (local-first)" || fail "local write missing on relay failure"
|
|
135
|
+
stop_stub
|
|
136
|
+
|
|
137
|
+
# ─── 5. Injection: a hostile actor/branch is JSON-escaped, never raw in the POST body ──────────
|
|
138
|
+
echo "--- 5. injection: hostile control bytes in actor/branch are escaped, not raw ---"
|
|
139
|
+
: > "$RECV"; start_stub ok
|
|
140
|
+
ROOT_E="$TMPDIR_EVAL/e"
|
|
141
|
+
# Build the hostile event in node (embed ESC 0x1b + BEL 0x07) so no control bytes enter the shell.
|
|
142
|
+
HOSTILE_EVT="$(node -e 'const esc=String.fromCharCode(27),bel=String.fromCharCode(7);process.stdout.write(JSON.stringify({type:"claim",subjectId:"inj-1",actor:"actor"+esc+"[31m"+bel+"EVIL",at:"t",branch:"agent/"+esc+"x/inj-1"}))')"
|
|
143
|
+
(
|
|
144
|
+
export FLOW_AGENTS_CONSOLE_LIVENESS_RELAY=1
|
|
145
|
+
export FLOW_AGENTS_CONSOLE_LIVENESS_ENDPOINT_URL="$ENDPOINT"
|
|
146
|
+
emit_event "$ROOT_E" "$HOSTILE_EVT"
|
|
147
|
+
)
|
|
148
|
+
wait_for_post || true
|
|
149
|
+
node -e '
|
|
150
|
+
const fs=require("fs"); const raw=fs.readFileSync(process.argv[1],"utf8").trim();
|
|
151
|
+
if(!raw){console.log("NO_POST");process.exit(0)}
|
|
152
|
+
const body=JSON.parse(raw.split("\n")[0]).body;
|
|
153
|
+
const hasRawCtl=/[\x00-\x08\x0b\x0c\x0e-\x1f]/.test(body);
|
|
154
|
+
console.log(hasRawCtl?"RAW":"ESCAPED");
|
|
155
|
+
' "$RECV" > "$TMPDIR_EVAL/inj.txt" 2>&1
|
|
156
|
+
if grep -q ESCAPED "$TMPDIR_EVAL/inj.txt"; then pass "hostile actor/branch control bytes are JSON-escaped, never raw in the POST body (injection discipline)"; else fail "raw control bytes reached the POST body: $(cat "$TMPDIR_EVAL/inj.txt")"; fi
|
|
157
|
+
stop_stub
|
|
158
|
+
|
|
159
|
+
echo ""
|
|
160
|
+
if [[ "$errors" -eq 0 ]]; then
|
|
161
|
+
echo "test_liveness_console_relay: all checks passed."
|
|
162
|
+
exit 0
|
|
163
|
+
else
|
|
164
|
+
echo "test_liveness_console_relay: $errors check(s) failed."
|
|
165
|
+
exit 1
|
|
166
|
+
fi
|
|
@@ -109,17 +109,13 @@ NODE
|
|
|
109
109
|
|
|
110
110
|
# is_valid_json_stdin <string> — true if the given string parses as JSON.
|
|
111
111
|
is_valid_json() {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
process.
|
|
115
|
-
process.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
} catch {
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
112
|
+
JSON_ARG="$1" node - <<'NODE'
|
|
113
|
+
try {
|
|
114
|
+
JSON.parse(process.env.JSON_ARG);
|
|
115
|
+
process.exit(0);
|
|
116
|
+
} catch {
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
123
119
|
NODE
|
|
124
120
|
}
|
|
125
121
|
|
|
@@ -342,6 +338,8 @@ fi
|
|
|
342
338
|
echo "--- D. End-to-end wrapper (claude-telemetry-hook.js) ---"
|
|
343
339
|
|
|
344
340
|
POST_TOOL_USE_PAYLOAD='{"hook_event_name":"PostToolUse","tool_name":"Bash","tool_input":{"command":"echo hi"},"tool_response":{"stdout":"hi"}}'
|
|
341
|
+
POST_TOOL_USE_PAYLOAD_FILE="$TMPDIR_EVAL/post-tool-use-payload.json"
|
|
342
|
+
printf '%s' "$POST_TOOL_USE_PAYLOAD" >"$POST_TOOL_USE_PAYLOAD_FILE"
|
|
345
343
|
|
|
346
344
|
# D1: a fresh (well past the 60s throttle, real clock) claim exists for the resolved
|
|
347
345
|
# actor -> exactly one heartbeat event is appended by the wrapper's postToolUse path.
|
|
@@ -349,7 +347,7 @@ D1_ROOT="$(new_scratch)"
|
|
|
349
347
|
D1_STALE_AT="$(iso_offset_ms -300000)"
|
|
350
348
|
seed_claim "$D1_ROOT" "d1-subj" "agent-hb" "$D1_STALE_AT" 1800
|
|
351
349
|
D1_OUT="$(cd "$D1_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb \
|
|
352
|
-
node "$CLAUDE_HOOK" PostToolUse dev
|
|
350
|
+
node "$CLAUDE_HOOK" PostToolUse dev <"$POST_TOOL_USE_PAYLOAD_FILE")"
|
|
353
351
|
D1_STATUS=$?
|
|
354
352
|
if [[ "$D1_STATUS" -eq 0 ]] \
|
|
355
353
|
&& is_valid_json "$D1_OUT" \
|
|
@@ -366,7 +364,7 @@ D2_ROOT="$(new_scratch)"
|
|
|
366
364
|
mkdir -p "$D2_ROOT/.kontourai/flow-agents/liveness"
|
|
367
365
|
printf '{not valid json' >"$D2_ROOT/.kontourai/flow-agents/$SNAPSHOT_FILENAME"
|
|
368
366
|
D2_OUT="$(cd "$D2_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb \
|
|
369
|
-
node "$CLAUDE_HOOK" PostToolUse dev
|
|
367
|
+
node "$CLAUDE_HOOK" PostToolUse dev <"$POST_TOOL_USE_PAYLOAD_FILE" 2>"$TMPDIR_EVAL/d2.err")"
|
|
370
368
|
D2_STATUS=$?
|
|
371
369
|
if [[ "$D2_STATUS" -eq 0 ]] \
|
|
372
370
|
&& is_valid_json "$D2_OUT" \
|
|
@@ -383,7 +381,7 @@ E_ROOT="$(new_scratch)"
|
|
|
383
381
|
E_STALE_AT="$(iso_offset_ms -300000)"
|
|
384
382
|
seed_claim "$E_ROOT" "e-subj" "agent-hb" "$E_STALE_AT" 1800
|
|
385
383
|
E_OUT="$(cd "$E_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb \
|
|
386
|
-
node "$CLAUDE_HOOK" PostToolUse dev
|
|
384
|
+
node "$CLAUDE_HOOK" PostToolUse dev <"$POST_TOOL_USE_PAYLOAD_FILE")"
|
|
387
385
|
E_STATUS=$?
|
|
388
386
|
if [[ "$E_STATUS" -eq 0 ]] && [[ "$(stream_line_count "$E_ROOT")" -eq 2 ]] \
|
|
389
387
|
&& grep -q '"type":"heartbeat"' "$(stream_file "$E_ROOT")"; then
|
|
@@ -396,11 +394,13 @@ fi
|
|
|
396
394
|
echo "--- F. Cross-runtime smoke (codex-telemetry-hook.js) ---"
|
|
397
395
|
|
|
398
396
|
CODEX_PAYLOAD='{"hook_event_name":"PostToolUse","tool_name":"shell","tool_input":{"command":"echo hi"}}'
|
|
397
|
+
CODEX_PAYLOAD_FILE="$TMPDIR_EVAL/codex-payload.json"
|
|
398
|
+
printf '%s' "$CODEX_PAYLOAD" >"$CODEX_PAYLOAD_FILE"
|
|
399
399
|
F_ROOT="$(new_scratch)"
|
|
400
400
|
F_STALE_AT="$(iso_offset_ms -300000)"
|
|
401
401
|
seed_claim "$F_ROOT" "f-subj" "agent-hb" "$F_STALE_AT" 1800
|
|
402
402
|
F_OUT="$(cd "$F_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb \
|
|
403
|
-
node "$CODEX_HOOK" PostToolUse dev
|
|
403
|
+
node "$CODEX_HOOK" PostToolUse dev <"$CODEX_PAYLOAD_FILE")"
|
|
404
404
|
F_STATUS=$?
|
|
405
405
|
if [[ "$F_STATUS" -eq 0 ]] && [[ "$(stream_line_count "$F_ROOT")" -eq 2 ]] \
|
|
406
406
|
&& grep -q '"type":"heartbeat"' "$(stream_file "$F_ROOT")"; then
|
|
@@ -415,8 +415,8 @@ echo "--- G. Wrapper-level throttle smoke ---"
|
|
|
415
415
|
G_ROOT="$(new_scratch)"
|
|
416
416
|
G_STALE_AT="$(iso_offset_ms -300000)"
|
|
417
417
|
seed_claim "$G_ROOT" "g-subj" "agent-hb" "$G_STALE_AT" 1800
|
|
418
|
-
(cd "$G_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb node "$CLAUDE_HOOK" PostToolUse dev
|
|
419
|
-
(cd "$G_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb node "$CLAUDE_HOOK" PostToolUse dev
|
|
418
|
+
(cd "$G_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb node "$CLAUDE_HOOK" PostToolUse dev <"$POST_TOOL_USE_PAYLOAD_FILE" >/dev/null)
|
|
419
|
+
(cd "$G_ROOT" && TELEMETRY_ENABLED=false FLOW_AGENTS_ACTOR=agent-hb node "$CLAUDE_HOOK" PostToolUse dev <"$POST_TOOL_USE_PAYLOAD_FILE" >/dev/null)
|
|
420
420
|
if [[ "$(stream_line_count "$G_ROOT")" -eq 2 ]]; then
|
|
421
421
|
_pass "two back-to-back wrapper invocations append exactly one heartbeat (real-clock throttle smoke, AC3)"
|
|
422
422
|
else
|