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
1 change: 1 addition & 0 deletions deploy/compose/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ services:
database: {condition: service_healthy}
environment:
OAC_PUBLIC_URL: &public-url ${OAC_PUBLIC_URL:-http://localhost:8080}
OAC_ALLOW_INSECURE_ORIGIN: ${OAC_ALLOW_INSECURE_ORIGIN:-}
OAC_INSTALLATION_ID_FILE: /run/oac/installation.id
OAC_DATABASE_URL: postgres://agents_api@database:5432/agents_api?sslmode=disable
OAC_DATABASE_PASSWORD_FILE: /run/database/password
Expand Down
16 changes: 12 additions & 4 deletions deploy/compose/test_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ def rendered_compose(directory):

class ComposeTests(unittest.TestCase):
@classmethod
def render(cls, public_url=None):
def render(cls, public_url=None, allow_insecure_origin=None):
env = dict(os.environ)
env.pop('OAC_PUBLIC_URL', None)
for name in ('OAC_IMAGE_CORE', 'OAC_IMAGE_WEB', 'OAC_IMAGE_INGRESS'):
for name in ('OAC_PUBLIC_URL', 'OAC_ALLOW_INSECURE_ORIGIN',
'OAC_IMAGE_CORE', 'OAC_IMAGE_WEB', 'OAC_IMAGE_INGRESS'):
env.pop(name, None)
env['OAC_DATA_DIR'] = '/tmp/oac-compose-fixture'
if public_url is not None:
env['OAC_PUBLIC_URL'] = public_url
if allow_insecure_origin is not None:
env['OAC_ALLOW_INSECURE_ORIGIN'] = allow_insecure_origin
return json.loads(subprocess.check_output(
['docker', 'compose', '--env-file', os.devnull, '-f', str(cls.compose_file),
'config', '--format', 'json'], env=env))
Expand Down Expand Up @@ -67,9 +69,15 @@ def test_compose_uses_private_services_and_ordered_initialization(self):
self.assertEqual(services['web']['healthcheck']['test'], ['CMD', '/usr/local/bin/oac-web', 'healthcheck'])
self.assertNotIn('python3', json.dumps(self.compose))
self.assertEqual(services['init']['environment']['OAC_REVISION'], 'd' * 40)
for name in ('OAC_EXECUTION_CONCURRENCY', 'OAC_DEFAULT_HARNESS', 'OAC_HARNESSES', 'OAC_WRITE_AUDIT_RETENTION', 'OAC_LOG_LEVEL'):
for name in ('OAC_EXECUTION_CONCURRENCY', 'OAC_DEFAULT_HARNESS', 'OAC_HARNESSES', 'OAC_WRITE_AUDIT_RETENTION', 'OAC_LOG_LEVEL', 'OAC_ALLOW_INSECURE_ORIGIN'):
self.assertEqual(services['core']['environment'][name], '', name)

def test_allow_insecure_origin_passes_through_to_core_only(self):
configured = self.render(public_url='http://10.0.0.5:8080', allow_insecure_origin='1')
self.assertEqual(configured['services']['core']['environment']['OAC_PUBLIC_URL'], 'http://10.0.0.5:8080')
self.assertEqual(configured['services']['core']['environment']['OAC_ALLOW_INSECURE_ORIGIN'], '1')
self.assertNotIn('OAC_ALLOW_INSECURE_ORIGIN', configured['services']['web']['environment'])

def test_public_url_can_be_configured_after_initial_startup(self):
for value in (None, '', 'https://oac.example.test', 'http://localhost:9080'):
with self.subTest(public_url=value):
Expand Down
6 changes: 6 additions & 0 deletions deploy/install.dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
install_dir="${OAC_INSTALL_DIR_DEFAULT:-$HOME/.oac/local}"
host_address="127.0.0.1"
web_port="8080"
allow_insecure_origin=0

if [[ -x "$HOME/.oac/build/env-docker/docker" ]]; then
PATH="$HOME/.oac/build/env-docker:$PATH"
Expand All @@ -16,9 +17,12 @@ fi
usage() {
cat <<'EOF'
Usage: install.dev.sh [--install-dir DIR] [--host ADDRESS] [--web-port PORT]
[--allow-insecure-origin]

Builds Core, Web and the init image from this checkout and starts them.
Open http://localhost:<port> and sign in with the printed Core key.
--allow-insecure-origin permits a non-loopback plain-HTTP public URL for
development and testing.
EOF
}

Expand All @@ -27,6 +31,7 @@ while [[ $# -gt 0 ]]; do
--install-dir) install_dir="${2:?}"; shift 2 ;;
--host) host_address="${2:?}"; shift 2 ;;
--web-port) web_port="${2:?}"; shift 2 ;;
--allow-insecure-origin) allow_insecure_origin=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
esac
Expand Down Expand Up @@ -120,6 +125,7 @@ OAC_IMAGE_CORE=$tag/core:dev
OAC_IMAGE_WEB=$tag/web:dev
OAC_IMAGE_INGRESS=$tag/ingress:dev
EOF
if [[ "$allow_insecure_origin" == 1 ]]; then echo "OAC_ALLOW_INSECURE_ORIGIN=1" >>"$install_dir/.env"; fi

