Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
- name: Test @vantio/cli
run: pnpm --filter @vantio/cli run test

- name: Test @vantio/gate-mcp
run: pnpm --filter @vantio/gate-mcp test

- name: Test @vantio/agent-sdk
run: pnpm --filter @vantio/agent-sdk run test

Expand Down Expand Up @@ -161,3 +164,6 @@ jobs:
run: |
python -m compileall -q vantio_install
python -m unittest discover -s tests -t . -v

- name: Test Optics docker observe example
run: python -m unittest deploy/docker/test_observe_example.py -v
24 changes: 24 additions & 0 deletions deploy/docker/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Strict context. Only the named observe example files are sent to the daemon.
*
!Dockerfile.observe
!agent.js
!package.json
!compose.observe.yml

# Secret and VCS names stay excluded even if a later exception is added.
**/.env
**/.env.*
**/.git
**/.git/**
**/.ssh
**/.ssh/**
**/*.pem
**/*.key
**/id_rsa
**/id_rsa.pub
**/*credentials*
**/secrets
**/secrets/**
**/.npmrc
**/.aws
**/.aws/**
17 changes: 8 additions & 9 deletions deploy/docker/Dockerfile.observe
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# Wrap any Node agent image with Vantio Optics (Sight Loop observe).
# Build: docker build -f deploy/docker/Dockerfile.observe -t my-agent:optics .
# Run: docker run --rm -v vantio-runs:/root/.vantio/runs my-agent:optics
# Optics observe example. Build context is this directory.
# The CLI pin is exact and matches packages/vantio-cli. It is not a range.
# CANDIDATE_ONLY_NOT_FOR_PUBLICATION: this file does not publish the package.
ARG BASE_IMAGE=node:22-bookworm-slim
FROM ${BASE_IMAGE}

RUN npm install -g @vantio/cli@^0.3.1
RUN npm install -g @vantio/cli@0.3.24

WORKDIR /app
COPY . /app
COPY package.json agent.js ./

# Default: observe the package start script. Override CMD as needed.
ENV VANTIO_OBSERVE=1
ENTRYPOINT ["vantio", "run"]
CMD ["npm", "start"]
# `vantio run node` attaches the Node interceptor. `npm` is not a wrapped runtime.
ENTRYPOINT ["vantio", "run", "node"]
CMD ["agent.js"]
3 changes: 3 additions & 0 deletions deploy/docker/agent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Started as `vantio run node agent.js`. Optics records supported Node traffic
// from this process. This example does not call the network.
console.log("vantio optics observe example: node process started");
16 changes: 6 additions & 10 deletions deploy/docker/compose.observe.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
# Example: run an agent under Optics and persist local run logs.
# Example: run a Node process under Optics and persist local run logs.
# Build context is this directory. It does not send the repository root.
services:
agent:
build:
context: ../..
dockerfile: deploy/docker/Dockerfile.observe
args:
BASE_IMAGE: node:22-bookworm-slim
environment:
- VANTIO_HOOKS=0
context: .
dockerfile: Dockerfile.observe
volumes:
- vantio-runs:/root/.vantio/runs
# command: ["node", "agent.js"]

# Optional: sidecar that tails proofs (placeholder — mount runs volume)
# Optional: read the local run logs the agent service wrote.
prove:
image: node:22-bookworm-slim
profiles: ["tools"]
Expand All @@ -21,7 +17,7 @@ services:
working_dir: /root
entrypoint: ["bash", "-lc"]
command:
- npm install -g @vantio/cli && vantio prove --format=md --list || true
- npm install -g @vantio/cli@0.3.24 && vantio prove --format=md --list

volumes:
vantio-runs:
8 changes: 8 additions & 0 deletions deploy/docker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "vantio-optics-observe-example",
"private": true,
"description": "Tiny Node process for the Optics observe image. Run only under vantio run node.",
"scripts": {
"start": "node agent.js"
}
}
122 changes: 122 additions & 0 deletions deploy/docker/test_observe_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""Contract for the Optics observe Docker example.

The example must pin an exact CLI version, keep secrets out of the build
context, and start Node under ``vantio run`` so observation actually attaches.
"""

from __future__ import annotations

import re
import unittest
from pathlib import Path

DOCKER = Path(__file__).resolve().parent
DOCKERFILE = DOCKER / "Dockerfile.observe"
COMPOSE = DOCKER / "compose.observe.yml"
IGNORE = DOCKER / ".dockerignore"
AGENT = DOCKER / "agent.js"

_PIN = re.compile(r"@vantio/cli@([^\s\"']+)")
_EXACT = re.compile(r"^\d+\.\d+\.\d+$")
_ENTRYPOINT = re.compile(r"^ENTRYPOINT\s+(\[.*\])\s*$", re.M)
_CMD = re.compile(r"^CMD\s+(\[.*\])\s*$", re.M)
_SECRET_LINES = (
"**/.env",
"**/.env.*",
"**/.git",
"**/.git/**",
"**/.ssh",
"**/.ssh/**",
"**/*.pem",
"**/*.key",
"**/id_rsa",
"**/*credentials*",
"**/secrets",
"**/secrets/**",
"**/.npmrc",
)


