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
80 changes: 48 additions & 32 deletions .github/RELEASE_NOTES_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,64 @@
# agentcookie {{VERSION}}
# agentcookie v1.0.0

Closed-beta release. Invitation only.
Continuous Mac to Linux cookie sync over Tailscale. Your agent runtime wakes up logged in.

## Install
## Highlights

Download `agentcookie-{{VERSION}}-darwin-arm64.tar.gz` from the assets below, then:
- **Mac to Linux sync**: Your Mac's Chrome sessions flow to a Linux agent runtime (Grok Bot, cloud VM, homelab server) via live CDP injection over Tailscale
- **Live CDP injection**: Cookies go directly into Chrome's in-memory store via `Storage.setCookies` - no SQLite write, no Keychain, no libsecret
- **Extra Chrome profile discovery**: Mac profiles (Profile 1, Profile 2, etc.) are auto-discovered and decrypted; extra-profile cookies flow to sidecar, adapters, and live CDP alongside Default profile cookies
- **Tailscale-only transport**: AES-256-GCM sealed envelopes over your tailnet's WireGuard channel
- **Security-by-default**: Linux sinks with missing policy ship nothing; explicit `policy: blocklist` required for sync-all

```
tar -xzf agentcookie-{{VERSION}}-darwin-arm64.tar.gz
cd agentcookie-{{VERSION}}-darwin-arm64
./install-beta.sh --as source # on your MacBook
# or
./install-beta.sh --as sink # on your second Mac
```
## Install

See `quickstart-beta.md` inside the tarball for the ten-minute walkthrough.
Download from the assets below and verify against `checksums.txt`:

## Verifying the binary
| Platform | Archive |
|----------|---------|
| macOS arm64 | `agentcookie_1.0.0_darwin_arm64.tar.gz` |
| Linux amd64 | `agentcookie_1.0.0_linux_amd64.tar.gz` |
| Linux arm64 | `agentcookie_1.0.0_linux_arm64.tar.gz` |

```
codesign --verify --strict --verbose=2 agentcookie
# expected: valid on disk / satisfies its Designated Requirement
```bash
# On Mac
curl -LO https://github.com/mvanhorn/agentcookie/releases/download/v1.0.0/agentcookie_1.0.0_darwin_arm64.tar.gz
curl -LO https://github.com/mvanhorn/agentcookie/releases/download/v1.0.0/checksums.txt
shasum -a 256 -c checksums.txt --ignore-missing
tar -xzf agentcookie_1.0.0_darwin_arm64.tar.gz
sudo mv agentcookie /usr/local/bin/

codesign -d -r- agentcookie
# expected: identifier "agentcookie" ... certificate leaf[subject.OU] = NM8VT393AR
# On Linux
curl -LO https://github.com/mvanhorn/agentcookie/releases/download/v1.0.0/agentcookie_1.0.0_linux_amd64.tar.gz
sha256sum -c checksums.txt --ignore-missing
tar -xzf agentcookie_1.0.0_linux_amd64.tar.gz
Comment on lines +31 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Linux checksum manifest is missing

When a Linux user follows these commands in a clean directory, sha256sum references a checksums.txt file that was never downloaded, causing the documented verification step to fail.

Suggested change
# On Linux
curl -LO https://github.com/mvanhorn/agentcookie/releases/download/v1.0.0/agentcookie_1.0.0_linux_amd64.tar.gz
sha256sum -c checksums.txt --ignore-missing
tar -xzf agentcookie_1.0.0_linux_amd64.tar.gz
# On Linux
curl -LO https://github.com/mvanhorn/agentcookie/releases/download/v1.0.0/agentcookie_1.0.0_linux_amd64.tar.gz
curl -LO https://github.com/mvanhorn/agentcookie/releases/download/v1.0.0/checksums.txt
sha256sum -c checksums.txt --ignore-missing
tar -xzf agentcookie_1.0.0_linux_amd64.tar.gz

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