(
cd "$install_dir"
Expand Down
8 changes: 6 additions & 2 deletions deploy/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ install_dir="${OAC_INSTALL_DIR_DEFAULT:-$HOME/.oac/core}"
public_url=""
host_address="0.0.0.0"
web_port="8080"
allow_insecure_origin=0
kept=0

usage() {
cat <<'EOF'
Usage: install.sh [--version TAG] [--install-dir DIR] [--public-url URL]
[--host ADDRESS] [--web-port PORT]
[--host ADDRESS] [--web-port PORT] [--allow-insecure-origin]

Installs Core, Web and PostgreSQL, and publishes Web on --web-port. HTTPS is
terminated by your reverse proxy or hosting platform.
terminated by your reverse proxy or hosting platform. --allow-insecure-origin
permits a non-loopback plain-HTTP --public-url for development and testing.
EOF
}

Expand All @@ -27,6 +29,7 @@ while [[ $# -gt 0 ]]; do
--public-url) public_url="${2:?}"; shift 2 ;;
--host) host_address="${2:?}"; shift 2 ;;
--web-port) web_port="${2:?}"; shift 2 ;;
--allow-insecure-origin) allow_insecure_origin=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
esac
Expand Down Expand Up @@ -97,6 +100,7 @@ umask 077
echo "OAC_HOST=$host_address"
echo "OAC_WEB_PORT=$web_port"
if [[ -n "$public_url" ]]; then echo "OAC_PUBLIC_URL=$public_url"; fi
if [[ "$allow_insecure_origin" == 1 ]]; then echo "OAC_ALLOW_INSECURE_ORIGIN=1"; fi
} >"$install_dir/.env"