class ObserveExampleTests(unittest.TestCase):
def test_cli_pin_is_exact_and_matches_the_tree(self) -> None:
cli = (DOCKER.parents[1] / "packages" / "vantio-cli" / "package.json").read_text(encoding="utf-8")
version = re.search(r'"version":\s*"([^"]+)"', cli)
self.assertIsNotNone(version)
expected = version.group(1)
pins = []
for path in (DOCKERFILE, COMPOSE):
for match in _PIN.finditer(path.read_text(encoding="utf-8")):
pins.append((path.name, match.group(1)))
self.assertTrue(pins, "the observe example does not pin @vantio/cli")
for name, pin in pins:
self.assertNotIn("^", pin, name)
self.assertNotIn("~", pin, name)
self.assertIsNotNone(_EXACT.fullmatch(pin), f"{name} pin {pin} is not exact")
self.assertEqual(pin, expected, name)
dockerfile = DOCKERFILE.read_text(encoding="utf-8")
self.assertNotIn("@vantio/cli@^", dockerfile)
self.assertNotIn("@vantio/cli@~", dockerfile)
self.assertNotRegex(dockerfile, r"npm install -g @vantio/cli(\s|$)")

def test_default_command_runs_node_under_vantio_run(self) -> None:
text = DOCKERFILE.read_text(encoding="utf-8")
entry = _ENTRYPOINT.search(text)
cmd = _CMD.search(text)
self.assertIsNotNone(entry)
self.assertIsNotNone(cmd)
self.assertEqual(entry.group(1), '["vantio", "run", "node"]')
self.assertNotIn('"npm"', cmd.group(1))
self.assertIn("agent.js", cmd.group(1))
self.assertNotIn("VANTIO_OBSERVE", text)
agent = AGENT.read_text(encoding="utf-8")
self.assertNotIn("fetch(", agent)
self.assertNotIn("http.request", agent)
compose = COMPOSE.read_text(encoding="utf-8")
self.assertNotIn("VANTIO_HOOKS=0", compose)
self.assertNotIn("|| true", compose)

def test_build_context_is_strict_and_excludes_secrets(self) -> None:
dockerfile = DOCKERFILE.read_text(encoding="utf-8")
self.assertNotIn("COPY .", dockerfile)
self.assertIn("COPY package.json agent.js", dockerfile)
compose = COMPOSE.read_text(encoding="utf-8")
self.assertNotIn("../..", compose)
self.assertIn("context: .", compose)
self.assertTrue(IGNORE.is_file(), ".dockerignore is missing")
ignored = IGNORE.read_text(encoding="utf-8")
for line in _SECRET_LINES:
self.assertIn(line, ignored.splitlines(), line)
self.assertIn("\n*\n", f"\n{ignored}")
for name in (".env", ".env.local", "id_rsa", "secrets/token", ".git/config", ".ssh/id_rsa", "keys/app.pem"):
self.assertTrue(_docker_ignored(ignored, name), name)
self.assertFalse(_docker_ignored(ignored, "agent.js"))
self.assertFalse(_docker_ignored(ignored, "package.json"))
self.assertFalse(_docker_ignored(ignored, "Dockerfile.observe"))


