bastion 0.55.3
ci / personal-data (push) Successful in 5s
ci / test (push) Successful in 3m51s
ci / fuzz (push) Successful in 2m55s

This commit is contained in:
Privatae
2026-10-25 23:16:45 +00:00
parent 77b7853ae1
commit 8822d5df85
136 changed files with 8638 additions and 1641 deletions
+55 -20
View File
@@ -1,14 +1,22 @@
# privatae-bastion
[![License: GPL v3+](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg)](LICENSE)
[![Go 1.25+](https://img.shields.io/badge/go-1.25%2B-00ADD8.svg)](client-go/go.mod)
[![Go 1.26+](https://img.shields.io/badge/go-1.26%2B-00ADD8.svg)](client-go/go.mod)
[![Platforms](https://img.shields.io/badge/platforms-linux%20%7C%20macOS%20%7C%20windows-lightgrey.svg)](#supported-platforms)
[![ci](https://git.privatae.ai/privatae/privatae-bastion/actions/workflows/ci.yml/badge.svg?branch=main)](https://git.privatae.ai/privatae/privatae-bastion/actions)
**One static Go binary that gives your AI Host access to a machine without SSH keys: it dials out, checks every signed grant on the machine itself, and keeps its own audit log.**
No Docker, no Python, no database, no separate WireGuard install. You pair the
binary with a short token from your host, and from then on your host can reach
The bastion itself needs no Docker, no Python, no database and no separate
WireGuard install. A few optional features use software the machine must
already have: coder runs, the service slot and the memory mirror need a
container runtime (Docker, Podman or nerdctl); folder search runs the bastion
agent, which needs Python 3.8 or later; host-written ops in Python need
`/usr/bin/python3`; and reading an app's accessibility tree on Linux needs
python3 with its AT-SPI bindings. Without them, those features say what is
missing and the rest works.
You pair the binary with a short token from your host, and from then on your host can reach
this machine only through the tunnel this bastion dials out and the lanes it
gates. Your files stay where they are. Nothing on this machine drives the host:
there is no MCP endpoint here.
@@ -261,14 +269,15 @@ Each point in full: [docs/security-model.md](docs/security-model.md); the link a
- **Egress for someone else reaches the public internet, never this
machine**: a coder run's proxy and an anchored machine's egress lane refuse
internal addresses and this machine's own (a coder run reaches a LAN host
you named). A local machine's egress lane vets no destination, and an address
that reaches this machine only through a 1:1 NAT is not covered. ([full text](docs/security-model.md))
you named). A local machine's egress lane refuses this machine and keeps
your LAN. An address that reaches this machine only through a 1:1 NAT is
not covered. ([full text](docs/security-model.md))
- **A terminal is checked here and logged.** On a local machine it opens when
the host asks; on an anchored one each needs an approval for that session;
a root terminal needs a code entered here. ([session lane](docs/lanes.md#session-lane))
- **Root commands run only under a grant given here with the code**, to the
anchor host, until the time you chose; a revoke or expiry stops a running
command within 2 seconds. ([session lane](docs/lanes.md#session-lane))
anchor host, until the time you chose and at most 30 days; a revoke or
expiry stops a running command within 2 seconds. ([session lane](docs/lanes.md#session-lane))
- **Root only where there is no one else to ask**: claiming ownership or the
anchor. ([modes](#local-and-networked-modes))
- **On macOS and Windows, a networked bastion is the system's service**, which
@@ -295,15 +304,20 @@ To report a security issue, please do not open a public issue. See
Every security claim names the test that fails if it stops being true, and
says where there is none. The full table is one file,
[docs/claims.md](docs/claims.md); `deploy/check-claims.sh` checks that every
test it cites exists in `client-go`.
test it cites exists in `client-go`. On GitHub, CI also runs every cited test
as root on the runner's own virtual machine, where the sandbox and namespace
tests a container cannot run do run, and fails if any of them skips.
## How this repo is published
Development happens in a private repository. This repository receives the
source of each published release as one snapshot commit, tagged
`v<version>`, with the tree identical to the commit the signed release
manifest names as `built_from`. Every binary can be rebuilt from the tag and
compared with the published one: see [Verify a release](#verify-a-release).
Development happens in a private repository, and its history is not
published. When a release is published, each change merged since the last one
arrives on GitHub as a commit with the same files, titled as the change was
and dated when it was merged; the copy at git.privatae.ai receives the release
as one commit. In both, the release is tagged `v<version>` on a commit whose
tree is identical to the commit the signed release manifest names as
`built_from`. Every binary can be rebuilt from the tag and compared with the
published one: see [Verify a release](#verify-a-release).
Issues and pull requests are welcome on GitHub, at
[github.com/Privatae/bastion](https://github.com/Privatae/bastion). An
@@ -326,7 +340,7 @@ rather than faked.
## Build from source
Requires Go 1.25 or newer. The binary is pure Go and builds with `cgo` off.
Requires Go 1.26 or newer (`client-go/go.mod`). The binary is pure Go and builds with `cgo` off.
```sh
git clone https://git.privatae.ai/privatae/privatae-bastion.git
@@ -358,8 +372,8 @@ It checks the release manifest's signature against the keys pinned in
`client-go/release_sign.go`, checks out the release's source, rebuilds it, and
compares every binary's sha256 with the published one.
From this release on, each public snapshot in this repository carries the tag
`v<version>` (for example `v0.43.0`). The manifest's `built_from` names the
Each published release in this repository carries the tag `v<version>` (for
example `v0.54.1`). The manifest's `built_from` names the
commit in the repository the release was built in, which is not a commit here,
so the script checks out the tag `v<version>` for the version the manifest
names, and prints which source it used. The tag is annotated and its message
@@ -372,8 +386,26 @@ bytes.
If the published version has no tag in your clone, the script says so and
stops without building. If it cannot fetch tags, it says that instead.
Releases from 0.43.0 on can be checked this way from a clone of this
repository.
Releases from 0.53.2 on can be checked this way from a clone of this
repository; the tags of earlier releases are not in it.
Each release on GitHub carries the six binaries, the signed manifest
`version.json`, its signature `version.json.<first 16 hex of its sha256>.sig`
and `SHA256SUMS`. The release workflow (`.github/workflows/release.yml`)
attaches them only after `deploy/release-assets.sh` has rebuilt the binaries
from the tag and the published signature has verified against the manifest
written from them, so they are the same bytes the installer and the
self-updater fetch. To check a download yourself, compare its sha256 with the
manifest's, and check the manifest's signature against the keys this source
pins (needs Go):
```sh
cd deploy/release-sign
go run . verify bastion <dir>/version.json <dir>/version.json.<…>.sig $(go run . pinned ../../client-go/release_sign.go)
```
`deploy/release-assets.sh v<version> <dir>` does all of it from a clone,
rebuild included, for any release from 0.53.2 on.
## Contributing
@@ -397,8 +429,11 @@ version 3 or (at your option) any later version. See [LICENSE](LICENSE).
Copyright Privatae LLC.
You may run it, read it, change it and redistribute it under that license. The
Privatae platform the bastion connects to is separate, proprietary software and
is not covered by this license.
Host the bastion connects to is separate software and is not covered by this
license: a C-Series Host is [Privatae/cseries](https://github.com/Privatae/cseries),
under AGPL-3.0-only, and a Host on Privatae's own platform is proprietary
software. See [SECURITY.md](SECURITY.md#what-you-still-have-to-trust) for what
the bastion holds each to.
The local console vendors [htmx](https://htmx.org) 2.0.10
(`client-go/uiassets/htmx.min.js`), which is distributed under the Zero-Clause