(
Expand Down
16 changes: 16 additions & 0 deletions deploy/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,24 @@ def test_env_holds_only_the_installation_choices(self):
def test_help_does_not_need_docker(self):
help_text = subprocess.run(["bash", str(INSTALL), "--help"], capture_output=True, text=True, check=True)
self.assertIn("--web-port", help_text.stdout)
self.assertIn("--allow-insecure-origin", help_text.stdout)
self.assertNotIn("--external-proxy", help_text.stdout)

def test_allow_insecure_origin_is_written_only_when_requested(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
completed, _ = self.install(root, "--public-url", "http://10.0.0.5:8080", "--allow-insecure-origin")
self.assertEqual(completed.returncode, 0, completed.stderr)
env = dict(line.split("=", 1) for line in (root / "oac/.env").read_text().splitlines())
self.assertEqual(env["OAC_PUBLIC_URL"], "http://10.0.0.5:8080")
self.assertEqual(env["OAC_ALLOW_INSECURE_ORIGIN"], "1")
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
completed, _ = self.install(root)
self.assertEqual(completed.returncode, 0, completed.stderr)
env = dict(line.split("=", 1) for line in (root / "oac/.env").read_text().splitlines())
self.assertNotIn("OAC_ALLOW_INSECURE_ORIGIN", env)

def write_executable(self, path, text):
path.write_text(text)
path.chmod(path.stat().st_mode | stat.S_IEXEC)
Expand Down
7 changes: 5 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Every setting of a Core installation has exactly one home. There are two kinds:

| Kind | Examples | Home | Change it with | Takes effect |
| --- | --- | --- | --- | --- |
| [Process settings](#process-settings-configjson) | Public URL, ports, logging, harnesses, execution concurrency, audit retention, OAuth origins, Runtime history export | `.env` in the installation directory (default `~/.oac/core`) | Edit `.env`, then run `oac apply` | `oac apply` recreates the services that read the changed settings |
| [Process settings](#process-settings-configjson) | Public URL, ports, logging, harnesses, execution concurrency, audit retention, OAuth origins, allow insecure origin, Runtime history export | `.env` in the installation directory (default `~/.oac/core`) | Edit `.env`, then run `oac apply` | `oac apply` recreates the services that read the changed settings |
| [Runtime settings](#runtime-settings-web) | Sandbox backend and size, nodes, Projects and keys, default models, executor credentials | Core's PostgreSQL database | Web, or the Core API (`/core/v1`) with the Core key | Saved without a Core restart; nodes prepare Runtime changes asynchronously |

Web's **System** page shows the installation's addresses, the default models, the sandbox configuration and, under **Startup settings**, the process settings Core loaded. Secrets live in [`data/secrets/`](#installation-directory), one copy each. No configuration file defines Projects or API keys.
Expand All @@ -31,6 +31,8 @@ Installer flags in [installation options](./getting-started/install-options.md)

`OAC_PUBLIC_URL` is the one origin that applications, nodes, sandboxes and self-hosted executors use. Core derives the daemon WebSocket URL, the self-hosted `remote_url` and each sandbox's connection address from it. The installation serves Web over HTTP on `OAC_WEB_PORT`; your reverse proxy or hosting platform terminates HTTPS and routes to that port.

A `http://` origin is accepted only for a loopback host. A development or test installation can set `OAC_ALLOW_INSECURE_ORIGIN=1` to accept a non-loopback one; TLS certificate verification stays on.

To change it, point the reverse proxy at the new address first, then edit `OAC_PUBLIC_URL` and run `oac apply`. Afterwards:

- Nodes on the old address get no new sandboxes: remove them in Web and add them again.
Expand All @@ -44,6 +46,7 @@ To change it, point the reverse proxy at the new address first, then edit `OAC_P
| Variable | Default | Meaning |
| --- | --- | --- |
| `OAC_PUBLIC_URL` | `http://localhost:8080` | Origin applications, nodes, sandboxes and self-hosted executors use. Managed domain setup writes the HTTPS origin and recreates Core and Web |
| `OAC_ALLOW_INSECURE_ORIGIN` | unset | `1` permits a non-loopback plain-HTTP `OAC_PUBLIC_URL` for development and testing. TLS certificate verification stays on |
| `OAC_HOST` | `127.0.0.1` | Address published by `ports.yaml`. `install.sh` sets `0.0.0.0` |
| `OAC_WEB_PORT` | `8080` | Host port of Web |
| `COMPOSE_FILE` | `compose.yaml:ports.yaml` | The Compose files. `ports.yaml` publishes Web and Core's loopback admin API; hosting platforms omit it |
Expand Down Expand Up @@ -150,7 +153,7 @@ Core reads only its environment. Compose interpolates `.env` into the service en
| `OAC_CREDENTIAL_KEY_FILE` | `data/secrets/core/credential.key` |
| `OAC_CORE_KEY_DIGESTS_FILE` | `data/secrets/core/core-key-digests.json`: a JSON array with the SHA-256 of the Core key |
| `OAC_INSTALLATION_ID_FILE` | `data/secrets/core/installation.id`: the installation ID, a canonical UUID. It enables the sandbox deployment and node routes and requires `OAC_PUBLIC_URL` and `OAC_CORE_KEY_DIGESTS_FILE`. Core refuses an ID other than the one its database recorded |
| `OAC_EXECUTION_CONCURRENCY`, `OAC_DEFAULT_HARNESS`, `OAC_HARNESSES`, `OAC_WRITE_AUDIT_RETENTION`, `OAC_OAUTH_TRUSTED_ORIGINS` | The matching [process settings](#settings). `oac-core check-config` validates them without starting Core |
| `OAC_EXECUTION_CONCURRENCY`, `OAC_DEFAULT_HARNESS`, `OAC_HARNESSES`, `OAC_WRITE_AUDIT_RETENTION`, `OAC_OAUTH_TRUSTED_ORIGINS`, `OAC_ALLOW_INSECURE_ORIGIN` | The matching [process settings](#settings). `oac-core check-config` validates them without starting Core |
| `OAC_HISTORY_SETTINGS_FILE` | Optional Runtime history file. Sensitive; the installation report says only whether it is set |
| `OAC_LOG_LEVEL`, `OAC_LOG_FORMAT`, `OAC_LOG_ADD_SOURCE` | Logging; Web reads the same three |
| `OAC_PROVIDER_ROOT` | Absolute adapter artifact root. The Core image sets `/opt/oac`. Each adapter owns its helper paths beneath this root |
Expand Down
5 changes: 4 additions & 1 deletion docs/getting-started/install-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ These flags are written to `.env` once. After installation, edit that file and r
| Flag | `.env` variable |
| --- | --- |
| `--public-url` | `OAC_PUBLIC_URL` |
| `--allow-insecure-origin` | `OAC_ALLOW_INSECURE_ORIGIN` |
| `--host` | `OAC_HOST` |
| `--web-port` | `OAC_WEB_PORT` |

`--allow-insecure-origin` permits a non-loopback plain-HTTP `--public-url` for development and testing. It is off by default; TLS certificate verification stays on.


## Installation actions

Expand All @@ -72,7 +75,7 @@ The installer saves no sandbox backend. After signing in, open **System** → **

The default installation publishes Web on `--web-port` (8080) at `--host 0.0.0.0`. Core's admin API stays on `127.0.0.1:8091`. PostgreSQL stays private. `--host` is an IPv4 or IPv6 address, without a port, scheme or zone. Use a concrete server IP in the browser, not a wildcard.

`--public-url` sets `OAC_PUBLIC_URL`, the origin applications, nodes and executors use. Set it to the HTTPS origin your reverse proxy serves.
`--public-url` sets `OAC_PUBLIC_URL`, the origin applications, nodes and executors use. Set it to the HTTPS origin your reverse proxy serves. A non-loopback `http://` origin needs `--allow-insecure-origin`; a loopback one does not.

### Ports

Expand Down
9 changes: 6 additions & 3 deletions docs/zh/configuration.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: "配置参考"
source: docs/configuration.md
source_hash: 610b3a85b453d00b575f9fb4d42c87ec89dc3803bb238fd4c36ef734aba6c7e2
source_hash: 1dbb0c3af7312e925639e9e0a3c868697ff7cbbd321d7aa387ca6732927a38a3
---

Core 安装的每项设置都恰好只有一个归属位置。共有两类:

| 类型 | 示例 | 归属位置 | 修改方式 | 生效方式 |
| --- | --- | --- | --- | --- |
| [进程设置](#process-settings-configjson) | 公共 URL、端口、日志、Harness、执行并发度、审计保留期、OAuth 来源、Runtime 历史记录导出 | 安装目录中的 `.env`(默认 `~/.oac/core`) | 编辑 `.env`,然后运行 `oac apply` | `oac apply` 会重新创建读取了这些已更改设置的服务 |
| [进程设置](#process-settings-configjson) | 公共 URL、端口、日志、Harness、执行并发度、审计保留期、OAuth 来源、允许不安全源地址、Runtime 历史记录导出 | 安装目录中的 `.env`(默认 `~/.oac/core`) | 编辑 `.env`,然后运行 `oac apply` | `oac apply` 会重新创建读取了这些已更改设置的服务 |
| [运行时设置](#runtime-settings-web) | 沙箱后端和大小、节点、项目和密钥、默认模型、执行器凭据 | Core 的 PostgreSQL 数据库 | 在 Web 中修改,或使用 Core 密钥调用 Core API(`/core/v1`) | 保存时无需重启 Core;节点会异步准备 Runtime 变更 |

Web 的 **System** 页面显示该安装的地址、默认模型和沙箱配置,并在 **Startup settings** 下以只读方式显示 Core 加载的进程设置。机密信息存放在 [`data/secrets/`](#installation-directory) 中,每项仅保存一份。没有任何配置文件定义项目或 API 密钥。
Expand All @@ -33,6 +33,8 @@ Web 的 **System** 页面显示该安装的地址、默认模型和沙箱配置

`OAC_PUBLIC_URL` 是应用、节点、沙箱和自托管执行器使用的唯一源地址。Core 从中派生守护进程 WebSocket URL、自托管 `remote_url` 和每个沙箱的连接地址。安装通过 `OAC_WEB_PORT` 以 HTTP 提供 Web;反向代理或托管平台终止 HTTPS 并把流量转到该端口。

`http://` 源地址仅对回环主机被接受。开发或测试安装可以设置 `OAC_ALLOW_INSECURE_ORIGIN=1` 来接受非回环源地址;TLS 证书校验保持不变。

要更改它,先把反向代理指向新地址,然后编辑 `OAC_PUBLIC_URL` 并运行 `oac apply`。之后:

- 使用旧地址的节点不会再获得新沙箱:请在 Web 中移除这些节点,然后重新添加。
Expand All @@ -48,6 +50,7 @@ Web 的 **System** 页面显示该安装的地址、默认模型和沙箱配置
| Variable | Default | Meaning |
| --- | --- | --- |
| `OAC_PUBLIC_URL` | `http://localhost:8080` | Origin applications, nodes, sandboxes and self-hosted executors use. Managed domain setup writes the HTTPS origin and recreates Core and Web |
| `OAC_ALLOW_INSECURE_ORIGIN` | unset | `1` permits a non-loopback plain-HTTP `OAC_PUBLIC_URL` for development and testing. TLS certificate verification stays on |
| `OAC_HOST` | `127.0.0.1` | Address published by `ports.yaml`. `install.sh` sets `0.0.0.0` |
| `OAC_WEB_PORT` | `8080` | Host port of Web |
| `COMPOSE_FILE` | `compose.yaml:ports.yaml` | The Compose files. `ports.yaml` publishes Web and Core's loopback admin API; hosting platforms omit it |
Expand Down Expand Up @@ -154,7 +157,7 @@ Core 只读取其环境。Compose 把 `.env` 插值进服务环境。Compose 必
| `OAC_CREDENTIAL_KEY_FILE` | `data/secrets/core/credential.key` |
| `OAC_CORE_KEY_DIGESTS_FILE` | `data/secrets/core/core-key-digests.json`:一个包含 Core 密钥 SHA-256 的 JSON 数组 |
| `OAC_INSTALLATION_ID_FILE` | `data/secrets/core/installation.id`:安装 ID,采用规范 UUID 格式。它会启用沙箱部署和节点路由,并要求设置 `OAC_PUBLIC_URL` 和 `OAC_CORE_KEY_DIGESTS_FILE`。如果 ID 与数据库记录的 ID 不一致,Core 会拒绝它,因此必须将两者一同保留 |
| `OAC_EXECUTION_CONCURRENCY`、`OAC_DEFAULT_HARNESS`、`OAC_HARNESSES`、`OAC_WRITE_AUDIT_RETENTION`、`OAC_OAUTH_TRUSTED_ORIGINS` | 对应的[进程设置](#settings)。`oac-core check-config` 会在不启动 Core 的情况下校验它们 |
| `OAC_EXECUTION_CONCURRENCY`、`OAC_DEFAULT_HARNESS`、`OAC_HARNESSES`、`OAC_WRITE_AUDIT_RETENTION`、`OAC_OAUTH_TRUSTED_ORIGINS`、`OAC_ALLOW_INSECURE_ORIGIN` | 对应的[进程设置](#settings)。`oac-core check-config` 会在不启动 Core 的情况下校验它们 |
| `OAC_HISTORY_SETTINGS_FILE` | 可选的 Runtime 历史文件。敏感;安装报告只说明它是否已设置 |
| `OAC_LOG_LEVEL`、`OAC_LOG_FORMAT`、`OAC_LOG_ADD_SOURCE` | `log.*`;Web 也读取这三个设置 |
| `OAC_PROVIDER_ROOT` | 适配器构件的绝对根目录。Core 镜像设置为 `/opt/oac`。每个适配器都拥有此根目录下的辅助路径 |
Expand Down
7 changes: 5 additions & 2 deletions docs/zh/getting-started/install-options.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "安装选项与高级部署"
source: docs/getting-started/install-options.md
source_hash: f9a5aae96ce8789030eda5cb399eac7c2e6bc6bd4d9bcce18138373c97cb0e96
source_hash: 53468efe866d0774ec60d015eb6c168dd5ae5170f6b7af0c1505a63e32362d11
---

[默认安装](install.md)无需任何选项。使用本页可以在现有反向代理后运行,或者在无法访问互联网时进行安装。
Expand Down Expand Up @@ -55,9 +55,12 @@ docker compose -f compose.yaml exec web oac-web core-key
| Flag | `.env` variable |
| --- | --- |
| `--public-url` | `OAC_PUBLIC_URL` |
| `--allow-insecure-origin` | `OAC_ALLOW_INSECURE_ORIGIN` |
| `--host` | `OAC_HOST` |
| `--web-port` | `OAC_WEB_PORT` |

`--allow-insecure-origin` 允许开发和测试使用非回环的明文 HTTP `--public-url`。默认关闭;TLS 证书校验保持不变。

## 安装操作 {#installation-actions}

`--install-dir` 选择安装目录。它不是进程设置。
Expand All @@ -76,7 +79,7 @@ docker compose -f compose.yaml exec web oac-web core-key

默认安装在 `--host 0.0.0.0` 的 `--web-port`(8080)上发布 Web。Core 的管理 API 留在 `127.0.0.1:8091`。PostgreSQL 保持私有。`--host` 是不含端口、协议或区域的 IPv4 或 IPv6 地址。请在浏览器中使用服务器的具体 IP,而不是通配地址。

`--public-url` 设置 `OAC_PUBLIC_URL`,即应用、节点和执行器使用的源地址。把它设为反向代理提供的 HTTPS 源地址。
`--public-url` 设置 `OAC_PUBLIC_URL`,即应用、节点和执行器使用的源地址。把它设为反向代理提供的 HTTPS 源地址。非回环的 `http://` 源地址需要 `--allow-insecure-origin`;回环地址不需要。

### 端口 {#ports}

Expand Down
Loading