def _docker_ignored(text: str, relpath: str) -> bool:
"""Last-match dockerignore check for the patterns this example uses."""
ignored = False
for raw in text.splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
negate = line.startswith("!")
pattern = line[1:] if negate else line
if _docker_match(pattern, relpath):
ignored = not negate
return ignored


def _docker_match(pattern: str, relpath: str) -> bool:
if pattern == "*":
return "/" not in relpath
regex = re.escape(pattern).replace(r"\*\*/", "(?:.*/)?")
regex = regex.replace(r"\*\*", ".*").replace(r"\*", "[^/]*")
if pattern.startswith("**/"):
return re.fullmatch(regex, relpath) is not None
return re.fullmatch(regex, relpath) is not None or re.fullmatch(regex, relpath.split("/")[-1]) is not None


if __name__ == "__main__":
unittest.main()
4 changes: 2 additions & 2 deletions docs/governance/VERSION-METADATA.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
{
"id": "gate-mcp",
"name": "@vantio/gate-mcp",
"version": "0.1.0",
"version": "0.1.1",
"manifest": "packages/vantio-gate-mcp/package.json",
"changelog": "docs/governance/changelogs/gate-mcp.md",
"changelog_heading": "## 0.1.0"
"changelog_heading": "## 0.1.1"
},
{
"id": "vscode",
Expand Down
2 changes: 1 addition & 1 deletion docs/governance/canonical/ai-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Use this guide when editing Vantio Optics documentation in this repository. Pack
"@vantio/agent-sdk": "0.2.4",
"vantio-agent-sdk": "3.1.0",
"@vantio/optics-mcp": "0.1.2",
"@vantio/gate-mcp": "0.1.0",
"@vantio/gate-mcp": "0.1.1",
"vantio-optics": "0.1.0",
"@vantio/optics-evidence-contract": "0.0.0-unstable-pre-1.0"
}
Expand Down
2 changes: 1 addition & 1 deletion docs/governance/canonical/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Free Optics runs with no account and no API key. Telemetry stays off unless `VAN
| Variable | Role |
|---|---|
| `DO_NOT_TRACK` | Set to `1` to keep telemetry off. |
| `VANTIO_API_BASE` | Base URL for the Gate MCP control-plane client. Default `https://api.vantio.ai`. Not required for free Optics. |
| `VANTIO_API_BASE` | Base URL for the Gate MCP control-plane client. Default `https://api.vantio.ai`. Not required for free Optics. `gate_get_policy` and `gate_residual_risk` read this from the environment. They do not take a host argument. |
| `VANTIO_API_KEY` | Control-plane key for Phantom Engine / Enterprise policy and ingest. Not required for free Optics. |
| `VANTIO_AUDIT_MODE` | Set to `1` to flag events as audit mode. |
| `VANTIO_CLOUD_INGEST` | Set to `true` or `1` before `reportAnomaly` / `report_anomaly` will send. |
Expand Down
6 changes: 6 additions & 0 deletions docs/governance/changelogs/gate-mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

This heading exists so a documentation release can require a changelog entry for the version already in `packages/vantio-gate-mcp/package.json`. It does not bump that version.

## 0.1.1

CANDIDATE_ONLY_NOT_FOR_PUBLICATION. Source version only. Not an npm release.

`gate_get_policy` and `gate_residual_risk` read `VANTIO_API_KEY` from the environment. They do not take an `api_key` tool argument. They also do not take an `api_base` tool argument. The control-plane host is `VANTIO_API_BASE`, or `https://api.vantio.ai` when that variable is unset or blank. A caller-supplied host is ignored. The tools still do not block network traffic.

## 0.1.0

