ci and compose update
This commit is contained in:
+1
-2
@@ -1,10 +1,10 @@
|
|||||||
GITEA_NETWORK=gitea
|
GITEA_NETWORK=gitea
|
||||||
|
AGENTCI_IMAGE=git.krtss.de/stanponomarev/agentci:latest
|
||||||
AGENTCI_GITEA_URL=http://gitea:3000
|
AGENTCI_GITEA_URL=http://gitea:3000
|
||||||
AGENTCI_BOT_USERNAME=agentci
|
AGENTCI_BOT_USERNAME=agentci
|
||||||
AGENTCI_BOT_NAME=Agent CI
|
AGENTCI_BOT_NAME=Agent CI
|
||||||
AGENTCI_BOT_EMAIL=agentci@localhost
|
AGENTCI_BOT_EMAIL=agentci@localhost
|
||||||
OPENCODE_SERVER_USERNAME=opencode
|
OPENCODE_SERVER_USERNAME=opencode
|
||||||
AGENTCI_OPENCODE_VERSION=^1
|
|
||||||
AGENTCI_PLAN_MODEL=openai/gpt-5.6-sol
|
AGENTCI_PLAN_MODEL=openai/gpt-5.6-sol
|
||||||
AGENTCI_PLAN_VARIANT=
|
AGENTCI_PLAN_VARIANT=
|
||||||
AGENTCI_IMPLEMENT_MODEL=openai/gpt-5.6-sol
|
AGENTCI_IMPLEMENT_MODEL=openai/gpt-5.6-sol
|
||||||
@@ -24,4 +24,3 @@ AGENTCI_INSTALL_SCRIPTS=
|
|||||||
AGENTCI_INSTALL_SCRIPT_TIMEOUT_SECONDS=900
|
AGENTCI_INSTALL_SCRIPT_TIMEOUT_SECONDS=900
|
||||||
AGENTCI_PYTHON_VERSION=3.13
|
AGENTCI_PYTHON_VERSION=3.13
|
||||||
AGENTCI_DOTNET_CHANNEL=10.0
|
AGENTCI_DOTNET_CHANNEL=10.0
|
||||||
CODEGRAPH_VERSION=1.3.1
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: Publish container image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: git.krtss.de
|
||||||
|
IMAGE_NAME: git.krtss.de/stanponomarev/agentci
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: Build and push
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out repository
|
||||||
|
uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||||
|
|
||||||
|
- name: Log in to Gitea registry
|
||||||
|
uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
uses: https://github.com/docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
pull: true
|
||||||
|
tags: |
|
||||||
|
${{ env.IMAGE_NAME }}:latest
|
||||||
|
${{ env.IMAGE_NAME }}:${{ gitea.sha }}
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.revision=${{ gitea.sha }}
|
||||||
|
org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
|
||||||
@@ -46,10 +46,11 @@ recreated.
|
|||||||
OpenCode models.
|
OpenCode models.
|
||||||
3. Create `secrets/gitea_token`, `secrets/webhook_secret`, and
|
3. Create `secrets/gitea_token`, `secrets/webhook_secret`, and
|
||||||
`secrets/opencode_server_password`. Use high-entropy values for both secret/password files.
|
`secrets/opencode_server_password`. Use high-entropy values for both secret/password files.
|
||||||
4. Build the image:
|
4. Log in to the Gitea container registry with a personal access token, then pull the image:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker compose build
|
docker login git.krtss.de
|
||||||
|
docker compose pull
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Authenticate the configured OpenCode providers before starting the persistent server:
|
5. Authenticate the configured OpenCode providers before starting the persistent server:
|
||||||
@@ -75,6 +76,22 @@ deployment, run the one-off `auth login` command above and then `docker compose
|
|||||||
healthy and every configured model exists, supports tool calls, accepts its configured variant, and
|
healthy and every configured model exists, supports tool calls, accepts its configured variant, and
|
||||||
has a connected provider. The worker leaves jobs queued while the runtime is unavailable.
|
has a connected provider. The worker leaves jobs queued while the runtime is unavailable.
|
||||||
|
|
||||||
|
### Image publishing
|
||||||
|
|
||||||
|
Every push to `master` runs `.gitea/workflows/publish-image.yaml` and publishes the image as both
|
||||||
|
`git.krtss.de/stanponomarev/agentci:latest` and
|
||||||
|
`git.krtss.de/stanponomarev/agentci:<full-commit-sha>`. Configure these repository Actions secrets
|
||||||
|
before the first run:
|
||||||
|
|
||||||
|
| Secret | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| `REGISTRY_USERNAME` | Username that owns the package or can write packages for the owner. |
|
||||||
|
| `REGISTRY_TOKEN` | Personal access token with package write permission. |
|
||||||
|
|
||||||
|
The automatic Gitea Actions token cannot publish packages. Compose uses `latest` by default; set
|
||||||
|
`AGENTCI_IMAGE=git.krtss.de/stanponomarev/agentci:<full-commit-sha>` in `.env` to deploy an immutable
|
||||||
|
revision.
|
||||||
|
|
||||||
## OpenCode
|
## OpenCode
|
||||||
|
|
||||||
Models use OpenCode's `provider/model` format. Planning, implementation, and research can use
|
Models use OpenCode's `provider/model` format. Planning, implementation, and research can use
|
||||||
@@ -84,10 +101,11 @@ configures the research subagent and defaults to `high`. `AGENTCI_EXPLORE_MODEL`
|
|||||||
`AGENTCI_EXPLORE_VARIANT` configure OpenCode's explore agent and default to
|
`AGENTCI_EXPLORE_VARIANT` configure OpenCode's explore agent and default to
|
||||||
`openai/gpt-5.6-luna` with `low`.
|
`openai/gpt-5.6-luna` with `low`.
|
||||||
|
|
||||||
`AGENTCI_OPENCODE_VERSION` controls the npm version or range installed into the image and defaults
|
The `AGENTCI_OPENCODE_VERSION` Docker build argument controls the npm version or range installed into
|
||||||
to `^1`. The build verifies that the resolved version is still OpenCode 1.x and prints it. Docker
|
the image and defaults to `^1`. The build verifies that the resolved version is still OpenCode 1.x
|
||||||
may reuse the cached installation layer until the configured version or build inputs change.
|
and prints it. Docker may reuse the cached installation layer until the configured version or build
|
||||||
Runtime auto-update is disabled so an image cannot cross into OpenCode 2.x after it is built.
|
inputs change. Runtime auto-update is disabled so an image cannot cross into OpenCode 2.x after it
|
||||||
|
is built.
|
||||||
|
|
||||||
The trusted configuration is `opencode/opencode.json`. OpenCode's default global and built-in-agent
|
The trusted configuration is `opencode/opencode.json`. OpenCode's default global and built-in-agent
|
||||||
permission policies remain in effect; Agent CI does not replace them with an allow-all policy.
|
permission policies remain in effect; Agent CI does not replace them with an allow-all policy.
|
||||||
@@ -172,7 +190,6 @@ uv run pyright
|
|||||||
uv run pytest
|
uv run pytest
|
||||||
uv run pytest --cov=agentci --cov-branch
|
uv run pytest --cov=agentci --cov-branch
|
||||||
docker compose config
|
docker compose config
|
||||||
docker compose build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The coverage command is an opt-in diagnostic report; the regular test run remains the default and
|
The coverage command is an opt-in diagnostic report; the regular test run remains the default and
|
||||||
|
|||||||
+5
-15
@@ -1,12 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
agentci:
|
agentci:
|
||||||
image: agentci:local
|
image: ${AGENTCI_IMAGE:-git.krtss.de/stanponomarev/agentci:latest}
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
args:
|
|
||||||
AGENTCI_OPENCODE_VERSION: ${AGENTCI_OPENCODE_VERSION:-^1}
|
|
||||||
CODEGRAPH_VERSION: ${CODEGRAPH_VERSION:-1.3.1}
|
|
||||||
TEA_VERSION: ${TEA_VERSION:-0.14.2}
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
opencode:
|
opencode:
|
||||||
@@ -39,7 +33,7 @@ services:
|
|||||||
- webhook_secret
|
- webhook_secret
|
||||||
- opencode_server_password
|
- opencode_server_password
|
||||||
volumes:
|
volumes:
|
||||||
- agentci_data:/var/lib/agentci
|
- ./data/agentci:/var/lib/agentci
|
||||||
- ./install-scripts:/etc/agentci/install-scripts:ro
|
- ./install-scripts:/etc/agentci/install-scripts:ro
|
||||||
tmpfs:
|
tmpfs:
|
||||||
- /run/agentci:mode=1777
|
- /run/agentci:mode=1777
|
||||||
@@ -50,7 +44,7 @@ services:
|
|||||||
- agentci_control
|
- agentci_control
|
||||||
|
|
||||||
opencode:
|
opencode:
|
||||||
image: agentci:local
|
image: ${AGENTCI_IMAGE:-git.krtss.de/stanponomarev/agentci:latest}
|
||||||
command: ["opencode", "serve", "--hostname", "0.0.0.0", "--port", "4096"]
|
command: ["opencode", "serve", "--hostname", "0.0.0.0", "--port", "4096"]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
@@ -81,8 +75,8 @@ services:
|
|||||||
- gitea_token
|
- gitea_token
|
||||||
- opencode_server_password
|
- opencode_server_password
|
||||||
volumes:
|
volumes:
|
||||||
- agentci_data:/var/lib/agentci
|
- ./data/agentci:/var/lib/agentci
|
||||||
- opencode_home:/var/lib/opencode
|
- ./data/opencode:/var/lib/opencode
|
||||||
tmpfs:
|
tmpfs:
|
||||||
- /run/agentci:mode=1777
|
- /run/agentci:mode=1777
|
||||||
expose:
|
expose:
|
||||||
@@ -105,10 +99,6 @@ secrets:
|
|||||||
opencode_server_password:
|
opencode_server_password:
|
||||||
file: ./secrets/opencode_server_password
|
file: ./secrets/opencode_server_password
|
||||||
|
|
||||||
volumes:
|
|
||||||
agentci_data:
|
|
||||||
opencode_home:
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
gitea:
|
gitea:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -126,11 +126,10 @@ def test_compose_services_have_expected_runtime_contract() -> None:
|
|||||||
"4096",
|
"4096",
|
||||||
]
|
]
|
||||||
|
|
||||||
build = _section(agentci, "build")
|
image = "${AGENTCI_IMAGE:-git.krtss.de/stanponomarev/agentci:latest}"
|
||||||
assert _mapping(build, "args", indent=6)["AGENTCI_OPENCODE_VERSION"] == (
|
assert _scalar(agentci, "image") == image
|
||||||
"${AGENTCI_OPENCODE_VERSION:-^1}"
|
assert _scalar(opencode, "image") == image
|
||||||
)
|
assert all(line.strip() != "build:" for line in [*agentci, *opencode])
|
||||||
assert all("no_cache" not in line for line in build)
|
|
||||||
|
|
||||||
dependency = _section(_section(agentci, "depends_on"), "opencode", indent=6)
|
dependency = _section(_section(agentci, "depends_on"), "opencode", indent=6)
|
||||||
assert _mapping([" dependency:", *dependency], "dependency", indent=6) == {
|
assert _mapping([" dependency:", *dependency], "dependency", indent=6) == {
|
||||||
@@ -157,6 +156,20 @@ def test_compose_has_no_sandbox_security_exceptions() -> None:
|
|||||||
assert forbidden not in compose
|
assert forbidden not in compose
|
||||||
|
|
||||||
|
|
||||||
|
def test_gitea_workflow_publishes_master_images() -> None:
|
||||||
|
lines = (ROOT / ".gitea" / "workflows" / "publish-image.yaml").read_text().splitlines()
|
||||||
|
push = _section(_section(lines, "on", indent=0), "push", indent=2)
|
||||||
|
|
||||||
|
assert _sequence(push, "branches", indent=4) == ["master"]
|
||||||
|
assert _mapping(lines, "env", indent=0)["IMAGE_NAME"] == (
|
||||||
|
"git.krtss.de/stanponomarev/agentci"
|
||||||
|
)
|
||||||
|
assert " ${{ env.IMAGE_NAME }}:latest" in lines
|
||||||
|
assert " ${{ env.IMAGE_NAME }}:${{ gitea.sha }}" in lines
|
||||||
|
assert " username: ${{ secrets.REGISTRY_USERNAME }}" in lines
|
||||||
|
assert " password: ${{ secrets.REGISTRY_TOKEN }}" in lines
|
||||||
|
|
||||||
|
|
||||||
def test_container_pins_opencode_major_version_contract() -> None:
|
def test_container_pins_opencode_major_version_contract() -> None:
|
||||||
lines = [line.strip() for line in (ROOT / "Dockerfile").read_text().splitlines()]
|
lines = [line.strip() for line in (ROOT / "Dockerfile").read_text().splitlines()]
|
||||||
build_arguments = {line.removeprefix("ARG ") for line in lines if line.startswith("ARG ")}
|
build_arguments = {line.removeprefix("ARG ") for line in lines if line.startswith("ARG ")}
|
||||||
|
|||||||
Reference in New Issue
Block a user