Skip to content

Commit 68e9d91

Browse files
authored
Merge pull request #492 from thevibeworks/feat/cloak-456
feat(cloak): -p cloak stealth-browser profile, auth sessions, non-gating release
2 parents eb98123 + d8ce2e7 commit 68e9d91

22 files changed

Lines changed: 1051 additions & 32 deletions

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ compose.yaml
3131

3232
# References directory (don't need in image)
3333
references/
34+
reference/
3435

3536
# Claude trace logs
3637
.claude-trace/

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ jobs:
169169
set -euo pipefail
170170
./scripts/test-install-agent-tooling.sh
171171
172+
- name: Smoke image/tag precedence
173+
shell: bash
174+
run: |
175+
set -euo pipefail
176+
./scripts/test-image-precedence.sh
177+
172178
- name: Smoke kimi auth wiring
173179
shell: bash
174180
run: |

.github/workflows/cloak-image.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Cloak Image
2+
3+
# Paths-filtered on purpose: the cloak build bakes a ~200MB Chromium binary,
4+
# too heavy for every PR. Nightly also skips cloak deliberately — it only
5+
# refreshes agent CLI versions, none of which live in the cloak layer.
6+
# Release builds and pushes the real :cloak tag.
7+
on:
8+
pull_request:
9+
branches: [ main ]
10+
paths:
11+
- "Dockerfile.cloak"
12+
- "scripts/cloak-entrypoint.sh"
13+
- "versions.env"
14+
- ".github/workflows/cloak-image.yml"
15+
push:
16+
branches: [ main ]
17+
paths:
18+
- "Dockerfile.cloak"
19+
- "scripts/cloak-entrypoint.sh"
20+
- "versions.env"
21+
- ".github/workflows/cloak-image.yml"
22+
23+
jobs:
24+
build-and-test:
25+
name: Build and Test Cloak Image
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
31+
- name: Load pinned versions
32+
id: pins
33+
shell: bash
34+
run: |
35+
set -euo pipefail
36+
source ./scripts/version-pins.sh
37+
load_version_pins
38+
emit_github_outputs "$GITHUB_OUTPUT"
39+
40+
# Build on top of the published rust image: this validates the cloak
41+
# layer itself without rebuilding the whole base/rust stack in CI.
42+
- name: Build cloak image
43+
run: |
44+
make build-cloak-image \
45+
IMAGE_NAME=deva-smoke \
46+
CLOAK_TAG=ci-cloak \
47+
RUST_IMAGE=ghcr.io/thevibeworks/deva:rust \
48+
CLOAKBROWSER_WRAPPER_VERSION="${{ steps.pins.outputs.cloakbrowser_wrapper_version }}"
49+
50+
- name: Test cloak image
51+
run: |
52+
make test-cloak \
53+
IMAGE_NAME=deva-smoke \
54+
CLOAK_TAG=ci-cloak

