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
10 changes: 0 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,9 @@
# browser JavaScript.
OAC_WEB_DEV_PROXY_TARGET=http://127.0.0.1:8091

# Legacy development proxy only. The console never calls /v1; the Vite server
# still forwards /v1 with this Project API key for older tooling such as
# scripts/core-doctor.mjs. Plaintext bearer file read
# only by the local Vite server; if unset, it checks this conventional path.
OAC_WEB_DEV_PROXY_TOKEN_FILE=~/.oac/dev/web-token

# Core reads its own environment, not this file. Core settings, including
# Runtime history sampling and export, are in docs/configuration.md.

# Alternative server-side value for the legacy /v1 development proxy. Never use a
# VITE_ prefix, and do not set this together with OAC_WEB_DEV_PROXY_TOKEN_FILE.
# OAC_WEB_DEV_PROXY_TOKEN=

# Public, non-secret opt-in for the reviewed Codex self_hosted Session profile.
# Leave unset unless Core execution, its executor registry, and executor origin
# are configured. This flag is presentation policy, not capability discovery.
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/api-acceptance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ on:
- 'go.sum'
- 'Makefile'
- 'scripts/build-core.sh'
- 'scripts/build-core-image.sh'
- 'scripts/build-core-image-context.sh'
- 'deploy/distribution/Dockerfile'
- '.github/workflows/api-acceptance.yml'
pull_request:
paths:
Expand All @@ -24,7 +25,8 @@ on:
- 'go.sum'
- 'Makefile'
- 'scripts/build-core.sh'
- 'scripts/build-core-image.sh'
- 'scripts/build-core-image-context.sh'
- 'deploy/distribution/Dockerfile'
- '.github/workflows/api-acceptance.yml'

permissions:
Expand Down Expand Up @@ -85,7 +87,7 @@ jobs:
run: |
python services/core/tests/official_client.py
go test ./services/core/internal/store -run '^(TestFunctionStateOfficialClientReadsAndLiveEvents|TestSavedReferenceRetryOfficialClient|TestAgentUpdateOfficialClient|TestAgentDeletionOfficialClient|TestSessionAgentFilterOfficialClient|TestSessionDeletionOfficialClient|TestEnvironmentInitialFailureOfficialClient|TestSelfHostedInitialCreationOfficialClient|TestSelfHostedCancellationOfficialClient|TestSelfHostedFunctionsOfficialClient|TestSelfHostedSteeringOfficialClient)$' -count=1
- name: Verify standalone container distribution
- name: Verify the distribution's Core image
env:
OAC_TEST_DATABASE_URL: postgres://agents_api:agents_api_test_only@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/oac_ci_tests?sslmode=disable
OAC_DEV_CORE_IMAGE: oac-core:ci
Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ This guide owns how to work in the repository: documentation ownership, the repo

## Repository boundary

This repository is the standalone execution substrate copied from Parsar at the revision in `provenance/source.json`. It holds the API and its migrations, the Runtime protocol and daemon, Harness adapters, shared execution packages, the standalone Core Web console and build/test tools.
This repository is the standalone execution substrate, copied from the Parsar repository. It holds the API and its migrations, the Runtime protocol and daemon, Harness adapters, shared execution packages, the standalone Core Web console and build/test tools.

Product users, workspaces, model catalogs, business assets, the Parsar product Web, product API and product migrations remain in Parsar. Do not import `server/`, `apps/parsar/`, product CLI/plugin packages or their deployment stack.

Preserve copied Runtime and protocol behavior. Go import paths use this repository's module and do not require fetching the original repository. The source snapshot and per-file hashes are an audit trail; future Core development need not preserve them. Do not automatically sync or delete the original repository's Core.
Preserve copied Runtime and protocol behavior. Go import paths use this repository's module and do not require fetching the original repository. Do not automatically sync or delete the original repository's Core.

### Product and execution service separation

Expand Down Expand Up @@ -116,7 +116,7 @@ It excludes Parsar product Web and server gates.
| `OAC_TEST_DATABASE_URL` | A dedicated test database. The full gate fails when it is missing. |
| `OAC_TEST_OFFICIAL_SDK_PYTHON` | The pinned official SDK interpreter |

The role needs `CREATE DATABASE`: managed-provider tests create and drop isolated `oac_*_tests` databases because provider identity is deployment-wide. `PARSAR_AGENTS_API_TEST_DATABASE_URL` is retired; `make check-database` reports its replacement when only the old name is set. Tests must not bypass the production provider-switch guard.
The role needs `CREATE DATABASE`: managed-provider tests create and drop isolated `oac_*_tests` databases because provider identity is deployment-wide. Tests must not bypass the production provider-switch guard.