Documentation baseline at `14249ba84ff1f3d5aa8ad7a7366172f29235c76e`. `@vantio/gate-mcp` remains a legacy compatibility package. Gate is not a separate product. Product behavior is unchanged by this documentation record.
4 changes: 2 additions & 2 deletions docs/governance/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ Free Optics runs with no account and no API key. Telemetry stays off unless `VAN
| Variable | Role |
|---|---|
| `DO_NOT_TRACK` | Set to `1` to keep telemetry off. |
| `VANTIO_API_BASE` | Base URL for the Gate MCP control-plane client. Default `https://api.vantio.ai`. Not required for free Optics. |
| `VANTIO_API_BASE` | Base URL for the Gate MCP control-plane client. Default `https://api.vantio.ai`. Not required for free Optics. `gate_get_policy` and `gate_residual_risk` read this from the environment. They do not take a host argument. |
| `VANTIO_API_KEY` | Control-plane key for Phantom Engine / Enterprise policy and ingest. Not required for free Optics. |
| `VANTIO_AUDIT_MODE` | Set to `1` to flag events as audit mode. |
| `VANTIO_CLOUD_INGEST` | Set to `true` or `1` before `reportAnomaly` / `report_anomaly` will send. |
Expand Down Expand Up @@ -954,7 +954,7 @@ Use this guide when editing Vantio Optics documentation in this repository. Pack
"@vantio/agent-sdk": "0.2.4",
"vantio-agent-sdk": "3.1.0",
"@vantio/optics-mcp": "0.1.2",
"@vantio/gate-mcp": "0.1.0",
"@vantio/gate-mcp": "0.1.1",
"vantio-optics": "0.1.0",
"@vantio/optics-evidence-contract": "0.0.0-unstable-pre-1.0"
}
Expand Down
42 changes: 42 additions & 0 deletions docs/planning/optics-audit-p1/04-INDEPENDENT-COUNCIL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Optics audit P1 independent council

Audience: review of source changes on this branch.

Status: `PENDING_INDEPENDENT_COUNCIL`

`council_pass`: false

`merge_state`: `WAITING_FOR_AUTHORIZED_REVIEWER`

Publication: `CANDIDATE_ONLY_NOT_FOR_PUBLICATION`. No npm publish, no PyPI publish, no install.vantio.ai go-live.

The producer wrote this packet and the tests. The producer does not sit this council and does not fill the verdict. Approval has to come from kvantio, and the author of the change is not that reviewer.

## Packet

| Finding | Result | Tests |
| --- | --- | --- |
| Installer `remove_stage` followed a stage symlink that stayed inside the parent, then `shutil.rmtree` raised instead of refusing | Reproduced. Removal now `lstat`s the stage, opens it with `O_NOFOLLOW`, and refuses a symlink. Child symlinks are unlinked. Their targets stay. | `tests.test_live_executor.LiveExecutorTests.test_remove_stage_refuses_symlink_and_does_not_follow_it`, `test_remove_stage_does_not_follow_a_symlink_inside_the_directory`, `test_fixture_remove_stage_refuses_symlink` |
| `_privilege_ok` treated `sudo` on `PATH`, and a docker-group socket writer, as a live grant | Reproduced. Live apply, rollback, and uninstall require effective uid 0. | `test_sudo_on_path_is_not_live_privilege`, `test_docker_group_without_effective_root_is_not_live_privilege`, `test_effective_root_is_live_privilege_without_sudo_on_path` |
| Observe image used `@vantio/cli@^0.3.1`, copied the repo context, and ran `vantio run npm start`, which does not attach the Node interceptor | Reproduced. Exact pin `0.3.24`, strict `.dockerignore`, `vantio run node agent.js`. | `deploy/docker/test_observe_example.py` |
| `gate_get_policy` and `gate_residual_risk` accepted `api_key` and sent that value | Reproduced. The key is `VANTIO_API_KEY` only. Source version `@vantio/gate-mcp` `0.1.1` is a candidate, not a registry release. | `packages/vantio-gate-mcp/test/api_key_env.test.js` |