.github/workflows/release.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ jobs:
5555
ccx_version: ${{ steps.pins.outputs.ccx_version }}
5656
copilot_api_version: ${{ steps.pins.outputs.copilot_api_version }}
5757
playwright_version: ${{ steps.pins.outputs.playwright_version }}
58+
cloakbrowser_wrapper_version: ${{ steps.pins.outputs.cloakbrowser_wrapper_version }}
5859
rust_toolchains: ${{ steps.pins.outputs.rust_toolchains }}
5960
rust_default_toolchain: ${{ steps.pins.outputs.rust_default_toolchain }}
6061
rust_targets: ${{ steps.pins.outputs.rust_targets }}
@@ -216,6 +217,63 @@ jobs:
216217
RUST_DEFAULT_TOOLCHAIN=${{ needs.load-version-pins.outputs.rust_default_toolchain }}
217218
RUST_TARGETS=${{ needs.load-version-pins.outputs.rust_targets }}
218219
220+
# Optional, non-gating: the cloak layer bakes a ~200MB Chromium per arch
221+
# (arm64 under QEMU), holds no agent CLIs, and changes only when
222+
# Dockerfile.cloak / cloak-entrypoint.sh / CLOAKBROWSER_WRAPPER_VERSION move
223+
# -- not on a deva.sh version bump. The GitHub Release must not be hostage to
224+
# it, so `release` does not wait on this job and a failure here does not fail
225+
# the release. Re-run this job alone to publish a missing -cloak tag.
226+
build-and-push-cloak:
227+
name: Build and Push Cloak Profile Image
228+
runs-on: ubuntu-latest
229+
needs: [prepare, load-version-pins, build-and-push-rust]
230+
continue-on-error: true
231+
permissions:
232+
contents: read
233+
packages: write
234+
steps:
235+
- name: Checkout
236+
uses: actions/checkout@v4
237+
with:
238+
ref: ${{ needs.prepare.outputs.release_tag }}
239+
240+
- name: Set up QEMU
241+
uses: docker/setup-qemu-action@v3
242+
243+
- name: Set up Docker Buildx
244+
uses: docker/setup-buildx-action@v3
245+
246+
- name: Log in to Container Registry
247+
uses: docker/login-action@v3
248+
with:
249+
registry: ${{ env.REGISTRY }}
250+
username: ${{ github.actor }}
251+
password: ${{ secrets.GITHUB_TOKEN }}
252+
253+
- name: Extract metadata for cloak profile
254+
id: meta-cloak
255+
uses: docker/metadata-action@v5
256+
with:
257+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
258+
tags: |
259+
type=raw,value=${{ needs.prepare.outputs.release_tag }}-cloak
260+
type=raw,value=cloak
261+
262+
- name: Build and push cloak image
263+
uses: docker/build-push-action@v5
264+
with:
265+
context: .
266+
file: ./Dockerfile.cloak
267+
platforms: linux/amd64,linux/arm64
268+
push: true
269+
tags: ${{ steps.meta-cloak.outputs.tags }}
270+
labels: ${{ steps.meta-cloak.outputs.labels }}
271+
cache-from: type=gha
272+
cache-to: type=gha,mode=max
273+
build-args: |
274+
BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.release_tag }}-rust
275+
CLOAKBROWSER_WRAPPER_VERSION=${{ needs.load-version-pins.outputs.cloakbrowser_wrapper_version }}
276+
219277
release:
220278
name: Create GitHub Release
221279
runs-on: ubuntu-latest
@@ -258,6 +316,10 @@ jobs:
258316
echo "- \`ghcr.io/${{ env.IMAGE_NAME }}:${RELEASE_TAG}-rust\`" >> release_notes.md
259317
echo "- \`ghcr.io/${{ env.IMAGE_NAME }}:rust\`" >> release_notes.md
260318
echo "" >> release_notes.md
319+
echo "**Cloak Profile (CloakBrowser stealth Chromium, headed) - optional:**" >> release_notes.md
320+
echo "- \`ghcr.io/${{ env.IMAGE_NAME }}:cloak\`" >> release_notes.md
321+
echo "- \`ghcr.io/${{ env.IMAGE_NAME }}:${RELEASE_TAG}-cloak\` (published when the non-gating cloak build finishes; it may lag this release)" >> release_notes.md
322+
echo "" >> release_notes.md
261323
echo "## Supported Architectures" >> release_notes.md
262324
echo "" >> release_notes.md
263325
echo "- linux/amd64" >> release_notes.md

