Sentinel Signal

Verify TrustOps VS Code / Copilot Enforcement

Source: docs/verify-trustops-vscode-enforcement.md

Document Content

Verify TrustOps VS Code / Copilot Enforcement

Architecture

Verify owns the decision and artifact control plane. It does not become the enforcement runtime:

canonical Verify evidence at cutoff T
  -> immutable organization policy version and resolved inventory
  -> trustops_decision_v1 evaluator
  -> immutable ALLOW / DENY / REVIEW / UNKNOWN snapshot
  -> pure target compiler
  -> VS Code contract validation, byte/rule preflight, and impact diff
  -> managed-settings.json + verify-manifest.json
  -> authenticated customer download
  -> customer-owned GitOps / MDM
  -> VS Code / GitHub Copilot enforcement

IntelligenceOrganization is the tenant root. Policies, snapshots, decisions, artifacts, rule mappings, downloads, and diffs are always resolved through the authenticated organization. A foreign object ID returns 404.

Policy and evidence contracts

IntelligenceEnforcementPolicy is a mutable name/status identity. Its IntelligenceEnforcementPolicyVersion children are append-only and guarded against update/delete. A version stores strict Pydantic-validated rules and the one-time resolution of every requested alias to a sorted canonical {server_id, registry_identifier} inventory. Reordering input does not alter the inventory fingerprint; later alias changes do not alter old versions.

Snapshot construction bulk-loads the full inventory and its source facts. In PostgreSQL it begins a REPEATABLE READ transaction before source reads. It does not perform per-server HTTP calls or SQL reads. evidence_cutoff_at is the newest semantic evidence timestamp in that stable fact set. The normalized evidence hash includes the fields actually used by the evaluator, including freshness timestamps, and excludes request time and unrelated row creation metadata.

The evaluator version is trustops_decision_v1, independent of the Verify build. Snapshot idempotency includes organization, policy version, evaluator version, and the complete input fingerprint. Only complete snapshots may be compiled; building and failed snapshots are rejected.

Reason codes are authoritative and deterministically ordered. UNKNOWN means evidence is insufficient, DENY means evidence violates a rule, and REVIEW means the evidence passes but human approval is required. Deny-only compilation never promotes UNKNOWN or REVIEW to DENY.

VS Code compiler and endpoint identity

The pure compiler accepts only an immutable McpDecisionSet and VscodeCompilationOptions. It has no SQLAlchemy, API, scoring, freshness, or approval dependency. Its target and schema identifiers are:

target = vscode_managed_settings
compiler_schema_version = vscode_managed_mcp_settings_v1

Every decision preserves Verify's authoritative_endpoint byte-for-byte. Target projection separately derives matcher_endpoint: HTTP/S is required; scheme and host are lowercased; default ports and fragments are removed; path case, query, and trailing slash are preserved. Wildcards and local commands are never generated. Duplicate endpoint decisions use DENY > UNKNOWN > REVIEW > ALLOW, while only effective ALLOW and DENY entries are emitted.

strict_allowlist produces exactly allowedMcpServers, deniedMcpServers, and allowManagedMcpServersOnly: true. deny_only produces exactly deniedMcpServers. Serialization is compact UTF-8 with fixed property/rule ordering and one final newline. There are no Verify keys or timestamps in the native file. An empty strict allowlist is valid but carries the high-severity STRICT_ALLOWLIST_EMPTY warning.

The configured size ceiling is MCP_VERIFY_MAX_VSCODE_POLICY_ARTIFACT_BYTES (default 2 MiB). Preview reports an oversized artifact without publishing it; generation returns a structured 422 and leaves the previous published artifact authoritative.

VS Code currently documents these managed settings for 1.130+ (allow/deny) and 1.132+ (allowManagedMcpServersOnly). Validate deployed values and source with Developer: Policy Diagnostics. File-based policy locations are:

  • macOS: /Library/Application Support/GitHubCopilot/managed-settings.json
  • Windows: %ProgramFiles%\GitHubCopilot\managed-settings.json
  • Linux: /etc/github-copilot/managed-settings.json

Microsoft's URL matcher behavior, rather than general URL equivalence, is the contract. In particular, test /mcp versus /mcp/, default versus explicit :443, and query-bearing endpoints against every supported VS Code release.

Publication, hashes, diff, and retention

Publication creates a generating row, compiles and validates in memory, hashes exact native bytes, serializes and separately hashes the manifest, uploads both to private versioned object keys, then atomically stores rule mappings, marks the artifact published, and supersedes the preceding artifact. An upload or validation failure marks only the candidate failed.

The manifest includes evaluator/compiler versions, policy and inventory, snapshot/cutoff/input fingerprint, decision and rule counts, size status, native SHA-256, scoring versions, Verify build, reason summary, warnings, exclusions, and deny_all_effective. Its own SHA-256 is stored in artifact metadata, not recursively inside the manifest.

Diffing compares effective matcher sets against the preceding artifact and reports newly allowed, newly denied, removed, unchanged, and reason-code deltas. Details are capped at 100 per category with truncation flags. The trustops.enforcement.changed webhook is queued only when effective allow or deny matcher sets materially change; it contains identifiers and counts, never policy bytes.

Governance history is retained: V1 has no automatic deletion of policy versions, snapshots, decisions, hashes, manifests, mappings, diffs, or native objects. Object lifecycle is a separate future governance decision.

API

All enforcement routes require intelligence:enforcement; the internal service token does not receive that scope.

POST /v1/intelligence/enforcement/policies
GET  /v1/intelligence/enforcement/policies/{policy_id}
POST /v1/intelligence/enforcement/policies/{policy_id}/versions
POST /v1/intelligence/enforcement/policies/{policy_id}/preview
GET  /v1/intelligence/enforcement/snapshots/{snapshot_id}
POST /v1/intelligence/enforcement/snapshots/{snapshot_id}/artifacts
GET  /v1/intelligence/enforcement/artifacts/{artifact_id}
GET  /v1/intelligence/enforcement/artifacts/{artifact_id}/diff
POST /v1/intelligence/enforcement/artifacts/{artifact_id}/download

Experimental MCP Registry v0.1 projection

Enable only with all three settings:

INTELLIGENCE_MCP_REGISTRY_PREVIEW_ENABLED=true
INTELLIGENCE_MCP_REGISTRY_PREVIEW_ORGANIZATION_ID=<test organization>
INTELLIGENCE_MCP_REGISTRY_PREVIEW_POLICY_ID=<test policy>

The anonymous preview reads the latest published artifact's complete snapshot, selects public ALLOW decisions, and treats ServerVersion.raw_registry_payload only as source input. Every response is a field-by-field projection through strict extra="forbid" Registry v0.1 models. Invalid or insufficient records are excluded rather than leaking stored extensions.

Routes implement deterministic ordering, search, cursor pagination, latest and specific versions, 404, ETag/304, Last-Modified, cache control, OPTIONS, and CORS. The prototype exposes no private registry data or authentication and is not a general-purpose customer registry.

Non-goals

Verify does not deploy MDM/Intune/Jamf/Group Policy/macOS profiles, mutate GitHub enterprise settings, install a VS Code extension or agent, retain customer deployment credentials, generate local-command/wildcard rules, change scoring/trust/identity/billing, merge tenant models, provide a dashboard, change the runtime gateway, or sign artifacts in V1.