### Contract and schema rules

Expand Down Expand Up @@ -168,6 +168,7 @@ Public project branding uses OpenAgentCore. The canonical vector mark is `docs/a

- An exception covers only its matched text: an allowed repository import cannot hide a retired setting elsewhere on the line.
- Keep exceptions narrow and explain the preserved contract or historical input.
- The guard also fails on an exception that excuses no retired identifier. Remove an exception together with the last text it covered.

These identities stay unchanged:

Expand Down
20 changes: 8 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SQLC_VERSION ?= v1.29.0
SQLC ?= go run github.com/sqlc-dev/sqlc/cmd/sqlc@$(SQLC_VERSION)
SWAG_VERSION ?= v1.16.4

.PHONY: help check check-database check-go check-sqlc sqlc-generate node-deps check-claude-sdk check-web check-mcode-harness build-daemon build-core build-core-release check-core docker-build-core check-core-container build-agents-runtime build-claude-runtime build-claude-sdk-runtime build-mcode-harness build-mcode-runtime
.PHONY: help check check-database check-go check-sqlc sqlc-generate node-deps check-claude-sdk check-web check-mcode-harness build-daemon build-core check-core docker-build-core check-core-container build-agents-runtime build-claude-runtime build-claude-sdk-runtime build-mcode-harness build-mcode-runtime

help:
@printf '%s\n' 'make build-core Build standalone Core commands' 'make build-daemon Build the execution daemon' 'make check Run Core, persistence and runtime checks' 'See README.md for runtime prerequisites and deployment.'
Expand All @@ -25,9 +25,6 @@ check-names:
python3 scripts/check-names.py

check-database:
@if [[ -n "$${PARSAR_AGENTS_API_TEST_DATABASE_URL+x}" && -z "$${OAC_TEST_DATABASE_URL+x}" ]]; then \
echo 'PARSAR_AGENTS_API_TEST_DATABASE_URL was renamed; set OAC_TEST_DATABASE_URL instead' >&2; exit 1; \
fi
@test -n "$${OAC_TEST_DATABASE_URL:-}" || { echo 'Set OAC_TEST_DATABASE_URL to a dedicated test PostgreSQL database' >&2; exit 1; }

sqlc-generate:
Expand Down Expand Up @@ -67,17 +64,19 @@ build-daemon:
build-core:
./scripts/build-core.sh

build-core-release:
./scripts/build-core-release.sh

check-core: build-core
# Persistence integration tests include bounded lifecycle waits that together exceed Go's 10m default.
go test ./services/core/... ./packages/agents-client/... -count=1 -timeout=20m
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s services/core/tests -p 'official_diagnostics_test.py'
PYTHONDONTWRITEBYTECODE=1 python3 services/core/deploy/e2b/managed_init_test.py

# The distribution's Core image, without the native installer catalog.
docker-build-core:
./scripts/build-core-image.sh
@set -e; root="$${OAC_DEV_HOME:-$$HOME/.oac}"; \
mkdir -p "$$root/cache/oac-core-builds"; \
context=$$(mktemp -d "$$root/cache/oac-core-builds/image.XXXXXX"); trap 'rm -rf "$$context"' EXIT; \
./scripts/build-core-image-context.sh "$$context"; \
docker build --platform linux/amd64 --tag "$${OAC_DEV_CORE_IMAGE:-oac-core:dev}" "$$context"

check-core-container: docker-build-core
OAC_DEV_CORE_IMAGE="$${OAC_DEV_CORE_IMAGE:-oac-core:dev}" OAC_TEST_SERVER_BIN="$(CURDIR)/services/core/tests/container_server.py" $${OAC_TEST_OFFICIAL_SDK_PYTHON:-python3} services/core/tests/official_client.py
Expand All @@ -95,7 +94,6 @@ check-web: check-web-unit check-web-acceptance

check-web-unit: node-deps
pnpm typecheck
pnpm test:core-doctor
pnpm test:web
pnpm --filter @oac/web build

Expand Down Expand Up @@ -156,10 +154,8 @@ check-distribution:
PYTHONDONTWRITEBYTECODE=1 python3 scripts/core-distribution-manifest.test.py
PYTHONDONTWRITEBYTECODE=1 python3 scripts/publish-core-release.test.py
PYTHONDONTWRITEBYTECODE=1 python3 scripts/install-release.test.py
PYTHONDONTWRITEBYTECODE=1 python3 scripts/promote-qualified-release.test.py
PYTHONDONTWRITEBYTECODE=1 python3 scripts/qualification-control.test.py
PYTHONDONTWRITEBYTECODE=1 python3 scripts/config-reference.py --check
bash -n deploy/install/install.sh deploy/install-release.sh scripts/build-web.sh scripts/build-core-distribution.sh scripts/prepare-release-runtimes.sh
bash -n deploy/install/install.sh deploy/install-release.sh scripts/build-web.sh scripts/build-core-distribution.sh scripts/build-core-image-context.sh scripts/prepare-release-runtimes.sh
./scripts/build-web.sh

build-core-distribution:
Expand Down
2 changes: 1 addition & 1 deletion apps/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ OAC_WEB_DEV_PROXY_TARGET=http://127.0.0.1:18092 pnpm dev:web

Open `http://127.0.0.1:4173` and sign in with the fixture-only key `fixture-core-key-3f9a2c71`.