AGENTS.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ runtime is Linux.
1919
- $HOME is /home/deva (not /root). sudo works without password.
2020
- Pre-installed: Node.js, Python (use `uv`, not pip), Go, git,
2121
gh, make, curl. pip is NOT in PATH.
22-
- Docker is available (socket mounted from host).
23-
- System packages and build caches persist across sessions.
22+
- Ephemeral container. Installed packages will not persist.
2423
- Container details are in DEVA_* environment variables.
2524
<!-- /deva:container-context -->

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
Makefile, Dockerfile(+rust), version-pins/upgrade/update scripts,
2424
ci/nightly/release workflows; tests added (release-utils registry,
2525
version-upgrade mock, install-tooling, and `test-kimi-auth.sh`).
26+
- cloak authenticated-session support (#456): composable pieces for logging
27+
into sites inside the stealth browser. The session persists via a host
28+
profile dir (`~/.config/deva/cloak-profile` -> Chromium `userDataDir`,
29+
auto-mounted for either path below) so a login done once survives container
30+
removal.
31+
- Interactive login over VNC: on OrbStack/native Linux the host reaches the
32+
container directly, so the agent starts `x11vnc` on the `:99` display on
33+
demand and you connect at the container IP -- no flag, no port publish.
34+
- `--cloak-vnc` (`DEVA_CLOAK_VNC=1`): Docker-Desktop fallback that publishes
35+
the VNC display on a host-loopback port (there the container IP is not
36+
routable). Auto-generates a VNC password (printed once) unless
37+
`DEVA_CLOAK_VNC_PASSWORD` is set; the published port is fixed at container
38+
create. Independent of `--cloak-browser`.
39+
- `--cloak-browser` (`DEVA_CLOAK_BROWSER=1`): an always-on CloakBrowser
40+
daemon (`cloak-browserd`) holds one headed, persistent browser on the
41+
cloak display with a loopback CDP endpoint. The agent drives it via
42+
`connectOverCDP(CLOAK_CDP_ENDPOINT)` -- the same live browser, not a
43+
throwaway. Starts post-UID-remap in docker-entrypoint so profile files
44+
match the mounted host owner.
45+
Documented in the `deva-cloak` skill.
46+
- cloak profile (#456): `deva.sh -p cloak <agent>` runs agents in a new
47+
image (`Dockerfile.cloak`, extends `:rust`) with CloakBrowser stealth
48+
Chromium, headed on Xvfb `:99` + openbox. The Chromium binary is baked
49+
at build time (hermetic, auto-update off); `CLOAKBROWSER_WRAPPER_VERSION`
50+
in versions.env pins the wrapper and thereby Chromium. Ships the
51+
`deva-cloak` skill (keyed off `DEVA_CLOAK=1`), `make build-cloak` /
52+
`test-cloak` targets, a paths-filtered `cloak-image.yml` CI workflow,
53+
and release pushes `:cloak` / `:vX.Y.Z-cloak` tags. cloak is an auxiliary
54+
image on its own cadence: nightly skips it (that layer holds no agent
55+
CLIs) and the release cloak job is non-gating (`continue-on-error`, not
56+
in the `release` job's `needs`) — a ~200MB Chromium bake per arch must
57+
never hold the GitHub Release hostage.
2658

2759
### Fixed
2860
- `--trace` launch killed by `cp: cannot create regular file
@@ -37,6 +69,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3769
test became the subshell's exit status and `set -e` killed every
3870
non-verbose traced launch right after the banner; the subshell now
3971
exits 0 explicitly.
72+
- image/tag precedence: a `.deva` config file setting `DEVA_DOCKER_TAG`
73+
(or `DEVA_DOCKER_IMAGE`) silently overrode the real environment and made
74+
CLI `-p` a no-op — `deva.sh -p cloak` with a config `DEVA_DOCKER_TAG=rust`
75+
launched rust, and even `DEVA_DOCKER_TAG=cloak deva.sh ...` was clobbered
76+
back to the config value. Precedence is now environment > config files >
77+
`-p` profile > default, with explicit CLI `-p` beating a config-file tag.
78+
Guarded by `scripts/test-image-precedence.sh` in CI.
4079

4180
## [0.16.0] - 2026-07-14
4281

0 commit comments

Comments
 (0)