g0 sentinel — MDM-deployed AI footprint discovery, PII exposure & governance - #194
Merged
Conversation
…e + governance (design) Committed-POC design for a ManageEngine-pushed sentinel: single self-contained binary, unattended AI footprint discovery, per-tool evidence-based PII exposure (no interception, no raw PII), MDM-collected snapshots rolled up into an org report, and a two-tier governance model (g0 decides, MDM enforces by default). Reuses existing endpoint/flows/enforcement/fleet code; TS + compiled binary, explicitly not a Rust rewrite. 6-week phasing, macOS-first, Windows depth as top risk. Co-Authored-By: Claude Fable 5 <[email protected]>
Five sourced research passes corrected the load-bearing assumptions: - ManageEngine Endpoint Central has NO native file-pull to console — the "MDM collects snapshot.json" model was wrong; add a thin customer-hosted collector + compact-summary via script output. Confirm Endpoint Central (not MDM Plus). Coarse scheduling → register own Scheduled Task/LaunchDaemon. Remediation is separate ME policy objects / REST API, not manifest ingest. - tree-sitter → web-tree-sitter (WASM) erases the native-single-binary blocker; Node SEA primary + Bun spike. Real long-pole is signing/notarization. - PII engine stays all-TS: OpenRedaction (MIT) + compromise + gitleaks rules; optional Presidio sidecar. No Python on endpoints. - OAuth grants + M365 web add-ins are NOT endpoint-scannable → reframe as SaaS admin-API connectors; endpoint-native surfaces (extensions, apps, coding agents, MCP, Outlook COM add-ins) lean in. - Positioning: differentiated vs network/proxy + SaaS-API camps; only Harmonic/Lanai run endpoint agents, both runtime-usage not static inventory. - Rust decision strengthened (WASM answers the perf worry) — stay TypeScript. Added §16 sources. Co-Authored-By: Claude Fable 5 <[email protected]>
… channel - Deployed unit is now a resident daemon (reuse src/daemon/ + resident watcher #193), not a one-shot scan: installed once, stays resident, streams deltas. - Default posture = well-behaved daemon (internal scheduling + targeted watches on high-signal paths), NOT hot-watch-everything — avoids EDR/AV collision and laptop resource cost. Aggressive real-time watch + blocking stays opt-in protect. - MDM-agnostic "dumb pipe" principle: MDM only pushes binary + config + trigger; same binary scales across Jamf, ManageEngine, Intune, Kandji, Workspace ONE via thin deployment recipes, not code forks. - Agent binary updated via MDM only; detection DB refreshes out-of-band (AV model). - Netskope dropped as a deployment channel (SSE ≠ MDM); model is MDM-only. - Added EDR-collision + daemon-lifecycle risks, EDR-allowlist to day-1 critical path, and EDR product as an open question. Co-Authored-By: Claude Fable 5 <[email protected]>
TDD, bite-sized tasks covering the two Phase-0 unknowns: - native tree-sitter → web-tree-sitter (WASM) migration: vendor grammar wasm, async initTreeSitter() preload keeping parseCode() sync, scan-bootstrap wiring, build/dist wasm bundling, parse-throughput perf gate. - single self-contained binary via Node SEA (Bun --compile fallback) with wasm embedded as SEA assets, proven to run with no node_modules. Plus a minimal `g0 sentinel scan` writing a snapshot (makes the binary demoable), and a day-1 logistics checklist (signing/notarization procurement, confirm Endpoint Central vs MDM Plus, EDR allowlist, pilot machines). Phases 1-4 deferred to their own plans. Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
…WASM) Co-Authored-By: Claude Fable 5 <[email protected]>
Preload relocated from runScan to runDiscovery — the universal entry every scan/flows/fleet/inventory/test/MCP path awaits before graph-build parses, so the sync parseCode() path never silently skips AST after the native->WASM move. Full suite: 2445 passed, 0 failed. Co-Authored-By: Claude Fable 5 <[email protected]>
- tsup onSuccess copies assets/wasm -> dist/assets/wasm - resolveWasmDir() walks up checking assets/wasm AND dist/assets/wasm so it resolves in dev (tsx), built bundles (dist/bin, dist/src), and the published package layout (verified: returns dist/assets/wasm with source assets hidden) Co-Authored-By: Claude Fable 5 <[email protected]>
~1.2k-line python file parses in 2.6 ms/parse (130 ms / 50 iters) under WASM web-tree-sitter — ~75x under the 200ms budget. Confirms the scheduled-scan workload is unaffected by the native->WASM move; the Rust-for-perf question is answered (spec §10). Existing hook-latency + watch-e2e perf gates still green. Co-Authored-By: Claude Fable 5 <[email protected]>
Reuses scanEndpoint() to emit a schema-v1 JSON snapshot (host + AI-tool footprint + endpoint score) atomically to a platform well-known path, and prints a compact summary line for MDM script-output capture (spec §8). Co-Authored-By: Claude Fable 5 <[email protected]>
…to Bun Co-Authored-By: Claude Fable 5 <[email protected]>
…, toolchain) Co-Authored-By: Claude Fable 5 <[email protected]>
Node SEA is incompatible with g0's ESM + top-level-await + import.meta.url codebase (CJS-only). Ship the binary via "bun build --compile" instead: - scripts/bun-entry.ts: Bun-only entry (never compiled by tsup) that embeds the 7 grammar wasm via file import attributes, maps them through a new setWasmFileResolver() hook, sets the version override, then dispatches like bin/g0. - parser.ts resolves wasm per-file (resolveWasmFile) so the embed override covers both the core and grammars. - fix binary crash: evidence-collector.ts did an unguarded top-level require of package.json; route through resilient getG0Version(). Add utils/version-override.ts; make version.ts + branding.ts override-aware and DRY. - remove dead native tree-sitter optionalDependencies; add bun devDependency. Verified in an isolated dir + clean env (no node_modules/assets): compiled self-test produced available:true, python:module, ts:program; product binary runs "g0 sentinel scan" (valid snapshot, empty stderr) and --version -> 2.1.0. Full suite: 2449 passed, 0 failed. Co-Authored-By: Claude Fable 5 <[email protected]>
…ruled out; WASM verified Co-Authored-By: Claude Fable 5 <[email protected]>
- docs/sentinel.md: g0 sentinel command reference (scan shipped; daemon/PII/ collector/governance/installers marked in-progress, linked to the design spec). - docs/solutions/mdm-ai-footprint-governance.md: customer-facing solution brief for MDM-deployed AI footprint discovery + PII exposure + governance (problem, architecture, per-MDM deploy recipes, governance model, shipped-vs-roadmap). - README + docs index: add Sentinel surface row (preview) and a Solutions section. Co-Authored-By: Claude Fable 5 <[email protected]>
Found via end-to-end testing: an unwritable --out (e.g. read-only path) dumped a
minified stack trace from writeSnapshotAtomic. Wrap the scan action so unattended
MDM runs emit a single clean line ('failed to write snapshot to <path>: <msg>')
and exit non-zero, per the never-crash contract.
Co-Authored-By: Claude Fable 5 <[email protected]>
…, no raw values Detects email/credit_card(Luhn)/us_ssn/ipv4(octet-validated)/phone/aws_access_key/ api_token/jwt/private_key over text, returning distinct counts per class and never the raw values (snapshots/reports must carry no raw PII). mergeCounts() aggregates across artifacts. Co-Authored-By: Claude Fable 5 <[email protected]>
For each tool: derive reach (callable MCP servers, network) and scan its local artifacts (session/history logs, config, MCP audit logs) for PII classes+counts via the classifier — locators carry per-file counts, never raw values. scoreExposure weights secrets/cards/ssn heaviest, amplified by reach. Co-Authored-By: Claude Fable 5 <[email protected]>
…port -> governance Completes the sentinel value chain (schema v2), all TDD: - snapshot v2: per-tool PII exposures + AI browser extensions + governance verdict + fleet-mergeable piiSummary; never carries raw PII. - exposure engine: per tool, reach (callable MCP servers + network) x evidenced PII (classes+counts over local session/history/MCP-audit artifacts, with per-file locators, no raw values); reach-amplified risk score. - browser-extensions: enumerate Chrome/Edge/Brave/Firefox extensions with merged permissions, AI detection, and CRXcavator-style permission risk scoring. - governance: guard0.policy.yaml (allow/deny/monitor by name / category: / glob), per-tool verdicts + machine compliance. - collector: resilient POST client + thin HTTP collector that writes snapshots to a dir (rejects non-snapshot POSTs); `g0 sentinel collect`. - report: self-contained HTML org roll-up (fleet summary, aggregate PII, per-machine exposure tables), HTML-escaped; `g0 sentinel report`. - `g0 sentinel scan` now builds exposures (installed tools), AI extensions, optional --policy governance, optional --post to a collector. Verified end-to-end on a synthetic machine: scan found 5 PII classes in a coding-agent history (no raw values), captured an AI extension, applied a policy, POSTed to the collector, and rendered an org report with zero raw-PII leakage. 36 sentinel tests pass. Co-Authored-By: Claude Fable 5 <[email protected]>
…rnance now shipped Co-Authored-By: Claude Fable 5 <[email protected]>
| res.end(JSON.stringify({ ok: true, file: path.basename(file) })); | ||
| } catch (err) { | ||
| res.writeHead(400, { 'content-type': 'application/json' }); | ||
| res.end(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) })); |
… tree-sitter) The native tree-sitter optionalDependencies were removed from package.json by hand-edit without regenerating the lockfile, so `npm ci` refused to run (package.json and package-lock.json out of sync) — failing every CI check at install. Regenerated the lockfile (131 stale entries removed); `npm ci` now passes, and lint/build/tests verified on a clean install. Co-Authored-By: Claude Fable 5 <[email protected]>
Root cause of the CI failures: regenerating package-lock.json on macOS pruned
platform-specific optional deps that Linux CI needs, so `npm ci` failed
('Missing @emnapi/core/@emnapi/runtime from lock file' — deps of vitest 4's
@rolldown/binding-wasm32-wasi).
- Drop `bun` from devDependencies: it's only needed for the local `build:bin`
packaging step (never run in CI) and dragged in 18 @oven/bun-* platform binaries
+ a rolldown/emnapi subtree, making the lockfile platform-fragile. build:bin now
guards with a clear 'install Bun' message if bun is absent.
- Rebuild the lockfile from main's known cross-platform-complete baseline, layering
only the two pure-JS additions (web-tree-sitter dep, tree-sitter-wasms devDep) and
removing the dead native tree-sitter optionalDependencies. Restored the two
@emnapi entries npm wrongly pruned. Validated: 0 unresolved deps across all
platforms; `npm ci` + lint + build + tests all clean.
Co-Authored-By: Claude Fable 5 <[email protected]>
g0 security scanScore 55/100 (F)
Findings
55 more findings
Gate: PASSED ✅ — See findings across every repo in your org → https://guard0.ai/signup?utm_source=github&utm_medium=pr_comment&utm_campaign=g0_action |
CI runs `npm test` before `npm run build`, so dist/assets/wasm didn't exist yet and tests/build/dist-wasm.test.ts failed (expected false to be true). Extract the assets->dist wasm copy into scripts/copy-wasm.mjs (shared by tsup.config.ts and the test); the test now runs the copy itself in beforeAll, so it validates the copy logic regardless of build order (assets/wasm is committed). Co-Authored-By: Claude Fable 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
g0 sentinel — an MDM-deployed agent that discovers each machine's AI footprint, shows per-tool PII exposure, rolls the fleet into one report, and enforces a governance policy. Driven by a committed-POC customer (ManageEngine shop, Windows + macOS all-staff).
This PR delivers the full software chain end-to-end (design → de-risk → complete feature set), all TDD. The last-mile items that need external procurement or a Windows host are called out at the bottom.
The customer ask → what ships here
bun build --compile)sentinel scan→ POSTs to a central collectorThe fleet flow
What's in the branch
Design:
docs/superpowers/specs/2026-07-23-g0-sentinel-fleet-ai-footprint-design.md(revised after 5 sourced research passes + the daemon-first / MDM-agnostic model), a Phase-0 plan, and a logistics checklist.Phase 0 de-risk: native
tree-sitter→web-tree-sitter(WASM) so nothing native blocks a single binary; 2.6 ms/parse benchmark; Node SEA ruled out (ESM + top-level await +import.meta.url) →bun build --compile.Feature chain (
src/sentinel/, schema v2):pii.ts— classifier: email/credit_card(Luhn)/us_ssn/ipv4/phone/aws_access_key/api_token/jwt/private_key → distinct counts, never raw values.exposure.ts— per-tool reach (callable MCP servers, network) × evidenced PII over the tool's local session/history/MCP-audit artifacts, with per-file locators + a risk score.browser-extensions.ts— Chrome/Edge/Brave/Firefox enumeration, merged permissions, AI detection, CRXcavator-style permission risk.governance.ts—guard0.policy.yaml(allow/deny/monitor by name /category:/ glob) → per-tool verdicts + machine compliance.collector.ts— resilient POST client + thin HTTP collector (rejects non-snapshot POSTs).report.ts— self-contained, HTML-escaped org report.g0 sentinel scan [--post --policy --no-pii],g0 sentinel collect,g0 sentinel report.Verification
typecheckclean; perf gate green (incl. the p95<100ms hook gate).Not in this PR (external boundaries, not skipped code)
Signed MSI + notarized PKG installers (need EV Authenticode + Apple Developer ID certs), the Windows runtime (needs a Windows host / cross-compile), live ManageEngine deployment (needs the customer console), snapshot signing (designed; reuse
inventory/sign.ts), the resident daemon (sentinel start; reusesrc/daemon/), and the MDM-enacted remediation manifest. The binary here is macOS/arm64.🤖 Generated with Claude Code