`pnpm dev:web` runs Vite on `127.0.0.1:4173` and proxies `/console`, `/node-install` and `/core/v1` to `OAC_WEB_DEV_PROXY_TARGET` (default `http://127.0.0.1:8091`). Vite reads the setting from the environment or the repository's `.env` file; it never reaches browser code. The target must serve the console routes. The development server also forwards `/v1` to the same target for local tooling such as `scripts/core-doctor.mjs`, adding a bearer token from `OAC_WEB_DEV_PROXY_TOKEN` or from the private file `OAC_WEB_DEV_PROXY_TOKEN_FILE` (default `~/.oac/dev/web-token`, used when it exists); the console itself never calls `/v1`. `apps/web/e2e/fixture-console.mjs` is a synthetic console service with deterministic data; `AGENTS_FIXTURE_PORT` changes its port (default 18092).
`pnpm dev:web` runs Vite on `127.0.0.1:4173` and proxies `/console`, `/node-install` and `/core/v1` to `OAC_WEB_DEV_PROXY_TARGET` (default `http://127.0.0.1:8091`). Vite reads the setting from the environment or the repository's `.env` file; it never reaches browser code. The target must serve the console routes. `apps/web/e2e/fixture-console.mjs` is a synthetic console service with deterministic data; `AGENTS_FIXTURE_PORT` changes its port (default 18092).

## Checks

Expand Down
4 changes: 3 additions & 1 deletion apps/web/e2e/access.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, test, type Page } from "@playwright/test";

import { expectManagementBoundary, FIXTURE_CORE_KEY, issueKeys, openConsole, resetFixture } from "./console";
import { expectManagementBoundary, FIXTURE_CORE_KEY, issueKeys, openConsole, recordV1Requests, resetFixture } from "./console";

test.afterEach(async ({ request }) => expectManagementBoundary(request));

