Skip to content

feat(runtime): probe<->sensor protocol, schema and conformance kit (#73) - #100

Merged
karthickmk2001 merged 1 commit into
mainfrom
feat/73-probe-protocol
Nov 12, 2026
Merged

karthickmk2001 merged 1 commit into
mainfrom
feat/73-probe-protocol

Conversation

@karthickmk2001

Copy link
Copy Markdown
Collaborator

Closes #73

What does this change, and why?

The one contract every runtime probe speaks to the sensor, written down, machine-checkable, and enforced in CI. A probe for a new runtime (#56, #74–#78) can now be built from docs/RUNTIME_PROTOCOL.md and checked with one command, without reading another probe's code.

Spec, in docs/RUNTIME_PROTOCOL.md:

Schema: src/secfoo/runtime/protocol.schema.json (2020-12) covers the control messages and $refs evidence.schema.json for events. secfoo/runtime/protocol.py validates the same rules, and a test checks the two agree.

Conformance kit: secfoo sensor conformance -- <command> (secfoo/runtime/conformance/kit.py).

  • It starts a fake sensor on loopback TCP that answers hello with welcome.
  • It runs the probe author's sample app once per step of a documented, runtime-neutral contract, passed in SECFOO_CONFORMANCE_STEP. The Python reference app is secfoo.runtime.conformance.sample_app.
  • It validates every line, and checks the issue's list:
Check What it proves
inert With SECFOO_SENSOR unset, no connection is made at all.
call / nocall hello comes first; the watched symbol counts exactly 3, or has no hit.
privacy The sample app passes a sentinel through a concrete URL (/users/8675309?token=…) and an Authorization header into the watched function; none of it, nor any query string or header value, reaches the wire.
fail-open The sensor is killed mid-run, and the app still finishes and exits 0.
overhead The marginal cost per watched call (from two loop sizes, so interpreter start-up doesn't skew it) is within --max-call-overhead-us (default 50 µs, against #51's 1 ms p99 per request). One-time start and exit work is reported separately, capped at --max-startup-seconds.

A test also runs the kit against a deliberately bad "probe" that connects while inert, sends a concrete URL and leaks the sentinel, and confirms it fails inert, call and privacy.

CI: .github/workflows/ci.yml runs the kit against the reference Python probe (#55) on every push.

Probe fixes the kit found (that's its job):

  • Watched symbols in submodules (pkg.mod.func) weren't resolved until the next flush, so a short-lived process recorded no hits. The import hook now handles a package __path__.
  • Hot-path cost. The app-code check ran path normalisation on every call to a non-app function. It's now cached per code object, bringing a watched call to about 1.5 µs.
  • Flush cost. The coverage denominator and package metadata were recomputed on every flush. Both are now cached.
  • Protocol fidelity: auth now follows hello, the probe adopts welcome.flush_interval, and it doubles its interval on slow.

Result on the reference probe (Windows, CPython 3.14), on both backends:

PASS inert      exit 0, 0 connection(s) with SECFOO_SENSOR unset
PASS call       3 valid line(s)
PASS nocall     2 valid line(s)
PASS privacy    3 valid line(s)
PASS fail-open  exit 0 after 2.7s with the sensor killed
PASS overhead   watched call 0.12us bare -> 1.53us probed (+1.41us per call, budget 50us); one-time start/exit 2.01s (budget 5s)
6/6 checks passed.

Scope note: #73's "done when" also says the sensor (#67) implements every transport. This PR fixes the contract and ships the probe side, the reference fake sensor and the kit. The real secfoo sensor run listener, with spooling, forwarding and service install, is #67's own deliverable and builds on protocol.validate_message.

Testing

  • pytest tests passes. 1221 passed locally. The only failures are the 4 existing Windows-only POSIX permission and symlink tests that fail on main too; Linux CI is unaffected.
  • ruff check . adds no new findings.
  • Added tests/test_runtime/test_protocol.py (17 tests):
    • hello, auth and welcome validation
    • invalid fields named in errors
    • event lines checked with the Runtime evidence format, storage and secfoo runtime ingest #53 rules
    • forbidden-data detection
    • the schema agreeing with the validator
    • the hello → auth → events order, and welcome/slow being honoured
    • the reference probe passing the full kit
    • the kit catching a bad probe
    • the CLI's exit codes
    • the sample app shipping in the package

🤖 Generated with Claude Code

docs/RUNTIME_PROTOCOL.md specifies activation, the SECFOO_SENSOR_ADDR transports, newline-framed hello/auth/welcome/slow plus #53 lines, privacy, fail-open and versioning; protocol.schema.json and protocol.py validate it. secfoo sensor conformance -- <cmd> runs a probe's sample app against a fake loopback sensor and checks inert, call/nocall, privacy (sentinel in URL and header), fail-open (sensor killed mid-run) and marginal per-call overhead. CI runs it against the reference Python probe. Fixes the kit found in the probe: submodule symbol resolution, per-call app-code check, per-flush recomputation, auth after hello, and honouring welcome/slow.

Closes #73

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
if self.kill and len(self.lines) > 1:
self.close()
break
except OSError:
self._stop.set()
try:
self._server.close()
except OSError:
@karthickmk2001
karthickmk2001 merged commit 8b2c93f into main Nov 12, 2026
6 checks passed
@karthickmk2001
karthickmk2001 deleted the feat/73-probe-protocol branch November 12, 2026 04:15
@github-actions

Copy link
Copy Markdown

Leaderboard update

karthickmk2001 now has 61 points (rank #1, Silver). 39 more to reach Gold.

Full leaderboard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Probe ↔ sensor protocol and conformance kit (one contract for every runtime)

2 participants