sudo mv agentcookie /usr/local/bin/
```

`spctl -a` is the wrong assessment tool for this CLI binary - it
expects an app bundle and reports "rejected: not an app" even when
the binary is correctly signed and notarized. Use the `codesign`
commands above instead. The notarization ticket is verified by
Apple's notary service on first launch.
Or build from source: `go install github.com/mvanhorn/agentcookie/cmd/agentcookie@v1.0.0`

## What's in this release
See the [README](https://github.com/mvanhorn/agentcookie/blob/main/README.md) for the full how-to.

{{CHANGELOG_BODY}}
## Honest limits

- **Linux SQLite write is 0**: Expected. Success is the `live_cdp: injected N cookies into M context(s)` line.
- **Omitted policy ships nothing**: On Linux, missing `blocklist.yaml` or omitted `policy:` means allowlist-empty. Write `policy: blocklist` with `domains: []` for sync-all on a trusted box.
- **Google/DBSC cookies**: Need local sign-in on the sink. Copied cookies expire in minutes.
- **Linux extra-profile SQLite stays unread**: Discovery and doctor/status name stores, but Chrome SQLite decryption requires macOS Keychain (no libsecret). Sidecar/plaintext and live CDP remain the Linux path.
- **CDP port is loopback-only**: Same-user processes can attach to `127.0.0.1:9223` and read injected cookies. This is the same-user trust boundary.
- **Cookie values never logged**: Cookie values do not appear in logs or doctor output.

## Security

## Known limits (closed beta)
- Tailscale 100.x bind required on Linux sinks; refuses to start on 0.0.0.0
- AES-256-GCM sealed envelopes with pairing-derived 32-byte keys
- Per-IP rate limiting on the pair endpoint (5 attempts before 429)
- Persistent replay defense via sequence tracking

- macOS only on both ends (Linux and Windows sinks are on the roadmap).
- Plaintext sidecar at rest is the default. Sealed sidecar infrastructure is wired up but off until U12 PP CLI migration ships in cli-printing-press.
- No live key rotation. To rotate, re-run `agentcookie wizard install` on both sides.
- eBay sessions are fingerprint-bound at the server side; expect `ebay-pp-cli` to fail authentication regardless of sync state.
## Support

## Reporting issues
Run `agentcookie doctor --json` on both machines and include the output when reporting issues.

DM the person who invited you. Include the output of `agentcookie doctor --json`.
## What's in this release

{{CHANGELOG_BODY}}
141 changes: 83 additions & 58 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,60 +9,66 @@ permissions:
contents: write

jobs:
goreleaser:
# Build Linux binaries on Ubuntu using .goreleaser.linux.yaml
build-linux:
runs-on: ubuntu-latest
if: ${{ vars.RELEASE_CI_ENABLED == 'true' }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

# Install cross-compiler for arm64
- name: install arm64 cross-compiler
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu

# Use goreleaser with the linux-specific config
- name: goreleaser linux
uses: goreleaser/goreleaser-action@v6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security Release actions use mutable tags

The new Linux build and artifact-transfer steps execute actions through mutable major-version tags in a release workflow with contents: write; an upstream tag change can alter the release build or assets without a repository change, and the GoReleaser action receives the repository token. Pin these new action references to immutable commit SHAs. How this was verified: The added GoReleaser step uses @v6 with GITHUB_TOKEN, while the workflow grants contents: write.

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

with:
distribution: goreleaser
version: "~> v2"
args: release --clean --config .goreleaser.linux.yaml --skip=publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: upload linux artifacts
uses: actions/upload-artifact@v4
with:
name: linux-binaries
path: dist/*.tar.gz

# Build darwin binaries on macOS (codesigning requires macOS)
build-darwin:
runs-on: macos-latest
# Skip the entire job when the signing secrets aren't configured.
# Releases are cut locally by the maintainer until CERTIFICATE_OSX_APPLICATION
# and AC_NOTARY_PASSWORD are populated; without this guard `make release`
# would fail on every tag and pollute the CI history.
if: ${{ vars.RELEASE_CI_ENABLED == 'true' }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-go@v5
with:
go-version: "1.24"
go-version-file: go.mod
cache: true

# Import the Developer ID Application certificate into a temporary
# keychain so codesign can find it. The .p12 bundle and its password
# are repo secrets. The action creates an ephemeral keychain, unlocks
# it, and adds it to the search list for the rest of the job.
#
# To enable CI-driven releases, the maintainer must add the following
# GitHub Actions secrets and set the `RELEASE_CI_ENABLED` repo variable
# to `true` (the job-level `if:` above gates on the variable):
# - CERTIFICATE_OSX_APPLICATION : base64-encoded .p12 of the
# Developer ID Application cert + private key
# - CERTIFICATE_OSX_APPLICATION_PASSWORD : password for the .p12
# - AC_NOTARY_PASSWORD : app-specific password for Apple notarytool
# The matching cert is Common Name
# "Developer ID Application: Matthew Charles Van Horn (NM8VT393AR)"
# See docs/runbook-v0.12-codesign.md for the export / renewal flow.
# Until the variable is flipped, releases are cut locally with
# `make release` + scripts/release-tarball.sh + `gh release create`.
- name: import Developer ID cert
if: ${{ secrets.CERTIFICATE_OSX_APPLICATION != '' }}
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
p12-password: ${{ secrets.CERTIFICATE_OSX_APPLICATION_PASSWORD }}

# Sanity: print which codesigning identities are visible to this
# runner. On a properly configured release this lists the Developer
# ID Application identity NM8VT393AR. If the secret is unset, the
# list will be empty and goreleaser's signing post-hook will fail
# fast with the runbook pointer.
- name: list codesigning identities
run: security find-identity -v -p codesigning

# Store the notarytool credentials in the runner's login keychain.
# The maintainer generates an app-specific password at
# appleid.apple.com and saves it as the AC_NOTARY_PASSWORD secret.
# See docs/runbook-v0.12-codesign.md "Notarization" for the
# one-time setup steps. Without this step, scripts/notarize.sh
# below would fail with a "credentials not found" error.
- name: setup notarytool credentials
if: ${{ secrets.AC_NOTARY_PASSWORD != '' }}
run: |
Expand All @@ -71,38 +77,57 @@ jobs:
--team-id NM8VT393AR \
--password "${{ secrets.AC_NOTARY_PASSWORD }}"

# Build, sign, notarize the agentcookie binary. After this step
# bin/agentcookie is fully launchable on any Mac without
# Gatekeeper interactive approval.
- name: make release
run: make release

# Bundle the notarized binary + install-beta.sh + quickstart into
# a single tarball friends can extract and run.
- name: build release tarball
run: scripts/release-tarball.sh "${{ github.ref_name }}"

# GoReleaser also runs to publish the standard cross-platform
# archives and the GitHub release entry with notes. It uses the
# signed bin/agentcookie produced above.
- name: goreleaser
uses: goreleaser/goreleaser-action@v6
- name: upload darwin artifacts
uses: actions/upload-artifact@v4
with:
distribution: goreleaser
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AGENTCOOKIE_SIGN_IDENTITY: "Developer ID Application: Matthew Charles Van Horn (NM8VT393AR)"
name: darwin-binaries
path: dist/*.tar.gz

# Publish release after both builds complete
publish:
runs-on: ubuntu-latest
needs: [build-linux, build-darwin]
if: ${{ vars.RELEASE_CI_ENABLED == 'true' }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: download linux artifacts
uses: actions/download-artifact@v4
with:
name: linux-binaries
path: dist/

- name: download darwin artifacts
uses: actions/download-artifact@v4
with:
name: darwin-binaries
path: dist/

- name: list artifacts
run: ls -la dist/

# Generate checksums for all archives
- name: generate checksums
run: |
cd dist
sha256sum *.tar.gz > checksums.txt
cat checksums.txt

# Attach the closed-beta bundle tarball to the GitHub release
# that goreleaser just created. The bundle is the install-script-
# consumable shape; goreleaser's own archives are the
# cross-platform binary archives.
- name: attach beta bundle to release
# Create the GitHub release with all assets
- name: create release
run: |
gh release upload "${{ github.ref_name }}" \
dist/agentcookie-*-darwin-arm64.tar.gz \
--clobber
gh release create "${{ github.ref_name }}" \
dist/*.tar.gz \
dist/checksums.txt \
--title "agentcookie ${{ github.ref_name }}" \
--generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Comment on lines +129 to 133

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Release template is bypassed

When a release tag is published, gh release create --generate-notes generates notes from GitHub metadata and never consumes .github/RELEASE_NOTES_TEMPLATE.md, causing the v1.0 release to omit the installation, security, and operational guidance prepared by this PR.

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

65 changes: 65 additions & 0 deletions .goreleaser.linux.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
version: 2

project_name: agentcookie

before:
hooks:
- go mod tidy

builds:
# Linux amd64 build: runs on ubuntu-latest with default gcc
- id: agentcookie-linux-amd64
main: ./cmd/agentcookie
binary: agentcookie
env:
- CGO_ENABLED=1
goos:
- linux
goarch:
- amd64
ldflags:
- -s -w -X github.com/mvanhorn/agentcookie/internal/cli.Version={{ .Version }}

# Linux arm64 build: runs on ubuntu-latest with cross-compiler
- id: agentcookie-linux-arm64
main: ./cmd/agentcookie
binary: agentcookie
env:
- CGO_ENABLED=1
- CC=aarch64-linux-gnu-gcc
goos:
- linux
goarch:
- arm64
ldflags:
- -s -w -X github.com/mvanhorn/agentcookie/internal/cli.Version={{ .Version }}

archives:
- id: agentcookie-linux
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files:
- LICENSE
- README.md
- docs/quickstart.md
- docs/threat-model.md
- docs/architecture.md
- docs/protocol.md
- docs/faq.md
- examples/source.yaml
- examples/sink.yaml
- examples/blocklist.yaml

checksum:
name_template: checksums.txt

snapshot:
version_template: "{{ incpatch .Version }}-next"

changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
- "^chore:"
- merge
7 changes: 2 additions & 5 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ before:
- go mod tidy

builds:
- id: agentcookie
# Darwin build: runs on macos-latest, codesigned
- id: agentcookie-darwin
main: ./cmd/agentcookie
binary: agentcookie
env:
Expand All @@ -19,10 +20,6 @@ builds:
- amd64
ldflags:
- -s -w -X github.com/mvanhorn/agentcookie/internal/cli.Version={{ .Version }}
# Sign each darwin binary in place before it is archived. Uses
# scripts/sign.sh so the local + release pipelines share one
# codesign invocation. AGENTCOOKIE_SIGN_IDENTITY is set by the
# release workflow (and defaults inside scripts/sign.sh if unset).
hooks:
post:
- cmd: scripts/sign.sh {{ .Path }}
Expand Down
Loading
Loading