Expand All @@ -13,6 +13,7 @@ const browserStorage = (page: Page) => page.evaluate(() => JSON.stringify({ ...w

test("signs in with the Core key, keeps it out of the browser, and signs out and back in", async ({ page, request }) => {
await resetFixture(request, "login");
await recordV1Requests(page);
await page.addInitScript(() => window.localStorage.setItem("agents-core-web.language", "en"));
await page.goto("/");

Expand Down Expand Up @@ -45,6 +46,7 @@ test("signs in with the Core key, keeps it out of the browser, and signs out and

test("opens a fresh install on the Overview's Getting started: a project and its key shown once, then the step is done", async ({ page, request }) => {
await resetFixture(request, "login", { fresh: true });
await recordV1Requests(page);
await page.addInitScript(() => window.localStorage.setItem("agents-core-web.language", "en"));
await page.goto("/");
await signIn(page, FIXTURE_CORE_KEY);
Expand Down
13 changes: 12 additions & 1 deletion apps/web/e2e/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,20 @@ export async function resetFixture(request: APIRequestContext, auth: "login" | "
await request.post(`${fixture}/__fixture/reset?auth=${auth}${options.fresh ? "&projects=none" : ""}&sandbox=${options.sandbox ?? "configured"}${options.nodes ? `&nodes=${options.nodes}` : ""}&installation=${options.installation ?? "public"}${options.credentials ? `&credentials=${options.credentials}` : ""}${options.installers ? `&installers=${options.installers}` : ""}${options.nodeArtifacts ? `&artifacts=${options.nodeArtifacts.join(",")}` : ""}`);
}

const v1Requests: string[] = [];

/** Records and aborts every browser request to the application API (/v1), which the console never calls. */
export async function recordV1Requests(page: Page) {
await page.route((url) => url.pathname === "/v1" || url.pathname.startsWith("/v1/"), (route) => {
v1Requests.push(`${route.request().method()} ${new URL(route.request().url()).pathname}`);
return route.abort();
});
}

/** Opens the console already signed in, in English. */
export async function openConsole(page: Page, request: APIRequestContext, hash = "overview", options: FixtureOptions = {}) {
await resetFixture(request, "authenticated", options);
await recordV1Requests(page);
await page.context().addCookies([{ name: "core_console", value: "fixture-session", url: web }]);
await page.addInitScript(() => window.localStorage.setItem("agents-core-web.language", "en"));
await page.goto(`/#${hash}`);
Expand Down Expand Up @@ -75,5 +86,5 @@ export async function writes(request: APIRequestContext): Promise<string[]> {
/** The console never calls /v1 and never sends its own Authorization header. */
export async function expectManagementBoundary(request: APIRequestContext) {
const { violations } = await (await request.get(`${fixture}/__fixture/requests`)).json();
expect(violations).toEqual([]);
expect([...v1Requests.splice(0), ...violations]).toEqual([]);
}
9 changes: 2 additions & 7 deletions apps/web/e2e/fixture-console.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Browser acceptance fixture: the console service's routes (/console/**) and the
// Core management tree it forwards (/core/v1/**: installation, projects, summary,
// audit log, metrics, harness default models and /core/v1/sandbox/**), with synthetic, deterministic data and
// in-memory writes. It never serves /v1; any /v1 request, and any
// browser-supplied Authorization header, is recorded so a test can assert that
// the console stays on its management boundary.
// in-memory writes. Any browser-supplied Authorization header is recorded so a
// test can assert that the console stays on its management boundary.
import http from "node:http";

import { domainState, domainRoute } from "./data/domain.mjs";
Expand Down Expand Up @@ -644,10 +643,6 @@ http.createServer(async (request, response) => {
if (url.pathname.startsWith("/__fixture/")) return await fixtureRoute(request, response, url);
// The console service serves its distribution manifest to anyone, as nodes download it.
if (url.pathname === "/node-install/manifest.json") return send(response, 200, manifest);
if (url.pathname === "/v1" || url.pathname.startsWith("/v1/")) {
state.violations.push(`${request.method} ${url.pathname}`);
return error(response, 404, "The console does not serve /v1.");
}
if (request.headers.authorization) state.violations.push(`Authorization header on ${request.method} ${url.pathname}`);
if (url.pathname.startsWith("/console/")) return await consoleRoute(request, response, url);
const signedIn = state.auth.mode === "authenticated" && request.headers.cookie?.includes(SESSION_COOKIE);
Expand Down
77 changes: 0 additions & 77 deletions apps/web/src/lib/vite-auth.test.ts

This file was deleted.

11 changes: 3 additions & 8 deletions apps/web/src/lib/vite-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,24 @@ function configure(env: Record<string, string>, command: ConfigEnv["command"] =
}

describe("Web Vite settings boundary", () => {
it("uses current flags and keeps proxy addresses and credentials out of browser definitions", async () => {
it("uses current flags and keeps the proxy address out of browser definitions", async () => {
const config = await configure({
OAC_WEB_DEV_PROXY_TARGET: "https://private-host-marker.example",
OAC_WEB_DEV_PROXY_TOKEN: "private-token-marker",
OAC_WEB_SELF_HOSTED_SESSIONS: "1",
OAC_WEB_OPENAI_HOSTED_SESSIONS: "1",
OAC_WEB_ENVIRONMENT_FILES: "1",
});
expect(config.define).toEqual({
__OAC_WEB_DEV_PROXY_AUTH__: "true",
__OAC_WEB_SELF_HOSTED_SESSIONS__: "true",
__OAC_WEB_OPENAI_HOSTED_SESSIONS__: "true",
__OAC_WEB_ENVIRONMENT_FILES__: "true",
__OAC_WEB_DOCKER_GUIDE__: "null",
__OAC_WEB_DOCKER_BACKEND_GUIDE__: "null",
});
expect(Object.keys(config.server?.proxy ?? {})).toEqual(["/console", "/node-install", "/core/v1"]);
expect(config.server?.proxy?.["/core/v1"]).toEqual({ target: "https://private-host-marker.example", changeOrigin: true });
expect(JSON.stringify(config.define)).not.toContain("private-");
});

it("does not read a development credential file during a production build", async () => {
const config = await configure({ OAC_WEB_DEV_PROXY_TOKEN_FILE: "/missing/private-file-marker" }, "build");
expect(config.define?.__OAC_WEB_DEV_PROXY_AUTH__).toBe("false");
expect(JSON.stringify(config.define)).not.toContain("private-file-marker");
});

});
Loading
Loading