CLI `0.3.25` and Python `3.1.1` are not staged. Those packages were not changed. The observe example pins the CLI version already in this tree, `0.3.24`.

## Residual

`api_base` is still a tool argument on the two gate-mcp fetch tools. A caller can choose the URL that receives `VANTIO_API_KEY`. The key itself is no longer a tool argument.

An outside stage symlink was already refused by `confine` before this change. The reproduced hole was a symlink whose target stayed inside the stage parent.

`vantio-install` stays `0.1.0-stage-a`. That string is sealed.

## Verdict

| Field | Value |
| --- | --- |
| Council identity | `PENDING` |
| Reviewer | `PENDING` — kvantio, non-author |
| Date | `PENDING` |
| Result | `PENDING` |
| Notes | `PENDING` |
12 changes: 6 additions & 6 deletions docs/programs/release-engineering/dossiers/optics-public.json
Original file line number Diff line number Diff line change
Expand Up @@ -349,21 +349,21 @@
"selector_is_integrity": false
},
"distribution": "public",
"filename": "@vantio-gate-mcp-0.1.0.source",
"filename": "@vantio-gate-mcp-0.1.1.source",
"hash_status": "UNRECORDED",
"role": "source-tree",
"sha256": null,
"source_commit": "UNRECORDED",
"version": "0.1.0"
"version": "0.1.1"
}
],
"clean_env": {
"status": "NOT_RUN"
},
"distribution": "public",
"docs_gate": {
"docs_version": "0.1.0",
"manifest_version": "0.1.0",
"docs_version": "0.1.1",
"manifest_version": "0.1.1",
"status": "MATCH"
},
"ordinary_client": {
Expand All @@ -379,10 +379,10 @@
"from_version": null,
"rollback_sha256": null,
"to_sha256": null,
"to_version": "0.1.0",
"to_version": "0.1.1",
"verified": false
},
"version": "0.1.0"
"version": "0.1.1"
},
{
"artifacts": [
Expand Down
4 changes: 2 additions & 2 deletions docs/programs/release-engineering/generated/evaluations.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
"status": "SATISFIED"
},
{
"detail": "@vantio-cli-0.3.24.source hash unrecorded; @vantio-agent-sdk-0.2.4.source hash unrecorded; @vantio-optics-mcp-0.1.2.source hash unrecorded; @vantio-gate-mcp-0.1.0.source hash unrecorded; vantio-optics-0.1.0.source hash unrecorded; @vantio-optics-evidence-contract-0.0.0-unstable-pre-1.0.source hash unrecorded",
"detail": "@vantio-cli-0.3.24.source hash unrecorded; @vantio-agent-sdk-0.2.4.source hash unrecorded; @vantio-optics-mcp-0.1.2.source hash unrecorded; @vantio-gate-mcp-0.1.1.source hash unrecorded; vantio-optics-0.1.0.source hash unrecorded; @vantio-optics-evidence-contract-0.0.0-unstable-pre-1.0.source hash unrecorded",
"id": "R3",
"status": "GAP"
},
{
"detail": "@vantio-cli-0.3.24.source custody hash unrecorded; @vantio-agent-sdk-0.2.4.source custody hash unrecorded; @vantio-optics-mcp-0.1.2.source custody hash unrecorded; @vantio-gate-mcp-0.1.0.source custody hash unrecorded; vantio-optics-0.1.0.source custody hash unrecorded; @vantio-optics-evidence-contract-0.0.0-unstable-pre-1.0.source custody hash unrecorded",
"detail": "@vantio-cli-0.3.24.source custody hash unrecorded; @vantio-agent-sdk-0.2.4.source custody hash unrecorded; @vantio-optics-mcp-0.1.2.source custody hash unrecorded; @vantio-gate-mcp-0.1.1.source custody hash unrecorded; vantio-optics-0.1.0.source custody hash unrecorded; @vantio-optics-evidence-contract-0.0.0-unstable-pre-1.0.source custody hash unrecorded",
"id": "R4",
"status": "GAP"
},
Expand Down
Loading
Loading