From 7bbea5946f3be2d51f783744dcf6df0557b05f0c Mon Sep 17 00:00:00 2001 From: sprooty Date: Fri, 11 Sep 2026 08:59:30 +0000 Subject: [PATCH 1/4] chore(release): bump product version to 0.7.0 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01RTSDrvA1SAhWJ5du1e1BKb --- .github/workflows/build.yml | 8 ++++---- mobile/package.json | 2 +- pyproject.toml | 2 +- src/vogt/__init__.py | 2 +- web/package.json | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a9b25b64..70eda02e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -416,7 +416,7 @@ jobs: build-args: | VOGT_SOURCE_REF=main VOGT_SOURCE_SHA=${{ github.sha }} - VOGT_PRODUCT_VERSION=0.6.2 + VOGT_PRODUCT_VERSION=0.7.0 cache-from: | type=registry,ref=${{ env.CACHE_IMAGE }}:stack-main type=registry,ref=${{ env.CACHE_IMAGE }}:demo-main @@ -532,7 +532,7 @@ jobs: build-args: | VOGT_SOURCE_REF=main VOGT_SOURCE_SHA=${{ github.sha }} - VOGT_PRODUCT_VERSION=0.6.2 + VOGT_PRODUCT_VERSION=0.7.0 provenance: true sbom: true cache-from: | @@ -666,7 +666,7 @@ jobs: CORE_IMAGE=${{ env.IMAGE }}@${{ needs.image.outputs.digest }} VOGT_SOURCE_REF=${{ github.ref_name }} VOGT_SOURCE_SHA=${{ github.sha }} - VOGT_PRODUCT_VERSION=0.6.2 + VOGT_PRODUCT_VERSION=0.7.0 INSTALL_AI_CLIENTS=true # Layer cache on the operator's registry, its own tag so the # stack and core streams cannot evict each other. @@ -716,7 +716,7 @@ jobs: CORE_IMAGE=${{ env.IMAGE }}@${{ needs.image.outputs.digest }} VOGT_SOURCE_REF=${{ github.ref_name }} VOGT_SOURCE_SHA=${{ github.sha }} - VOGT_PRODUCT_VERSION=0.6.2 + VOGT_PRODUCT_VERSION=0.7.0 INSTALL_AI_CLIENTS=true provenance: true sbom: true diff --git a/mobile/package.json b/mobile/package.json index 4029111e..8898fc90 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -1,6 +1,6 @@ { "name": "vogt-mobile", - "version": "0.6.2", + "version": "0.7.0", "license": "AGPL-3.0-only", "private": true, "type": "module", diff --git a/pyproject.toml b/pyproject.toml index a0eae102..2e355ac1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "vogt" -version = "0.6.2" +version = "0.7.0" description = "A product development environment for the AI era" readme = "README.md" requires-python = ">=3.11" diff --git a/src/vogt/__init__.py b/src/vogt/__init__.py index 7317cb86..f96bea0a 100644 --- a/src/vogt/__init__.py +++ b/src/vogt/__init__.py @@ -2,6 +2,6 @@ from __future__ import annotations -__version__ = "0.6.2" +__version__ = "0.7.0" __all__ = ["__version__"] diff --git a/web/package.json b/web/package.json index c50329c1..30f9a899 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "vogt-web", - "version": "0.6.2", + "version": "0.7.0", "license": "AGPL-3.0-only", "private": true, "type": "module", From 2027bdc5551be954cc4ee86753475b762db7eeb9 Mon Sep 17 00:00:00 2001 From: sprooty Date: Fri, 11 Sep 2026 08:59:30 +0000 Subject: [PATCH 2/4] chore(release): relock uv.lock for 0.7.0 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01RTSDrvA1SAhWJ5du1e1BKb --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index f5de5b51..332ed7b8 100644 --- a/uv.lock +++ b/uv.lock @@ -995,7 +995,7 @@ wheels = [ [[package]] name = "vogt" -version = "0.6.2" +version = "0.7.0" source = { editable = "." } dependencies = [ { name = "cryptography" }, From af572a7a9e3c95b9d571e9d891325614e9376017 Mon Sep 17 00:00:00 2001 From: sprooty Date: Fri, 11 Sep 2026 08:59:30 +0000 Subject: [PATCH 3/4] chore(release): bump remaining 0.6.2 pins to 0.7.0 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01RTSDrvA1SAhWJ5du1e1BKb --- .github/workflows/ci.yml | 2 +- deploy/.env.example | 2 +- deploy/engine.overlay.yml | 2 +- deploy/examples/custom-stack/Dockerfile | 2 +- deploy/stack.compose.yml | 4 ++-- deploy/vogt.compose.yml | 2 +- docs/CUSTOMISATION.md | 2 +- docs/DEPLOYMENT.md | 10 +++++----- scripts/clean_consumer_smoke.sh | 2 +- tests/test_product_version.py | 4 ++-- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f96d37f1..12c7a24e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -188,7 +188,7 @@ jobs: - run: uv sync --locked - name: canonical product version is aligned - run: uv run --no-sync python scripts/check_product_version.py 0.6.2 + run: uv run --no-sync python scripts/check_product_version.py 0.7.0 - name: ruff (lint) run: uv run --no-sync ruff check . diff --git a/deploy/.env.example b/deploy/.env.example index 788253c8..4adeb0cc 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -22,7 +22,7 @@ VOGT_BIND_IP=127.0.0.1 # The image to run. Pin a digest in anything you would call a deployment. # Ignored when you add deploy/vogt.build.yml, which builds from the checkout. -# VOGT_IMAGE=ghcr.io/thedancingdeveloper-org/vogt:0.6.2 +# VOGT_IMAGE=ghcr.io/thedancingdeveloper-org/vogt:0.7.0 # The uid the container runs as. The gid is always 0 — that is what makes the # data directory writable at any uid. Set this to whoever owns the files this diff --git a/deploy/engine.overlay.yml b/deploy/engine.overlay.yml index a3e592f7..d5dbebb3 100644 --- a/deploy/engine.overlay.yml +++ b/deploy/engine.overlay.yml @@ -61,7 +61,7 @@ services: # container carries both halves. Defaults to the same public image the # base would run, so the embedded core matches it; pin a digest for a # real deployment. The Dockerfile already carries a public default too. - CORE_IMAGE: "${VOGT_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt:0.6.2}" + CORE_IMAGE: "${VOGT_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt:0.7.0}" # Optional image-managed agent CLIs. When enabled, versions come from # engine/agent-versions.env unless an operator deliberately overrides # one with a reproducible build arg. diff --git a/deploy/examples/custom-stack/Dockerfile b/deploy/examples/custom-stack/Dockerfile index 8cf6c853..4f7a00dd 100644 --- a/deploy/examples/custom-stack/Dockerfile +++ b/deploy/examples/custom-stack/Dockerfile @@ -17,7 +17,7 @@ # it is validating; the default is a real published digest so the file builds # as-is. Resolve the current one with: # -# docker buildx imagetools inspect ghcr.io/thedancingdeveloper-org/vogt-stack:0.6.2 +# docker buildx imagetools inspect ghcr.io/thedancingdeveloper-org/vogt-stack:0.7.0 # ARG STACK_IMAGE=ghcr.io/thedancingdeveloper-org/vogt-stack@sha256:31cda6daa29442d37d128d1bb10959ddf5cc7128a3e443ecde3f6ef1ea0616b0 FROM ${STACK_IMAGE} diff --git a/deploy/stack.compose.yml b/deploy/stack.compose.yml index 336cfa1e..5ec0f5ab 100644 --- a/deploy/stack.compose.yml +++ b/deploy/stack.compose.yml @@ -43,7 +43,7 @@ services: # `prod-` tags in the same repository are the maintainer's own pods: # same CLIs, plus estate integrations that address one estate's # infrastructure and mean nothing outside it. See DEPLOYMENT.md. - image: ${VOGT_STACK_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt-stack:0.6.2} + image: ${VOGT_STACK_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt-stack:0.7.0} restart: unless-stopped # tini as PID 1 reaps the processes agent sessions leave behind. The @@ -225,7 +225,7 @@ services: # Digest-pin this for a real deployment, exactly as the stack # image above. Pin the release family (`X.Y.Z`, `latest`); the default is a # tag so the file is runnable as-is. - image: ${VOGT_VOICE_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt-voice:0.6.2} + image: ${VOGT_VOICE_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt-voice:0.7.0} restart: unless-stopped # It only reads its baked models and writes audio to tmpfs, so it can run # locked down even though the pod beside it cannot. diff --git a/deploy/vogt.compose.yml b/deploy/vogt.compose.yml index 0801ef61..0939d3f0 100644 --- a/deploy/vogt.compose.yml +++ b/deploy/vogt.compose.yml @@ -29,7 +29,7 @@ services: # digest — publishing an image and moving a deployment are separate acts, # and a digest is the only form of "which image is this" a # rebuild cannot silently change. - image: ${VOGT_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt:0.6.2} + image: ${VOGT_IMAGE:-ghcr.io/thedancingdeveloper-org/vogt:0.7.0} restart: unless-stopped # The image runs as any uid so long as the gid is 0: `/var/lib/vogt` is diff --git a/docs/CUSTOMISATION.md b/docs/CUSTOMISATION.md index f59e846b..89e952d8 100644 --- a/docs/CUSTOMISATION.md +++ b/docs/CUSTOMISATION.md @@ -381,7 +381,7 @@ pattern: a Dockerfile a few lines long that starts `FROM` the published `vogt-stack` digest and adds what your sessions need. Keep it in your fork, build it in your CI, deploy it by digest. -The core image (`ghcr.io/thedancingdeveloper-org/vogt:0.6.2`) is a build +The core image (`ghcr.io/thedancingdeveloper-org/vogt:0.7.0`) is a build input to the stack image rather than something to deploy on its own. It is also built to be a base — `USER root`, install, `USER 1000:0`, keeping `ENTRYPOINT ["vogt"]` and the `root:0`-owned data directory — so extend it diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index d05951a6..29133b24 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -41,7 +41,7 @@ sidecar, released as a pair and run by one Compose file, on by default (`COMPOSE_PROFILES=voice`). The engine is not optional: it is the only way in. The core image, -`ghcr.io/thedancingdeveloper-org/vogt:0.6.2`, is also published at every +`ghcr.io/thedancingdeveloper-org/vogt:0.7.0`, is also published at every release because the stack image is built from it by digest and the release manifest records both — it is a build input, not a deployment target. `deploy/vogt.compose.yml` and `deploy/engine.overlay.yml` run a core and an @@ -105,8 +105,8 @@ Everything an operator chooses lives in `deploy/.env`, read by | `ENGINE_BIND` | no | `127.0.0.1` | Host interface the port is published on. Loopback until you mean to expose it. | | `ENGINE_PORT` | no | `8910` | Host port the container's 8910 is published on. | | `ENGINE_PUBLIC_URL` | no | — | The URL clients reach the stack at. Set it once there is a stable one (§4). | -| `VOGT_STACK_IMAGE` | no | `ghcr.io/thedancingdeveloper-org/vogt-stack:0.6.2` | The image to run. Pin a digest (§6). | -| `VOGT_VOICE_IMAGE` | no | `ghcr.io/thedancingdeveloper-org/vogt-voice:0.6.2` | The sidecar. Pin the same release as the stack. | +| `VOGT_STACK_IMAGE` | no | `ghcr.io/thedancingdeveloper-org/vogt-stack:0.7.0` | The image to run. Pin a digest (§6). | +| `VOGT_VOICE_IMAGE` | no | `ghcr.io/thedancingdeveloper-org/vogt-voice:0.7.0` | The sidecar. Pin the same release as the stack. | | `COMPOSE_PROFILES` | no | `voice` | Clear it to run without the sidecar; the voice controls stay present but inert. | | `VOGT_BOOTSTRAP_CORE_TOKEN_ACTOR` | no | `agent:engine` | Who the adopted core token acts as. | | `VOGT_BOOTSTRAP_CORE_TOKEN_SCOPES` | no | `read,work.write,project.write` | What it may do. Everything in the pod can read the file, so this is the blast radius. | @@ -301,9 +301,9 @@ a deployment are separate acts, and the digest line is what moves one. Resolve the digests of a release: ```console -docker buildx imagetools inspect ghcr.io/thedancingdeveloper-org/vogt-stack:0.6.2 \ +docker buildx imagetools inspect ghcr.io/thedancingdeveloper-org/vogt-stack:0.7.0 \ | grep -m 1 Digest -docker buildx imagetools inspect ghcr.io/thedancingdeveloper-org/vogt-voice:0.6.2 \ +docker buildx imagetools inspect ghcr.io/thedancingdeveloper-org/vogt-voice:0.7.0 \ | grep -m 1 Digest ``` diff --git a/scripts/clean_consumer_smoke.sh b/scripts/clean_consumer_smoke.sh index 25864e24..b0cef50a 100755 --- a/scripts/clean_consumer_smoke.sh +++ b/scripts/clean_consumer_smoke.sh @@ -4,7 +4,7 @@ # credential, no knowledge of the maintainer estate. # # scripts/clean_consumer_smoke.sh -# VOGT_STACK_IMAGE=…/vogt-stack:0.6.2 VOGT_VOICE_IMAGE=…/vogt-voice:0.6.2 \ +# VOGT_STACK_IMAGE=…/vogt-stack:0.7.0 VOGT_VOICE_IMAGE=…/vogt-voice:0.7.0 \ # scripts/clean_consumer_smoke.sh # # It differs from `e2e_stack_smoke.sh` (which walks a *running* stack somebody diff --git a/tests/test_product_version.py b/tests/test_product_version.py index 4f38daf0..de7a049f 100644 --- a/tests/test_product_version.py +++ b/tests/test_product_version.py @@ -16,7 +16,7 @@ def test_product_version_contract_is_in_sync() -> None: result = subprocess.run( - [sys.executable, "scripts/check_product_version.py", "0.6.2"], + [sys.executable, "scripts/check_product_version.py", "0.7.0"], cwd=ROOT, capture_output=True, text=True, @@ -28,6 +28,6 @@ def test_product_version_contract_is_in_sync() -> None: def test_android_version_name_is_derived_from_the_canonical_mobile_manifest() -> None: package = (ROOT / "mobile/package.json").read_text(encoding="utf-8") gradle = (ROOT / "mobile/android/app/build.gradle").read_text(encoding="utf-8") - assert '"version": "0.6.2"' in package + assert '"version": "0.7.0"' in package assert "new JsonSlurper().parse(file('../../package.json'))" in gradle assert "versionName androidVersionName" in gradle From 20979e98d6b3db914c5e9a85f667c7790ffa291f Mon Sep 17 00:00:00 2001 From: sprooty Date: Fri, 11 Sep 2026 08:59:30 +0000 Subject: [PATCH 4/4] chore(security): enable Dependabot and scheduled security-alert triage Add .github/dependabot.yml (weekly pip/npm/cargo/docker/actions updates) and a scheduled security-alert-triage workflow that opens one labelled security issue per open Dependabot/CodeQL alert, keyed by a stable marker so reruns update rather than duplicate. Document both, plus the required-check and Advanced Security settings to enable, in SECURITY.md. Complements the dependency-review workflow already on main. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01RTSDrvA1SAhWJ5du1e1BKb --- .github/dependabot.yml | 31 +++++++++++++++++ .github/workflows/security-alerts.yml | 49 +++++++++++++++++++++++++++ SECURITY.md | 29 ++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/security-alerts.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..dba2a58f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 +updates: + - package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + - package-ecosystem: npm + directory: "/web" + schedule: + interval: weekly + - package-ecosystem: npm + directory: "/mobile" + schedule: + interval: weekly + - package-ecosystem: cargo + directory: "/engine" + schedule: + interval: weekly + - package-ecosystem: cargo + directory: "/voice" + schedule: + interval: weekly + - package-ecosystem: docker + directory: "/" + schedule: + interval: weekly + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly diff --git a/.github/workflows/security-alerts.yml b/.github/workflows/security-alerts.yml new file mode 100644 index 00000000..2d1b5e53 --- /dev/null +++ b/.github/workflows/security-alerts.yml @@ -0,0 +1,49 @@ +name: security alert triage + +on: + schedule: + - cron: "17 4 * * *" + workflow_dispatch: + +permissions: + contents: read + issues: write + security-events: read + +jobs: + triage: + name: track open security alerts + runs-on: [self-hosted] + steps: + - name: create or update tracking issues + env: + GH_TOKEN: ${{ github.token }} + REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + api="repos/$REPOSITORY" + alerts="$(gh api --paginate "$api/dependabot/alerts?state=open" 2>/dev/null || printf '[]')" + codeql="$(gh api --paginate "$api/code-scanning/alerts?state=open" 2>/dev/null || printf '[]')" + create_issue() { + local marker="$1" title="$2" body="$3" + if ! gh issue list --state open --search "in:body $marker" --json number --jq 'length' | grep -q '^0$'; then return; fi + gh issue create --title "$title" --body "$body" --label security + } + while IFS=$'\t' read -r number summary; do + [ -n "$number" ] || continue + marker="" + create_issue "$marker" "Security alert: $summary" "$marker + + Dependabot alert **#$number** is open. Review the advisory, affected dependency, and remediation PR; close this issue after verification. + + Source: GitHub Dependabot alerts." + done < <(printf '%s' "$alerts" | jq -r '.[] | [(.number|tostring), (.security_advisory.summary // .dependency.package.name)] | @tsv') + while IFS=$'\t' read -r number rule; do + [ -n "$number" ] || continue + marker="" + create_issue "$marker" "CodeQL alert: $rule" "$marker + + CodeQL alert **#$number** is open. Triage the finding, record the disposition, and close this issue once fixed or documented. + + Source: GitHub code scanning alerts." + done < <(printf '%s' "$codeql" | jq -r '.[] | [(.number|tostring), (.rule.description // .rule.id)] | @tsv') diff --git a/SECURITY.md b/SECURITY.md index 830cb456..10eba0ee 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -80,6 +80,35 @@ of scope unless you can show real impact. ## CI and self-hosted runners +### Automated dependency and code scanning + +GitHub dependency graph and Dependabot security updates are enabled for every +manifest Vogt ships (`.github/dependabot.yml`). Pull requests run the +`dependency review` workflow, which blocks a change introducing a high or +critical severity dependency advisory. CodeQL scans Python, TypeScript, +JavaScript, and Rust on pull requests, pushes to `main`, and weekly. + +The scheduled `security alert triage` workflow reads open Dependabot and +CodeQL alerts and creates one labelled `security` issue per alert. The issue +contains the alert number as a stable marker, so reruns update the queue +without creating duplicates. Maintainers record remediation or disposition in +that issue before closing it. + +After enabling these workflows, configure repository Settings → Rules → Rulesets +(or branch protection for `main`) with these required checks: + +- `ci` +- `dependency review` +- `analyze (python)` +- `analyze (javascript-typescript)` +- `analyze (rust)` +- `runner-policy` + +Also enable **Dependency graph**, **Dependabot alerts**, and **Dependabot +security updates** under Settings → Advanced Security. These are repository +settings and therefore cannot be represented in tracked files; verify them +after a repository transfer or visibility change. + This is a public repository, and `pull_request`-triggered jobs run on the project's self-hosted runner pool (`ci.yml`, `codeql.yml`, `runner-policy.yml`, `docs.yml`, `mirror-base-images.yml`). Those jobs run